From 6d6b4a3d0adf36f336285b102754a62bc26c284d Mon Sep 17 00:00:00 2001 From: Niki Zadeh Date: Tue, 6 Jan 2015 16:16:11 -0500 Subject: [PATCH 001/361] Merge updates from diomond brnach since riga - Diamond development branch has updates that were missed to come to releases since siena. - These do not change answers if not turned on. - Bug fix for bilin function. Turn it on by old_bug_bilin = .false. it is off by default to reproduce answers. - Adding grounding_fraction and clipping_depth parameters. - Adding optional argument to pass ocean depth. - Adding some new diagnostics. - Adding some checksums and functional unit test. --- icebergs.F90 | 54 +++++++++++++++++++------- icebergs_framework.F90 | 88 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 118 insertions(+), 24 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 51f8a80..2569967 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -26,7 +26,7 @@ module ice_bergs use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell -use ice_bergs_framework, only: nclasses +use ice_bergs_framework, only: nclasses,old_bug_bilin use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory @@ -69,17 +69,19 @@ module ice_bergs subroutine icebergs_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, ocean_depth, maskmap) ! Arguments type(icebergs), pointer :: bergs integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) -logical, intent(in), optional :: maskmap(:,:) integer, intent(in) :: dom_x_flags, dom_y_flags real, intent(in) :: dt type (time_type), intent(in) :: Time ! current time real, dimension(:,:), intent(in) :: ice_lon, ice_lat, ice_wet real, dimension(:,:), intent(in) :: ice_dx, ice_dy, ice_area real, dimension(:,:), intent(in) :: cos_rot, sin_rot +real, dimension(:,:), intent(in), optional :: ocean_depth +logical, intent(in), optional :: maskmap(:,:) + integer :: stdlogunit, stderrunit ! Get the stderr and stdlog unit numbers @@ -90,7 +92,7 @@ subroutine icebergs_init(bergs, & call ice_bergs_framework_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, ocean_depth=ocean_depth, maskmap=maskmap) call mpp_clock_begin(bergs%clock_ior) call ice_bergs_io_init(bergs,io_layout) @@ -402,7 +404,7 @@ subroutine thermodynamics(bergs) type(icebergs_gridded), pointer :: grd real :: M, T, W, L, SST, Vol, Ln, Wn, Tn, nVol, IC, Dn real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv -real :: Mnew, Mnew1, Mnew2 +real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb integer :: i,j, stderrunit type(iceberg), pointer :: this, next @@ -541,6 +543,7 @@ subroutine thermodynamics(bergs) T=Tn Tn=Wn Wn=T + Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) for grounding end if endif @@ -565,8 +568,13 @@ subroutine thermodynamics(bergs) & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 - if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling) + if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then + if (bergs%grounding_fraction>0.) then + Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) + if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) + endif + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling) + endif endif this=>next @@ -584,8 +592,13 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR + real, parameter :: rho_seawater=1035. Mass=(Mberg+Mbits)*scaling + ! This line attempts to "clip" the weight felt by the ocean. The concept of + ! clipping is non-physical and this step should be replaced by grounding. + if (grd%clipping_depth>0.) Mass=min(Mass,grd%clipping_depth*grd%area(i,j)*rho_seawater) + xL=min(0.5, max(0., 0.5-x)) xR=min(0.5, max(0., x-0.5)) xC=max(0., 1.-(xL+xR)) @@ -631,7 +644,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, real :: hxm, hxp real, parameter :: ssh_coast=0.00 - cos_rot=bilin(grd, grd%cos, i, j, xi, yj) + cos_rot=bilin(grd, grd%cos, i, j, xi, yj) ! If true, uses the inverted bilin function sin_rot=bilin(grd, grd%sin, i, j, xi, yj) uo=bilin(grd, grd%uo, i, j, xi, yj) @@ -991,6 +1004,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_stored_ice, grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) if (grd%id_real_calving>0) & lerr=send_data(grd%id_real_calving, grd%real_calving(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) + if (grd%id_ssh>0) & + lerr=send_data(grd%id_ssh, grd%ssh(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_fax>0) & + lerr=send_data(grd%id_fax, tauxa(:,:), Time) + if (grd%id_fay>0) & + lerr=send_data(grd%id_fay, tauya(:,:), Time) + ! Dump icebergs to screen if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_run, status') @@ -1231,14 +1251,16 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass) +subroutine icebergs_incr_mass(bergs, mass, Time) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass +type(time_type), intent(in), optional :: Time ! Local variables integer :: i, j type(icebergs_gridded), pointer :: grd real :: dmda +logical :: lerr if (.not. associated(bergs)) return @@ -1256,8 +1278,8 @@ subroutine icebergs_incr_mass(bergs, mass) if (debug) then - bergs%grd%tmp(:,:)=0.; bergs%grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass - call grd_chksum2(bergs%grd, bergs%grd%tmp, 'mass in (incr)') + grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass + call grd_chksum2(grd, grd%tmp, 'mass in (incr)') endif call mpp_update_domains(grd%mass_on_ocean, grd%domain) @@ -1283,12 +1305,15 @@ subroutine icebergs_incr_mass(bergs, mass) + (grd%mass_on_ocean(i ,j-1,8)+grd%mass_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda + if (grd%id_mass_on_ocn>0) grd%tmp(i,j)=dmda enddo; enddo + if (present(Time).and. (grd%id_mass_on_ocn>0)) & + lerr=send_data(grd%id_mass_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (debug) then - call grd_chksum3(bergs%grd, bergs%grd%mass_on_ocean, 'mass bergs (incr)') - bergs%grd%tmp(:,:)=0.; bergs%grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass - call grd_chksum2(bergs%grd, bergs%grd%tmp, 'mass out (incr)') + grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass + call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') + call grd_chksum2(grd, grd%tmp, 'mass out (incr)') endif call mpp_clock_end(bergs%clock_int) @@ -2162,6 +2187,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%msk) deallocate(bergs%grd%cos) deallocate(bergs%grd%sin) + deallocate(bergs%grd%ocean_depth) deallocate(bergs%grd%calving) deallocate(bergs%grd%calving_hflx) deallocate(bergs%grd%stored_heat) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3988990..b94c42c 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -33,15 +33,16 @@ module ice_bergs_framework logical :: use_roundoff_fix=.true. ! Use a "fix" for the round-off discrepancy between is_point_in_cell() and pos_within_cell() logical :: old_bug_rotated_weights=.false. ! Skip the rotation of off-center weights for rotated halo updates logical :: make_calving_reproduce=.false. ! Make the calving.res.nc file reproduce across pe count changes. +logical :: old_bug_bilin=.true. ! If true, uses the inverted bilin function (use False to get correct answer) character(len=10) :: restart_input_dir = 'INPUT/' integer, parameter :: delta_buf=25 ! Size by which to increment buffers real, parameter :: pi_180=pi/180. ! Converts degrees to radians logical :: fix_restart_dates=.true. ! After a restart, check that bergs were created before the current model date - +logical :: do_unit_tests=.false. ! Conduct some unit tests !Public params !Niki: write a subroutine to expose these public nclasses,buffer_width,buffer_width_traj -public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,use_roundoff_fix +public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,old_bug_bilin,use_roundoff_fix public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget public orig_read @@ -81,6 +82,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: msk=>null() ! Ocean-land mask (1=ocean) real, dimension(:,:), pointer :: cos=>null() ! Cosine from rotation matrix to lat-lon coords real, dimension(:,:), pointer :: sin=>null() ! Sine from rotation matrix to lat-lon coords + real, dimension(:,:), pointer :: ocean_depth=>NULL() ! Depth of ocean (m) real, dimension(:,:), pointer :: uo=>null() ! Ocean zonal flow (m/s) real, dimension(:,:), pointer :: vo=>null() ! Ocean meridional flow (m/s) real, dimension(:,:), pointer :: ui=>null() ! Ice zonal flow (m/s) @@ -118,6 +120,10 @@ module ice_bergs_framework integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 + integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1 + + real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. + end type icebergs_gridded type :: xyt @@ -158,7 +164,7 @@ module ice_bergs_framework integer :: traj_sample_hrs integer :: verbose_hrs integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers - real :: rho_bergs ! Density of icebergs + real :: rho_bergs ! Density of icebergs [kg/m^3] real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0null(), ibuffer_n=>null() type(buffer), pointer :: obuffer_s=>null(), ibuffer_s=>null() type(buffer), pointer :: obuffer_e=>null(), ibuffer_e=>null() @@ -212,7 +219,7 @@ module ice_bergs_framework subroutine ice_bergs_framework_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, ocean_depth, maskmap) use mpp_parameter_mod, only: SCALAR_PAIR, CGRID_NE, BGRID_NE, CORNER, AGRID use mpp_domains_mod, only: mpp_update_domains, mpp_define_domains @@ -233,13 +240,15 @@ subroutine ice_bergs_framework_init(bergs, & ! Arguments type(icebergs), pointer :: bergs integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) -logical, intent(in), optional :: maskmap(:,:) integer, intent(in) :: dom_x_flags, dom_y_flags real, intent(in) :: dt type (time_type), intent(in) :: Time ! current time real, dimension(:,:), intent(in) :: ice_lon, ice_lat, ice_wet real, dimension(:,:), intent(in) :: ice_dx, ice_dy, ice_area real, dimension(:,:), intent(in) :: cos_rot, sin_rot +real, dimension(:,:), intent(in),optional :: ocean_depth +logical, intent(in), optional :: maskmap(:,:) + ! Namelist parameters (and defaults) integer :: halo=4 ! Width of halo region integer :: traj_sample_hrs=24 ! Period between sampling of position for trajectory storage @@ -253,6 +262,8 @@ subroutine ice_bergs_framework_init(bergs, & logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean real :: speed_limit=0. ! CFL speed limit for a berg +real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs +logical :: do_unit_tests=.false. ! Conduct some unit tests real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) @@ -262,7 +273,7 @@ subroutine ice_bergs_framework_init(bergs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, & - old_bug_rotated_weights, make_calving_reproduce, restart_input_dir, orig_read + old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -353,6 +364,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%msk(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%msk(:,:)=0. allocate( grd%cos(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%cos(:,:)=1. allocate( grd%sin(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%sin(:,:)=0. + allocate( grd%ocean_depth(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%ocean_depth(:,:)=0. allocate( grd%calving(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%calving(:,:)=0. allocate( grd%calving_hflx(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%calving_hflx(:,:)=0. allocate( grd%stored_heat(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%stored_heat(:,:)=0. @@ -391,6 +403,8 @@ subroutine ice_bergs_framework_init(bergs, & grd%lon(is:ie,js:je)=ice_lon(:,:) grd%lat(is:ie,js:je)=ice_lat(:,:) grd%area(is:ie,js:je)=ice_area(:,:) !sis2 has *(4.*pi*radius*radius) + if(present(ocean_depth)) grd%ocean_depth(is:ie,js:je)=ocean_depth(:,:) + ! Copy data declared on ice model data domain is=grd%isc-1; ie=grd%iec+1; js=grd%jsc-1; je=grd%jec+1 grd%dx(is:ie,js:je)=ice_dx(:,:) @@ -406,6 +420,7 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_update_domains(grd%msk, grd%domain) call mpp_update_domains(grd%cos, grd%domain, position=CORNER) call mpp_update_domains(grd%sin, grd%domain, position=CORNER) + call mpp_update_domains(grd%ocean_depth, grd%domain) call mpp_update_domains(grd%parity_x, grd%parity_y, grd%domain, gridtype=AGRID) ! If either parity_x/y is -ve, we need rotation of vectors ! Sanitize lon and lat at the SW edges @@ -485,6 +500,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%passive_mode=passive_mode bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit + bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) allocate( bergs%distribution(nclasses) ); bergs%distribution(:)=distribution(:) @@ -528,6 +544,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Virtual coverage by icebergs', 'm^2') grd%id_mass=register_diag_field('icebergs', 'mass', axes, Time, & 'Iceberg density field', 'kg/(m^2)') + grd%id_mass_on_ocn=register_diag_field('icebergs', 'mass_on_ocean', axes, Time, & + 'Iceberg density field felt by ocean', 'kg/(m^2)') grd%id_stored_ice=register_diag_field('icebergs', 'stored_ice', axes3d, Time, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & @@ -550,6 +568,12 @@ subroutine ice_bergs_framework_init(bergs, & 'Sea ice concentration', '(fraction)') grd%id_hi=register_diag_field('icebergs', 'hi', axes, Time, & 'Sea ice thickness', 'm') + grd%id_ssh=register_diag_field('icebergs', 'ssh', axes, Time, & + 'Sea surface hieght', 'm') + grd%id_fax=register_diag_field('icebergs', 'taux', axes, Time, & + 'X-stress on ice from atmosphere', 'N m^-2') + grd%id_fay=register_diag_field('icebergs', 'tauy', axes, Time, & + 'Y-stress on ice from atmosphere', 'N m^-2') ! Static fields id_class=register_static_field('icebergs', 'lon', axes, & @@ -564,6 +588,9 @@ subroutine ice_bergs_framework_init(bergs, & id_class=register_static_field('icebergs', 'mask', axes, & 'wet point mask', 'none') if (id_class>0) lerr=send_data(id_class, grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec)) + id_class=register_static_field('icebergs', 'ocean_depth', axes, & + 'ocean depth', 'm') + if (id_class>0) lerr=send_data(id_class, grd%ocean_depth(grd%isc:grd%iec,grd%jsc:grd%jec)) if (debug) then call grd_chksum2(grd, grd%lon, 'init lon') @@ -574,6 +601,11 @@ subroutine ice_bergs_framework_init(bergs, & call grd_chksum2(grd, grd%msk, 'init msk') call grd_chksum2(grd, grd%cos, 'init cos') call grd_chksum2(grd, grd%sin, 'init sin') + call grd_chksum2(grd, grd%ocean_depth, 'init ocean_depth') + endif + + if (do_unit_tests) then + if (unitTests(bergs)) call error_mesg('diamonds, icebergs_init', 'Unit tests failed!', FATAL) endif !write(stderrunit,*) 'diamonds: done' @@ -2428,6 +2460,7 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%msk, 'msk') call grd_chksum2(grd, grd%cos, 'cos') call grd_chksum2(grd, grd%sin, 'sin') + call grd_chksum2(grd, grd%ocean_depth, 'depth') end subroutine checksum_gridded @@ -2714,9 +2747,13 @@ real function bilin(grd, fld, i, j, xi, yj) integer, intent(in) :: i, j ! Local variables - bilin=(fld(i,j )*(1.-xi)+fld(i-1,j )*xi)*(1.-yj) & - +(fld(i,j-1)*(1.-xi)+fld(i-1,j-1)*xi)*yj - + if (old_bug_bilin) then + bilin=(fld(i,j )*(1.-xi)+fld(i-1,j )*xi)*(1.-yj) & + +(fld(i,j-1)*(1.-xi)+fld(i-1,j-1)*xi)*yj + else + bilin=(fld(i,j )*xi+fld(i-1,j )*(1.-xi))*yj & + +(fld(i,j-1)*xi+fld(i-1,j-1)*(1.-xi))*(1.-yj) + endif end function bilin ! ############################################################################## @@ -2740,4 +2777,35 @@ subroutine print_fld(grd, fld, label) end subroutine print_fld +! ############################################################################## + +logical function unitTests(bergs) + type(icebergs), pointer :: bergs + type(icebergs_gridded), pointer :: grd + ! Local variables + integer :: stderrunit,i,j + + ! This function returns True is a unit test fails + unitTests=.false. + ! For convenience + grd=>bergs%grd + stderrunit=stderr() + + i=grd%isc; j=grd%jsc + call localTest( bilin(grd, grd%lon, i, j, 0., 1.), grd%lon(i-1,j) ) + call localTest( bilin(grd, grd%lon, i, j, 1., 1.), grd%lon(i,j) ) + call localTest( bilin(grd, grd%lat, i, j, 1., 0.), grd%lat(i,j-1) ) + call localTest( bilin(grd, grd%lat, i, j, 1., 1.), grd%lat(i,j) ) + + contains + subroutine localTest(answer, rightAnswer) + real, intent(in) :: answer, rightAnswer + if (answer==rightAnswer) return + unitTests=.true. + write(stderrunit,*) 'a=',answer,'b=',rightAnswer + end subroutine localTest +end function unitTests + +! ############################################################################## + end module From 93467eb168a5d879e8d244a21f0b6206d4926f9c Mon Sep 17 00:00:00 2001 From: Niki Zadeh Date: Thu, 15 Jan 2015 13:07:01 -0500 Subject: [PATCH 002/361] Make interfaces compatible with SIS - The icebergs_init interface needed a minor modification to make it compatible with SIS without changing answers. --- icebergs.F90 | 5 +++-- icebergs_framework.F90 | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 51f8a80..17d2492 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -69,11 +69,12 @@ module ice_bergs subroutine icebergs_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, maskmap, fractional_area) ! Arguments type(icebergs), pointer :: bergs integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) logical, intent(in), optional :: maskmap(:,:) +logical, intent(in), optional :: fractional_area integer, intent(in) :: dom_x_flags, dom_y_flags real, intent(in) :: dt type (time_type), intent(in) :: Time ! current time @@ -90,7 +91,7 @@ subroutine icebergs_init(bergs, & call ice_bergs_framework_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, maskmap, fractional_area) call mpp_clock_begin(bergs%clock_ior) call ice_bergs_io_init(bergs,io_layout) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3988990..b8a0328 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -212,7 +212,7 @@ module ice_bergs_framework subroutine ice_bergs_framework_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & - cos_rot, sin_rot, maskmap) + cos_rot, sin_rot, maskmap, fractional_area) use mpp_parameter_mod, only: SCALAR_PAIR, CGRID_NE, BGRID_NE, CORNER, AGRID use mpp_domains_mod, only: mpp_update_domains, mpp_define_domains @@ -234,6 +234,7 @@ subroutine ice_bergs_framework_init(bergs, & type(icebergs), pointer :: bergs integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) logical, intent(in), optional :: maskmap(:,:) +logical, intent(in), optional :: fractional_area integer, intent(in) :: dom_x_flags, dom_y_flags real, intent(in) :: dt type (time_type), intent(in) :: Time ! current time @@ -391,6 +392,10 @@ subroutine ice_bergs_framework_init(bergs, & grd%lon(is:ie,js:je)=ice_lon(:,:) grd%lat(is:ie,js:je)=ice_lat(:,:) grd%area(is:ie,js:je)=ice_area(:,:) !sis2 has *(4.*pi*radius*radius) + !For SIS not to change answers + if(present(fractional_area)) then + if(fractional_area) grd%area(is:ie,js:je)=ice_area(:,:) *(4.*pi*radius*radius) + endif ! Copy data declared on ice model data domain is=grd%isc-1; ie=grd%iec+1; js=grd%jsc-1; je=grd%jec+1 grd%dx(is:ie,js:je)=ice_dx(:,:) From fd86d0a0a836a035b29013f477c152f8141608ad Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 22 Apr 2015 10:06:38 -0400 Subject: [PATCH 003/361] Added License and README following DOC guidance - In preparation for pushing to GitHub --- LICENSE.md | 553 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 15 ++ 2 files changed, 568 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a05d37a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,553 @@ +This file is part of the NOAA-GFDL iceberg model, referred to as +NOAA-GFDL/icebergs. The majority of this code was written by authors at +Princeton University who originally provided this software under version 3 of +the Gnu General Public License, which is provided below. + +The intent of this license is to ensure free and unrestricted access to the +iceberg software, and to pass on those rights to modified versions this +software. + + +GNU GENERAL PUBLIC LICENSE +========================== + +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. http://fsf.org/ + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +## Preamble + +The GNU General Public License is a free, copyleft license for software and other +kinds of works. + +The licenses for most software and other practical works are designed to take away +your freedom to share and change the works. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change all versions of a +program--to make sure it remains free software for all its users. We, the Free +Software Foundation, use the GNU General Public License for most of our software; it +applies also to any other work released this way by its authors. You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General +Public Licenses are designed to make sure that you have the freedom to distribute +copies of free software (and charge for them if you wish), that you receive source +code or can get it if you want it, that you can change the software or use pieces of +it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or +asking you to surrender the rights. Therefore, you have certain responsibilities if +you distribute copies of the software, or if you modify it: responsibilities to +respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, +you must pass on to the recipients the same freedoms that you received. You must make +sure that they, too, receive or can get the source code. And you must show them these +terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert +copyright on the software, and (2) offer you this License giving you legal permission +to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is +no warranty for this free software. For both users' and authors' sake, the GPL +requires that modified versions be marked as changed, so that their problems will not +be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of +the software inside them, although the manufacturer can do so. This is fundamentally +incompatible with the aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we have designed +this version of the GPL to prohibit the practice for those products. If such problems +arise substantially in other domains, we stand ready to extend this provision to +those domains in future versions of the GPL, as needed to protect the freedom of +users. + +Finally, every program is threatened constantly by software patents. States should +not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that patents +applied to a free program could make it effectively proprietary. To prevent this, the +GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +## TERMS AND CONDITIONS + +### 0. Definitions. + +"This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact copy. The +resulting work is called a "modified version" of the earlier work or a +work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on +the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for infringement under +applicable copyright law, except executing it on a computer or modifying a private +copy. Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the +extent that it includes a convenient and prominently visible feature that (1) +displays an appropriate copyright notice, and (2) tells the user that there is no +warranty for the work (except to the extent that warranties are provided), that +licensees may convey the work under this License, and how to view a copy of this +License. If the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of a +work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of interfaces +specified for a particular programming language, one that is widely used among +developers working in that language. + +The "System Libraries" of an executable work include anything, other than +the work as a whole, that (a) is included in the normal form of packaging a Major +Component, but which is not part of that Major Component, and (b) serves only to +enable use of the work with that Major Component, or to implement a Standard +Interface for which an implementation is available to the public in source code form. +A "Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system (if any) on which +the executable work runs, or a compiler used to produce the work, or an object code +interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the +source code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. However, +it does not include the work's System Libraries, or general-purpose tools or +generally available free programs which are used unmodified in performing those +activities but which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for the work, and +the source code for shared libraries and dynamically linked subprograms that the work +is specifically designed to require, such as by intimate data communication or +control flow between those subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +### 2. Basic Permissions. + +All rights granted under this License are granted for the term of copyright on the +Program, and are irrevocable provided the stated conditions are met. This License +explicitly affirms your unlimited permission to run the unmodified Program. The +output from running a covered work is covered by this License only if the output, +given its content, constitutes a covered work. This License acknowledges your rights +of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey covered +works to others for the sole purpose of having them make modifications exclusively +for you, or provide you with facilities for running those works, provided that you +comply with the terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for you must do so +exclusively on your behalf, under your direction and control, on terms that prohibit +them from making any copies of your copyrighted material outside their relationship +with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological measure under any +applicable law fulfilling obligations under article 11 of the WIPO copyright treaty +adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention +of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of +technological measures to the extent such circumvention is effected by exercising +rights under this License with respect to the covered work, and you disclaim any +intention to limit operation or modification of the work as a means of enforcing, +against the work's users, your or third parties' legal rights to forbid circumvention +of technological measures. + +### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you receive it, in any +medium, provided that you conspicuously and appropriately publish on each copy an +appropriate copyright notice; keep intact all notices stating that this License and +any non-permissive terms added in accord with section 7 apply to the code; keep +intact all notices of the absence of any warranty; and give all recipients a copy of +this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer +support or warranty protection for a fee. + +### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to produce it from +the Program, in the form of source code under the terms of section 4, provided that +you also meet all of these conditions: + +* **a)** The work must carry prominent notices stating that you modified it, and giving a +relevant date. +* **b)** The work must carry prominent notices stating that it is released under this +License and any conditions added under section 7. This requirement modifies the +requirement in section 4 to "keep intact all notices". +* **c)** You must license the entire work, as a whole, under this License to anyone who +comes into possession of a copy. This License will therefore apply, along with any +applicable section 7 additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no permission to license the +work in any other way, but it does not invalidate such permission if you have +separately received it. +* **d)** If the work has interactive user interfaces, each must display Appropriate Legal +Notices; however, if the Program has interactive interfaces that do not display +Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are +not by their nature extensions of the covered work, and which are not combined with +it such as to form a larger program, in or on a volume of a storage or distribution +medium, is called an "aggregate" if the compilation and its resulting +copyright are not used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work in an aggregate +does not cause this License to apply to the other parts of the aggregate. + +### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of sections 4 and +5, provided that you also convey the machine-readable Corresponding Source under the +terms of this License, in one of these ways: + +* **a)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by the Corresponding Source fixed on a +durable physical medium customarily used for software interchange. +* **b)** Convey the object code in, or embodied in, a physical product (including a +physical distribution medium), accompanied by a written offer, valid for at least +three years and valid for as long as you offer spare parts or customer support for +that product model, to give anyone who possesses the object code either (1) a copy of +the Corresponding Source for all the software in the product that is covered by this +License, on a durable physical medium customarily used for software interchange, for +a price no more than your reasonable cost of physically performing this conveying of +source, or (2) access to copy the Corresponding Source from a network server at no +charge. +* **c)** Convey individual copies of the object code with a copy of the written offer to +provide the Corresponding Source. This alternative is allowed only occasionally and +noncommercially, and only if you received the object code with such an offer, in +accord with subsection 6b. +* **d)** Convey the object code by offering access from a designated place (gratis or for +a charge), and offer equivalent access to the Corresponding Source in the same way +through the same place at no further charge. You need not require recipients to copy +the Corresponding Source along with the object code. If the place to copy the object +code is a network server, the Corresponding Source may be on a different server +(operated by you or a third party) that supports equivalent copying facilities, +provided you maintain clear directions next to the object code saying where to find +the Corresponding Source. Regardless of what server hosts the Corresponding Source, +you remain obligated to ensure that it is available for as long as needed to satisfy +these requirements. +* **e)** Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are being +offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the +Corresponding Source as a System Library, need not be included in conveying the +object code work. + +A "User Product" is either (1) a "consumer product", which +means any tangible personal property which is normally used for personal, family, or +household purposes, or (2) anything designed or sold for incorporation into a +dwelling. In determining whether a product is a consumer product, doubtful cases +shall be resolved in favor of coverage. For a particular product received by a +particular user, "normally used" refers to a typical or common use of +that class of product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected to use, the +product. A product is a consumer product regardless of whether the product has +substantial commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install and execute +modified versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the continued +functioning of the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for +use in, a User Product, and the conveying occurs as part of a transaction in which +the right of possession and use of the User Product is transferred to the recipient +in perpetuity or for a fixed term (regardless of how the transaction is +characterized), the Corresponding Source conveyed under this section must be +accompanied by the Installation Information. But this requirement does not apply if +neither you nor any third party retains the ability to install modified object code +on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to +continue to provide support service, warranty, or updates for a work that has been +modified or installed by the recipient, or for the User Product in which it has been +modified or installed. Access to a network may be denied when the modification itself +materially and adversely affects the operation of the network or violates the rules +and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with +this section must be in a format that is publicly documented (and with an +implementation available to the public in source code form), and must require no +special password or key for unpacking, reading or copying. + +### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. Additional +permissions that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part may be +used separately under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when you +modify the work.) You may place additional permissions on material, added by you to a +covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a +covered work, you may (if authorized by the copyright holders of that material) +supplement the terms of this License with terms: + +* **a)** Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or +* **b)** Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed by works +containing it; or +* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that +modified versions of such material be marked in reasonable ways as different from the +original version; or +* **d)** Limiting the use for publicity purposes of names of licensors or authors of the +material; or +* **e)** Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or +* **f)** Requiring indemnification of licensors and authors of that material by anyone +who conveys the material (or modified versions of it) with contractual assumptions of +liability to the recipient, for any liability that these contractual assumptions +directly impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you received +it, or any part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. If a +license document contains a further restriction but permits relicensing or conveying +under this License, you may add to a covered work material governed by the terms of +that license document, provided that the further restriction does not survive such +relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in +the relevant source files, a statement of the additional terms that apply to those +files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a +separately written license, or stated as exceptions; the above requirements apply +either way. + +### 8. Termination. + +You may not propagate or modify a covered work except as expressly provided under +this License. Any attempt otherwise to propagate or modify it is void, and will +automatically terminate your rights under this License (including any patent licenses +granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a +particular copyright holder is reinstated (a) provisionally, unless and until the +copyright holder explicitly and finally terminates your license, and (b) permanently, +if the copyright holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, this +is the first time you have received notice of violation of this License (for any +work) from that copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of +parties who have received copies or rights from you under this License. If your +rights have been terminated and not permanently reinstated, you do not qualify to +receive new licenses for the same material under section 10. + +### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy of the +Program. Ancillary propagation of a covered work occurring solely as a consequence of +using peer-to-peer transmission to receive a copy likewise does not require +acceptance. However, nothing other than this License grants you permission to +propagate or modify any covered work. These actions infringe copyright if you do not +accept this License. Therefore, by modifying or propagating a covered work, you +indicate your acceptance of this License to do so. + +### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives a license +from the original licensors, to run, modify and propagate that work, subject to this +License. You are not responsible for enforcing compliance by third parties with this +License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an organization, or +merging organizations. If propagation of a covered work results from an entity +transaction, each party to that transaction who receives a copy of the work also +receives whatever licenses to the work the party's predecessor in interest had or +could give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if the predecessor +has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or +affirmed under this License. For example, you may not impose a license fee, royalty, +or other charge for exercise of rights granted under this License, and you may not +initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging +that any patent claim is infringed by making, using, selling, offering for sale, or +importing the Program or any portion of it. + +### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The work thus +licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or +controlled by the contributor, whether already acquired or hereafter acquired, that +would be infringed by some manner, permitted by this License, of making, using, or +selling its contributor version, but do not include claims that would be infringed +only as a consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant patent +sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license +under the contributor's essential patent claims, to make, use, sell, offer for sale, +import and otherwise run, modify and propagate the contents of its contributor +version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent (such as an +express permission to practice a patent or covenant not to sue for patent +infringement). To "grant" such a patent license to a party means to make +such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free of charge +and under the terms of this License, through a publicly available network server or +other readily accessible means, then you must either (1) cause the Corresponding +Source to be so available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner consistent with +the requirements of this License, to extend the patent license to downstream +recipients. "Knowingly relying" means you have actual knowledge that, but +for the patent license, your conveying the covered work in a country, or your +recipient's use of the covered work in a country, would infringe one or more +identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you +convey, or propagate by procuring conveyance of, a covered work, and grant a patent +license to some of the parties receiving the covered work authorizing them to use, +propagate, modify or convey a specific copy of the covered work, then the patent +license you grant is automatically extended to all recipients of the covered work and +works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on the +non-exercise of one or more of the rights that are specifically granted under this +License. You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which you make +payment to the third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties who would receive +the covered work from you, a discriminatory patent license (a) in connection with +copies of the covered work conveyed by you (or copies made from those copies), or (b) +primarily for and in connection with specific products or compilations that contain +the covered work, unless you entered into that arrangement, or that patent license +was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available to you +under applicable patent law. + +### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot convey a covered work so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not convey it at all. For example, if you +agree to terms that obligate you to collect a royalty for further conveying from +those to whom you convey the Program, the only way you could satisfy both those terms +and this License would be to refrain entirely from conveying the Program. + +### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have permission to link or +combine any covered work with a work licensed under version 3 of the GNU Affero +General Public License into a single combined work, and to convey the resulting work. +The terms of this License will continue to apply to the part which is the covered +work, but the special requirements of the GNU Affero General Public License, section +13, concerning interaction through a network will apply to the combination as such. + +### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the GNU +General Public License from time to time. Such new versions will be similar in spirit +to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that +a certain numbered version of the GNU General Public License "or any later +version" applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published by the +Free Software Foundation. If the Program does not specify a version number of the GNU +General Public License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU +General Public License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no +additional obligations are imposed on any author or copyright holder as a result of +your choosing to follow a later version. + +### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE +QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY +COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS +PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE +OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be +given local legal effect according to their terms, reviewing courts shall apply local +law that most closely approximates an absolute waiver of all civil liability in +connection with the Program, unless a warranty or assumption of liability accompanies +a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS diff --git a/README.md b/README.md new file mode 100644 index 0000000..bfd98be --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +Disclaimer +========== + +The United States Department of Commerce (DOC) GitHub project code is provided +on an "as is" basis and the user assumes responsibility for its use. DOC has +relinquished control of the information and no longer has responsibility to +protect the integrity, confidentiality, or availability of the information. Any +claims against the Department of Commerce stemming from the use of its GitHub +project will be governed by all applicable Federal law. Any reference to +specific commercial products, processes, or services by service mark, +trademark, manufacturer, or otherwise, does not constitute or imply their +endorsement, recommendation or favoring by the Department of Commerce. The +Department of Commerce seal and logo, or the seal and logo of a DOC bureau, +shall not be used in any manner to imply endorsement of any commercial product +or activity by DOC or the United States Government. From 319be1311f81b7579ea504d659dee75ee727cb59 Mon Sep 17 00:00:00 2001 From: "Alistair Adcroft (Work account)" Date: Tue, 26 May 2015 22:13:05 -0400 Subject: [PATCH 004/361] Updated README.md - With link to gitlab, following DOC guidance. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index bfd98be..fd73b8a 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,6 @@ endorsement, recommendation or favoring by the Department of Commerce. The Department of Commerce seal and logo, or the seal and logo of a DOC bureau, shall not be used in any manner to imply endorsement of any commercial product or activity by DOC or the United States Government. + +This project code is made available through GitHub but is managed by NOAA-GFDL +at https://gitlab.gfdl.noaa.gov. From b01c65bf43324b14fe574fdfd39a60abc1fdcd81 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 1 Jun 2015 15:43:47 -0400 Subject: [PATCH 005/361] Commented out call to save restart in icebergs_end() - icebergs_save_restart() is called directly by SIS1 and SIS2 so we do not need to call it a second time. If icebergs were controlled by the coupler then the icebergs would need to take responsibility for the restarts at the end of the run. - Fixes warnings of form "icebergs.res.nc is already registered with other restart_file_type data" - No answer changes. --- icebergs.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 33e5c2d..4c0965a 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2164,7 +2164,11 @@ subroutine icebergs_end(bergs) if (.not.associated(bergs)) return - call icebergs_save_restart(bergs) + ! icebergs_save_restart() is called directly by SIS1 and SIS2 so + ! we do not need to call it a second time. If icebergs were controlled + ! by the coupler then the icebergs would need to take responsibility for + ! the restarts at the end of the run. + !call icebergs_save_restart(bergs) call mpp_clock_begin(bergs%clock_ini) ! Delete bergs and structures From 85fa3c18769a31355bde7dd28b9e0ba7a4647cb7 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 22 May 2015 14:39:01 -0400 Subject: [PATCH 006/361] Added explicit accelerations output to the accel subrouting Also added axe, aye (1,2,3,4) to evolve subrouting inside the accel calls (to make the changes consistant) --- icebergs.F90 | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 4c0965a..7f5fea6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,13 +112,15 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axe, aye, debug_flag) !Seperated total acceleration (ax, ay) and implicit part (bx ,by) accelerations - Alon +!subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs type(iceberg), pointer :: berg integer, intent(in) :: i, j real, intent(in) :: xi, yj, lat, uvel, vvel, uvel0, vvel0, dt -real, intent(inout) :: ax, ay +!real, intent(inout) :: ax, ay !old version - Alon +real, intent(inout) :: ax, ay, axe, aye ! Added explicit accelerations to output -Alon logical, optional :: debug_flag ! Local variables type(icebergs_gridded), pointer :: grd @@ -128,7 +130,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop real, parameter :: alpha=0.0, beta=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. -real :: lambda, detA, A11, A12, axe, aye, D_hi +real :: lambda, detA, A11, A12, D_hi ! Removed axe, aye from line - Alon +!real :: lambda, detA, A11, A12, axe, aye, D_hi !old version - Alon real :: uveln, vveln, us, vs, speed, loc_dx, new_speed logical :: dumpit integer :: itloop @@ -189,6 +192,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_atm=c_atm*sqrt( (us-ua)**2+(vs-va)**2 ) drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) +!Alon's proposed change - This would change it to Bob's improved scheme. +! !us=uveln; vs=vveln This line is no longer needed +! drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel-uo)**2+(vvel-vo)**2 )) +! drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel-ua)**2+(vvel-va)**2 )) +! drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel-ui)**2+(vvel-vi)**2 )) + ! Explicit accelerations !axe= f_cori*vvel -gravity*ssh_x +wave_rad*uwave & ! -drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) @@ -1477,10 +1486,10 @@ subroutine evolve_icebergs(bergs) type(icebergs), pointer :: bergs ! Local variables type(icebergs_gridded), pointer :: grd -real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1 -real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2 -real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3 -real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4 +real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axe1, aye1 !axe1 and aye1 added by Alon +real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axe2, aye2 !axe2 and aye2 added by Alon +real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axe3, aye3 !axe3 and aye3 added by Alon +real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axe4, aye4 !axe4 and aye4 added by Alon real :: uveln, vveln, lonn, latn real :: x1, xdot1, xddot1, y1, ydot1, yddot1 real :: x2, xdot2, xddot2, y2, ydot2, yddot2 @@ -1561,7 +1570,7 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1) + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1) !axe1, aye1 - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) @@ -1605,7 +1614,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, debug_flag=.true.) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1614,7 +1623,7 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2) + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2) !axe2, aye2 - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) @@ -1658,10 +1667,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, debug_flag=.true.) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, debug_flag=.true.) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1670,7 +1679,7 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3) + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3) !axe3, aye3 - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) @@ -1712,13 +1721,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, debug_flag=.true.) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, debug_flag=.true.) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, debug_flag=.true.) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, debug_flag=.true.) !axe3, aye3 - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1727,7 +1736,7 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4) + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4) !axe4, aye4 - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 @@ -1781,16 +1790,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, debug_flag=.true.) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, debug_flag=.true.) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, debug_flag=.true.) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, debug_flag=.true.) !axe3, aye3 - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, debug_flag=.true.) + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, debug_flag=.true.) !axe4, aye4 - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') From 413726aa121b3f52d2885d2a7ae3e8b29e52f4bf Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 1 Jun 2015 10:30:39 -0400 Subject: [PATCH 007/361] Added an if statement for choosing Range Katta or Verlet. Does not change the answers. --- icebergs.F90 | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7f5fea6..52142ae 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,7 +112,7 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axe, aye, debug_flag) !Seperated total acceleration (ax, ay) and implicit part (bx ,by) accelerations - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, debug_flag) !Saving exp acceleration for Verlet - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs @@ -120,7 +120,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a integer, intent(in) :: i, j real, intent(in) :: xi, yj, lat, uvel, vvel, uvel0, vvel0, dt !real, intent(inout) :: ax, ay !old version - Alon -real, intent(inout) :: ax, ay, axe, aye ! Added explicit accelerations to output -Alon +real, intent(inout) :: ax, ay, axn, ayn ! Added explicit accelerations to output -Alon logical, optional :: debug_flag ! Local variables type(icebergs_gridded), pointer :: grd @@ -130,8 +130,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop real, parameter :: alpha=0.0, beta=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. -real :: lambda, detA, A11, A12, D_hi ! Removed axe, aye from line - Alon -!real :: lambda, detA, A11, A12, axe, aye, D_hi !old version - Alon +real :: lambda, detA, A11, A12, axe, aye, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed logical :: dumpit integer :: itloop @@ -236,7 +235,14 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a vveln=vvel0+dt*ay enddo ! itloop - + +!Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon + axn=-gravity*ssh_x +wave_rad*uwave !Alon + ayn=-gravity*ssh_y +wave_rad*vwave !Alon + + + + ! Limit speed of bergs based on a CFL criteria if (bergs%speed_limit>0.) then speed=sqrt(uveln*uveln+vveln*vveln) ! Speed of berg @@ -1501,6 +1507,7 @@ subroutine evolve_icebergs(bergs) integer :: i1,j1,i2,j2,i3,j3,i4,j4 real :: xi, yj logical :: bounced, on_tangential_plane, error_flag +logical :: Ranga_not_verlet ! Ranga_not_verlet=1 for Range Katta, =0 for Verlet method. Added by Alon type(iceberg), pointer :: berg integer :: stderrunit @@ -1530,6 +1537,10 @@ subroutine evolve_icebergs(bergs) dt_6=dt/6. Rearth=6360.e3 + !Choosing time stepping scheme - Alon + Ranga_not_verlet=.true. !true=Ranga Katta, False=Verlet , Alon + + berg=>bergs%first do while (associated(berg)) ! loop over all bergs @@ -1562,7 +1573,9 @@ subroutine evolve_icebergs(bergs) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - ! A1 = A(X1) + if (Ranga_not_verlet) then !Start of the Range Katta Loop -Added by Alon + + ! A1 = A(X1) lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) @@ -1814,6 +1827,9 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) enddo endif + + endif ! End of the Range Katta Loop -added by Alon + berg%lon=lonn berg%lat=latn From ba1d7d8f96a0bb99a36a56b7d872cb9ee00ea339 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 1 Jun 2015 11:25:08 -0400 Subject: [PATCH 008/361] Flag for verlet vs Ranga Katta added. Not changes to the answers. --- icebergs.F90 | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 52142ae..d40b05f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,7 +112,7 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, debug_flag) !Saving exp acceleration for Verlet - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, Ranga_not_verlet, debug_flag) !Saving exp acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs @@ -133,9 +133,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: lambda, detA, A11, A12, axe, aye, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed logical :: dumpit +logical, intent(in) :: Ranga_not_verlet ! Flag to specify whether it is Range Katta or Verlet integer :: itloop integer :: stderrunit + ! Get the stderr unit number. stderrunit = stderr() @@ -204,6 +206,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! -drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) axe=-gravity*ssh_x +wave_rad*uwave aye=-gravity*ssh_y +wave_rad*vwave + + if (.not.Ranga_not_verlet) then ! When using Verlet, use only half the explicit acceleration, Added by Alon + axe=axe/2 + aye=aye/2 + endif + if (alpha>0.) then ! If implicit, use time-level (n) rather than RK4 latest axe=axe+f_cori*vvel0 aye=aye-f_cori*uvel0 @@ -1583,7 +1591,7 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1) !axe1, aye1 - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet) !axe1, aye1 ,Ranga_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) @@ -1627,7 +1635,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1636,7 +1644,7 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2) !axe2, aye2 - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet) !axe2, aye2, Ranga_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) @@ -1680,10 +1688,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet- Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1692,7 +1700,7 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3) !axe3, aye3 - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet) !axe3, aye3, Ranga_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) @@ -1734,13 +1742,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, debug_flag=.true.) !axe3, aye3 - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet, debug_flag=.true.) !axe3, aye3, Ranga_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1749,7 +1757,7 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4) !axe4, aye4 - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, Ranga_not_verlet) !axe4, aye4, Ranga_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 @@ -1803,16 +1811,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, debug_flag=.true.) !axe1, aye1 - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, debug_flag=.true.) !axe2, aye2 - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, debug_flag=.true.) !axe3, aye3 - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet, debug_flag=.true.) !axe3, aye3, Ranga_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, debug_flag=.true.) !axe4, aye4 - Added by Alon + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, Ranga_not_verlet, debug_flag=.true.) !axe4, aye4, Ranga_not_verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') From a3a1bc001fc6c9769b74e43fc13d95490b6e33c3 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 1 Jun 2015 17:35:55 -0400 Subject: [PATCH 009/361] Added in Velocity Verlet time stepping option into the evolve routine. It is not quite working yet, as I have not saved the implicit and explicit accelerations from the previous step yet. This will involve editing many subroutines. This commit only has changes to evolve and accel --- icebergs.F90 | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index d40b05f..8add4b2 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1505,11 +1505,13 @@ subroutine evolve_icebergs(bergs) real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axe3, aye3 !axe3 and aye3 added by Alon real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axe4, aye4 !axe4 and aye4 added by Alon real :: uveln, vveln, lonn, latn -real :: x1, xdot1, xddot1, y1, ydot1, yddot1 +real :: x1, xdot1, xddot1, y1, ydot1, yddot1 real :: x2, xdot2, xddot2, y2, ydot2, yddot2 real :: x3, xdot3, xddot3, y3, ydot3, yddot3 real :: x4, xdot4, xddot4, y4, ydot4, yddot4 real :: xn, xdotn, yn, ydotn +real :: bxddot, byddot ! Added by Alon +real :: axn, ayn, bxn, byn ! Added by Alon - explicit and implicit accelations from the previous step real :: r180_pi, dt, dt_2, dt_6, dydl, Rearth integer :: i, j integer :: i1,j1,i2,j2,i3,j3,i4,j4 @@ -1838,6 +1840,120 @@ subroutine evolve_icebergs(bergs) endif ! End of the Range Katta Loop -added by Alon +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + if (.not.Ranga_not_verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon + + ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step + ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting + ! Positions and velocity is updated by + ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n + ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax + +lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + dydl=r180_pi/Rearth + uvel1=berg%uvel; vvel1=berg%vvel + +!Temporary, remember to remove!!!! +axn=0.0 +ayn=0.0 +bxn=0.0 +byn=0.0 + + +! Turn the velocities into u_star, v_star. - Alon (not sure how this works with tangent plane) + uvel1=uvel1+dt_2*axn !Alon + vvel1=vvel1+dt_2*ayn !Alon + +if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) + u1=uvel1*dxdl1; v1=vvel1*dydl + + if (on_tangential_plane) call rotvec_to_tang(lon1,bxn,byn,bxddot,byddot) !Added by Alon -rotation of implicit velocity. + +!Solving for new position + if (on_tangential_plane) then + xn=x1+dt_2*xdot1+(dt*dt*(bxddot)/2) ; yn=y1+dt_2*ydot1+(dt*dt*(byddot/2)) !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + else + lonn=lon1+dt_2*u1+(dt*dt*(bxn)/2) ; latn=lat1+dt_2*v1+(dt*dt*(byn/2)) !Alon + uvel2=uvel1+dt*ax1; vvel2=vvel1+dt*ay1 !Alon , we call it uvel2, vvel2 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + endif + dxdl2=r180_pi/(Rearth*cos(latn*pi_180)) + + +!Solving for the new velocity + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet) !axe1, aye1 ,Ranga_not_verlet - Added by Alon + if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + if (on_tangential_plane) then + xdotn=xdot1+dt*xddot1; ydotn=ydot1+dt*yddot1 !Alon + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + else + uvel2=uvel1+dt*ax1; vvel2=vvel1+dt*ay1 !Alon , we call it uvel2, vvel2 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + endif + uveln=uvel2*dxdl2; vveln=vvel2*dydl !Converted to degrees. + +!Adjusting mass... + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) + i2=i; j2=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + +!Debugging + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lonn=',lon1,lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,latn=',lat1,latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,un,u0=',uvel1,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,vn,v0=',vvel1,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& + & dt*ax1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& + & dt*ay1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,un,u0=',& + & dt*uvel1,dt*uvel2,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,vn,v0=',& + & dt*vvel1,dt*vvel2,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u_n (deg)=',& + & dt*u1,dt*uveln + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v_n (deg)=',& + & dt*v1,dt*vveln + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon + + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif + + + + endif ! End of the Verlet Stepiing -added by Alon +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! berg%lon=lonn berg%lat=latn From cc107b35913b833cdd0582f5e019b903570675e2 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 2 Jun 2015 13:48:15 -0400 Subject: [PATCH 010/361] Add explicit and implicit accelerations (axn, ayn, bxn, byn) to the iceberg type. This will be used for the Verlet stepping scheme. The Runge-Kutta scheme is working and this change does not change the answers. The Verlet scheme is not working yet. --- icebergs.F90 | 88 +++++++++++++++++++++++------------------ icebergs_framework.F90 | 72 ++++++++++++++++++++++++++-------- icebergs_io.F90 | 89 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 193 insertions(+), 56 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 8add4b2..b1e528e 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,15 +112,15 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, Ranga_not_verlet, debug_flag) !Saving exp acceleration for Verlet, Adding Verlet flag - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs type(iceberg), pointer :: berg integer, intent(in) :: i, j real, intent(in) :: xi, yj, lat, uvel, vvel, uvel0, vvel0, dt -!real, intent(inout) :: ax, ay !old version - Alon -real, intent(inout) :: ax, ay, axn, ayn ! Added explicit accelerations to output -Alon +real, intent(inout) :: ax, ay +real, intent(inout) :: axn, ayn, bxn, byn ! Added implicit and explicit accelerations to output -Alon logical, optional :: debug_flag ! Local variables type(icebergs_gridded), pointer :: grd @@ -133,7 +133,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: lambda, detA, A11, A12, axe, aye, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed logical :: dumpit -logical, intent(in) :: Ranga_not_verlet ! Flag to specify whether it is Range Katta or Verlet +logical, intent(in) :: Runge_not_verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit @@ -156,6 +156,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a W=berg%width L=berg%length +!Initializing accelerations - Alon. (I am not 100% sure this is needed). I'm not sure what is output if variable is not defined in the subroutine. + axn=0. + ayn=0. + bxn=0. + byn=0. + hi=min(hi,D) D_hi=max(0.,D-hi) @@ -207,7 +213,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a axe=-gravity*ssh_x +wave_rad*uwave aye=-gravity*ssh_y +wave_rad*vwave - if (.not.Ranga_not_verlet) then ! When using Verlet, use only half the explicit acceleration, Added by Alon + if (.not.Runge_not_verlet) then ! When using Verlet, use only half the explicit acceleration, Added by Alon axe=axe/2 aye=aye/2 endif @@ -247,7 +253,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon axn=-gravity*ssh_x +wave_rad*uwave !Alon ayn=-gravity*ssh_y +wave_rad*vwave !Alon - + bxn= ax-(axn/2) !Alon + byn= ay-(ayn/2) !Alon @@ -1454,6 +1461,10 @@ subroutine calve_icebergs(bergs) newberg%yj=yj newberg%uvel=0. newberg%vvel=0. + newberg%axn=0. !Added by Alon + newberg%ayn=0. !Added by Alon + newberg%bxn=0. !Added by Alon + newberg%byn=0. !Added by Alon newberg%mass=bergs%initial_mass(k) newberg%thickness=bergs%initial_thickness(k) newberg%width=bergs%initial_width(k) @@ -1500,11 +1511,11 @@ subroutine evolve_icebergs(bergs) type(icebergs), pointer :: bergs ! Local variables type(icebergs_gridded), pointer :: grd -real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axe1, aye1 !axe1 and aye1 added by Alon -real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axe2, aye2 !axe2 and aye2 added by Alon -real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axe3, aye3 !axe3 and aye3 added by Alon -real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axe4, aye4 !axe4 and aye4 added by Alon -real :: uveln, vveln, lonn, latn +real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1 +real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2 +real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3 +real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4 +real :: uveln, vveln, lonn, latn, un, vn, dxdln real :: x1, xdot1, xddot1, y1, ydot1, yddot1 real :: x2, xdot2, xddot2, y2, ydot2, yddot2 real :: x3, xdot3, xddot3, y3, ydot3, yddot3 @@ -1517,7 +1528,7 @@ subroutine evolve_icebergs(bergs) integer :: i1,j1,i2,j2,i3,j3,i4,j4 real :: xi, yj logical :: bounced, on_tangential_plane, error_flag -logical :: Ranga_not_verlet ! Ranga_not_verlet=1 for Range Katta, =0 for Verlet method. Added by Alon +logical :: Runge_not_verlet ! Runge_not_verlet=1 for Runge Kutta, =0 for Verlet method. Added by Alon type(iceberg), pointer :: berg integer :: stderrunit @@ -1548,7 +1559,7 @@ subroutine evolve_icebergs(bergs) Rearth=6360.e3 !Choosing time stepping scheme - Alon - Ranga_not_verlet=.true. !true=Ranga Katta, False=Verlet , Alon + Runge_not_verlet=.true. !true=Runge Kutta, False=Verlet , Alon berg=>bergs%first @@ -1583,7 +1594,7 @@ subroutine evolve_icebergs(bergs) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - if (Ranga_not_verlet) then !Start of the Range Katta Loop -Added by Alon + if (Runge_not_verlet) then !Start of the Runge-Kutta Loop -Added by Alon ! A1 = A(X1) lon1=berg%lon; lat1=berg%lat @@ -1593,7 +1604,7 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet) !axe1, aye1 ,Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn,ayn, bxn, byn ,Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) @@ -1637,7 +1648,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1646,7 +1657,7 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet) !axe2, aye2, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) @@ -1690,10 +1701,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet- Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !ax, aye1, Runge_not_verlet- Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1702,7 +1713,7 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet) !axe3, aye3, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) @@ -1744,13 +1755,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet, debug_flag=.true.) !axe3, aye3, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1759,7 +1770,7 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, Ranga_not_verlet) !axe4, aye4, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 @@ -1813,16 +1824,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axe2, aye2, Ranga_not_verlet, debug_flag=.true.) !axe2, aye2, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axe3, aye3, Ranga_not_verlet, debug_flag=.true.) !axe3, aye3, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axe4, aye4, Ranga_not_verlet, debug_flag=.true.) !axe4, aye4, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') @@ -1838,11 +1849,11 @@ subroutine evolve_icebergs(bergs) enddo endif - endif ! End of the Range Katta Loop -added by Alon + endif ! End of the Runge-Kutta Loop -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (.not.Ranga_not_verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon + if (.not.Runge_not_verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting @@ -1856,12 +1867,9 @@ subroutine evolve_icebergs(bergs) dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel -!Temporary, remember to remove!!!! -axn=0.0 -ayn=0.0 -bxn=0.0 -byn=0.0 - +!Loading past acceleartions - Alon + axn=berg%axn; ayn=berg%ayn !Alon + byn=berg%bxn; byn=berg%byn !Alon ! Turn the velocities into u_star, v_star. - Alon (not sure how this works with tangent plane) uvel1=uvel1+dt_2*axn !Alon @@ -1884,7 +1892,7 @@ subroutine evolve_icebergs(bergs) !Solving for the new velocity - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet) !axe1, aye1 ,Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) if (on_tangential_plane) then xdotn=xdot1+dt*xddot1; ydotn=ydot1+dt*yddot1 !Alon @@ -1933,7 +1941,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axe1, aye1, Ranga_not_verlet, debug_flag=.true.) !axe1, aye1, Ranga_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1959,6 +1967,10 @@ subroutine evolve_icebergs(bergs) berg%lat=latn berg%uvel=uveln berg%vvel=vveln + berg%axn=axn !Alon + berg%ayn=ayn !Alon + berg%bxn=bxn !Alon + berg%byn=byn !Alon berg%ine=i berg%jne=j berg%xi=xi diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 48dfe14..ecc3efd 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,8 +15,8 @@ module ice_bergs_framework implicit none ; private -integer, parameter :: buffer_width=20 -integer, parameter :: buffer_width_traj=23 +integer, parameter :: buffer_width=24 !Changed from 20 to 24 by Alon +integer, parameter :: buffer_width_traj=27 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -129,6 +129,7 @@ module ice_bergs_framework type :: xyt real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel + real :: axn, ayn, bxn, byn !Explicit and implicit accelerations !Alon real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi real :: mass_of_bits, heat_density integer :: year @@ -139,6 +140,7 @@ module ice_bergs_framework type(iceberg), pointer :: prev=>null(), next=>null() ! State variables (specific to the iceberg, needed for restarts) real :: lon, lat, uvel, vvel, mass, thickness, width, length + real :: axn, ayn, bxn, byn !Explicit and implicit accelerations !Alon real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density integer :: start_year @@ -932,6 +934,10 @@ subroutine pack_berg_into_buffer2(berg, buff, n) buff%data(18,n)=berg%heat_density buff%data(19,n)=berg%ine buff%data(20,n)=berg%jne + buff%data(21,n)=berg%axn !Alon + buff%data(22,n)=berg%ayn !Alon + buff%data(23,n)=berg%bxn !Alon + buff%data(24,n)=berg%byn !Alon end subroutine pack_berg_into_buffer2 @@ -970,6 +976,7 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) logical, optional :: force_append ! Local variables !real :: lon, lat, uvel, vvel, xi, yj + !real :: start_lon, start_lat, start_day, start_mass !integer :: ine, jne, start_year logical :: lres @@ -1006,7 +1013,12 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) call add_new_berg_to_list(first, localberg) else - lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + localberg%axn=buff%data(21,n) !Alon + localberg%ayn=buff%data(22,n) !Alon + localberg%bxn=buff%data(23,n) !Alon + localberg%byn=buff%data(24,n) !Alon + + lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) call add_new_berg_to_list(first, localberg) @@ -1020,6 +1032,8 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat write(stderrunit,*) localberg%lon,localberg%lat write(stderrunit,*) localberg%uvel,localberg%vvel + write(stderrunit,*) localberg%axn,localberg%ayn !Alon + write(stderrunit,*) localberg%bxn,localberg%byn !Alon write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) @@ -1163,6 +1177,10 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(21,n)=traj%sst buff%data(22,n)=traj%cn buff%data(23,n)=traj%hi + buff%data(24,n)=traj%axn !Alon + buff%data(25,n)=traj%ayn !Alon + buff%data(26,n)=traj%bxn !Alon + buff%data(27,n)=traj%byn !Alon end subroutine pack_traj_into_buffer2 @@ -1200,6 +1218,10 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%sst=buff%data(21,n) traj%cn=buff%data(22,n) traj%hi=buff%data(23,n) + traj%axn=buff%data(24,n) !Alon + traj%ayn=buff%data(25,n) !Alon + traj%bxn=buff%data(26,n) !Alon + traj%byn=buff%data(27,n) !Alon call append_posn(first, traj) @@ -1448,6 +1470,10 @@ logical function sameberg(berg1, berg2) if (berg1%thickness.ne.berg2%thickness) return if (berg1%width.ne.berg2%width) return if (berg1%length.ne.berg2%length) return + if (berg1%axn.ne.berg2%axn) return !Alon + if (berg1%ayn.ne.berg2%ayn) return !Alon + if (berg1%bxn.ne.berg2%bxn) return !Alon + if (berg1%byn.ne.berg2%byn) return !Alon sameberg=.true. ! passing the above tests mean that bergs 1 and 2 are identical end function sameberg @@ -1533,10 +1559,12 @@ subroutine print_berg(iochan, berg, label) ' xi,yj=', berg%xi, berg%yj, & ' lon,lat=', berg%lon, berg%lat, & ' u,v=', berg%uvel, berg%vvel, & + ' axn,ayn=', berg%axn, berg%ayn, & + ' bxn,byn=', berg%bxn, berg%byn, & ' p,n=', associated(berg%prev), associated(berg%next) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f10.4))') & label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi - +!Two lines above added by Alon end subroutine print_berg ! ############################################################################## @@ -1613,6 +1641,10 @@ subroutine record_posn(bergs) posn%sst=this%sst posn%cn=this%cn posn%hi=this%hi + posn%axn=this%axn + posn%ayn=this%ayn + posn%bxn=this%bxn + posn%byn=this%byn call push_posn(this%trajectory, posn) @@ -2619,8 +2651,8 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) nbergs=count_bergs(bergs) call mpp_max(nbergs) - allocate( fld( nbergs, 11 ) ) - allocate( fld2( nbergs, 11 ) ) + allocate( fld( nbergs, 15 ) ) !Changed from 11 to 15 by Alon + allocate( fld2( nbergs, 15 ) ) !Changed from 11 to 15 by Alon allocate( icnt( grd%isd:grd%ied, grd%jsd:grd%jed ) ) fld(:,:)=0. fld2(:,:)=0. @@ -2640,9 +2672,13 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) fld(i,6) = this%thickness fld(i,7) = this%width fld(i,8) = this%length - fld(i,9) = time_hash(this) - fld(i,10) = pos_hash(this) - fld(i,11) = float(iberg) + fld(i,9) = this%axn !added by Alon + fld(i,10) = this%ayn !added by Alon + fld(i,11) = this%bxn !added by Alon + fld(i,12) = this%byn !added by Alon + fld(i,13) = time_hash(this) !Changed from 9 to 13 by Alon + fld(i,14) = pos_hash(this) !Changed from 10 to 12 by Alon + fld(i,15) = float(iberg) !Changed from 11 to 15 by Alon icnt(this%ine,this%jne)=icnt(this%ine,this%jne)+1 fld2(i,:) = fld(i,:)*float( icnt(this%ine,this%jne) ) !*float( i ) grd%tmp(this%ine,this%jne)=grd%tmp(this%ine,this%jne)+time_hash(this)*pos_hash(this)+log(this%mass) @@ -2695,8 +2731,8 @@ integer function berg_chksum(berg ) ! Arguments type(iceberg), pointer :: berg ! Local variables -real :: rtmp(28) -integer :: itmp(28+3), i8=0, ichk1, ichk2, ichk3 +real :: rtmp(32) !Changed from 28 to 32 by Alon +integer :: itmp(32+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 32 by Alon integer :: i rtmp(:)=0. @@ -2727,14 +2763,18 @@ integer function berg_chksum(berg ) rtmp(26)=berg%ssh_y rtmp(27)=berg%cn rtmp(28)=berg%hi + rtmp(29)=berg%axn !Added by Alon + rtmp(30)=berg%ayn !Added by Alon + rtmp(31)=berg%bxn !Added by Alon + rtmp(32)=berg%byn !Added by Alon - itmp(1:28)=transfer(rtmp,i8) - itmp(29)=berg%start_year - itmp(30)=berg%ine - itmp(31)=berg%jne + itmp(1:32)=transfer(rtmp,i8) !Changed from 28 to 32 by Alon + itmp(33)=berg%start_year !Changed from 29 to 33 by Alon + itmp(34)=berg%ine !Changed from 30 to 34 by Alon + itmp(35)=berg%jne !Changed from 31 to 35 by Alon ichk1=0; ichk2=0; ichk3=0 - do i=1,28+3 + do i=1,32+3 !Changd from 28 to 32 by Alon ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 154fca6..21bc0bd 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -103,6 +103,10 @@ subroutine write_restart(bergs) uvel, & vvel, & mass, & + axn, & + ayn, & + bxn, & + byn, & thickness, & width, & length, & @@ -140,6 +144,10 @@ subroutine write_restart(bergs) allocate(uvel(nbergs)) allocate(vvel(nbergs)) allocate(mass(nbergs)) + allocate(axn(nbergs)) + allocate(ayn(nbergs)) + allocate(bxn(nbergs)) + allocate(byn(nbergs)) allocate(thickness(nbergs)) allocate(width(nbergs)) allocate(length(nbergs)) @@ -170,6 +178,10 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_restart,filename,'uvel',uvel,longname='zonal velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'vvel',vvel,longname='meridional velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'mass',mass,longname='mass',units='kg') + id = register_restart_field(bergs_restart,filename,'axn',mass,longname='explicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'ayn',mass,longname='explicit meridional acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'bxn',mass,longname='inplicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'byn',mass,longname='implicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ine',ine,longname='i index',units='none') id = register_restart_field(bergs_restart,filename,'jne',jne,longname='j index',units='none') id = register_restart_field(bergs_restart,filename,'thickness',thickness,longname='thickness',units='m') @@ -200,6 +212,8 @@ subroutine write_restart(bergs) uvel(i) = this%uvel; vvel(i) = this%vvel ine(i) = this%ine; jne(i) = this%jne mass(i) = this%mass; thickness(i) = this%thickness + axn(i) = this%axn; ayn(i) = this%ayn !Added by Alon + bxn(i) = this%bxn; byn(i) = this%byn !Added by Alon width(i) = this%width; length(i) = this%length start_lon(i) = this%start_lon; start_lat(i) = this%start_lat start_year(i) = this%start_year; start_day(i) = this%start_day @@ -217,6 +231,10 @@ subroutine write_restart(bergs) uvel, & vvel, & mass, & + axn, & + ayn, & + bxn, & + byn, & thickness, & width, & length, & @@ -227,6 +245,7 @@ subroutine write_restart(bergs) mass_scaling, & mass_of_bits, & heat_density ) +!axn, ayn, bxn, byn above added by Alon deallocate( & ine, & @@ -270,6 +289,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer, dimension(:), allocatable :: found_restart_int integer :: k, ierr, ncid, dimid, nbergs_in_file integer :: lonid, latid, uvelid, vvelid, ineid, jneid +integer :: axnid, aynid, bxnid, bynid !Added by Alon integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, start_dayid, start_massid integer :: scaling_id, mass_of_bits_id, heat_density_id @@ -332,6 +352,10 @@ subroutine read_restart_bergs_orig(bergs,Time) uvelid=inq_var(ncid, 'uvel') vvelid=inq_var(ncid, 'vvel') massid=inq_var(ncid, 'mass') + axnid=inq_var(ncid, 'axn') !Alon + aynid=inq_var(ncid, 'ayn') !Alon + bxnid=inq_var(ncid, 'bxn') !Alon + bynid=inq_var(ncid, 'byn') !Alon thicknessid=inq_var(ncid, 'thickness') widthid=inq_var(ncid, 'width') lengthid=inq_var(ncid, 'length') @@ -381,6 +405,10 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%uvel=get_double(ncid, uvelid, k) localberg%vvel=get_double(ncid, vvelid, k) localberg%mass=get_double(ncid, massid, k) + localberg%axn=get_double(ncid, axnid, k) !Alon + localberg%ayn=get_double(ncid, aynid, k) !Alon + localberg%bxn=get_double(ncid, bxnid, k) !Alon + localberg%byn=get_double(ncid, bynid, k) !Alon localberg%thickness=get_double(ncid, thicknessid, k) localberg%width=get_double(ncid, widthid, k) localberg%length=get_double(ncid, lengthid, k) @@ -478,15 +506,31 @@ subroutine generate_bergs(bergs,Time) localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=-1. localberg%vvel=0. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=1. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=-1. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) endif enddo; enddo @@ -521,6 +565,10 @@ subroutine read_restart_bergs(bergs,Time) uvel, & vvel, & mass, & + axn, & + ayn, & + bxn, & + byn, & thickness, & width, & length, & @@ -531,7 +579,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & heat_density - +!axn, ayn, bxn, byn added by Alon integer, allocatable, dimension(:) :: ine, & jne, & start_year @@ -560,6 +608,10 @@ subroutine read_restart_bergs(bergs,Time) allocate(uvel(nbergs_in_file)) allocate(vvel(nbergs_in_file)) allocate(mass(nbergs_in_file)) + allocate(axn(nbergs_in_file)) !Alon + allocate(ayn(nbergs_in_file)) !Alon + allocate(bxn(nbergs_in_file)) !Alon + allocate(byn(nbergs_in_file)) !Alon allocate(thickness(nbergs_in_file)) allocate(width(nbergs_in_file)) allocate(length(nbergs_in_file)) @@ -580,6 +632,10 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) + call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) call read_unlimited_axis(filename,'width',width,domain=grd%domain) call read_unlimited_axis(filename,'length',length,domain=grd%domain) @@ -628,6 +684,10 @@ subroutine read_restart_bergs(bergs,Time) localberg%uvel=uvel(k) localberg%vvel=vvel(k) localberg%mass=mass(k) + localberg%axn=axn(k) !Alon + localberg%ayn=ayn(k) !Alon + localberg%bxn=bxn(k) !Alon + localberg%byn=byn(k) !Alon localberg%thickness=thickness(k) localberg%width=width(k) localberg%length=length(k) @@ -654,6 +714,10 @@ subroutine read_restart_bergs(bergs,Time) uvel, & vvel, & mass, & + axn, & + ayn, & + bxn, & + byn, & thickness, & width, & length, & @@ -664,7 +728,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & heat_density ) - +!axn, ayn, bxn, byn above added by Alon. deallocate( & ine, & jne, & @@ -719,15 +783,31 @@ subroutine generate_bergs(bergs,Time) localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=-1. localberg%vvel=0. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=1. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=-1. + localberg%axn=0. !Alon + localberg%ayn=0. !Alon + localberg%bxn=0. !Alon + localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) endif enddo; enddo @@ -820,6 +900,7 @@ subroutine write_trajectory(trajectory) ! Local variables integer :: iret, ncid, i_dim, i integer :: lonid, latid, yearid, dayid, uvelid, vvelid +!integer :: axnid, aynid, bxnid, bynid !Added by Alon integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid integer :: cnid, hiid integer :: mid, did, wid, lid, mbid, hdid @@ -923,6 +1004,10 @@ subroutine write_trajectory(trajectory) dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) + !axnid = def_var(ncid, 'axn', NF_DOUBLE, i_dim) !Alon + !aynid = def_var(ncid, 'ayn', NF_DOUBLE, i_dim) !Alon + !bxnid = def_var(ncid, 'bxn', NF_DOUBLE, i_dim) !Alon + !bynid = def_var(ncid, 'byn', NF_DOUBLE, i_dim) !Alon uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) From 4312f7090956a90e6794ca39f14fd0a78b345237 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 2 Jun 2015 14:28:07 -0400 Subject: [PATCH 011/361] Changed the submodule accel. The predictive corrective step when calculating the accelerations has been changed so that in the second iteration, it uses 0.5*(|u_o-u_n|+|u_o-u_star|). Previously it used |u_o-0.5*(u_n+u_star)|. This change does change the answers. --- icebergs.F90 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index b1e528e..91e6393 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -194,16 +194,17 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a uveln=uvel; vveln=vvel ! Copy starting uvel, vvel do itloop=1,2 ! Iterate on drag coefficients - us=0.5*(uveln+uvel); vs=0.5*(vveln+vvel) - drag_ocn=c_ocn*sqrt( (us-uo)**2+(vs-vo)**2 ) - drag_atm=c_atm*sqrt( (us-ua)**2+(vs-va)**2 ) - drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) +! These four lines commented out by Alon to use Bob's scheme rather than Alistairs. (will change answers) + ! us=0.5*(uveln+uvel); vs=0.5*(vveln+vvel) + ! drag_ocn=c_ocn*sqrt( (us-uo)**2+(vs-vo)**2 ) + ! drag_atm=c_atm*sqrt( (us-ua)**2+(vs-va)**2 ) + ! drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) !Alon's proposed change - This would change it to Bob's improved scheme. -! !us=uveln; vs=vveln This line is no longer needed -! drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel-uo)**2+(vvel-vo)**2 )) -! drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel-ua)**2+(vvel-va)**2 )) -! drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel-ui)**2+(vvel-vi)**2 )) + !us=uveln; vs=vveln This line is no longer needed + drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel-uo)**2+(vvel-vo)**2 )) + drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel-ua)**2+(vvel-va)**2 )) + drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel-ui)**2+(vvel-vi)**2 )) ! Explicit accelerations !axe= f_cori*vvel -gravity*ssh_x +wave_rad*uwave & From 6ffda6c16e2a8115b94b8dfc95dd15cdf4850f45 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 3 Jun 2015 15:16:21 -0400 Subject: [PATCH 012/361] Verlet algorithm now seems to be working. I have not yet tested it thoughouly though. --- icebergs.F90 | 80 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 91e6393..95ee614 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -191,7 +191,9 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a c_ice=rho_ice /M*(0.5*Cd_iv*W*hi ) if (abs(ui)+abs(vi).eq.0.) c_ice=0. - uveln=uvel; vveln=vvel ! Copy starting uvel, vvel +! uveln=uvel; vveln=vvel ! Copy starting uvel, vvel !Commented out by Alon + uveln=uvel0; vveln=vvel0 ! Copy starting uvel, vvel !Added by Alon + do itloop=1,2 ! Iterate on drag coefficients ! These four lines commented out by Alon to use Bob's scheme rather than Alistairs. (will change answers) @@ -202,9 +204,9 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !Alon's proposed change - This would change it to Bob's improved scheme. !us=uveln; vs=vveln This line is no longer needed - drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel-uo)**2+(vvel-vo)**2 )) - drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel-ua)**2+(vvel-va)**2 )) - drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel-ui)**2+(vvel-vi)**2 )) + drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) + drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) + drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) ! Explicit accelerations !axe= f_cori*vvel -gravity*ssh_x +wave_rad*uwave & @@ -1560,7 +1562,7 @@ subroutine evolve_icebergs(bergs) Rearth=6360.e3 !Choosing time stepping scheme - Alon - Runge_not_verlet=.true. !true=Runge Kutta, False=Verlet , Alon + Runge_not_verlet=.False. !true=Runge Kutta, False=Verlet , Alon berg=>bergs%first @@ -1862,6 +1864,8 @@ subroutine evolve_icebergs(bergs) ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax +!print *, 'you are here!' + lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) @@ -1870,45 +1874,52 @@ subroutine evolve_icebergs(bergs) !Loading past acceleartions - Alon axn=berg%axn; ayn=berg%ayn !Alon - byn=berg%bxn; byn=berg%byn !Alon + bxn=berg%bxn; byn=berg%byn !Alon -! Turn the velocities into u_star, v_star. - Alon (not sure how this works with tangent plane) - uvel1=uvel1+dt_2*axn !Alon - vvel1=vvel1+dt_2*ayn !Alon +! Velocities used to update the position + uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon + vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon -if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) - u1=uvel1*dxdl1; v1=vvel1*dydl +if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) + u2=uvel2*dxdl1; v2=vvel2*dydl - if (on_tangential_plane) call rotvec_to_tang(lon1,bxn,byn,bxddot,byddot) !Added by Alon -rotation of implicit velocity. !Solving for new position if (on_tangential_plane) then - xn=x1+dt_2*xdot1+(dt*dt*(bxddot)/2) ; yn=y1+dt_2*ydot1+(dt*dt*(byddot/2)) !Alon + xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon call rotpos_from_tang(xn,yn,lonn,latn) else - lonn=lon1+dt_2*u1+(dt*dt*(bxn)/2) ; latn=lat1+dt_2*v1+(dt*dt*(byn/2)) !Alon - uvel2=uvel1+dt*ax1; vvel2=vvel1+dt*ay1 !Alon , we call it uvel2, vvel2 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon endif - dxdl2=r180_pi/(Rearth*cos(latn*pi_180)) + dxdln=r180_pi/(Rearth*cos(latn*pi_180)) + +! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon + +!Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + i2=i; j2=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + + +!Calling the acceleration + call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon !Solving for the new velocity - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon - if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) if (on_tangential_plane) then - xdotn=xdot1+dt*xddot1; ydotn=ydot1+dt*yddot1 !Alon + call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) + call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) else - uvel2=uvel1+dt*ax1; vvel2=vvel1+dt*ay1 !Alon , we call it uvel2, vvel2 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + uvel4=uvel3+dt*ax1; vvel4=vvel3+dt*ay1 !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln endif - uveln=uvel2*dxdl2; vveln=vvel2*dydl !Converted to degrees. + uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. -!Adjusting mass... - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) - i2=i; j2=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) !Debugging if (.not.error_flag) then @@ -1925,16 +1936,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lonn=',lon1,lonn,berg%lon write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,latn=',lat1,latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,un,u0=',uvel1,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,vn,v0=',vvel1,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& & dt*ax1 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& & dt*ay1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,un,u0=',& - & dt*uvel1,dt*uvel2,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,vn,v0=',& - & dt*vvel1,dt*vvel2,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u3,un,u0=',& + & dt*uvel3,dt*uveln,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v3,vn,v0=',& + & dt*vvel3,dt*vveln,dt*berg%vvel write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u_n (deg)=',& & dt*u1,dt*uveln write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v_n (deg)=',& @@ -1942,7 +1953,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1964,6 +1975,7 @@ subroutine evolve_icebergs(bergs) endif ! End of the Verlet Stepiing -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!print *, 'you are here again!'; berg%lon=lonn berg%lat=latn berg%uvel=uveln From 717d0ef0645ec5fdf11488f69247a76ed5c4073c Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 3 Jun 2015 16:19:49 -0400 Subject: [PATCH 013/361] Runge_not_Verlet added to name list so that you can choose which time stepping scheme to use at runtime. --- icebergs.F90 | 4 ++-- icebergs_framework.F90 | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 95ee614..014ae56 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1562,8 +1562,8 @@ subroutine evolve_icebergs(bergs) Rearth=6360.e3 !Choosing time stepping scheme - Alon - Runge_not_verlet=.False. !true=Runge Kutta, False=Verlet , Alon - + !Runge_not_verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon + Runge_not_verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon berg=>bergs%first do while (associated(berg)) ! loop over all bergs diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ecc3efd..c6eff4b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -177,6 +177,7 @@ module ice_bergs_framework logical :: add_weight_to_ocean=.true. ! Add weight of bergs to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean + logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -266,6 +267,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: time_average_weight=.false. ! Time average the weight on the ocean real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs +logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) @@ -275,7 +277,7 @@ subroutine ice_bergs_framework_init(bergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & - time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, & + time_average_weight, generate_test_icebergs, speed_limit, Runge_not_Verlet, fix_restart_dates, use_roundoff_fix, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction ! Local variables @@ -494,6 +496,7 @@ subroutine ice_bergs_framework_init(bergs, & ! enddo !endif + ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs @@ -507,6 +510,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%passive_mode=passive_mode bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit + bergs%Runge_not_Verlet=Runge_not_Verlet !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) From 9dff46b367ecb58068106625f46127926ce1c046 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 8 Jun 2015 17:53:41 -0400 Subject: [PATCH 014/361] Flag added which allows the user to input a calving freq distribution rather than a mass flux distribution. If this flag is on, the code converts the input freq distribution into a mass flux distribution. --- icebergs_framework.F90 | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 48dfe14..7a3edb6 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -265,8 +265,9 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: do_unit_tests=.false. ! Conduct some unit tests +logical :: input_freq_distribution=.false. ! Alon: flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) -real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) +real, dimension(nclasses) :: distribution=(/0.25, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , Also 0.24 changed to 0.25 by Alon real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, & @@ -274,7 +275,7 @@ subroutine ice_bergs_framework_init(bergs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, & - old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction + old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -282,6 +283,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: minl logical :: lerr integer :: stdlogunit, stderrunit +real :: Total_mass !Added by Alon ! Get the stderr and stdlog unit numbers stderrunit=stderr() @@ -492,6 +494,21 @@ subroutine ice_bergs_framework_init(bergs, & ! enddo !endif + +!Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) +if (input_freq_distribution) then + Total_mass=0. + do j=1:nclasses + Total_mass=Total_mass+(distribution(j)*initial_mass(j)) + enddo + do j=1:nclasses + distribution(j)=(distribution(j)*initial_mass(j))/Total_mass + enddo +endif + + + + ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs From 15f3388c0ab1c8fc3faeea1f12b3b6fa9a7c4fc2 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 9 Jun 2015 09:10:27 -0400 Subject: [PATCH 015/361] Flag for using mass vs freq distribution has been included. --- icebergs_framework.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 7a3edb6..1917e4a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -498,10 +498,10 @@ subroutine ice_bergs_framework_init(bergs, & !Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) if (input_freq_distribution) then Total_mass=0. - do j=1:nclasses + do j=1,nclasses Total_mass=Total_mass+(distribution(j)*initial_mass(j)) enddo - do j=1:nclasses + do j=1,nclasses distribution(j)=(distribution(j)*initial_mass(j))/Total_mass enddo endif From 93329cba647751c95cf062c1f1aa9fa04cb0f9c8 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 9 Jun 2015 10:16:30 -0400 Subject: [PATCH 016/361] RK and Verlet schemes are giving different answers. Fixed one bug in Verlet scheme. Still need to test it further. --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 014ae56..b160b06 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1907,7 +1907,7 @@ subroutine evolve_icebergs(bergs) !Calling the acceleration - call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon !Solving for the new velocity if (on_tangential_plane) then From 603171613491d19dc58496896531f715e938f461 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 9 Jun 2015 10:28:04 -0400 Subject: [PATCH 017/361] Changed 0.25 back to 0.24 on the smallest category of the iceberg distribution since I was getting the error messaged "Calving is Over distributed". --- icebergs_framework.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 1917e4a..944dad0 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -267,7 +267,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: do_unit_tests=.false. ! Conduct some unit tests logical :: input_freq_distribution=.false. ! Alon: flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) -real, dimension(nclasses) :: distribution=(/0.25, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , Also 0.24 changed to 0.25 by Alon +real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, & From cebcdb4ce17dd9a8593bfaa3f84eeadd3754519e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 9 Jun 2015 15:58:14 -0400 Subject: [PATCH 018/361] Alpha set = 1 in the accel scheme (to make the drag implicit).:wq --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index b160b06..2cff261 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -129,7 +129,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: alpha=0.0, beta=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real, parameter :: alpha=1.0, beta=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. real :: lambda, detA, A11, A12, axe, aye, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed logical :: dumpit From b5604eb3fc5b3da8017ecf3b4780b06902257cef Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 11 Jun 2015 16:54:34 -0400 Subject: [PATCH 019/361] Changes to acceleration and evolve subroutines in order to make them resemble Alon's code more closely. Trying to get Verlet and RK to agree. Introduced Crank Nicolson Coriolis. Introduced axn, ayn into RK algorthim. --- icebergs.F90 | 181 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 106 insertions(+), 75 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2cff261..a52ff16 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -129,14 +129,17 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: alpha=1.0, beta=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. -real :: lambda, detA, A11, A12, axe, aye, D_hi +real, parameter :: alpha=1.0, beta=1.0, C_N=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed +real :: u_star, v_star !Added by Alon logical :: dumpit logical, intent(in) :: Runge_not_verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit + u_star=uvel0+(dt/2.*axn) !Alon + v_star=vvel0+(dt/2.*ayn) !Alon ! Get the stderr unit number. stderrunit = stderr() @@ -191,75 +194,90 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a c_ice=rho_ice /M*(0.5*Cd_iv*W*hi ) if (abs(ui)+abs(vi).eq.0.) c_ice=0. -! uveln=uvel; vveln=vvel ! Copy starting uvel, vvel !Commented out by Alon - uveln=uvel0; vveln=vvel0 ! Copy starting uvel, vvel !Added by Alon + + ! Half half accelerations - axn, ayn + if (.not.Runge_not_verlet) then + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave + else + ! Not half half accelerations - for RK + bxn=-gravity*ssh_x +wave_rad*uwave + byn=-gravity*ssh_y +wave_rad*vwave + endif + + if (alpha>0.) then ! If implicit Coriolis, use u_star rather than RK4 latest !Alon + if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon + axn=axn+f_cori*v_star + ayn=ayn-f_cori*u_star + else + bxn=bxn+f_cori*v_star + byn=byn-f_cori*u_star + endif + else + bxn=bxn+f_cori*vvel + byn=byn-f_cori*uvel + endif + + us=uvel0; vs=vvel0 ! us, vs are equivolent to u_pred in Alon's code. It is the variable that changes in the loop. do itloop=1,2 ! Iterate on drag coefficients -! These four lines commented out by Alon to use Bob's scheme rather than Alistairs. (will change answers) - ! us=0.5*(uveln+uvel); vs=0.5*(vveln+vvel) - ! drag_ocn=c_ocn*sqrt( (us-uo)**2+(vs-vo)**2 ) - ! drag_atm=c_atm*sqrt( (us-ua)**2+(vs-va)**2 ) - ! drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) - -!Alon's proposed change - This would change it to Bob's improved scheme. - !us=uveln; vs=vveln This line is no longer needed - drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) - drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) - drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) - - ! Explicit accelerations - !axe= f_cori*vvel -gravity*ssh_x +wave_rad*uwave & - ! -drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) - !aye=-f_cori*uvel -gravity*ssh_y +wave_rad*vwave & - ! -drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) - axe=-gravity*ssh_x +wave_rad*uwave - aye=-gravity*ssh_y +wave_rad*vwave - - if (.not.Runge_not_verlet) then ! When using Verlet, use only half the explicit acceleration, Added by Alon - axe=axe/2 - aye=aye/2 - endif - - if (alpha>0.) then ! If implicit, use time-level (n) rather than RK4 latest - axe=axe+f_cori*vvel0 - aye=aye-f_cori*uvel0 - else - axe=axe+f_cori*vvel - aye=aye-f_cori*uvel - endif - if (beta>0.) then ! If implicit, use time-level (n) rather than RK4 latest - axe=axe-drag_ocn*(uvel0-uo) -drag_atm*(uvel0-ua) -drag_ice*(uvel0-ui) - aye=aye-drag_ocn*(vvel0-vo) -drag_atm*(vvel0-va) -drag_ice*(vvel0-vi) + !Alon's proposed change - using Bob's improved scheme. + drag_ocn=c_ocn*0.5*(sqrt( (us-uo)**2+(vs-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) + drag_atm=c_atm*0.5*(sqrt( (us-ua)**2+(vs-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) + drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) + + +! RHS_x=(axn/2) + bxn- drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) +! RHS_y=(ayn/2) + byn -drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) + + + RHS_x=(axn/2) + bxn + RHS_y=(ayn/2) + byn + + if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest + RHS_x=RHS_x - drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) + RHS_y=RHS_y - drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) else - axe=axe-drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) - aye=aye-drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) + RHS_x=RHS_x - drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) + RHS_y=RHS_y - drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) endif - ! Solve for implicit accelerations + ! Solve for implicit accelerations if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice - A11=1.+beta*dt*lambda - A12=alpha*dt*f_cori + A11=1.+dt*lambda + A12=dt/2.*f_cori !Think about this more for non-Crank Nicolson. Why use dt_2? detA=1./(A11**2+A12**2) - ax=detA*(A11*axe+A12*aye) - ay=detA*(A11*aye-A12*axe) + ax=detA*(A11*RHS_x+A12*RHS_y) + ay=detA*(A11*RHS_y-A12*RHS_x) else - ax=axe; ay=aye + ax=RHS_x; ay=RHS_x endif - uveln=uvel0+dt*ax - vveln=vvel0+dt*ay + us=u_star+dt*ax ! Alon + vs=v_star+dt*ay ! Alon enddo ! itloop + uveln=us !Updated velocities + vveln=vs !Updated velocities + + !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon - axn=-gravity*ssh_x +wave_rad*uwave !Alon - ayn=-gravity*ssh_y +wave_rad*vwave !Alon + axn=0. + ayn=0. + if (.not.Runge_not_verlet) then + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave + endif + if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon + axn=axn+f_cori*vveln + ayn=ayn-f_cori*uveln + endif bxn= ax-(axn/2) !Alon byn= ay-(ayn/2) !Alon - ! Limit speed of bergs based on a CFL criteria if (bergs%speed_limit>0.) then @@ -308,7 +326,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a 'd*(u-ua)=',-drag_atm*(uvel-ua), & 'd*(u-ui)=',-drag_ice*(uvel-ui) write(stderrunit,100) mpp_pe(),'U accel.', & - 'axe=',axe, & + 'RHS_x=',RHS_x, & 'ax=',ax, & 'ax(cori)=',detA*(A11*(f_cori*vvel)+A12*(-f_cori*uvel)), & 'ax(grav)=',detA*(A11*(-gravity*ssh_x)+A12*(-gravity*ssh_y)), & @@ -326,7 +344,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a 'd*(v-va)=',-drag_atm*(vvel-va), & 'd*(v-vi)=',-drag_ice*(vvel-vi) write(stderrunit,100) mpp_pe(),'V accel. pe=', & - 'aye=',aye, & + 'RHS_y=',RHS_y, & 'ay=',ay, & 'ay(cori)=',detA*(-A12*(f_cori*vvel)+A11*(-f_cori*uvel)), & 'ay(grav)=',detA*(-A12*(-gravity*ssh_x)+A11*(-gravity*ssh_y)), & @@ -1514,16 +1532,16 @@ subroutine evolve_icebergs(bergs) type(icebergs), pointer :: bergs ! Local variables type(icebergs_gridded), pointer :: grd -real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1 -real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2 -real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3 -real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4 +real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axn1, ayn1 +real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axn2, ayn2 +real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axn3, ayn3 +real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axn4, ayn4 real :: uveln, vveln, lonn, latn, un, vn, dxdln -real :: x1, xdot1, xddot1, y1, ydot1, yddot1 -real :: x2, xdot2, xddot2, y2, ydot2, yddot2 -real :: x3, xdot3, xddot3, y3, ydot3, yddot3 -real :: x4, xdot4, xddot4, y4, ydot4, yddot4 -real :: xn, xdotn, yn, ydotn +real :: x1, xdot1, xddot1, y1, ydot1, yddot1, xddot1n, yddot1n +real :: x2, xdot2, xddot2, y2, ydot2, yddot2, xddot2n, yddot2n +real :: x3, xdot3, xddot3, y3, ydot3, yddot3, xddot3n, yddot3n +real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n +real :: xn, xdotn, yn, ydotn, xddotn, yddotn real :: bxddot, byddot ! Added by Alon real :: axn, ayn, bxn, byn ! Added by Alon - explicit and implicit accelations from the previous step real :: r180_pi, dt, dt_2, dt_6, dydl, Rearth @@ -1607,8 +1625,9 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn,ayn, bxn, byn ,Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet) !axn,ayn, bxn, byn ,Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) !if (debug) write(stderr(),*) 'diamonds, evolve: x2=...' @@ -1651,7 +1670,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1660,8 +1679,9 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) + if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' @@ -1704,10 +1724,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !ax, aye1, Runge_not_verlet- Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet- Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1716,8 +1736,9 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) + if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' @@ -1758,13 +1779,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1773,8 +1794,9 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) + if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 @@ -1783,14 +1805,22 @@ subroutine evolve_icebergs(bergs) yn=y1+dt_6*( (ydot1+ydot4)+2.*(ydot2+ydot3) ) xdotn=xdot1+dt_6*( (xddot1+xddot4)+2.*(xddot2+xddot3) ) ydotn=ydot1+dt_6*( (yddot1+yddot4)+2.*(yddot2+yddot3) ) + xddotn=( (xddot1n+xddot4n)+2.*(xddot2n+xddot3n) )/6. !Alon + yddotn=( (yddot1n+yddot4n)+2.*(yddot2n+yddot3n) )/6. !Alon call rotpos_from_tang(xn,yn,lonn,latn) call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + call rotvec_from_tang(lonn,xddotn,yddotn,axn,ayn) !Alon else lonn=berg%lon+dt_6*( (u1+u4)+2.*(u2+u3) ) latn=berg%lat+dt_6*( (v1+v4)+2.*(v2+v3) ) uveln=berg%uvel+dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) + axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon + ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon endif + + + i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & @@ -1906,8 +1936,9 @@ subroutine evolve_icebergs(bergs) call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) -!Calling the acceleration - call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon +!Calling the acceleration (note that the velocity is converted to u_star inside the accel script) +! call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon !Solving for the new velocity if (on_tangential_plane) then From c6412ed35edf3435c1b6f9ba383641c1f7e6a7f1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 11 Jun 2015 17:45:47 -0400 Subject: [PATCH 020/361] A few more corrections. RK now works when Crank Nicolson is off, but crashes when CN is on. --- icebergs.F90 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index a52ff16..d44164e 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -129,7 +129,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: alpha=1.0, beta=1.0, C_N=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real, parameter :: alpha=1.0, beta=1.0, C_N=0.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon @@ -247,7 +247,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice A11=1.+dt*lambda - A12=dt/2.*f_cori !Think about this more for non-Crank Nicolson. Why use dt_2? + A12=dt*f_cori + if (C_N>0.) then !For Crank-Nicolson Coriolis term. + A12=A12/2. + endif + detA=1./(A11**2+A12**2) ax=detA*(A11*RHS_x+A12*RHS_y) ay=detA*(A11*RHS_y-A12*RHS_x) @@ -1681,7 +1685,7 @@ subroutine evolve_icebergs(bergs) u2=uvel2*dxdl2; v2=vvel2*dydl call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) - if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) + if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' @@ -1738,7 +1742,7 @@ subroutine evolve_icebergs(bergs) u3=uvel3*dxdl3; v3=vvel3*dydl call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) - if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) + if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' From 4b08f7a9caa58184cf2f9006d301d2efbc5c6f0e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 12 Jun 2015 16:30:00 -0400 Subject: [PATCH 021/361] Another bug fixed. RK and Verlet are still not matching, but it is looking better. --- icebergs.F90 | 88 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d44164e..5877b14 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,7 +112,7 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs @@ -129,17 +129,18 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: alpha=1.0, beta=1.0, C_N=0.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real, parameter :: alpha=1.0, beta=1.0, C_N=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon logical :: dumpit -logical, intent(in) :: Runge_not_verlet ! Flag to specify whether it is Runge-Kutta or Verlet +logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit - u_star=uvel0+(dt/2.*axn) !Alon - v_star=vvel0+(dt/2.*ayn) !Alon +!print *, 'axn=',axn,'ayn=',ayn + u_star=uvel0+(axn*(dt/2.)) !Alon + v_star=vvel0+(ayn*(dt/2.)) !Alon ! Get the stderr unit number. stderrunit = stderr() @@ -150,7 +151,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interpolate gridded fields to berg call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) - f_cori=(2.*omega)*sin(pi_180*lat) + f_cori=(2.*omega)*sin(pi_180*lat) +! f_cori=0. M=berg%mass T=berg%thickness ! total thickness @@ -194,9 +196,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a c_ice=rho_ice /M*(0.5*Cd_iv*W*hi ) if (abs(ui)+abs(vi).eq.0.) c_ice=0. +!Turning drag off for testing - Alon +!c_ocn=0. +!c_atm=0. +!c_ice=0. ! Half half accelerations - axn, ayn - if (.not.Runge_not_verlet) then + if (.not.Runge_not_Verlet) then axn=-gravity*ssh_x +wave_rad*uwave ayn=-gravity*ssh_y +wave_rad*vwave else @@ -228,10 +234,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) -! RHS_x=(axn/2) + bxn- drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) -! RHS_y=(ayn/2) + byn -drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) - - RHS_x=(axn/2) + bxn RHS_y=(ayn/2) + byn @@ -271,7 +273,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon axn=0. ayn=0. - if (.not.Runge_not_verlet) then + if (.not.Runge_not_Verlet) then axn=-gravity*ssh_x +wave_rad*uwave ayn=-gravity*ssh_y +wave_rad*vwave endif @@ -1553,7 +1555,7 @@ subroutine evolve_icebergs(bergs) integer :: i1,j1,i2,j2,i3,j3,i4,j4 real :: xi, yj logical :: bounced, on_tangential_plane, error_flag -logical :: Runge_not_verlet ! Runge_not_verlet=1 for Runge Kutta, =0 for Verlet method. Added by Alon +logical :: Runge_not_Verlet ! Runge_not_Verlet=1 for Runge Kutta, =0 for Verlet method. Added by Alon type(iceberg), pointer :: berg integer :: stderrunit @@ -1584,8 +1586,8 @@ subroutine evolve_icebergs(bergs) Rearth=6360.e3 !Choosing time stepping scheme - Alon - !Runge_not_verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon - Runge_not_verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon + !Runge_not_Verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon + Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon berg=>bergs%first do while (associated(berg)) ! loop over all bergs @@ -1619,7 +1621,16 @@ subroutine evolve_icebergs(bergs) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - if (Runge_not_verlet) then !Start of the Runge-Kutta Loop -Added by Alon + + + if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop -Added by Alon, MP2 + + !Loading past acceleartions - Alon + axn=berg%axn; ayn=berg%ayn !Alon + axn1=axn; axn2=axn; axn3=axn; axn4=axn + ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn + + ! A1 = A(X1) lon1=berg%lon; lat1=berg%lat @@ -1629,7 +1640,8 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet) !axn,ayn, bxn, byn ,Runge_not_verlet - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !axn,ayn, bxn, byn ,Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon @@ -1674,7 +1686,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1683,7 +1695,8 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon @@ -1728,10 +1741,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet- Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet- Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1740,7 +1753,7 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon @@ -1783,13 +1796,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1798,7 +1811,7 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) @@ -1861,16 +1874,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') @@ -1890,7 +1903,7 @@ subroutine evolve_icebergs(bergs) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (.not.Runge_not_verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon + if (.not.Runge_not_Verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting @@ -1935,14 +1948,14 @@ subroutine evolve_icebergs(bergs) !Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" +! call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) !Calling the acceleration (note that the velocity is converted to u_star inside the accel script) -! call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon - call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet) !axn, ayn, bxn, byn ,Runge_not_verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn ,Runge_not_Verlet - Added by Alon !Solving for the new velocity if (on_tangential_plane) then @@ -1951,10 +1964,11 @@ subroutine evolve_icebergs(bergs) xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) else - uvel4=uvel3+dt*ax1; vvel4=vvel3+dt*ay1 !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + uvel4=uvel3+(dt*ax1); vvel4=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln endif - uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. - +! uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. (Perhaps this should not be here) + uveln=uvel4 + vveln=vvel4 !Debugging if (.not.error_flag) then @@ -1988,7 +2002,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) From 1711492f928ce63ab665744bd03003a2062776ec Mon Sep 17 00:00:00 2001 From: Niki Zadeh Date: Thu, 18 Jun 2015 18:45:06 -0400 Subject: [PATCH 022/361] Fix issue #1 the apparent hang in writing the trajectories - Model run apparently hangs at the end when trying to write icebergs trajectories This is not an i/o issue but due to the root pe (or io_tile_root_pes) traversing a linked list of millions of nodes. It just take a long long time. - This fix "push"es the nodes at the top of the list instead of trying to find the tail to append it. The list will be in reverse order and has to be reversed before writing to file. --- icebergs_framework.F90 | 29 ++++++++++++++++++++++++++++- icebergs_io.F90 | 7 +++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 48dfe14..148cde2 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -65,6 +65,7 @@ module ice_bergs_framework public checksum_gridded public grd_chksum2,grd_chksum3 public fix_restart_dates, offset_berg_dates +public reverse_list type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -1201,7 +1202,9 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%cn=buff%data(22,n) traj%hi=buff%data(23,n) - call append_posn(first, traj) +! call append_posn(first, traj) !This call could take a very long time (as if the run hangs) if there are millions of nodes in the list. Use push_posn instead and reverse the list later before writing the file. +! + call push_posn(first, traj) end subroutine unpack_traj_from_buffer2 @@ -1623,6 +1626,30 @@ end subroutine record_posn ! ############################################################################## +subroutine reverse_list(list) + ! Arguments + type(xyt), pointer :: list + + ! Local variables + type(xyt), pointer :: head,tail,node + integer :: i + + i=0 + head=>list + tail=>list + node=>list%next + list%next=>null() + do while (associated(node)) + head=>node + node=>node%next + head%next=>tail + tail=>head + i=i+1 + enddo + list=>head + print*,'reverse_list number of nodes= ',i +end subroutine reverse_list + subroutine push_posn(trajectory, posn_vals) ! Arguments type(xyt), pointer :: trajectory diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 154fca6..48b4c36 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -22,6 +22,7 @@ module ice_bergs_io use ice_bergs_framework, only: pack_berg_into_buffer2,unpack_berg_from_buffer2 use ice_bergs_framework, only: pack_traj_into_buffer2,unpack_traj_from_buffer2 use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell,append_posn +use ice_bergs_framework, only: push_posn use ice_bergs_framework, only: add_new_berg_to_list,destroy_iceberg use ice_bergs_framework, only: increase_ibuffer,increase_ibuffer_traj,grd_chksum2,grd_chksum3 use ice_bergs_framework, only: sum_mass,sum_heat,bilin @@ -29,7 +30,7 @@ module ice_bergs_io use ice_bergs_framework, only: nclasses, buffer_width, buffer_width_traj use ice_bergs_framework, only: verbose, really_debug, debug, restart_input_dir,make_calving_reproduce use ice_bergs_framework, only: ignore_ij_restart, use_slow_find,generate_test_icebergs,print_berg - +use ice_bergs_framework, only: reverse_list implicit none ; private @@ -844,7 +845,7 @@ subroutine write_trajectory(trajectory) if(associated(trajectory)) then this=>trajectory do while (associated(this)) - call append_posn(traj4io, this) + call push_posn(traj4io, this) this=>this%next enddo endif @@ -854,6 +855,7 @@ subroutine write_trajectory(trajectory) ntrajs_sent_io =0 ntrajs_rcvd_io =0 + if(is_io_tile_root_pe) then !Receive trajs from all pes in this I/O tile !FRAGILE!SCARY! do np=2,size(io_tile_pelist) ! Note: np starts from 2 to exclude self @@ -867,6 +869,7 @@ subroutine write_trajectory(trajectory) enddo endif enddo + call reverse_list(traj4io) else !Pack and Send trajs to the root pe for this I/O tile if (associated(trajectory)) then From 34783215c04328be28cfd628e5d838bec9ddceb8 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 22 Jun 2015 16:24:24 -0400 Subject: [PATCH 023/361] Included a spring force between icebergs. Damping has not been included yet. Have not looked closely to see if it works, but it does run. --- icebergs.F90 | 156 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 7 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5877b14..5e0a896 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -112,6 +112,138 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init + +! ############################################################################## + +subroutine interactive_force(bergs,berg,IA_x, IA_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 +type(icebergs), pointer :: bergs +type(iceberg), pointer :: berg +type(iceberg), pointer :: other_berg +real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg +real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg +real :: L_crit, r_dist_x, r_dist_y, r_dist, A_o, trapped, T_min +real :: Rearth +real :: kappa_s, accel_spring +real, intent(inout) :: IA_x, IA_y +integer :: stderrunit + +Rearth=6360.e3 +kappa_s=1.e-4 + +! Get the stderr unit number. Not sure what this does + stderrunit = stderr() + +IA_x=0. +IA_y=0. + +L1=berg%length +W1=berg%width +T1=berg%thickness +A1=L1*W1 +R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) +lon1=berg%lon; lat1=berg%lat +call rotpos_to_tang(lon1,lat1,x1,y1) + + other_berg=>bergs%first + do while (associated(other_berg)) ! loop over all other bergs - Need to think about which icebergs to loop over + L2=other_berg%length + W2=other_berg%width + T2=other_berg%thickness + A2=L2*W2 + R2=sqrt(A2/pi) ! Interaction radius of the other iceberg + L_crit=(R1+R2) + lon2=berg%lon; lat2=berg%lat + call rotpos_to_tang(lon2,lat2,x2,y2) + + r_dist_x=x1-x2 ; r_dist_y=y1-y2 + r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + + call overlap_area(R1,R2,r_dist,A_o,trapped) + T_min=min(T1,T2) + accel_spring=kappa_s*(T_min/T1)*(A_o/A1) + + if (r_dist>0) then + IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) + IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) + endif + + other_berg=>other_berg%next + enddo ! loop over all bergs + + contains + + + subroutine overlap_area(R1,R2,d,A,trapped) + real, intent(in) :: R1, R2, d + real, intent(out) :: A, Trapped + real :: R1_sq, R2_sq, d_sq + R1_sq=R1**2 + R2_sq=R2**2 + d_sq=d**2 + Trapped=0. + +if (d>0) then + if (d<(R1+R2)) then + if (d>abs(R1-R2)) then + A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) + else + A=min(pi*R1_sq,pi*R2_sq) + Trapped=1. + endif + else + A=0. + endif +else + A=0. ! No area of perfectly overlapping bergs (ie: a berg interacting with itself) +endif + + end subroutine overlap_area + + + subroutine rotpos_to_tang(lon, lat, x, y) + ! Arguments + real, intent(in) :: lon, lat + real, intent(out) :: x, y + ! Local variables + real :: r,colat,clon,slon + + if (lat>90.) then + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat + call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) + endif + if (lat==90.) then + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat + call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) + endif + + colat=90.-lat + r=Rearth*(colat*pi_180) + clon=cos(lon*pi_180) + slon=sin(lon*pi_180) + x=r*clon + y=r*slon + + end subroutine rotpos_to_tang + + + +end subroutine interactive_force + + +! ############################################################################## + + +!call Interactive_damping(bergs,berg, P_11, P_12, P_21, P_22, P_times_u_x, P_times_u_y) ! Damping forces, Made by Alon. + + + + + + +!end subroutine interactive_force + +! ############################################################################## + subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments @@ -133,6 +265,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon +real :: IA_x, IA_y !Added by Alon +real :: P_11, P_12, P_21, P_22, P_time_u_x, P_times_u_y !Added by Alon logical :: dumpit logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop @@ -148,7 +282,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! For convenience grd=>bergs%grd - ! Interpolate gridded fields to berg + ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) f_cori=(2.*omega)*sin(pi_180*lat) @@ -167,6 +301,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=0. byn=0. +! Interactive spring acceleration - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! + call Interactive_force(bergs,berg,IA_x, IA_y) ! Spring forces, Made by Alon. + +!IA_x=0. +!IA_y=0. + + hi=min(hi,D) D_hi=max(0.,D-hi) @@ -203,12 +344,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Half half accelerations - axn, ayn if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave - ayn=-gravity*ssh_y +wave_rad*vwave + axn=-gravity*ssh_x +wave_rad*uwave + IA_x + ayn=-gravity*ssh_y +wave_rad*vwave + IA_y else ! Not half half accelerations - for RK - bxn=-gravity*ssh_x +wave_rad*uwave - byn=-gravity*ssh_y +wave_rad*vwave + bxn=-gravity*ssh_x +wave_rad*uwave + IA_x + byn=-gravity*ssh_y +wave_rad*vwave + IA_y endif if (alpha>0.) then ! If implicit Coriolis, use u_star rather than RK4 latest !Alon @@ -233,6 +374,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_atm=c_atm*0.5*(sqrt( (us-ua)**2+(vs-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) +! call Interactive_damping(bergs,berg, P_11, P_12, P_21, P_22, P_times_u_x, P_times_u_y) ! Damping forces, Made by Alon. RHS_x=(axn/2) + bxn RHS_y=(ayn/2) + byn @@ -274,8 +416,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a axn=0. ayn=0. if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave - ayn=-gravity*ssh_y +wave_rad*vwave + axn=-gravity*ssh_x +wave_rad*uwave + IA_x + ayn=-gravity*ssh_y +wave_rad*vwave + IA_y endif if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon axn=axn+f_cori*vveln From 6f02e55dc7d4f8675b251dbe4e4decc0c6d6d0ee Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 23 Jun 2015 10:12:10 -0400 Subject: [PATCH 024/361] Interactive force and damping on relative motion have been included. As it stands, each iceberg looks at all other icebergs in its list (which I think only includes icebergs on the same tile). This needs to be thought through. The current scheme is also not order independent, and has not been tested. --- icebergs.F90 | 83 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5e0a896..e90ca55 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -115,26 +115,35 @@ end subroutine icebergs_init ! ############################################################################## -subroutine interactive_force(bergs,berg,IA_x, IA_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 +subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 type(icebergs), pointer :: bergs type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg -real :: L_crit, r_dist_x, r_dist_y, r_dist, A_o, trapped, T_min +real :: r_dist_x, r_dist_y, r_dist, A_o, trapped, T_min +real, intent(in) :: u0,v0, u1, v1 +real :: P_11, P_12, P_21, P_22 +real :: u2, v2 real :: Rearth -real :: kappa_s, accel_spring -real, intent(inout) :: IA_x, IA_y +real :: kappa_s, accel_spring, p_ia, p_ia_coef, q_ia +real, intent(out) :: IA_x, IA_y +real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y integer :: stderrunit Rearth=6360.e3 kappa_s=1.e-4 +p_ia=2.*sqrt(kappa_s) ! Critical damping +q_ia=(2.*sqrt(kappa_s)/5) ! Critical damping /5 (just a guess) ! Get the stderr unit number. Not sure what this does stderrunit = stderr() IA_x=0. IA_y=0. +P_ia_11=0. ; P_ia_12=0. ; P_ia_22=0. +P_ia_times_u_x=0. ; P_ia_times_u_y=0. + L1=berg%length W1=berg%width @@ -149,9 +158,10 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y) !Calculating interactive for L2=other_berg%length W2=other_berg%width T2=other_berg%thickness + u2=other_berg%uvel + v2=other_berg%vvel A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - L_crit=(R1+R2) lon2=berg%lon; lat2=berg%lat call rotpos_to_tang(lon2,lat2,x2,y2) @@ -160,13 +170,46 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y) !Calculating interactive for call overlap_area(R1,R2,r_dist,A_o,trapped) T_min=min(T1,T2) - accel_spring=kappa_s*(T_min/T1)*(A_o/A1) - if (r_dist>0) then + !Calculating spring force (later this should only be done on the first time around) + accel_spring=kappa_s*(T_min/T1)*(A_o/A1) + if ((r_dist>0) .AND. (r_dist< (R1+R2)) ) then IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) endif + + !Working out the damping + + !Paralel velocity + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + + p_ia_coef=p_ia*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 + p_ia_coef=q_ia*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + other_berg=>other_berg%next enddo ! loop over all bergs @@ -225,25 +268,12 @@ subroutine rotpos_to_tang(lon, lat, x, y) end subroutine rotpos_to_tang - - end subroutine interactive_force ! ############################################################################## -!call Interactive_damping(bergs,berg, P_11, P_12, P_21, P_22, P_times_u_x, P_times_u_y) ! Damping forces, Made by Alon. - - - - - - -!end subroutine interactive_force - -! ############################################################################## - subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments @@ -266,7 +296,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon real :: IA_x, IA_y !Added by Alon -real :: P_11, P_12, P_21, P_22, P_time_u_x, P_times_u_y !Added by Alon +real :: P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y !Added by Alon logical :: dumpit logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop @@ -302,11 +332,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a byn=0. ! Interactive spring acceleration - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! - call Interactive_force(bergs,berg,IA_x, IA_y) ! Spring forces, Made by Alon. - -!IA_x=0. -!IA_y=0. - +!P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0. ; P_ia22=0. ; P_times_u_x=0. P_times_u_y=0. ; IA_x=0. ; IA_y=0. +call Interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. hi=min(hi,D) D_hi=max(0.,D-hi) @@ -374,7 +401,9 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_atm=c_atm*0.5*(sqrt( (us-ua)**2+(vs-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) -! call Interactive_damping(bergs,berg, P_11, P_12, P_21, P_22, P_times_u_x, P_times_u_y) ! Damping forces, Made by Alon. + if (itloop>1) then + call Interactive_force(bergs, berg, IA_x, IA_y, us, vs, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + endif RHS_x=(axn/2) + bxn RHS_y=(ayn/2) + byn From c4c94c1a1c7324b4395a2eea3b27fb7bce084885 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 23 Jun 2015 14:56:46 -0400 Subject: [PATCH 025/361] Small change - bxn byn are now calculated correctly in RK. --- icebergs.F90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/icebergs.F90 b/icebergs.F90 index e90ca55..96891b2 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2005,6 +2005,9 @@ subroutine evolve_icebergs(bergs) vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon + bxn=(((ax1+ax4)+2.*(ax2+ax3) )/6) - (axn/2) + byn=(((ay1+ay4)+2.*(ay2+ay3) )/6) - (ayn/2) + endif From da6038755cbed5847d7d5db835a0b049939e90b3 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Jun 2015 15:37:43 -0400 Subject: [PATCH 026/361] The interactive damping has been added. --- icebergs.F90 | 57 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 96891b2..ae147f4 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -298,10 +298,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: IA_x, IA_y !Added by Alon real :: P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y !Added by Alon logical :: dumpit +logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit +interactive_icebergs_on=.true. + !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon v_star=vvel0+(ayn*(dt/2.)) !Alon @@ -331,10 +334,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=0. byn=0. -! Interactive spring acceleration - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! -!P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0. ; P_ia22=0. ; P_times_u_x=0. P_times_u_y=0. ; IA_x=0. ; IA_y=0. -call Interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. - hi=min(hi,D) D_hi=max(0.,D-hi) @@ -371,14 +370,28 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Half half accelerations - axn, ayn if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave + IA_x - ayn=-gravity*ssh_y +wave_rad*vwave + IA_y + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave else ! Not half half accelerations - for RK - bxn=-gravity*ssh_x +wave_rad*uwave + IA_x - byn=-gravity*ssh_y +wave_rad*vwave + IA_y + bxn=-gravity*ssh_x +wave_rad*uwave + byn=-gravity*ssh_y +wave_rad*vwave endif + +! Interactive spring acceleration - (Does the spring part need to be called twice?) +if (interactive_icebergs_on) then + call Interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + if (.not.Runge_not_Verlet) then + axn=axn + IA_x + ayn=ayn + IA_y + else + bxn=bxn + IA_x + byn=byn + IA_y + endif +endif + + if (alpha>0.) then ! If implicit Coriolis, use u_star rather than RK4 latest !Alon if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon axn=axn+f_cori*v_star @@ -401,21 +414,33 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_atm=c_atm*0.5*(sqrt( (us-ua)**2+(vs-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) - if (itloop>1) then - call Interactive_force(bergs, berg, IA_x, IA_y, us, vs, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. - endif - RHS_x=(axn/2) + bxn RHS_y=(ayn/2) + byn if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest - RHS_x=RHS_x - drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) - RHS_y=RHS_y - drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) + RHS_x=RHS_x - drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) + RHS_y=RHS_y - drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) else - RHS_x=RHS_x - drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) - RHS_y=RHS_y - drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) + RHS_x=RHS_x - drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) + RHS_y=RHS_y - drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) endif +if (interactive_icebergs_on) then + if (itloop>1) then + call Interactive_force(bergs, berg, IA_x, IA_y, us, vs, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + endif + if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest + RHS_x=RHS_x -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) + RHS_y=RHS_y -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) + else + RHS_x=RHS_x - (((P_ia_11*uvel)+(P_ia_12*vvel))-P_ia_times_u_x) + RHS_y=RHS_y - (((P_ia_21*uvel)+(P_ia_22*vvel))-P_ia_times_u_y) + endif +endif + + + + ! Solve for implicit accelerations if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice From 78556e57cab3dc7448b749da561881d7b9475151 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Jun 2015 15:44:27 -0400 Subject: [PATCH 027/361] Removed the Runge_not_Verlet flag from the acceleration calls, and loaded it instead inside the accel subroutine. --- icebergs.F90 | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index ae147f4..89170d4 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -274,7 +274,7 @@ end subroutine interactive_force ! ############################################################################## -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs @@ -299,11 +299,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y !Added by Alon logical :: dumpit logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. -logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet +logical :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit interactive_icebergs_on=.true. +Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon @@ -1836,8 +1837,8 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !axn,ayn, bxn, byn ,Runge_not_Verlet - Added by Alon - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 + !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon @@ -1882,7 +1883,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1891,8 +1892,8 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 + !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon @@ -1937,10 +1938,10 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet- Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -1949,7 +1950,7 @@ subroutine evolve_icebergs(bergs) endif dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon @@ -1992,13 +1993,13 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -2007,7 +2008,7 @@ subroutine evolve_icebergs(bergs) endif dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) @@ -2073,16 +2074,16 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') @@ -2154,7 +2155,7 @@ subroutine evolve_icebergs(bergs) !Calling the acceleration (note that the velocity is converted to u_star inside the accel script) - call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn ,Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon !Solving for the new velocity if (on_tangential_plane) then @@ -2201,7 +2202,7 @@ subroutine evolve_icebergs(bergs) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, Runge_not_Verlet, debug_flag=.true.) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) From 408e0873c8be2e39f3dde1e2df036cc6c8eee31d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Jun 2015 15:56:44 -0400 Subject: [PATCH 028/361] interactive_icebergs_on flag has been added to the namelist. This allows the user to turn on and off the spring and damping forces between icebergs. --- icebergs.F90 | 2 +- icebergs_framework.F90 | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 89170d4..54ecff6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -303,8 +303,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a integer :: itloop integer :: stderrunit -interactive_icebergs_on=.true. Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon +interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index c6eff4b..b53f504 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -178,6 +178,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -268,6 +269,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon +logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) @@ -277,7 +279,7 @@ subroutine ice_bergs_framework_init(bergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & - time_average_weight, generate_test_icebergs, speed_limit, Runge_not_Verlet, fix_restart_dates, use_roundoff_fix, & + time_average_weight, generate_test_icebergs, speed_limit, Runge_not_Verlet, interactive_icebergs_on, fix_restart_dates, use_roundoff_fix, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction ! Local variables @@ -511,6 +513,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%interactive_icebergs_on=interactive_icebergs_on !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) From a153bd63870c8ca5f75d267c4d3a197d8e7fb641 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Jun 2015 18:37:38 -0400 Subject: [PATCH 029/361] Fixed a number of bugs in the iceberg code. The iceberg interactions are now working. The model can run for a few days (have not tested for longer). Still need to make the code order invarient, and also to limit the amount of interactions to nearest neighbours. --- icebergs.F90 | 121 ++++++++++++++++++++++++++--------------- icebergs_framework.F90 | 11 +++- 2 files changed, 88 insertions(+), 44 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 54ecff6..bca9ac9 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -126,22 +126,32 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real :: P_11, P_12, P_21, P_22 real :: u2, v2 real :: Rearth -real :: kappa_s, accel_spring, p_ia, p_ia_coef, q_ia +real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y integer :: stderrunit Rearth=6360.e3 -kappa_s=1.e-4 -p_ia=2.*sqrt(kappa_s) ! Critical damping -q_ia=(2.*sqrt(kappa_s)/5) ! Critical damping /5 (just a guess) +!spring_coef=1.e-4 +spring_coef=bergs%spring_coef +!radial_damping_coef=bergs%radial_damping_coef +!tangental_damping_coef=bergs%tangental_damping_coef + +!Using critical values for damping rather than manually setting the damping. +radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping +tangental_damping_coef=(2.*sqrt(spring_coef)/5) ! Critical damping /5 (just a guess) + +!radial_damping_coef=1.e-4 +!tangental_damping_coef=1.e-4 + + ! Get the stderr unit number. Not sure what this does stderrunit = stderr() IA_x=0. IA_y=0. -P_ia_11=0. ; P_ia_12=0. ; P_ia_22=0. +P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. P_ia_times_u_x=0. ; P_ia_times_u_y=0. @@ -172,43 +182,46 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i T_min=min(T1,T2) !Calculating spring force (later this should only be done on the first time around) - accel_spring=kappa_s*(T_min/T1)*(A_o/A1) - if ((r_dist>0) .AND. (r_dist< (R1+R2)) ) then - IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) - IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - endif + accel_spring=spring_coef*(T_min/T1)*(A_o/A1) + if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then + IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) + IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - !Working out the damping + !Working out the damping !Paralel velocity - P_11=(r_dist_x*r_dist_x)/(r_dist**2) - P_12=(r_dist_x*r_dist_y)/(r_dist**2) - P_22=(r_dist_y*r_dist_y)/(r_dist**2) - - p_ia_coef=p_ia*(T_min/T1)*(A_o/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - - !Normal velocities - P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - p_ia_coef=q_ia*(T_min/T1)*(A_o/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_21=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + p_ia_coef=radial_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 + p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + +!print *, 'P_11',P_11 +!print *, 'P_21',P_21 +!print *, 'P_12',P_12 +!print *, 'P_22',P_22 + endif other_berg=>other_berg%next enddo ! loop over all bergs @@ -225,7 +238,7 @@ subroutine overlap_area(R1,R2,d,A,trapped) d_sq=d**2 Trapped=0. -if (d>0) then +if (d>0.) then if (d<(R1+R2)) then if (d>abs(R1-R2)) then A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) @@ -292,7 +305,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop real, parameter :: alpha=1.0, beta=1.0, C_N=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. -real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi +real :: lambda, detA, A11, A12, A21, A22, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon real :: IA_x, IA_y !Added by Alon @@ -390,6 +403,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=bxn + IA_x byn=byn + IA_y endif +!print *,'IA_x=',IA_x +!print *,'IA_x=',IA_x,'IA_y',IA_y +!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 +!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y + endif @@ -446,14 +464,31 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice A11=1.+dt*lambda - A12=dt*f_cori + A22=1.+dt*lambda + A12=-dt*f_cori + A21=dt*f_cori + !A12=dt*f_cori !Removed by ALon (in order to have the entire matrix. I hope the sign is correct) + if (C_N>0.) then !For Crank-Nicolson Coriolis term. A12=A12/2. + A21=A21/2. endif - detA=1./(A11**2+A12**2) - ax=detA*(A11*RHS_x+A12*RHS_y) - ay=detA*(A11*RHS_y-A12*RHS_x) + if (interactive_icebergs_on) then + A11=A11+P_ia_11 + A12=A12+P_ia_12 + A21=A21+P_ia_21 + A22=A22+P_ia_22 + endif + + detA=1./((A11*A22)-(A12*A21)) + ax=detA*(A22*RHS_x-A12*RHS_y) + ay=detA*(A11*RHS_y-A21*RHS_x) + +!Alistair's version removed by Alon +! detA=1./(A11**2+A12**2) +! ax=detA*(A11*RHS_x+A12*RHS_y) +! ay=detA*(A11*RHS_y-A12*RHS_x) else ax=RHS_x; ay=RHS_x endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index b53f504..ae836b5 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -167,6 +167,9 @@ module ice_bergs_framework integer :: verbose_hrs integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers real :: rho_bergs ! Density of icebergs [kg/m^3] + real :: spring_coef ! Spring contant for iceberg interactions - Alon + real :: radial_damping_coef ! Coef for relative iceberg motion damping (radial component) -Alon + real :: tangental_damping_coef ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0 Date: Thu, 25 Jun 2015 18:00:49 -0400 Subject: [PATCH 030/361] Saving before attempting to make the iceberg action order invarient --- icebergs.F90 | 21 ++++++++++++--------- icebergs_framework.F90 | 5 ++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index bca9ac9..0c69411 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -126,6 +126,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real :: P_11, P_12, P_21, P_22 real :: u2, v2 real :: Rearth +logical :: critical_interaction_damping_on real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y @@ -134,16 +135,15 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i Rearth=6360.e3 !spring_coef=1.e-4 spring_coef=bergs%spring_coef -!radial_damping_coef=bergs%radial_damping_coef -!tangental_damping_coef=bergs%tangental_damping_coef +radial_damping_coef=bergs%radial_damping_coef +tangental_damping_coef=bergs%tangental_damping_coef +critical_interaction_damping_on=bergs%critical_interaction_damping_on !Using critical values for damping rather than manually setting the damping. -radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping -tangental_damping_coef=(2.*sqrt(spring_coef)/5) ! Critical damping /5 (just a guess) - -!radial_damping_coef=1.e-4 -!tangental_damping_coef=1.e-4 - +if (critical_interaction_damping_on) then + radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping + tangental_damping_coef=(2.*sqrt(spring_coef)/5) ! Critical damping /5 (just a guess) +endif ! Get the stderr unit number. Not sure what this does @@ -164,7 +164,10 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i call rotpos_to_tang(lon1,lat1,x1,y1) other_berg=>bergs%first - do while (associated(other_berg)) ! loop over all other bergs - Need to think about which icebergs to loop over + +!Note: This summing should be made order invarient. +!Note: Need to limit how many icebergs we search over + do while (associated(other_berg)) ! loop over all other bergs L2=other_berg%length W2=other_berg%width T2=other_berg%thickness diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ae836b5..d388d26 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -182,6 +182,7 @@ module ice_bergs_framework logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon + logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -276,6 +277,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon +logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) @@ -285,7 +287,7 @@ subroutine ice_bergs_framework_init(bergs, & distribution, spring_coef, radial_damping_coef, tangental_damping_coef , mass_scaling, initial_thickness, verbose_hrs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & - time_average_weight, generate_test_icebergs, speed_limit, Runge_not_Verlet, interactive_icebergs_on, fix_restart_dates, use_roundoff_fix, & + time_average_weight, generate_test_icebergs, speed_limit, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, fix_restart_dates, use_roundoff_fix, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction ! Local variables @@ -522,6 +524,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%critical_interaction_damping_on=critical_interaction_damping_on !Alon bergs%interactive_icebergs_on=interactive_icebergs_on !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean From 6854f3a6c4efd158de835c3943df3b48b8b1bf90 Mon Sep 17 00:00:00 2001 From: Niki Zadeh Date: Fri, 26 Jun 2015 17:11:02 -0400 Subject: [PATCH 031/361] Add capabality to write one traj file per core - Timings show that in long run simulations writing one trajectory file per tile io has a sever impact on model timing. Specifically Termination time can become larger than the Main loop time. - This update bypasses using the io_layout for trajectory files and forces one file per processor (the way old iceberg model behaved till ulm) by setting a namelist icebergs_nml: force_all_pes_traj = .true. - This is a temporary fix to let people run long run simulations until we find a proper fix. --- icebergs_framework.F90 | 9 +++++++-- icebergs_io.F90 | 35 +++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 148cde2..239b8ac 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -39,12 +39,14 @@ module ice_bergs_framework real, parameter :: pi_180=pi/180. ! Converts degrees to radians logical :: fix_restart_dates=.true. ! After a restart, check that bergs were created before the current model date logical :: do_unit_tests=.false. ! Conduct some unit tests +logical :: force_all_pes_traj=.false. ! Force all pes write trajectory files regardless of io_layout +logical :: reverse_traj=.false. ! Force trajectories to be written in reverse order into files to save time !Public params !Niki: write a subroutine to expose these public nclasses,buffer_width,buffer_width_traj public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,old_bug_bilin,use_roundoff_fix public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget -public orig_read +public orig_read, force_all_pes_traj, reverse_traj !Public types @@ -165,6 +167,7 @@ module ice_bergs_framework integer :: traj_sample_hrs integer :: verbose_hrs integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers + integer :: clock_trw, clock_trp real :: rho_bergs ! Density of icebergs [kg/m^3] real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits @@ -275,7 +278,8 @@ subroutine ice_bergs_framework_init(bergs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, & - old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction + old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction,& + force_all_pes_traj, reverse_traj ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -324,6 +328,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%clock_ior=mpp_clock_id( 'Icebergs-I/O read', flags=clock_flag_default, grain=CLOCK_SUBCOMPONENT ) bergs%clock_iow=mpp_clock_id( 'Icebergs-I/O write', flags=clock_flag_default, grain=CLOCK_SUBCOMPONENT ) bergs%clock_dia=mpp_clock_id( 'Icebergs-diagnostics', flags=clock_flag_default, grain=CLOCK_SUBCOMPONENT ) + call mpp_clock_begin(bergs%clock) call mpp_clock_begin(bergs%clock_ini) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 48b4c36..3a4bdc6 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -16,6 +16,10 @@ module ice_bergs_io use fms_io_mod, only : register_restart_axis, register_restart_field, set_domain, nullify_domain use fms_io_mod, only : read_unlimited_axis =>read_compressed, field_exist, get_field_size +use mpp_mod, only : mpp_clock_begin, mpp_clock_end, mpp_clock_id +use mpp_mod, only : CLOCK_COMPONENT, CLOCK_SUBCOMPONENT, CLOCK_LOOP +use fms_mod, only : clock_flag_default + use time_manager_mod, only: time_type, get_date, get_time, set_date, operator(-) use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer @@ -30,7 +34,7 @@ module ice_bergs_io use ice_bergs_framework, only: nclasses, buffer_width, buffer_width_traj use ice_bergs_framework, only: verbose, really_debug, debug, restart_input_dir,make_calving_reproduce use ice_bergs_framework, only: ignore_ij_restart, use_slow_find,generate_test_icebergs,print_berg -use ice_bergs_framework, only: reverse_list +use ice_bergs_framework, only: reverse_list, force_all_pes_traj, reverse_traj implicit none ; private @@ -49,6 +53,8 @@ module ice_bergs_io integer, allocatable,save :: io_tile_pelist(:) logical :: is_io_tile_root_pe = .true. +integer :: clock_trw,clock_trp + #ifdef _FILE_VERSION character(len=128) :: version = _FILE_VERSION #else @@ -82,6 +88,9 @@ subroutine ice_bergs_io_init(bergs, io_layout) io_npes = io_layout(1)*io_layout(2) endif + clock_trw=mpp_clock_id( 'Icebergs-traj write', flags=clock_flag_default, grain=CLOCK_SUBCOMPONENT ) + clock_trp=mpp_clock_id( 'Icebergs-traj prepare', flags=clock_flag_default, grain=CLOCK_SUBCOMPONENT ) + end subroutine ice_bergs_io_init ! ############################################################################## @@ -839,9 +848,10 @@ subroutine write_trajectory(trajectory) stderrunit=stderr() !Assemble the list of trajectories from all pes in this I/O tile + call mpp_clock_begin(clock_trp) !First add the trajs on the io_tile_root_pe (if any) to the I/O list - if(is_io_tile_root_pe) then + if(is_io_tile_root_pe .OR. force_all_pes_traj ) then if(associated(trajectory)) then this=>trajectory do while (associated(this)) @@ -851,11 +861,12 @@ subroutine write_trajectory(trajectory) endif endif + if(.NOT. force_all_pes_traj ) then + !Now gather and append the bergs from all pes in the io_tile to the list on corresponding io_tile_root_pe ntrajs_sent_io =0 ntrajs_rcvd_io =0 - if(is_io_tile_root_pe) then !Receive trajs from all pes in this I/O tile !FRAGILE!SCARY! do np=2,size(io_tile_pelist) ! Note: np starts from 2 to exclude self @@ -869,7 +880,7 @@ subroutine write_trajectory(trajectory) enddo endif enddo - call reverse_list(traj4io) +! if(.NOT. reverse_traj .AND. associated(traj4io)) call reverse_list(traj4io) else !Pack and Send trajs to the root pe for this I/O tile if (associated(trajectory)) then @@ -888,14 +899,25 @@ subroutine write_trajectory(trajectory) endif endif + endif !.NOT. force_all_pes_traj + + !Here traj4io has all the trajectories in completely reverse order (last position of the last berg first) + !If a correct order is prefered in the trajectory file then reverse the linked list + !This may increase the the termination time of the model by a lot!!! + if(is_io_tile_root_pe .OR. force_all_pes_traj ) then + if(.NOT. reverse_traj .AND. associated(traj4io)) call reverse_list(traj4io) + endif + + call mpp_clock_end(clock_trp) !Now start writing in the io_tile_root_pe if there are any bergs in the I/O list + call mpp_clock_begin(clock_trw) - if(is_io_tile_root_pe .AND. associated(traj4io)) then + if((force_all_pes_traj .OR. is_io_tile_root_pe) .AND. associated(traj4io)) then call get_instance_filename("iceberg_trajectories.nc", filename) - if(io_tile_id(1) .ge. 0) then !io_tile_root_pes write + if(io_tile_id(1) .ge. 0 .AND. .NOT. force_all_pes_traj) then !io_tile_root_pes write if(io_npes .gt. 1) then !attach tile_id to filename only if there is more than one I/O pe if (io_tile_id(1)<10000) then write(filename,'(A,".",I4.4)') trim(filename), io_tile_id(1) @@ -1034,6 +1056,7 @@ subroutine write_trajectory(trajectory) if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_close failed',mpp_pe(),filename endif !(is_io_tile_root_pe .AND. associated(traj4io)) + call mpp_clock_end(clock_trw) end subroutine write_trajectory From 59e3853de10e53ad1e0ab43c998bc08e41e2976b Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 7 Jul 2015 13:42:23 -0400 Subject: [PATCH 032/361] Iceberg interactions are now order invarient, and icebergs interact with the positions of other icebergs at time n --- icebergs.F90 | 43 +++++++++++++++----- icebergs_framework.F90 | 68 +++++++++++++++++++++++-------- icebergs_io.F90 | 91 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 165 insertions(+), 37 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 0c69411..5071421 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -171,11 +171,11 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i L2=other_berg%length W2=other_berg%width T2=other_berg%thickness - u2=other_berg%uvel - v2=other_berg%vvel + u2=other_berg%uvel_old !Old values are used to make it order invariant + v2=other_berg%vvel_old !Old values are used to make it order invariant A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - lon2=berg%lon; lat2=berg%lat + lon2=berg%lon_old; lat2=berg%lat_old !Old values are used to make it order invariant call rotpos_to_tang(lon2,lat2,x2,y2) r_dist_x=x1-x2 ; r_dist_y=y1-y2 @@ -1793,6 +1793,7 @@ subroutine evolve_icebergs(bergs) logical :: Runge_not_Verlet ! Runge_not_Verlet=1 for Runge Kutta, =0 for Verlet method. Added by Alon type(iceberg), pointer :: berg integer :: stderrunit +logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. ! 4th order Runge-Kutta to solve: ! d/dt X = V, d/dt V = A @@ -1813,6 +1814,8 @@ subroutine evolve_icebergs(bergs) ! For convenience grd=>bergs%grd + interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon + ! Common constants r180_pi=1./pi_180 dt=bergs%dt @@ -2161,6 +2164,8 @@ subroutine evolve_icebergs(bergs) axn=berg%axn; ayn=berg%ayn !Alon bxn=berg%bxn; byn=berg%byn !Alon + + ! Velocities used to update the position uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon @@ -2262,27 +2267,43 @@ subroutine evolve_icebergs(bergs) endif ! End of the Verlet Stepiing -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!print *, 'you are here again!'; - berg%lon=lonn - berg%lat=latn - berg%uvel=uveln - berg%vvel=vveln +!Saving all the iceberg variables. berg%axn=axn !Alon berg%ayn=ayn !Alon berg%bxn=bxn !Alon berg%byn=byn !Alon + berg%lon=lonn + berg%lat=latn + berg%uvel=uveln + berg%vvel=vveln berg%ine=i berg%jne=j berg%xi=xi berg%yj=yj - !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) - - !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') + !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) + !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') + berg=>berg%next enddo ! loop over all bergs +! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) + if (interactive_icebergs_on) then + berg=>bergs%first + do while (associated(berg)) ! loop over all bergs + + !Updating iceberg positions and velocities + berg%lon_old=berg%lon + berg%lat_old=berg%lat + berg%uvel_old=berg%uvel + berg%vvel_old=berg%vvel + + berg=>berg%next + enddo ! loop over all bergs + + + endif contains subroutine rotpos_to_tang(lon, lat, x, y) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d388d26..70c09c9 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,8 +15,8 @@ module ice_bergs_framework implicit none ; private -integer, parameter :: buffer_width=24 !Changed from 20 to 24 by Alon -integer, parameter :: buffer_width_traj=27 !Changed from 23 by Alon +integer, parameter :: buffer_width=28 !Changed from 20 to 28 by Alon +integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -129,7 +129,7 @@ module ice_bergs_framework type :: xyt real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel - real :: axn, ayn, bxn, byn !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi real :: mass_of_bits, heat_density integer :: year @@ -140,7 +140,7 @@ module ice_bergs_framework type(iceberg), pointer :: prev=>null(), next=>null() ! State variables (specific to the iceberg, needed for restarts) real :: lon, lat, uvel, vvel, mass, thickness, width, length - real :: axn, ayn, bxn, byn !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_old, lat_old !Explicit and implicit accelerations !Alon real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density integer :: start_year @@ -957,6 +957,10 @@ subroutine pack_berg_into_buffer2(berg, buff, n) buff%data(22,n)=berg%ayn !Alon buff%data(23,n)=berg%bxn !Alon buff%data(24,n)=berg%byn !Alon + buff%data(25,n)=berg%uvel_old !Alon + buff%data(26,n)=berg%vvel_old !Alon + buff%data(27,n)=berg%lon_old !Alon + buff%data(28,n)=berg%lat_old !Alon end subroutine pack_berg_into_buffer2 @@ -1036,6 +1040,10 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) localberg%ayn=buff%data(22,n) !Alon localberg%bxn=buff%data(23,n) !Alon localberg%byn=buff%data(24,n) !Alon + localberg%uvel_old=buff%data(25,n) !Alon + localberg%vvel_old=buff%data(26,n) !Alon + localberg%lon_old=buff%data(27,n) !Alon + localberg%lat_old=buff%data(28,n) !Alon lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then @@ -1053,6 +1061,8 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) write(stderrunit,*) localberg%uvel,localberg%vvel write(stderrunit,*) localberg%axn,localberg%ayn !Alon write(stderrunit,*) localberg%bxn,localberg%byn !Alon + write(stderrunit,*) localberg%uvel_old,localberg%vvel_old !Alon + write(stderrunit,*) localberg%lon_old,localberg%lat_old !Alon write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) @@ -1200,6 +1210,10 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(25,n)=traj%ayn !Alon buff%data(26,n)=traj%bxn !Alon buff%data(27,n)=traj%byn !Alon + buff%data(28,n)=traj%uvel_old !Alon + buff%data(29,n)=traj%vvel_old !Alon + buff%data(30,n)=traj%lon_old !Alon + buff%data(31,n)=traj%lat_old !Alon end subroutine pack_traj_into_buffer2 @@ -1241,6 +1255,10 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%ayn=buff%data(25,n) !Alon traj%bxn=buff%data(26,n) !Alon traj%byn=buff%data(27,n) !Alon + traj%uvel_old=buff%data(28,n) !Alon + traj%vvel_old=buff%data(29,n) !Alon + traj%lon_old=buff%data(30,n) !Alon + traj%lat_old=buff%data(31,n) !Alon call append_posn(first, traj) @@ -1493,6 +1511,10 @@ logical function sameberg(berg1, berg2) if (berg1%ayn.ne.berg2%ayn) return !Alon if (berg1%bxn.ne.berg2%bxn) return !Alon if (berg1%byn.ne.berg2%byn) return !Alon + if (berg1%uvel_old.ne.berg2%uvel_old) return !Alon + if (berg1%vvel_old.ne.berg2%vvel_old) return !Alon + if (berg1%lon_old.ne.berg2%lon_old) return !Alon + if (berg1%lat_old.ne.berg2%lat_old) return !Alon sameberg=.true. ! passing the above tests mean that bergs 1 and 2 are identical end function sameberg @@ -1580,6 +1602,8 @@ subroutine print_berg(iochan, berg, label) ' u,v=', berg%uvel, berg%vvel, & ' axn,ayn=', berg%axn, berg%ayn, & ' bxn,byn=', berg%bxn, berg%byn, & + ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old, & + ' lon_old,lat_old=', berg%lon_old, berg%lat_old, & ' p,n=', associated(berg%prev), associated(berg%next) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f10.4))') & label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi @@ -1664,6 +1688,10 @@ subroutine record_posn(bergs) posn%ayn=this%ayn posn%bxn=this%bxn posn%byn=this%byn + posn%uvel_old=this%uvel_old + posn%vvel_old=this%vvel_old + posn%lon_old=this%lon_old + posn%lat_old=this%lat_old call push_posn(this%trajectory, posn) @@ -2670,8 +2698,8 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) nbergs=count_bergs(bergs) call mpp_max(nbergs) - allocate( fld( nbergs, 15 ) ) !Changed from 11 to 15 by Alon - allocate( fld2( nbergs, 15 ) ) !Changed from 11 to 15 by Alon + allocate( fld( nbergs, 19 ) ) !Changed from 11 to 19 by Alon + allocate( fld2( nbergs, 19 ) ) !Changed from 11 to 19 by Alon allocate( icnt( grd%isd:grd%ied, grd%jsd:grd%jed ) ) fld(:,:)=0. fld2(:,:)=0. @@ -2695,9 +2723,13 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) fld(i,10) = this%ayn !added by Alon fld(i,11) = this%bxn !added by Alon fld(i,12) = this%byn !added by Alon - fld(i,13) = time_hash(this) !Changed from 9 to 13 by Alon - fld(i,14) = pos_hash(this) !Changed from 10 to 12 by Alon - fld(i,15) = float(iberg) !Changed from 11 to 15 by Alon + fld(i,13) = this%uvel_old !added by Alon + fld(i,14) = this%vvel_old !added by Alon + fld(i,15) = this%lon_old !added by Alon + fld(i,16) = this%lat_old !added by Alon + fld(i,17) = time_hash(this) !Changed from 9 to 17 by Alon + fld(i,18) = pos_hash(this) !Changed from 10 to 18 by Alon + fld(i,19) = float(iberg) !Changed from 11 to 19 by Alon icnt(this%ine,this%jne)=icnt(this%ine,this%jne)+1 fld2(i,:) = fld(i,:)*float( icnt(this%ine,this%jne) ) !*float( i ) grd%tmp(this%ine,this%jne)=grd%tmp(this%ine,this%jne)+time_hash(this)*pos_hash(this)+log(this%mass) @@ -2750,8 +2782,8 @@ integer function berg_chksum(berg ) ! Arguments type(iceberg), pointer :: berg ! Local variables -real :: rtmp(32) !Changed from 28 to 32 by Alon -integer :: itmp(32+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 32 by Alon +real :: rtmp(34) !Changed from 28 to 34 by Alon +integer :: itmp(34+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon integer :: i rtmp(:)=0. @@ -2786,14 +2818,18 @@ integer function berg_chksum(berg ) rtmp(30)=berg%ayn !Added by Alon rtmp(31)=berg%bxn !Added by Alon rtmp(32)=berg%byn !Added by Alon + rtmp(33)=berg%uvel_old !Added by Alon + rtmp(34)=berg%vvel_old !Added by Alon + rtmp(35)=berg%lat_old !Added by Alon + rtmp(36)=berg%lon_old !Added by Alon - itmp(1:32)=transfer(rtmp,i8) !Changed from 28 to 32 by Alon - itmp(33)=berg%start_year !Changed from 29 to 33 by Alon - itmp(34)=berg%ine !Changed from 30 to 34 by Alon - itmp(35)=berg%jne !Changed from 31 to 35 by Alon + itmp(1:36)=transfer(rtmp,i8) !Changed from 28 to 36 by Alon + itmp(37)=berg%start_year !Changed from 29 to 37 by Alon + itmp(38)=berg%ine !Changed from 30 to 38 by Alon + itmp(39)=berg%jne !Changed from 31 to 39 by Alon ichk1=0; ichk2=0; ichk3=0 - do i=1,32+3 !Changd from 28 to 32 by Alon + do i=1,36+3 !Changd from 28 to 36 by Alon ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 21bc0bd..9f6410c 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -100,11 +100,15 @@ subroutine write_restart(bergs) type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & lat, & + lon_old, & + lat_old, & uvel, & vvel, & mass, & axn, & ayn, & + uvel_old, & + vvel_old, & bxn, & byn, & thickness, & @@ -122,6 +126,7 @@ subroutine write_restart(bergs) jne, & start_year +!uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. ! For convenience grd=>bergs%grd @@ -141,13 +146,17 @@ subroutine write_restart(bergs) allocate(lon(nbergs)) allocate(lat(nbergs)) + allocate(lon_old(nbergs)) !Alon + allocate(lat_old(nbergs)) !Alon allocate(uvel(nbergs)) allocate(vvel(nbergs)) allocate(mass(nbergs)) - allocate(axn(nbergs)) - allocate(ayn(nbergs)) - allocate(bxn(nbergs)) - allocate(byn(nbergs)) + allocate(axn(nbergs)) !Alon + allocate(ayn(nbergs)) !Alon + allocate(uvel_old(nbergs)) !Alon + allocate(vvel_old(nbergs)) !Alon + allocate(bxn(nbergs)) !Alon + allocate(byn(nbergs)) !Alon allocate(thickness(nbergs)) allocate(width(nbergs)) allocate(length(nbergs)) @@ -175,11 +184,15 @@ subroutine write_restart(bergs) ! Define Variables id = register_restart_field(bergs_restart,filename,'lon',lon,longname='longitude',units='degrees_E') id = register_restart_field(bergs_restart,filename,'lat',lat,longname='latitude',units='degrees_N') + id = register_restart_field(bergs_restart,filename,'lon_old',lon_old,longname='longitude',units='degrees_E') !Alon + id = register_restart_field(bergs_restart,filename,'lat_old',lat_old,longname='latitude',units='degrees_N') !Alon id = register_restart_field(bergs_restart,filename,'uvel',uvel,longname='zonal velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'vvel',vvel,longname='meridional velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'mass',mass,longname='mass',units='kg') id = register_restart_field(bergs_restart,filename,'axn',mass,longname='explicit zonal acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ayn',mass,longname='explicit meridional acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'uvel_old',mass,longname='old explicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'vvel_old',mass,longname='old explicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'bxn',mass,longname='inplicit zonal acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'byn',mass,longname='implicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ine',ine,longname='i index',units='none') @@ -209,10 +222,12 @@ subroutine write_restart(bergs) if(associated(bergs%first)) this=>bergs%first do i=1,nbergs lon(i) = this%lon; lat(i) = this%lat + lon_old(i) = this%lon_old; lat_old(i) = this%lat_old !Alon uvel(i) = this%uvel; vvel(i) = this%vvel ine(i) = this%ine; jne(i) = this%jne mass(i) = this%mass; thickness(i) = this%thickness axn(i) = this%axn; ayn(i) = this%ayn !Added by Alon + uvel_old(i) = this%uvel_old; vvel_old(i) = this%vvel_old !Added by Alon bxn(i) = this%bxn; byn(i) = this%byn !Added by Alon width(i) = this%width; length(i) = this%length start_lon(i) = this%start_lon; start_lat(i) = this%start_lat @@ -228,11 +243,15 @@ subroutine write_restart(bergs) deallocate( & lon, & lat, & + lon_old, & + lat_old, & uvel, & vvel, & mass, & axn, & ayn, & + uvel_old, & + vvel_old, & bxn, & byn, & thickness, & @@ -245,7 +264,7 @@ subroutine write_restart(bergs) mass_scaling, & mass_of_bits, & heat_density ) -!axn, ayn, bxn, byn above added by Alon +!axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon deallocate( & ine, & @@ -288,8 +307,8 @@ subroutine read_restart_bergs_orig(bergs,Time) ! Local variables integer, dimension(:), allocatable :: found_restart_int integer :: k, ierr, ncid, dimid, nbergs_in_file -integer :: lonid, latid, uvelid, vvelid, ineid, jneid -integer :: axnid, aynid, bxnid, bynid !Added by Alon +integer :: lonid, latid, uvelid, vvelid, ineid, jneid +integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid, lon_oldid, lat_oldid !Added by Alon integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, start_dayid, start_massid integer :: scaling_id, mass_of_bits_id, heat_density_id @@ -349,11 +368,15 @@ subroutine read_restart_bergs_orig(bergs,Time) lonid=inq_var(ncid, 'lon') latid=inq_var(ncid, 'lat') + lon_oldid=inq_var(ncid, 'lon_old') !Alon + lat_oldid=inq_var(ncid, 'lat_old') !Alon uvelid=inq_var(ncid, 'uvel') vvelid=inq_var(ncid, 'vvel') massid=inq_var(ncid, 'mass') axnid=inq_var(ncid, 'axn') !Alon aynid=inq_var(ncid, 'ayn') !Alon + uvel_oldid=inq_var(ncid, 'uvel_old') !Alon + vvel_oldid=inq_var(ncid, 'vvel_old') !Alon bxnid=inq_var(ncid, 'bxn') !Alon bynid=inq_var(ncid, 'byn') !Alon thicknessid=inq_var(ncid, 'thickness') @@ -407,6 +430,10 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%mass=get_double(ncid, massid, k) localberg%axn=get_double(ncid, axnid, k) !Alon localberg%ayn=get_double(ncid, aynid, k) !Alon + localberg%uvel_old=get_double(ncid, uvel_oldid, k) !Alon + localberg%vvel_old=get_double(ncid, vvel_oldid, k) !Alon + localberg%lon_old=get_double(ncid, lon_oldid, k) !Alon + localberg%lat_old=get_double(ncid, lat_oldid, k) !Alon localberg%bxn=get_double(ncid, bxnid, k) !Alon localberg%byn=get_double(ncid, bynid, k) !Alon localberg%thickness=get_double(ncid, thicknessid, k) @@ -492,6 +519,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) + localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) @@ -508,6 +537,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -515,6 +546,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -522,6 +555,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=1. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -529,6 +564,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=-1. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -562,11 +599,15 @@ subroutine read_restart_bergs(bergs,Time) real, allocatable, dimension(:) :: lon, & lat, & + lon_old, & + lat_old, & uvel, & vvel, & mass, & axn, & ayn, & + uvel_old, & + vvel_old, & bxn, & byn, & thickness, & @@ -579,7 +620,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & heat_density -!axn, ayn, bxn, byn added by Alon +!axn, ayn, uvel_old, vvel_old, lon_old, lat_old, bxn, byn added by Alon integer, allocatable, dimension(:) :: ine, & jne, & start_year @@ -605,11 +646,15 @@ subroutine read_restart_bergs(bergs,Time) if(nbergs_in_file > 0) then allocate(lon(nbergs_in_file)) allocate(lat(nbergs_in_file)) + allocate(lon_old(nbergs_in_file)) !Alon + allocate(lat_old(nbergs_in_file)) !Alon allocate(uvel(nbergs_in_file)) allocate(vvel(nbergs_in_file)) allocate(mass(nbergs_in_file)) allocate(axn(nbergs_in_file)) !Alon allocate(ayn(nbergs_in_file)) !Alon + allocate(uvel_old(nbergs_in_file)) !Alon + allocate(vvel_old(nbergs_in_file)) !Alon allocate(bxn(nbergs_in_file)) !Alon allocate(byn(nbergs_in_file)) !Alon allocate(thickness(nbergs_in_file)) @@ -629,11 +674,15 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) + call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) @@ -686,6 +735,10 @@ subroutine read_restart_bergs(bergs,Time) localberg%mass=mass(k) localberg%axn=axn(k) !Alon localberg%ayn=ayn(k) !Alon + localberg%uvel_old=uvel_old(k) !Alon + localberg%vvel_old=vvel_old(k) !Alon + localberg%lon_old=lon_old(k) !Alon + localberg%lat_old=lat_old(k) !Alon localberg%bxn=bxn(k) !Alon localberg%byn=byn(k) !Alon localberg%thickness=thickness(k) @@ -711,11 +764,15 @@ subroutine read_restart_bergs(bergs,Time) deallocate( & lon, & lat, & + lon_old, & + lat_old, & uvel, & vvel, & mass, & axn, & ayn, & + uvel_old, & + vvel_old, & bxn, & byn, & thickness, & @@ -728,7 +785,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & heat_density ) -!axn, ayn, bxn, byn above added by Alon. +!axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon. deallocate( & ine, & jne, & @@ -769,6 +826,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) + localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) @@ -785,6 +844,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -792,6 +853,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -799,6 +862,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=1. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -806,6 +871,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel=-1. localberg%axn=0. !Alon localberg%ayn=0. !Alon + localberg%uvel_old=0. !Alon + localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%first, localberg) @@ -900,7 +967,7 @@ subroutine write_trajectory(trajectory) ! Local variables integer :: iret, ncid, i_dim, i integer :: lonid, latid, yearid, dayid, uvelid, vvelid -!integer :: axnid, aynid, bxnid, bynid !Added by Alon +!integer :: axnid, aynid, uvel_oldid, vvel_oldid, lat_oldid, lon_oldid, bxnid, bynid !Added by Alon integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid integer :: cnid, hiid integer :: mid, did, wid, lid, mbid, hdid @@ -1006,6 +1073,10 @@ subroutine write_trajectory(trajectory) vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) !axnid = def_var(ncid, 'axn', NF_DOUBLE, i_dim) !Alon !aynid = def_var(ncid, 'ayn', NF_DOUBLE, i_dim) !Alon + !uvel_oldid = def_var(ncid, 'uvel_old', NF_DOUBLE, i_dim) !Alon + !vvel_oldid = def_var(ncid, 'vvel_old', NF_DOUBLE, i_dim) !Alon + !lon_oldid = def_var(ncid, 'lon_old', NF_DOUBLE, i_dim) !Alon + !lat_oldid = def_var(ncid, 'lat_old', NF_DOUBLE, i_dim) !Alon !bxnid = def_var(ncid, 'bxn', NF_DOUBLE, i_dim) !Alon !bynid = def_var(ncid, 'byn', NF_DOUBLE, i_dim) !Alon uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) From 19107e7d38c1c518b916f0b4b4c7b960cc4e1cc5 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 16 Jul 2015 10:36:18 -0400 Subject: [PATCH 033/361] Updated write_trajectory() to not clobber existing file - write_trajectory() now appends data to an existing file. This is a pre-requisite to being able to write trajectories mid-run and thereby reduce the extreme i/o buffer sizes and i/o PE memory requirements when writing trajectories only at the end of the run. - Relevant to issue #1. - No answer changes. --- icebergs_io.F90 | 225 ++++++++++++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 82 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 154fca6..6e763c4 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -833,6 +833,7 @@ subroutine write_trajectory(trajectory) integer :: ntrajs_sent_io,ntrajs_rcvd_io integer :: from_pe,np type(buffer), pointer :: obuffer_io=>null(), ibuffer_io=>null() +logical :: io_is_in_append_mode ! Get the stderr unit number stderrunit=stderr() @@ -909,93 +910,132 @@ subroutine write_trajectory(trajectory) endif if (verbose) write(*,'(2a)') 'diamonds, write_trajectory: creating ',filename - iret = nf_create(filename, NF_CLOBBER, ncid) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_create failed' - - ! Dimensions - iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_def_dim i failed' - - ! Variables - lonid = def_var(ncid, 'lon', NF_DOUBLE, i_dim) - latid = def_var(ncid, 'lat', NF_DOUBLE, i_dim) - yearid = def_var(ncid, 'year', NF_INT, i_dim) - dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) - uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) - vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) - uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) - void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) - uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) - viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) - uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) - vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) - mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) - mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) - hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) - did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) - wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) - lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) - sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) - sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) - sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) - cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) - hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) - - ! Attributes - iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) - iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_minor_version', NF_INT, 1, 1) - call put_att(ncid, lonid, 'long_name', 'longitude') - call put_att(ncid, lonid, 'units', 'degrees_E') - call put_att(ncid, latid, 'long_name', 'latitude') - call put_att(ncid, latid, 'units', 'degrees_N') - call put_att(ncid, yearid, 'long_name', 'year') - call put_att(ncid, yearid, 'units', 'years') - call put_att(ncid, dayid, 'long_name', 'year day') - call put_att(ncid, dayid, 'units', 'days') - call put_att(ncid, uvelid, 'long_name', 'zonal spped') - call put_att(ncid, uvelid, 'units', 'm/s') - call put_att(ncid, vvelid, 'long_name', 'meridional spped') - call put_att(ncid, vvelid, 'units', 'm/s') - call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') - call put_att(ncid, uoid, 'units', 'm/s') - call put_att(ncid, void, 'long_name', 'ocean meridional spped') - call put_att(ncid, void, 'units', 'm/s') - call put_att(ncid, uiid, 'long_name', 'ice zonal spped') - call put_att(ncid, uiid, 'units', 'm/s') - call put_att(ncid, viid, 'long_name', 'ice meridional spped') - call put_att(ncid, viid, 'units', 'm/s') - call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') - call put_att(ncid, uaid, 'units', 'm/s') - call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') - call put_att(ncid, vaid, 'units', 'm/s') - call put_att(ncid, mid, 'long_name', 'mass') - call put_att(ncid, mid, 'units', 'kg') - call put_att(ncid, mbid, 'long_name', 'mass_of_bits') - call put_att(ncid, mbid, 'units', 'kg') - call put_att(ncid, hdid, 'long_name', 'heat_density') - call put_att(ncid, hdid, 'units', 'J/kg') - call put_att(ncid, did, 'long_name', 'thickness') - call put_att(ncid, did, 'units', 'm') - call put_att(ncid, wid, 'long_name', 'width') - call put_att(ncid, wid, 'units', 'm') - call put_att(ncid, lid, 'long_name', 'length') - call put_att(ncid, lid, 'units', 'm') - call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') - call put_att(ncid, sshxid, 'units', 'non-dim') - call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') - call put_att(ncid, sshyid, 'units', 'non-dim') - call put_att(ncid, sstid, 'long_name', 'sea surface temperature') - call put_att(ncid, sstid, 'units', 'degrees_C') - call put_att(ncid, cnid, 'long_name', 'sea ice concentration') - call put_att(ncid, cnid, 'units', 'none') - call put_att(ncid, hiid, 'long_name', 'sea ice thickness') - call put_att(ncid, hiid, 'units', 'm') + io_is_in_append_mode = .false. + iret = nf_create(filename, NF_NOCLOBBER, ncid) + if (iret .ne. NF_NOERR) then + iret = nf_open(filename, NF_WRITE, ncid) + io_is_in_append_mode = .true. + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_open failed' + endif + + if (io_is_in_append_mode) then + iret = nf_inq_dimid(ncid, 'i', i_dim) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimid i failed' + lonid = inq_varid(ncid, 'lon') + latid = inq_varid(ncid, 'lat') + yearid = inq_varid(ncid, 'year') + dayid = inq_varid(ncid, 'day') + uvelid = inq_varid(ncid, 'uvel') + vvelid = inq_varid(ncid, 'vvel') + uoid = inq_varid(ncid, 'uo') + void = inq_varid(ncid, 'vo') + uiid = inq_varid(ncid, 'ui') + viid = inq_varid(ncid, 'vi') + uaid = inq_varid(ncid, 'ua') + vaid = inq_varid(ncid, 'va') + mid = inq_varid(ncid, 'mass') + mbid = inq_varid(ncid, 'mass_of_bits') + hdid = inq_varid(ncid, 'heat_density') + did = inq_varid(ncid, 'thickness') + wid = inq_varid(ncid, 'width') + lid = inq_varid(ncid, 'length') + sshxid = inq_varid(ncid, 'ssh_x') + sshyid = inq_varid(ncid, 'ssh_y') + sstid = inq_varid(ncid, 'sst') + cnid = inq_varid(ncid, 'cn') + hiid = inq_varid(ncid, 'hi') + else + ! Dimensions + iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_def_dim i failed' + + ! Variables + lonid = def_var(ncid, 'lon', NF_DOUBLE, i_dim) + latid = def_var(ncid, 'lat', NF_DOUBLE, i_dim) + yearid = def_var(ncid, 'year', NF_INT, i_dim) + dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) + uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) + vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) + uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) + void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) + uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) + viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) + uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) + vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) + mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) + mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) + hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) + did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) + wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) + lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) + sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) + sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) + sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) + cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) + hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) + + ! Attributes + iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) + iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_minor_version', NF_INT, 1, 1) + call put_att(ncid, lonid, 'long_name', 'longitude') + call put_att(ncid, lonid, 'units', 'degrees_E') + call put_att(ncid, latid, 'long_name', 'latitude') + call put_att(ncid, latid, 'units', 'degrees_N') + call put_att(ncid, yearid, 'long_name', 'year') + call put_att(ncid, yearid, 'units', 'years') + call put_att(ncid, dayid, 'long_name', 'year day') + call put_att(ncid, dayid, 'units', 'days') + call put_att(ncid, uvelid, 'long_name', 'zonal spped') + call put_att(ncid, uvelid, 'units', 'm/s') + call put_att(ncid, vvelid, 'long_name', 'meridional spped') + call put_att(ncid, vvelid, 'units', 'm/s') + call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') + call put_att(ncid, uoid, 'units', 'm/s') + call put_att(ncid, void, 'long_name', 'ocean meridional spped') + call put_att(ncid, void, 'units', 'm/s') + call put_att(ncid, uiid, 'long_name', 'ice zonal spped') + call put_att(ncid, uiid, 'units', 'm/s') + call put_att(ncid, viid, 'long_name', 'ice meridional spped') + call put_att(ncid, viid, 'units', 'm/s') + call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') + call put_att(ncid, uaid, 'units', 'm/s') + call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') + call put_att(ncid, vaid, 'units', 'm/s') + call put_att(ncid, mid, 'long_name', 'mass') + call put_att(ncid, mid, 'units', 'kg') + call put_att(ncid, mbid, 'long_name', 'mass_of_bits') + call put_att(ncid, mbid, 'units', 'kg') + call put_att(ncid, hdid, 'long_name', 'heat_density') + call put_att(ncid, hdid, 'units', 'J/kg') + call put_att(ncid, did, 'long_name', 'thickness') + call put_att(ncid, did, 'units', 'm') + call put_att(ncid, wid, 'long_name', 'width') + call put_att(ncid, wid, 'units', 'm') + call put_att(ncid, lid, 'long_name', 'length') + call put_att(ncid, lid, 'units', 'm') + call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') + call put_att(ncid, sshxid, 'units', 'non-dim') + call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') + call put_att(ncid, sshyid, 'units', 'non-dim') + call put_att(ncid, sstid, 'long_name', 'sea surface temperature') + call put_att(ncid, sstid, 'units', 'degrees_C') + call put_att(ncid, cnid, 'long_name', 'sea ice concentration') + call put_att(ncid, cnid, 'units', 'none') + call put_att(ncid, hiid, 'long_name', 'sea ice thickness') + call put_att(ncid, hiid, 'units', 'm') + endif ! End define mode iret = nf_enddef(ncid) ! Write variables - this=>traj4io; i=0 + this=>traj4io + if (io_is_in_append_mode) then + iret = nf_inq_dimlen(ncid, i_dim, i) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimlen i failed' + else + i = 0 + endif do while (associated(this)) i=i+1 call put_double(ncid, lonid, i, this%lon) @@ -1086,6 +1126,27 @@ end function def_var ! ############################################################################## +integer function inq_varid(ncid, var) +! Arguments +integer, intent(in) :: ncid +character(len=*), intent(in) :: var +! Local variables +integer :: iret +integer :: stderrunit + + ! Get the stderr unit number + stderrunit=stderr() + + iret = nf_inq_varid(ncid, var, inq_varid) + if (iret .ne. NF_NOERR) then + write(stderrunit,*) 'diamonds, inq_varid: nf_inq_varid failed for ',trim(var) + call error_mesg('diamonds, inq_varid', 'netcdf function returned a failure!', FATAL) + endif + +end function inq_varid + +! ############################################################################## + subroutine put_att(ncid, id, att, attval) ! Arguments integer, intent(in) :: ncid, id From 150ae95810e35ad44505fe2e28c7175404a0518c Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 16 Jul 2015 11:33:34 -0400 Subject: [PATCH 034/361] Ensure that trajectory memory is deallocated - We now deallocate the links in the trajectory chain when packing into the i/o buffer. This is in preparation for repeatedly calling write_trajectory(), see issue #1. - No answer changes. --- icebergs_io.F90 | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 6e763c4..a895e79 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -848,6 +848,7 @@ subroutine write_trajectory(trajectory) call append_posn(traj4io, this) this=>this%next enddo + trajectory => null() endif endif @@ -869,16 +870,14 @@ subroutine write_trajectory(trajectory) endif enddo else - !Pack and Send trajs to the root pe for this I/O tile - if (associated(trajectory)) then - this=>trajectory - do while (associated(this)) - ntrajs_sent_io = ntrajs_sent_io +1 - call pack_traj_into_buffer2(this, obuffer_io, ntrajs_sent_io) - - this=>this%next - enddo - endif + ! Pack and send trajectories to the root PE for this I/O tile + do while (associated(trajectory)) + ntrajs_sent_io = ntrajs_sent_io +1 + call pack_traj_into_buffer2(trajectory, obuffer_io, ntrajs_sent_io) + this => trajectory ! Need to keep pointer in order to free up the links memory + trajectory => trajectory%next ! This will eventually result in trajectory => null() + deallocate(this) ! Delete the link from memory + enddo call mpp_send(ntrajs_sent_io, plen=1, to_pe=io_tile_root_pe, tag=COMM_TAG_11) if (ntrajs_sent_io .gt. 0) then @@ -1064,8 +1063,7 @@ subroutine write_trajectory(trajectory) deallocate(this) this=>next enddo - trajectory=>null() - + ! Finish up iret = nf_close(ncid) if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_close failed',mpp_pe(),filename From cea20742b3d88a6a8588d50edb57c3d780f71833 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 16 Jul 2015 16:32:14 -0400 Subject: [PATCH 035/361] Nullify pointers on repeated calls to write_trajectory() - When calling write_trajectory() a second time, the declaration type(buffer), pointer :: obuffer_io=>null() does not nullify the pointer. Added explicit nullification in the code in addition. - No answer changes. --- icebergs_io.F90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index a895e79..38314d7 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -829,7 +829,7 @@ subroutine write_trajectory(trajectory) integer :: stderrunit !I/O vars -type(xyt), pointer :: traj4io=>NULL() +type(xyt), pointer :: traj4io=>null() integer :: ntrajs_sent_io,ntrajs_rcvd_io integer :: from_pe,np type(buffer), pointer :: obuffer_io=>null(), ibuffer_io=>null() @@ -837,6 +837,9 @@ subroutine write_trajectory(trajectory) ! Get the stderr unit number stderrunit=stderr() + traj4io=>null() + obuffer_io=>null() + ibuffer_io=>null() !Assemble the list of trajectories from all pes in this I/O tile From 6af1a8027ffff02a39b39a913782de464cf4538a Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 16 Jul 2015 16:34:02 -0400 Subject: [PATCH 036/361] Corrected terminal message for creating trajectory file - Message used to say "creating" even when appending. - No answer changes. --- icebergs_io.F90 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 38314d7..cfff9ca 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -910,7 +910,6 @@ subroutine write_trajectory(trajectory) write(filename,'(A,".",I6.6)') trim(filename), mpp_pe() endif endif - if (verbose) write(*,'(2a)') 'diamonds, write_trajectory: creating ',filename io_is_in_append_mode = .false. iret = nf_create(filename, NF_NOCLOBBER, ncid) @@ -919,6 +918,13 @@ subroutine write_trajectory(trajectory) io_is_in_append_mode = .true. if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_open failed' endif + if (verbose) then + if (io_is_in_append_mode) then + write(*,'(2a)') 'diamonds, write_trajectory: appending to ',filename + else + write(*,'(2a)') 'diamonds, write_trajectory: creating ',filename + endif + endif if (io_is_in_append_mode) then iret = nf_inq_dimid(ncid, 'i', i_dim) From a3913a7bf23c3c22d8fcc57ba47d17fcfe559f0c Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 16 Jul 2015 16:35:19 -0400 Subject: [PATCH 037/361] Added ability to frequently write trajectories - traj_write_hrs controls interval between writing trajectories. - Should help with issue #1. - No answer changes. --- icebergs.F90 | 20 +++++++++++--------- icebergs_framework.F90 | 30 +++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 4c0965a..fa60754 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -29,7 +29,7 @@ module ice_bergs use ice_bergs_framework, only: nclasses,old_bug_bilin use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list -use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory +use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory,move_all_trajectories use ice_bergs_framework, only: record_posn,check_position,print_berg,print_bergs,print_fld use ice_bergs_framework, only: add_new_berg_to_list,delete_iceberg_from_list,destroy_iceberg use ice_bergs_framework, only: grd_chksum2,grd_chksum3 @@ -762,7 +762,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd -logical :: lerr, sample_traj, lbudget, lverbose +logical :: lerr, sample_traj, write_traj, lbudget, lverbose real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask @@ -804,6 +804,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%traj_sample_hrs>0) then if (mod(24*iday+ihr,bergs%traj_sample_hrs).eq.0) sample_traj=.true. end if + write_traj=.false. + if (bergs%traj_write_hrs>0) then + if (mod(24*iday+ihr,bergs%traj_write_hrs).eq.0) write_traj=.true. + end if lverbose=.false. if (bergs%verbose_hrs>0) then if (mod(24*iday+ihr,bergs%verbose_hrs).eq.0) lverbose=verbose @@ -961,6 +965,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! For each berg, record call mpp_clock_begin(bergs%clock_dia) if (sample_traj.and.associated(bergs%first)) call record_posn(bergs) + if (write_traj) then + call move_all_trajectories(bergs) + call write_trajectory(bergs%trajectories) + endif ! Gridded diagnostics if (grd%id_uo>0) & @@ -2172,13 +2180,7 @@ subroutine icebergs_end(bergs) call mpp_clock_begin(bergs%clock_ini) ! Delete bergs and structures - this=>bergs%first - do while (associated(this)) - next=>this%next - call move_trajectory(bergs, this) - call destroy_iceberg(this) - this=>next - enddo + call move_all_trajectories(bergs, delete_bergs=.true.) call write_trajectory(bergs%trajectories) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 48dfe14..c17afe1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -59,7 +59,7 @@ module ice_bergs_framework public add_new_berg_to_list, count_out_of_order, check_for_duplicates public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position -public move_trajectory +public move_trajectory, move_all_trajectories public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell public sum_mass,sum_heat,bilin,yearday,bergs_chksum public checksum_gridded @@ -161,7 +161,7 @@ module ice_bergs_framework real :: dt ! Time-step between iceberg calls (should make adaptive?) integer :: current_year real :: current_yearday ! 1.00-365.99 - integer :: traj_sample_hrs + integer :: traj_sample_hrs, traj_write_hrs integer :: verbose_hrs integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers real :: rho_bergs ! Density of icebergs [kg/m^3] @@ -253,6 +253,7 @@ subroutine ice_bergs_framework_init(bergs, & ! Namelist parameters (and defaults) integer :: halo=4 ! Width of halo region integer :: traj_sample_hrs=24 ! Period between sampling of position for trajectory storage +integer :: traj_write_hrs=480 ! Period between writing sampled trajectories to disk integer :: verbose_hrs=24 ! Period between verbose messages real :: rho_bergs=850. ! Density of icebergs real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs @@ -269,7 +270,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, & +namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, traj_write_hrs, initial_mass, & distribution, mass_scaling, initial_thickness, verbose_hrs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & @@ -495,6 +496,7 @@ subroutine ice_bergs_framework_init(bergs, & ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs + bergs%traj_write_hrs=traj_write_hrs bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo bergs%rho_bergs=rho_bergs @@ -1703,6 +1705,28 @@ end subroutine move_trajectory ! ############################################################################## +subroutine move_all_trajectories(bergs, delete_bergs) +! Arguments +type(icebergs), pointer :: bergs +logical, optional, intent(in) :: delete_bergs +! Local variables +type(iceberg), pointer :: this, next +logical :: delete_bergs_after_moving_traj + + delete_bergs_after_moving_traj = .false. + if (present(delete_bergs)) delete_bergs_after_moving_traj = delete_bergs + this=>bergs%first + do while (associated(this)) + next=>this%next + call move_trajectory(bergs, this) + ! if (delete_bergs_after_moving_traj) call destroy_iceberg(this) + this=>next + enddo + +end subroutine move_all_trajectories + +! ############################################################################## + logical function find_cell_by_search(grd, x, y, i, j) ! Arguments type(icebergs_gridded), pointer :: grd From 22f3ced337f049876a2171d02579a01a652f37c3 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 17 Jul 2015 10:32:11 -0400 Subject: [PATCH 038/361] the line >>>>> left over from the merge conflicts has been removed. The code does not seem to compile, but the problem probably lies outside of the iceberg code. --- icebergs_framework.F90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d6274fb..2ad5343 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -512,9 +512,6 @@ subroutine ice_bergs_framework_init(bergs, & endif - - ->>>>>>> dev/master ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs From 314713b900f0fe739c9818983964e8e71428f0c7 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 17 Jul 2015 13:20:22 -0400 Subject: [PATCH 039/361] Reverted the reverse_list changes - The reverse_list option creates files that we cannot read with the current analysis tools. I'm reverting this before implementing an alternative solution. - No answer changes (for normal order mode). --- icebergs_framework.F90 | 34 +---- icebergs_io.F90 | 333 ++++++++++++++++++++--------------------- 2 files changed, 165 insertions(+), 202 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 6b82394..d996b2c 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -40,13 +40,12 @@ module ice_bergs_framework logical :: fix_restart_dates=.true. ! After a restart, check that bergs were created before the current model date logical :: do_unit_tests=.false. ! Conduct some unit tests logical :: force_all_pes_traj=.false. ! Force all pes write trajectory files regardless of io_layout -logical :: reverse_traj=.false. ! Force trajectories to be written in reverse order into files to save time !Public params !Niki: write a subroutine to expose these public nclasses,buffer_width,buffer_width_traj public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,old_bug_bilin,use_roundoff_fix public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget -public orig_read, force_all_pes_traj, reverse_traj +public orig_read, force_all_pes_traj !Public types @@ -67,7 +66,6 @@ module ice_bergs_framework public checksum_gridded public grd_chksum2,grd_chksum3 public fix_restart_dates, offset_berg_dates -public reverse_list type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -281,7 +279,7 @@ subroutine ice_bergs_framework_init(bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, & - input_freq_distribution, force_all_pes_traj, reverse_traj + input_freq_distribution, force_all_pes_traj ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -1226,9 +1224,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%cn=buff%data(22,n) traj%hi=buff%data(23,n) -! call append_posn(first, traj) !This call could take a very long time (as if the run hangs) if there are millions of nodes in the list. Use push_posn instead and reverse the list later before writing the file. -! - call push_posn(first, traj) + call append_posn(first, traj) end subroutine unpack_traj_from_buffer2 @@ -1650,30 +1646,6 @@ end subroutine record_posn ! ############################################################################## -subroutine reverse_list(list) - ! Arguments - type(xyt), pointer :: list - - ! Local variables - type(xyt), pointer :: head,tail,node - integer :: i - - i=0 - head=>list - tail=>list - node=>list%next - list%next=>null() - do while (associated(node)) - head=>node - node=>node%next - head%next=>tail - tail=>head - i=i+1 - enddo - list=>head - print*,'reverse_list number of nodes= ',i -end subroutine reverse_list - subroutine push_posn(trajectory, posn_vals) ! Arguments type(xyt), pointer :: trajectory diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 2130e04..6935b56 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -34,7 +34,7 @@ module ice_bergs_io use ice_bergs_framework, only: nclasses, buffer_width, buffer_width_traj use ice_bergs_framework, only: verbose, really_debug, debug, restart_input_dir,make_calving_reproduce use ice_bergs_framework, only: ignore_ij_restart, use_slow_find,generate_test_icebergs,print_berg -use ice_bergs_framework, only: reverse_list, force_all_pes_traj, reverse_traj +use ice_bergs_framework, only: force_all_pes_traj implicit none ; private @@ -885,7 +885,6 @@ subroutine write_trajectory(trajectory) enddo endif enddo -! if(.NOT. reverse_traj .AND. associated(traj4io)) call reverse_list(traj4io) else ! Pack and send trajectories to the root PE for this I/O tile do while (associated(trajectory)) @@ -904,22 +903,14 @@ subroutine write_trajectory(trajectory) endif !.NOT. force_all_pes_traj - !Here traj4io has all the trajectories in completely reverse order (last position of the last berg first) - !If a correct order is prefered in the trajectory file then reverse the linked list - !This may increase the the termination time of the model by a lot!!! - if(is_io_tile_root_pe .OR. force_all_pes_traj ) then - if(.NOT. reverse_traj .AND. associated(traj4io)) call reverse_list(traj4io) - endif - call mpp_clock_end(clock_trp) - !Now start writing in the io_tile_root_pe if there are any bergs in the I/O list call mpp_clock_begin(clock_trw) if((force_all_pes_traj .OR. is_io_tile_root_pe) .AND. associated(traj4io)) then - call get_instance_filename("iceberg_trajectories.nc", filename) + call get_instance_filename("iceberg_trajectories.nc", filename) if(io_tile_id(1) .ge. 0 .AND. .NOT. force_all_pes_traj) then !io_tile_root_pes write if(io_npes .gt. 1) then !attach tile_id to filename only if there is more than one I/O pe if (io_tile_id(1)<10000) then @@ -936,171 +927,171 @@ subroutine write_trajectory(trajectory) endif endif - io_is_in_append_mode = .false. - iret = nf_create(filename, NF_NOCLOBBER, ncid) - if (iret .ne. NF_NOERR) then - iret = nf_open(filename, NF_WRITE, ncid) - io_is_in_append_mode = .true. - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_open failed' - endif - if (verbose) then + io_is_in_append_mode = .false. + iret = nf_create(filename, NF_NOCLOBBER, ncid) + if (iret .ne. NF_NOERR) then + iret = nf_open(filename, NF_WRITE, ncid) + io_is_in_append_mode = .true. + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_open failed' + endif + if (verbose) then + if (io_is_in_append_mode) then + write(*,'(2a)') 'diamonds, write_trajectory: appending to ',filename + else + write(*,'(2a)') 'diamonds, write_trajectory: creating ',filename + endif + endif + if (io_is_in_append_mode) then - write(*,'(2a)') 'diamonds, write_trajectory: appending to ',filename + iret = nf_inq_dimid(ncid, 'i', i_dim) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimid i failed' + lonid = inq_varid(ncid, 'lon') + latid = inq_varid(ncid, 'lat') + yearid = inq_varid(ncid, 'year') + dayid = inq_varid(ncid, 'day') + uvelid = inq_varid(ncid, 'uvel') + vvelid = inq_varid(ncid, 'vvel') + uoid = inq_varid(ncid, 'uo') + void = inq_varid(ncid, 'vo') + uiid = inq_varid(ncid, 'ui') + viid = inq_varid(ncid, 'vi') + uaid = inq_varid(ncid, 'ua') + vaid = inq_varid(ncid, 'va') + mid = inq_varid(ncid, 'mass') + mbid = inq_varid(ncid, 'mass_of_bits') + hdid = inq_varid(ncid, 'heat_density') + did = inq_varid(ncid, 'thickness') + wid = inq_varid(ncid, 'width') + lid = inq_varid(ncid, 'length') + sshxid = inq_varid(ncid, 'ssh_x') + sshyid = inq_varid(ncid, 'ssh_y') + sstid = inq_varid(ncid, 'sst') + cnid = inq_varid(ncid, 'cn') + hiid = inq_varid(ncid, 'hi') else - write(*,'(2a)') 'diamonds, write_trajectory: creating ',filename + ! Dimensions + iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_def_dim i failed' + + ! Variables + lonid = def_var(ncid, 'lon', NF_DOUBLE, i_dim) + latid = def_var(ncid, 'lat', NF_DOUBLE, i_dim) + yearid = def_var(ncid, 'year', NF_INT, i_dim) + dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) + uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) + vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) + uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) + void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) + uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) + viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) + uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) + vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) + mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) + mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) + hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) + did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) + wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) + lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) + sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) + sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) + sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) + cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) + hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) + + ! Attributes + iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) + iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_minor_version', NF_INT, 1, 1) + call put_att(ncid, lonid, 'long_name', 'longitude') + call put_att(ncid, lonid, 'units', 'degrees_E') + call put_att(ncid, latid, 'long_name', 'latitude') + call put_att(ncid, latid, 'units', 'degrees_N') + call put_att(ncid, yearid, 'long_name', 'year') + call put_att(ncid, yearid, 'units', 'years') + call put_att(ncid, dayid, 'long_name', 'year day') + call put_att(ncid, dayid, 'units', 'days') + call put_att(ncid, uvelid, 'long_name', 'zonal spped') + call put_att(ncid, uvelid, 'units', 'm/s') + call put_att(ncid, vvelid, 'long_name', 'meridional spped') + call put_att(ncid, vvelid, 'units', 'm/s') + call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') + call put_att(ncid, uoid, 'units', 'm/s') + call put_att(ncid, void, 'long_name', 'ocean meridional spped') + call put_att(ncid, void, 'units', 'm/s') + call put_att(ncid, uiid, 'long_name', 'ice zonal spped') + call put_att(ncid, uiid, 'units', 'm/s') + call put_att(ncid, viid, 'long_name', 'ice meridional spped') + call put_att(ncid, viid, 'units', 'm/s') + call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') + call put_att(ncid, uaid, 'units', 'm/s') + call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') + call put_att(ncid, vaid, 'units', 'm/s') + call put_att(ncid, mid, 'long_name', 'mass') + call put_att(ncid, mid, 'units', 'kg') + call put_att(ncid, mbid, 'long_name', 'mass_of_bits') + call put_att(ncid, mbid, 'units', 'kg') + call put_att(ncid, hdid, 'long_name', 'heat_density') + call put_att(ncid, hdid, 'units', 'J/kg') + call put_att(ncid, did, 'long_name', 'thickness') + call put_att(ncid, did, 'units', 'm') + call put_att(ncid, wid, 'long_name', 'width') + call put_att(ncid, wid, 'units', 'm') + call put_att(ncid, lid, 'long_name', 'length') + call put_att(ncid, lid, 'units', 'm') + call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') + call put_att(ncid, sshxid, 'units', 'non-dim') + call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') + call put_att(ncid, sshyid, 'units', 'non-dim') + call put_att(ncid, sstid, 'long_name', 'sea surface temperature') + call put_att(ncid, sstid, 'units', 'degrees_C') + call put_att(ncid, cnid, 'long_name', 'sea ice concentration') + call put_att(ncid, cnid, 'units', 'none') + call put_att(ncid, hiid, 'long_name', 'sea ice thickness') + call put_att(ncid, hiid, 'units', 'm') endif - endif - if (io_is_in_append_mode) then - iret = nf_inq_dimid(ncid, 'i', i_dim) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimid i failed' - lonid = inq_varid(ncid, 'lon') - latid = inq_varid(ncid, 'lat') - yearid = inq_varid(ncid, 'year') - dayid = inq_varid(ncid, 'day') - uvelid = inq_varid(ncid, 'uvel') - vvelid = inq_varid(ncid, 'vvel') - uoid = inq_varid(ncid, 'uo') - void = inq_varid(ncid, 'vo') - uiid = inq_varid(ncid, 'ui') - viid = inq_varid(ncid, 'vi') - uaid = inq_varid(ncid, 'ua') - vaid = inq_varid(ncid, 'va') - mid = inq_varid(ncid, 'mass') - mbid = inq_varid(ncid, 'mass_of_bits') - hdid = inq_varid(ncid, 'heat_density') - did = inq_varid(ncid, 'thickness') - wid = inq_varid(ncid, 'width') - lid = inq_varid(ncid, 'length') - sshxid = inq_varid(ncid, 'ssh_x') - sshyid = inq_varid(ncid, 'ssh_y') - sstid = inq_varid(ncid, 'sst') - cnid = inq_varid(ncid, 'cn') - hiid = inq_varid(ncid, 'hi') - else - ! Dimensions - iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_def_dim i failed' - - ! Variables - lonid = def_var(ncid, 'lon', NF_DOUBLE, i_dim) - latid = def_var(ncid, 'lat', NF_DOUBLE, i_dim) - yearid = def_var(ncid, 'year', NF_INT, i_dim) - dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) - uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) - vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) - uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) - void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) - uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) - viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) - uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) - vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) - mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) - mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) - hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) - did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) - wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) - lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) - sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) - sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) - sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) - cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) - hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) - - ! Attributes - iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) - iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_minor_version', NF_INT, 1, 1) - call put_att(ncid, lonid, 'long_name', 'longitude') - call put_att(ncid, lonid, 'units', 'degrees_E') - call put_att(ncid, latid, 'long_name', 'latitude') - call put_att(ncid, latid, 'units', 'degrees_N') - call put_att(ncid, yearid, 'long_name', 'year') - call put_att(ncid, yearid, 'units', 'years') - call put_att(ncid, dayid, 'long_name', 'year day') - call put_att(ncid, dayid, 'units', 'days') - call put_att(ncid, uvelid, 'long_name', 'zonal spped') - call put_att(ncid, uvelid, 'units', 'm/s') - call put_att(ncid, vvelid, 'long_name', 'meridional spped') - call put_att(ncid, vvelid, 'units', 'm/s') - call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') - call put_att(ncid, uoid, 'units', 'm/s') - call put_att(ncid, void, 'long_name', 'ocean meridional spped') - call put_att(ncid, void, 'units', 'm/s') - call put_att(ncid, uiid, 'long_name', 'ice zonal spped') - call put_att(ncid, uiid, 'units', 'm/s') - call put_att(ncid, viid, 'long_name', 'ice meridional spped') - call put_att(ncid, viid, 'units', 'm/s') - call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') - call put_att(ncid, uaid, 'units', 'm/s') - call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') - call put_att(ncid, vaid, 'units', 'm/s') - call put_att(ncid, mid, 'long_name', 'mass') - call put_att(ncid, mid, 'units', 'kg') - call put_att(ncid, mbid, 'long_name', 'mass_of_bits') - call put_att(ncid, mbid, 'units', 'kg') - call put_att(ncid, hdid, 'long_name', 'heat_density') - call put_att(ncid, hdid, 'units', 'J/kg') - call put_att(ncid, did, 'long_name', 'thickness') - call put_att(ncid, did, 'units', 'm') - call put_att(ncid, wid, 'long_name', 'width') - call put_att(ncid, wid, 'units', 'm') - call put_att(ncid, lid, 'long_name', 'length') - call put_att(ncid, lid, 'units', 'm') - call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') - call put_att(ncid, sshxid, 'units', 'non-dim') - call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') - call put_att(ncid, sshyid, 'units', 'non-dim') - call put_att(ncid, sstid, 'long_name', 'sea surface temperature') - call put_att(ncid, sstid, 'units', 'degrees_C') - call put_att(ncid, cnid, 'long_name', 'sea ice concentration') - call put_att(ncid, cnid, 'units', 'none') - call put_att(ncid, hiid, 'long_name', 'sea ice thickness') - call put_att(ncid, hiid, 'units', 'm') - endif - - ! End define mode - iret = nf_enddef(ncid) - - ! Write variables - this=>traj4io - if (io_is_in_append_mode) then - iret = nf_inq_dimlen(ncid, i_dim, i) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimlen i failed' - else - i = 0 - endif - do while (associated(this)) - i=i+1 - call put_double(ncid, lonid, i, this%lon) - call put_double(ncid, latid, i, this%lat) - call put_int(ncid, yearid, i, this%year) - call put_double(ncid, dayid, i, this%day) - call put_double(ncid, uvelid, i, this%uvel) - call put_double(ncid, vvelid, i, this%vvel) - call put_double(ncid, uoid, i, this%uo) - call put_double(ncid, void, i, this%vo) - call put_double(ncid, uiid, i, this%ui) - call put_double(ncid, viid, i, this%vi) - call put_double(ncid, uaid, i, this%ua) - call put_double(ncid, vaid, i, this%va) - call put_double(ncid, mid, i, this%mass) - call put_double(ncid, hdid, i, this%heat_density) - call put_double(ncid, did, i, this%thickness) - call put_double(ncid, wid, i, this%width) - call put_double(ncid, lid, i, this%length) - call put_double(ncid, sshxid, i, this%ssh_x) - call put_double(ncid, sshyid, i, this%ssh_y) - call put_double(ncid, sstid, i, this%sst) - call put_double(ncid, cnid, i, this%cn) - call put_double(ncid, hiid, i, this%hi) - next=>this%next - deallocate(this) - this=>next - enddo + ! End define mode + iret = nf_enddef(ncid) + + ! Write variables + this=>traj4io + if (io_is_in_append_mode) then + iret = nf_inq_dimlen(ncid, i_dim, i) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_inq_dimlen i failed' + else + i = 0 + endif + do while (associated(this)) + i=i+1 + call put_double(ncid, lonid, i, this%lon) + call put_double(ncid, latid, i, this%lat) + call put_int(ncid, yearid, i, this%year) + call put_double(ncid, dayid, i, this%day) + call put_double(ncid, uvelid, i, this%uvel) + call put_double(ncid, vvelid, i, this%vvel) + call put_double(ncid, uoid, i, this%uo) + call put_double(ncid, void, i, this%vo) + call put_double(ncid, uiid, i, this%ui) + call put_double(ncid, viid, i, this%vi) + call put_double(ncid, uaid, i, this%ua) + call put_double(ncid, vaid, i, this%va) + call put_double(ncid, mid, i, this%mass) + call put_double(ncid, hdid, i, this%heat_density) + call put_double(ncid, did, i, this%thickness) + call put_double(ncid, wid, i, this%width) + call put_double(ncid, lid, i, this%length) + call put_double(ncid, sshxid, i, this%ssh_x) + call put_double(ncid, sshyid, i, this%ssh_y) + call put_double(ncid, sstid, i, this%sst) + call put_double(ncid, cnid, i, this%cn) + call put_double(ncid, hiid, i, this%hi) + next=>this%next + deallocate(this) + this=>next + enddo - ! Finish up - iret = nf_close(ncid) - if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_close failed',mpp_pe(),filename + ! Finish up + iret = nf_close(ncid) + if (iret .ne. NF_NOERR) write(stderrunit,*) 'diamonds, write_trajectory: nf_close failed',mpp_pe(),filename endif !(is_io_tile_root_pe .AND. associated(traj4io)) call mpp_clock_end(clock_trw) From 255fb345477c7700f667972a09105cba86deac11 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 17 Jul 2015 13:49:11 -0400 Subject: [PATCH 040/361] Fix order of trajectory segments for local PE - For either force_all_pes_traj or the local trajectory segments to the I/O PE, the segments were out of order. --- icebergs_io.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 6935b56..bac10b4 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -859,7 +859,7 @@ subroutine write_trajectory(trajectory) if(associated(trajectory)) then this=>trajectory do while (associated(this)) - call push_posn(traj4io, this) + call append_posn(traj4io, this) this=>this%next enddo trajectory => null() From 788d956e5aa72253cf773b1d261b73d75e2e5fac Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 17 Jul 2015 13:51:32 -0400 Subject: [PATCH 041/361] Fixed uninitialized variable in write_restart() - stderrunit was used but not set. --- icebergs_io.F90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index bac10b4..2c00b21 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -128,6 +128,9 @@ subroutine write_restart(bergs) jne, & start_year + ! Get the stderr unit number + stderrunit=stderr() + ! For convenience grd=>bergs%grd From 4a60f45ecef732439f0040e3e3935805af068e01 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 17 Jul 2015 17:34:55 -0400 Subject: [PATCH 042/361] Changes have been made to the code so that the default gives the same result as dev/master I have not checked that they actually give the same results yet. I have introduced flags such as use_predictive_corrective, which default to zero, but are set to 1 when Verlet is used. --- icebergs.F90 | 57 +++++++++++++++++++++++++++++++----------- icebergs_framework.F90 | 9 ++++--- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index b7930dd..1d09ed9 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -129,15 +129,36 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: alpha=1.0, beta=1.0, C_N=1.0, accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real, parameter :: accel_lim=1.e-2, Cr0=0.06, vel_lim=15. +real :: alpha, beta, C_N real :: lambda, detA, A11, A12, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon logical :: dumpit +logical :: use_new_predictive_corrective !Flad to use Bob's predictive corrective scheme. (default off) logical, intent(in) :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet integer :: itloop integer :: stderrunit +!These values are no longer set as parameters, but rather can be changed as variables. +alpha=0.0 +beta=1.0 +C_N=0.0 +use_new_predictive_corrective=bergs%use_new_predictive_corrective ! Loading directly from namelist/default , Alon + + +!Alon: Verlet requires implicit Coriolis and implicit drag. +!Alon: Also, I think that the implicit Coriolis with RK gives icebergs which do not complete inertial circles. +if (.not.Runge_not_Verlet) then +alpha=1.0 +C_N=1.0 +beta=1.0 +use_new_predictive_corrective=.True. +endif + + + + !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon v_star=vvel0+(ayn*(dt/2.)) !Alon @@ -223,16 +244,27 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=bxn+f_cori*vvel byn=byn-f_cori*uvel endif - - us=uvel0; vs=vvel0 ! us, vs are equivolent to u_pred in Alon's code. It is the variable that changes in the loop. + + if (use_new_predictive_corrective) then + uveln=uvel0; vveln=vvel0 ! Discuss this change with Alistair. Alon thinks that it is needed. + else + uveln=uvel; vveln=vvel + endif do itloop=1,2 ! Iterate on drag coefficients + if (use_new_predictive_corrective) then !Alon's proposed change - using Bob's improved scheme. - drag_ocn=c_ocn*0.5*(sqrt( (us-uo)**2+(vs-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) - drag_atm=c_atm*0.5*(sqrt( (us-ua)**2+(vs-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) - drag_ice=c_ice*0.5*(sqrt( (us-ui)**2+(vs-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) - + drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) + drag_atm=c_atm*0.5*(sqrt( (uveln-ua)**2+(vveln-va)**2 )+sqrt( (uvel0-ua)**2+(vvel0-va)**2 )) + drag_ice=c_ice*0.5*(sqrt( (uveln-ui)**2+(vveln-vi)**2 )+sqrt( (uvel0-ui)**2+(vvel0-vi)**2 )) + else + !Original Scheme + us=0.5*(uveln+uvel); vs=0.5*(vveln+vvel) + drag_ocn=c_ocn*sqrt( (us-uo)**2+(vs-vo)**2 ) + drag_atm=c_atm*sqrt( (us-ua)**2+(vs-va)**2 ) + drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) + endif RHS_x=(axn/2) + bxn RHS_y=(ayn/2) + byn @@ -248,8 +280,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Solve for implicit accelerations if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice - A11=1.+dt*lambda - A12=dt*f_cori + A11=1.+beta*dt*lambda + A12=alpha*dt*f_cori if (C_N>0.) then !For Crank-Nicolson Coriolis term. A12=A12/2. endif @@ -261,14 +293,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ax=RHS_x; ay=RHS_x endif - us=u_star+dt*ax ! Alon - vs=v_star+dt*ay ! Alon + uveln=u_star+dt*ax ! Alon + vveln=v_star+dt*ay ! Alon enddo ! itloop - uveln=us !Updated velocities - vveln=vs !Updated velocities - !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon axn=0. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 50c49ee..7c70429 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -179,7 +179,8 @@ module ice_bergs_framework logical :: add_weight_to_ocean=.true. ! Add weight of bergs to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean - logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -270,7 +271,8 @@ subroutine ice_bergs_framework_init(bergs, & logical :: time_average_weight=.false. ! Time average the weight on the ocean real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs -logical :: Runge_not_Verlet=.false. !True=Runge Kuttai, False=Verlet. - Added by Alon +logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests logical :: input_freq_distribution=.false. ! Alon: flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) @@ -281,7 +283,7 @@ subroutine ice_bergs_framework_init(bergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, & - time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, & + time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, use_new_predictive_corrective, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj ! Local variables @@ -530,6 +532,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) From 9e16bc45deb7796927d66c91627b9ad49b50b9c5 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 23 Jul 2015 09:17:50 -0400 Subject: [PATCH 043/361] Changes the dt to dt/2 in the acceleration call of the Runge Kutta algorithm. I think that it should actually be dt, rather than dt/2, but changing it to dt/2 makes the model match the answers with dev/master when on default mode. This branch alon_verlet is now set up such that if it is run on default mode, it returns the same answers as dev/master. In this way it can be added into the main code. --- icebergs.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 1d09ed9..025b043 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1677,8 +1677,8 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !axn,ayn, bxn, byn ,Runge_not_Verlet - Added by Alon - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !axn,ayn, bxn, byn ,Runge_not_Verlet - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon @@ -1732,8 +1732,8 @@ subroutine evolve_icebergs(bergs) endif dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl - !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !axn, ayn, bxn, byn, Runge_not_Verlet - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn, Runge_not_Verlet) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon From 924e1c39be9790abc648b32cfe5f0a1ee340bbff Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 24 Jul 2015 15:08:07 -0400 Subject: [PATCH 044/361] Corrected size of fixed array in bergs_chksum() - Size of arrays needed to be extended to accommodate additional quantities in the check sum. - No answer changes. --- icebergs_framework.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 035fd39..30066d1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2826,8 +2826,8 @@ integer function berg_chksum(berg ) ! Arguments type(iceberg), pointer :: berg ! Local variables -real :: rtmp(34) !Changed from 28 to 34 by Alon -integer :: itmp(34+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon +real :: rtmp(36) !Changed from 28 to 34 by Alon +integer :: itmp(36+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon integer :: i rtmp(:)=0. From ba076374f745710d3f9f376108630ef13047257e Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 27 Jul 2015 13:45:04 -0400 Subject: [PATCH 045/361] Replaced global linked-list with grid of linked-lists - Each PE used to have a singe linked-list which contained all the icebergs on that PE. Now we have a 2D array of lists, needed to efficiently implement berg-berg interactions. - bergs4io buffer was deleted since it wasn't being used. - Added an optional "with_halos" argument to count_bergs(). - This should not change answers - yet to be tested. --- icebergs.F90 | 1266 ++++++++++++++++++++-------------------- icebergs_framework.F90 | 551 +++++++++-------- icebergs_io.F90 | 99 ++-- 3 files changed, 989 insertions(+), 927 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d8326b9..87a7a53 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -131,6 +131,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y integer :: stderrunit +integer :: grdi, grdj Rearth=6360.e3 !spring_coef=1.e-4 @@ -163,7 +164,8 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i lon1=berg%lon; lat1=berg%lat call rotpos_to_tang(lon1,lat1,x1,y1) - other_berg=>bergs%first + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + other_berg=>bergs%list(grdi,grdj)%first !Note: This summing should be made order invarient. !Note: Need to limit how many icebergs we search over @@ -228,6 +230,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i other_berg=>other_berg%next enddo ! loop over all bergs + enddo ; enddo contains @@ -730,176 +733,179 @@ subroutine thermodynamics(bergs) integer :: i,j, stderrunit type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. +integer :: grdi, grdj ! For convenience grd=>bergs%grd - this=>bergs%first - do while(associated(this)) - if (debug) call check_position(grd, this, 'thermodynamics (top)') - - call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & - this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & - this%cn, this%hi) - SST=this%sst - IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration - M=this%mass - T=this%thickness ! total thickness - ! D=(bergs%rho_bergs/rho_seawater)*T ! draught (keel depth) - ! F=T-D ! freeboard - W=this%width - L=this%length - i=this%ine - j=this%jne - Vol=T*W*L - - ! Environment - dvo=sqrt((this%uvel-this%uo)**2+(this%vvel-this%vo)**2) - dva=sqrt((this%ua-this%uo)**2+(this%va-this%vo)**2) - Ss=1.5*(dva**0.5)+0.1*dva ! Sea state - - ! Melt rates in m/s - Mv=max( 7.62e-3*SST+1.29e-3*(SST**2), 0.) &! Buoyant convection at sides - *perday ! convert to m/s - Mb=max( 0.58*(dvo**0.8)*(SST+4.0)/(L**0.2), 0.) &! Basal turbulent melting - *perday ! convert to m/s - Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion - *perday ! convert to m/s - - if (bergs%use_operator_splitting) then - ! Operator split update of volume/mass - Tn=max(T-Mb*bergs%dt,0.) ! new total thickness (m) - nVol=Tn*W*L ! new volume (m^3) - Mnew1=(nVol/Vol)*M ! new mass (kg) - dMb=M-Mnew1 ! mass lost to basal melting (>0) (kg) - - Ln=max(L-Mv*bergs%dt,0.) ! new length (m) - Wn=max(W-Mv*bergs%dt,0.) ! new width (m) - nVol=Tn*Wn*Ln ! new volume (m^3) - Mnew2=(nVol/Vol)*M ! new mass (kg) - dMv=Mnew1-Mnew2 ! mass lost to buoyant convection (>0) (kg) - - Ln=max(Ln-Me*bergs%dt,0.) ! new length (m) - Wn=max(Wn-Me*bergs%dt,0.) ! new width (m) - nVol=Tn*Wn*Ln ! new volume (m^3) - Mnew=(nVol/Vol)*M ! new mass (kg) - dMe=Mnew2-Mnew ! mass lost to erosion (>0) (kg) - dM=M-Mnew ! mass lost to all erosion and melting (>0) (kg) - else - ! Update dimensions of berg - Ln=max(L-(Mv+Me)*(bergs%dt),0.) ! (m) - Wn=max(W-(Mv+Me)*(bergs%dt),0.) ! (m) - Tn=max(T-Mb*(bergs%dt),0.) ! (m) - ! Update volume and mass of berg - nVol=Tn*Wn*Ln ! (m^3) - Mnew=(nVol/Vol)*M ! (kg) - dM=M-Mnew ! (kg) - dMb=(M/Vol)*(W*L)*Mb*bergs%dt ! approx. mass loss to basal melting (kg) - dMe=(M/Vol)*(T*(W+L))*Me*bergs%dt ! approx. mass lost to erosion (kg) - dMv=(M/Vol)*(T*(W+L))*Mv*bergs%dt ! approx. mass loss to buoyant convection (kg) - endif - - ! Bergy bits - if (bergs%bergy_bit_erosion_fraction>0.) then - Mbits=this%mass_of_bits ! mass of bergy bits (kg) - dMbitsE=bergs%bergy_bit_erosion_fraction*dMe ! change in mass of bits (kg) - nMbits=Mbits+dMbitsE ! add new bergy bits to mass (kg) - Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters - Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) - Mbb=max( 0.58*(dvo**0.8)*(SST+2.0)/(Lbits**0.2), 0.) &! Basal turbulent melting (for bits) - *perday ! convert to m/s - Mbb=bergs%rho_bergs*Abits*Mbb ! in kg/s - dMbitsM=min(Mbb*bergs%dt,nMbits) ! bergy bits mass lost to melting (kg) - nMbits=nMbits-dMbitsM ! remove mass lost to bergy bits melt - if (Mnew==0.) then ! if parent berg has completely melted then - dMbitsM=dMbitsM+nMbits ! instantly melt all the bergy bits - nMbits=0. + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + if (debug) call check_position(grd, this, 'thermodynamics (top)') + + call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & + this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & + this%cn, this%hi) + SST=this%sst + IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration + M=this%mass + T=this%thickness ! total thickness + ! D=(bergs%rho_bergs/rho_seawater)*T ! draught (keel depth) + ! F=T-D ! freeboard + W=this%width + L=this%length + i=this%ine + j=this%jne + Vol=T*W*L + + ! Environment + dvo=sqrt((this%uvel-this%uo)**2+(this%vvel-this%vo)**2) + dva=sqrt((this%ua-this%uo)**2+(this%va-this%vo)**2) + Ss=1.5*(dva**0.5)+0.1*dva ! Sea state + + ! Melt rates in m/s + Mv=max( 7.62e-3*SST+1.29e-3*(SST**2), 0.) &! Buoyant convection at sides + *perday ! convert to m/s + Mb=max( 0.58*(dvo**0.8)*(SST+4.0)/(L**0.2), 0.) &! Basal turbulent melting + *perday ! convert to m/s + Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion + *perday ! convert to m/s + + if (bergs%use_operator_splitting) then + ! Operator split update of volume/mass + Tn=max(T-Mb*bergs%dt,0.) ! new total thickness (m) + nVol=Tn*W*L ! new volume (m^3) + Mnew1=(nVol/Vol)*M ! new mass (kg) + dMb=M-Mnew1 ! mass lost to basal melting (>0) (kg) + + Ln=max(L-Mv*bergs%dt,0.) ! new length (m) + Wn=max(W-Mv*bergs%dt,0.) ! new width (m) + nVol=Tn*Wn*Ln ! new volume (m^3) + Mnew2=(nVol/Vol)*M ! new mass (kg) + dMv=Mnew1-Mnew2 ! mass lost to buoyant convection (>0) (kg) + + Ln=max(Ln-Me*bergs%dt,0.) ! new length (m) + Wn=max(Wn-Me*bergs%dt,0.) ! new width (m) + nVol=Tn*Wn*Ln ! new volume (m^3) + Mnew=(nVol/Vol)*M ! new mass (kg) + dMe=Mnew2-Mnew ! mass lost to erosion (>0) (kg) + dM=M-Mnew ! mass lost to all erosion and melting (>0) (kg) + else + ! Update dimensions of berg + Ln=max(L-(Mv+Me)*(bergs%dt),0.) ! (m) + Wn=max(W-(Mv+Me)*(bergs%dt),0.) ! (m) + Tn=max(T-Mb*(bergs%dt),0.) ! (m) + ! Update volume and mass of berg + nVol=Tn*Wn*Ln ! (m^3) + Mnew=(nVol/Vol)*M ! (kg) + dM=M-Mnew ! (kg) + dMb=(M/Vol)*(W*L)*Mb*bergs%dt ! approx. mass loss to basal melting (kg) + dMe=(M/Vol)*(T*(W+L))*Me*bergs%dt ! approx. mass lost to erosion (kg) + dMv=(M/Vol)*(T*(W+L))*Mv*bergs%dt ! approx. mass loss to buoyant convection (kg) endif - else - Abits=0. - dMbitsE=0. - dMbitsM=0. - nMbits=this%mass_of_bits ! retain previous value incase non-zero - endif - - ! Add melting to the grid and field diagnostics - if (grd%area(i,j).ne.0.) then - melt=(dM-(dMbitsE-dMbitsM))/bergs%dt ! kg/s - grd%floating_melt(i,j)=grd%floating_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s - melt=melt*this%heat_density ! kg/s x J/kg = J/s - grd%calving_hflx(i,j)=grd%calving_hflx(i,j)+melt/grd%area(i,j)*this%mass_scaling ! W/m2 - bergs%net_heat_to_ocean=bergs%net_heat_to_ocean+melt*this%mass_scaling*bergs%dt ! J - melt=dM/bergs%dt ! kg/s - grd%berg_melt(i,j)=grd%berg_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s - melt=dMbitsE/bergs%dt ! mass flux into bergy bits in kg/s - grd%bergy_src(i,j)=grd%bergy_src(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s - melt=dMbitsM/bergs%dt ! melt rate of bergy bits in kg/s - grd%bergy_melt(i,j)=grd%bergy_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s - if(grd%id_melt_buoy>0) then - melt=dMb/bergs%dt ! melt rate due to buoyancy term in kg/s - grd%melt_buoy(i,j)=grd%melt_buoy(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + + ! Bergy bits + if (bergs%bergy_bit_erosion_fraction>0.) then + Mbits=this%mass_of_bits ! mass of bergy bits (kg) + dMbitsE=bergs%bergy_bit_erosion_fraction*dMe ! change in mass of bits (kg) + nMbits=Mbits+dMbitsE ! add new bergy bits to mass (kg) + Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + Mbb=max( 0.58*(dvo**0.8)*(SST+2.0)/(Lbits**0.2), 0.) &! Basal turbulent melting (for bits) + *perday ! convert to m/s + Mbb=bergs%rho_bergs*Abits*Mbb ! in kg/s + dMbitsM=min(Mbb*bergs%dt,nMbits) ! bergy bits mass lost to melting (kg) + nMbits=nMbits-dMbitsM ! remove mass lost to bergy bits melt + if (Mnew==0.) then ! if parent berg has completely melted then + dMbitsM=dMbitsM+nMbits ! instantly melt all the bergy bits + nMbits=0. + endif + else + Abits=0. + dMbitsE=0. + dMbitsM=0. + nMbits=this%mass_of_bits ! retain previous value incase non-zero endif - if(grd%id_melt_eros>0) then - melt=dMe/bergs%dt ! erosion rate in kg/s - grd%melt_eros(i,j)=grd%melt_eros(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + + ! Add melting to the grid and field diagnostics + if (grd%area(i,j).ne.0.) then + melt=(dM-(dMbitsE-dMbitsM))/bergs%dt ! kg/s + grd%floating_melt(i,j)=grd%floating_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + melt=melt*this%heat_density ! kg/s x J/kg = J/s + grd%calving_hflx(i,j)=grd%calving_hflx(i,j)+melt/grd%area(i,j)*this%mass_scaling ! W/m2 + bergs%net_heat_to_ocean=bergs%net_heat_to_ocean+melt*this%mass_scaling*bergs%dt ! J + melt=dM/bergs%dt ! kg/s + grd%berg_melt(i,j)=grd%berg_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + melt=dMbitsE/bergs%dt ! mass flux into bergy bits in kg/s + grd%bergy_src(i,j)=grd%bergy_src(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + melt=dMbitsM/bergs%dt ! melt rate of bergy bits in kg/s + grd%bergy_melt(i,j)=grd%bergy_melt(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + if(grd%id_melt_buoy>0) then + melt=dMb/bergs%dt ! melt rate due to buoyancy term in kg/s + grd%melt_buoy(i,j)=grd%melt_buoy(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + endif + if(grd%id_melt_eros>0) then + melt=dMe/bergs%dt ! erosion rate in kg/s + grd%melt_eros(i,j)=grd%melt_eros(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + endif + if(grd%id_melt_conv>0) then + melt=dMv/bergs%dt ! melt rate due to convection term in kg/s + grd%melt_conv(i,j)=grd%melt_conv(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + endif + else + stderrunit = stderr() + write(stderrunit,*) 'diamonds, thermodynamics: berg appears to have grounded!!!! PE=',mpp_pe(),i,j + call print_berg(stderrunit,this,'thermodynamics, grounded') + if (associated(this%trajectory)) & + write(stderrunit,*) 'traj=',this%trajectory%lon,this%trajectory%lat + write(stderrunit,*) 'msk=',grd%msk(i,j),grd%area(i,j) + call error_mesg('diamonds, thermodynamics', 'berg appears to have grounded!', FATAL) endif - if(grd%id_melt_conv>0) then - melt=dMv/bergs%dt ! melt rate due to convection term in kg/s - grd%melt_conv(i,j)=grd%melt_conv(i,j)+melt/grd%area(i,j)*this%mass_scaling ! kg/m2/s + + ! Rolling + Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) + if ( Dn>0. ) then + if ( max(Wn,Ln)0. ) then - if ( max(Wn,Ln)W) - this%mass=Mnew - this%mass_of_bits=nMbits - this%thickness=Tn - this%width=min(Wn,Ln) - this%length=max(Wn,Ln) - - next=>this%next - - ! Did berg completely melt? - if (Mnew<=0.) then ! Delete the berg - call move_trajectory(bergs, this) - call delete_iceberg_from_list(bergs%first, this) - bergs%nbergs_melted=bergs%nbergs_melted+1 - else ! Diagnose mass distribution on grid - if (grd%id_virtual_area>0)& - & grd%virtual_area(i,j)=grd%virtual_area(i,j)+(Wn*Ln+Abits)*this%mass_scaling ! m^2 - if (grd%id_mass>0 .or. bergs%add_weight_to_ocean)& - & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 - if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& - & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 - if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then - if (bergs%grounding_fraction>0.) then - Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) - if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) + + ! Store the new state of iceberg (with L>W) + this%mass=Mnew + this%mass_of_bits=nMbits + this%thickness=Tn + this%width=min(Wn,Ln) + this%length=max(Wn,Ln) + + next=>this%next + + ! Did berg completely melt? + if (Mnew<=0.) then ! Delete the berg + call move_trajectory(bergs, this) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first, this) + bergs%nbergs_melted=bergs%nbergs_melted+1 + else ! Diagnose mass distribution on grid + if (grd%id_virtual_area>0)& + & grd%virtual_area(i,j)=grd%virtual_area(i,j)+(Wn*Ln+Abits)*this%mass_scaling ! m^2 + if (grd%id_mass>0 .or. bergs%add_weight_to_ocean)& + & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 + if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& + & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 + if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then + if (bergs%grounding_fraction>0.) then + Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) + if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) + endif + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling) endif - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling) endif - endif - - this=>next - enddo + + this=>next + enddo + enddo ; enddo end subroutine thermodynamics @@ -1263,7 +1269,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! For each berg, evolve call mpp_clock_begin(bergs%clock_mom) - if (associated(bergs%first)) call evolve_icebergs(bergs) + call evolve_icebergs(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (evolved)',ignore_halo_violation=.true.) if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) @@ -1277,14 +1283,14 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Iceberg thermodynamics (melting) + rolling call mpp_clock_begin(bergs%clock_the) - if (associated(bergs%first)) call thermodynamics(bergs) + call thermodynamics(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (thermo)') if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) ! For each berg, record call mpp_clock_begin(bergs%clock_dia) - if (sample_traj.and.associated(bergs%first)) call record_posn(bergs) + if (sample_traj) call record_posn(bergs) if (write_traj) then call move_all_trajectories(bergs) call write_trajectory(bergs%trajectories) @@ -1376,10 +1382,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (lbudget) then bergs%stored_end=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) bergs%stored_heat_end=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) - bergs%floating_mass_end=sum_mass(bergs%first) - bergs%icebergs_mass_end=sum_mass(bergs%first,justbergs=.true.) - bergs%bergy_mass_end=sum_mass(bergs%first,justbits=.true.) - bergs%floating_heat_end=sum_heat(bergs%first) + bergs%floating_mass_end=sum_mass(bergs) + bergs%icebergs_mass_end=sum_mass(bergs,justbergs=.true.) + bergs%bergy_mass_end=sum_mass(bergs,justbits=.true.) + bergs%floating_heat_end=sum_heat(bergs) grd%tmpc(:,:)=0.; call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r call icebergs_incr_mass(bergs, grd%tmpc) @@ -1775,7 +1781,7 @@ subroutine calve_icebergs(bergs) newberg%mass_scaling=bergs%mass_scaling(k) newberg%mass_of_bits=0. newberg%heat_density=grd%stored_heat(i,j)/grd%stored_ice(i,j,k) ! This is in J/kg - call add_new_berg_to_list(bergs%first, newberg) + call add_new_berg_to_list(bergs%list(i,j)%first, newberg) calved_to_berg=bergs%initial_mass(k)*bergs%mass_scaling(k) ! Units of kg ! Heat content heat_to_berg=calved_to_berg*newberg%heat_density ! Units of J @@ -1830,6 +1836,7 @@ subroutine evolve_icebergs(bergs) type(iceberg), pointer :: berg integer :: stderrunit logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. +integer :: grdi, grdj ! 4th order Runge-Kutta to solve: ! d/dt X = V, d/dt V = A @@ -1860,487 +1867,488 @@ subroutine evolve_icebergs(bergs) Rearth=6360.e3 !Choosing time stepping scheme - Alon - !Runge_not_Verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon - Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon + !Runge_not_Verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon + Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon - berg=>bergs%first - do while (associated(berg)) ! loop over all bergs - - if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - call print_berg(stderrunit, berg, 'evolve_iceberg, berg is not in proper starting cell') - write(stderrunit,'(a,i3,2(i4,3f8.2))') 'evolve_iceberg: pe,lon/lat(i,j)=', mpp_pe(), & - berg%ine,berg%lon,grd%lon(berg%ine-1,berg%jne-1),grd%lon(berg%ine,berg%jne), & - berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) - endif - - if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - - i=berg%ine - j=berg%jne - xi=berg%xi - yj=berg%yj - bounced=.false. - on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. - i1=i;j1=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + call print_berg(stderrunit, berg, 'evolve_iceberg, berg is not in proper starting cell') + write(stderrunit,'(a,i3,2(i4,3f8.2))') 'evolve_iceberg: pe,lon/lat(i,j)=', mpp_pe(), & + berg%ine,berg%lon,grd%lon(berg%ine-1,berg%jne-1),grd%lon(berg%ine,berg%jne), & + berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) + endif + if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop -Added by Alon, MP2 + i=berg%ine + j=berg%jne + xi=berg%xi + yj=berg%yj + bounced=.false. + on_tangential_plane=.false. + if (berg%lat>89.) on_tangential_plane=.true. + i1=i;j1=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - !Loading past acceleartions - Alon - axn=berg%axn; ayn=berg%ayn !Alon - axn1=axn; axn2=axn; axn3=axn; axn4=axn - ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn + if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop -Added by Alon, MP2 - ! A1 = A(X1) - lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - dydl=r180_pi/Rearth - uvel1=berg%uvel; vvel1=berg%vvel - if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) - u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon - !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 - if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) - if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon + ! Loading past accelerations - Alon + axn=berg%axn; ayn=berg%ayn !Alon + axn1=axn; axn2=axn; axn3=axn; axn4=axn + ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn - ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) - !if (debug) write(stderr(),*) 'diamonds, evolve: x2=...' - if (on_tangential_plane) then - x2=x1+dt_2*xdot1; y2=y1+dt_2*ydot1 - xdot2=xdot1+dt_2*xddot1; ydot2=ydot1+dt_2*yddot1 - call rotpos_from_tang(x2,y2,lon2,lat2) - call rotvec_from_tang(lon2,xdot2,ydot2,uvel2,vvel2) - else - lon2=lon1+dt_2*u1; lat2=lat1+dt_2*v1 - uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) - i2=i; j2=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2=',lon1,lon2,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2=',lat1,lat2,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u0=',uvel1,uvel2,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v0=',vvel1,vvel2,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2=',dt*ax1,dt*ax2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2=',dt*ay1,dt*ay2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u0=',dt*uvel1,dt*uvel2,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v0=',dt*vvel1,dt*vvel2,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) - endif - dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) - u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 - if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) - if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon - ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) - !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' - if (on_tangential_plane) then - x3=x1+dt_2*xdot2; y3=y1+dt_2*ydot2 - xdot3=xdot1+dt_2*xddot2; ydot3=ydot1+dt_2*yddot2 - call rotpos_from_tang(x3,y3,lon3,lat3) - call rotvec_from_tang(lon3,xdot3,ydot3,uvel3,vvel3) - else - lon3=lon1+dt_2*u2; lat3=lat1+dt_2*v2 - uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) - i3=i; j3=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i=',i1,i2,i3,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j=',j1,j2,j3,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3=',lon1,lon2,lon3,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3=',lat1,lat2,lat3,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u0=',uvel1,uvel2,uvel3,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v0=',vvel1,vvel2,vvel3,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3=',dt*ax1,dt*ax2,dt*ax3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3=',dt*ay1,dt*ay2,dt*ay3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) - endif - dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) - u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) - if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon - ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) - !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' - if (on_tangential_plane) then - x4=x1+dt*xdot3; y4=y1+dt*ydot3 - xdot4=xdot1+dt*xddot3; ydot4=ydot1+dt*yddot3 - call rotpos_from_tang(x4,y4,lon4,lat4) - call rotvec_from_tang(lon4,xdot4,ydot4,uvel4,vvel4) - else - lon4=lon1+dt*u3; lat4=lat1+dt*v3 - uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag) - i4=i; j4=j - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4=',lon1,lon2,lon3,lon4,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4=',lat1,lat2,lat3,lat4,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,u0=',uvel1,uvel2,uvel3,uvel4,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,v0=',vvel1,vvel2,vvel3,vvel4,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4=',dt*ax1,dt*ax2,dt*ax3,dt*ax4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4=',dt*ay1,dt*ay2,dt*ay3,dt*ay4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) - endif - dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) - u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) - if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) + ! A1 = A(X1) + lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + dydl=r180_pi/Rearth + uvel1=berg%uvel; vvel1=berg%vvel + if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) + u1=uvel1*dxdl1; v1=vvel1*dydl + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 + if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon + + ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) + !if (debug) write(stderr(),*) 'diamonds, evolve: x2=...' + if (on_tangential_plane) then + x2=x1+dt_2*xdot1; y2=y1+dt_2*ydot1 + xdot2=xdot1+dt_2*xddot1; ydot2=ydot1+dt_2*yddot1 + call rotpos_from_tang(x2,y2,lon2,lat2) + call rotvec_from_tang(lon2,xdot2,ydot2,uvel2,vvel2) + else + lon2=lon1+dt_2*u1; lat2=lat1+dt_2*v1 + uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) + i2=i; j2=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2=',lon1,lon2,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2=',lat1,lat2,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u0=',uvel1,uvel2,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v0=',vvel1,vvel2,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2=',dt*ax1,dt*ax2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2=',dt*ay1,dt*ay2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u0=',dt*uvel1,dt*uvel2,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v0=',dt*vvel1,dt*vvel2,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) + endif + dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) + u2=uvel2*dxdl2; v2=vvel2*dydl + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 + if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) + if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon + + ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) + !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' + if (on_tangential_plane) then + x3=x1+dt_2*xdot2; y3=y1+dt_2*ydot2 + xdot3=xdot1+dt_2*xddot2; ydot3=ydot1+dt_2*yddot2 + call rotpos_from_tang(x3,y3,lon3,lat3) + call rotvec_from_tang(lon3,xdot3,ydot3,uvel3,vvel3) + else + lon3=lon1+dt_2*u2; lat3=lat1+dt_2*v2 + uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) + i3=i; j3=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i=',i1,i2,i3,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j=',j1,j2,j3,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3=',lon1,lon2,lon3,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3=',lat1,lat2,lat3,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u0=',uvel1,uvel2,uvel3,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v0=',vvel1,vvel2,vvel3,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3=',dt*ax1,dt*ax2,dt*ax3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3=',dt*ay1,dt*ay2,dt*ay3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) + endif + dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) + u3=uvel3*dxdl3; v3=vvel3*dydl + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) + if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon + + ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) + !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' + if (on_tangential_plane) then + x4=x1+dt*xdot3; y4=y1+dt*ydot3 + xdot4=xdot1+dt*xddot3; ydot4=ydot1+dt*yddot3 + call rotpos_from_tang(x4,y4,lon4,lat4) + call rotvec_from_tang(lon4,xdot4,ydot4,uvel4,vvel4) + else + lon4=lon1+dt*u3; lat4=lat1+dt*v3 + uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag) + i4=i; j4=j + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4=',lon1,lon2,lon3,lon4,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4=',lat1,lat2,lat3,lat4,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,u0=',uvel1,uvel2,uvel3,uvel4,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,v0=',vvel1,vvel2,vvel3,vvel4,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4=',dt*ax1,dt*ax2,dt*ax3,dt*ax4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4=',dt*ay1,dt*ay2,dt*ay3,dt*ay4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 3' + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) + endif + dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) + u4=uvel4*dxdl4; v4=vvel4*dydl + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) + if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) + + ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 + ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 + if (on_tangential_plane) then + xn=x1+dt_6*( (xdot1+xdot4)+2.*(xdot2+xdot3) ) + yn=y1+dt_6*( (ydot1+ydot4)+2.*(ydot2+ydot3) ) + xdotn=xdot1+dt_6*( (xddot1+xddot4)+2.*(xddot2+xddot3) ) + ydotn=ydot1+dt_6*( (yddot1+yddot4)+2.*(yddot2+yddot3) ) + xddotn=( (xddot1n+xddot4n)+2.*(xddot2n+xddot3n) )/6. !Alon + yddotn=( (yddot1n+yddot4n)+2.*(yddot2n+yddot3n) )/6. !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + call rotvec_from_tang(lonn,xddotn,yddotn,axn,ayn) !Alon + else + lonn=berg%lon+dt_6*( (u1+u4)+2.*(u2+u3) ) + latn=berg%lat+dt_6*( (v1+v4)+2.*(v2+v3) ) + uveln=berg%uvel+dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) + vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) + axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon + ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon + bxn=(((ax1+ax4)+2.*(ax2+ax3) )/6) - (axn/2) + byn=(((ay1+ay4)+2.*(ay2+ay3) )/6) - (ayn/2) - ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 - ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 - if (on_tangential_plane) then - xn=x1+dt_6*( (xdot1+xdot4)+2.*(xdot2+xdot3) ) - yn=y1+dt_6*( (ydot1+ydot4)+2.*(ydot2+ydot3) ) - xdotn=xdot1+dt_6*( (xddot1+xddot4)+2.*(xddot2+xddot3) ) - ydotn=ydot1+dt_6*( (yddot1+yddot4)+2.*(yddot2+yddot3) ) - xddotn=( (xddot1n+xddot4n)+2.*(xddot2n+xddot3n) )/6. !Alon - yddotn=( (yddot1n+yddot4n)+2.*(yddot2n+yddot3n) )/6. !Alon - call rotpos_from_tang(xn,yn,lonn,latn) - call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) - call rotvec_from_tang(lonn,xddotn,yddotn,axn,ayn) !Alon - else - lonn=berg%lon+dt_6*( (u1+u4)+2.*(u2+u3) ) - latn=berg%lat+dt_6*( (v1+v4)+2.*(v2+v3) ) - uveln=berg%uvel+dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) - vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) - axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon - ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon - bxn=(((ax1+ax4)+2.*(ax2+ax3) )/6) - (axn/2) - byn=(((ay1+ay4)+2.*(ay2+ay3) )/6) - (ayn/2) - - endif - - - - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - - if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4,lonn=',lon1,lon2,lon3,lon4,lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4,latn=',lat1,lat2,lat3,lat4,latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,un,u0=',uvel1,uvel2,uvel3,uvel4,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,vn,v0=',vvel1,vvel2,vvel3,vvel4,vveln,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4,axn=',& - & dt*ax1,dt*ax2,dt*ax3,dt*ax4,dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4,ayn=',& - & dt*ay1,dt*ay2,dt*ay3,dt*ay4,dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,un,u0=',& - & dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*uveln,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,vn,v0=',& - & dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*vveln,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u_rk (deg)=',& - & dt*u1,dt*u2,dt*u3,dt*u4,dt_6*( (u1+u4)+2.*(u2+u3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v_rk (deg)=',& - & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) - write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 4' - error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - endif - - endif ! End of the Runge-Kutta Loop -added by Alon + endif + + + + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4,lonn=',lon1,lon2,lon3,lon4,lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4,latn=',lat1,lat2,lat3,lat4,latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,un,u0=',uvel1,uvel2,uvel3,uvel4,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,vn,v0=',vvel1,vvel2,vvel3,vvel4,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4,axn=',& + & dt*ax1,dt*ax2,dt*ax3,dt*ax4,dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4,ayn=',& + & dt*ay1,dt*ay2,dt*ay3,dt*ay4,dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,un,u0=',& + & dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*uveln,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,vn,v0=',& + & dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*vveln,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u_rk (deg)=',& + & dt*u1,dt*u2,dt*u3,dt*u4,dt_6*( (u1+u4)+2.*(u2+u3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v_rk (deg)=',& + & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 3' + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 4' + error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif + + endif ! End of the Runge-Kutta Loop -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (.not.Runge_not_Verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon - - ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step - ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting - ! Positions and velocity is updated by - ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n - ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax - -!print *, 'you are here!' - -lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - dydl=r180_pi/Rearth - uvel1=berg%uvel; vvel1=berg%vvel - -!Loading past acceleartions - Alon - axn=berg%axn; ayn=berg%ayn !Alon - bxn=berg%bxn; byn=berg%byn !Alon - - - -! Velocities used to update the position - uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon - vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon - -if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) - u2=uvel2*dxdl1; v2=vvel2*dydl - - -!Solving for new position - if (on_tangential_plane) then - xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon - call rotpos_from_tang(xn,yn,lonn,latn) - else - lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon - endif - dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - -! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) - uvel3=uvel1+(dt_2*axn) !Alon - vvel3=vvel1+(dt_2*ayn) !Alon - - -!Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" -! call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" - i2=i; j2=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - - -!Calling the acceleration (note that the velocity is converted to u_star inside the accel script) - call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - -!Solving for the new velocity - if (on_tangential_plane) then - call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) - call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) - xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon - call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) - else - uvel4=uvel3+(dt*ax1); vvel4=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln - endif -! uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. (Perhaps this should not be here) - uveln=uvel4 - vveln=vvel4 - -!Debugging - if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lonn=',lon1,lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,latn=',lat1,latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& - & dt*ax1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& - & dt*ay1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u3,un,u0=',& - & dt*uvel3,dt*uveln,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v3,vn,v0=',& - & dt*vvel3,dt*vveln,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u_n (deg)=',& - & dt*u1,dt*uveln - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v_n (deg)=',& - & dt*v1,dt*vveln - write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - endif - + if (.not.Runge_not_Verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon + ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step + ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting + ! Positions and velocity is updated by + ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n + ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax + + !print *, 'you are here!' + + lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + dydl=r180_pi/Rearth + uvel1=berg%uvel; vvel1=berg%vvel + + ! Loading past acceleartions - Alon + axn=berg%axn; ayn=berg%ayn !Alon + bxn=berg%bxn; byn=berg%byn !Alon + + + + ! Velocities used to update the position + uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon + vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon + + if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) + u2=uvel2*dxdl1; v2=vvel2*dydl + + + ! Solving for new position + if (on_tangential_plane) then + xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + else + lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon + endif + dxdln=r180_pi/(Rearth*cos(latn*pi_180)) + + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon + + + ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + ! call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + i2=i; j2=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + + + ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + + !Solving for the new velocity + if (on_tangential_plane) then + call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) + call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + else + uvel4=uvel3+(dt*ax1); vvel4=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + endif + ! uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. (Perhaps this should not be here) + uveln=uvel4 + vveln=vvel4 + + ! Debugging + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lonn=',lon1,lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,latn=',lat1,latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& + & dt*ax1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& + & dt*ay1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u3,un,u0=',& + & dt*uvel3,dt*uveln,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v3,vn,v0=',& + & dt*vvel3,dt*vveln,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u_n (deg)=',& + & dt*u1,dt*uveln + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v_n (deg)=',& + & dt*v1,dt*vveln + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif - endif ! End of the Verlet Stepiing -added by Alon + endif ! End of the Verlet Stepiing -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!Saving all the iceberg variables. - berg%axn=axn !Alon - berg%ayn=ayn !Alon - berg%bxn=bxn !Alon - berg%byn=byn !Alon - berg%lon=lonn - berg%lat=latn - berg%uvel=uveln - berg%vvel=vveln - berg%ine=i - berg%jne=j - berg%xi=xi - berg%yj=yj - !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) - !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') - if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') - - - berg=>berg%next - enddo ! loop over all bergs - -! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) - if (interactive_icebergs_on) then - berg=>bergs%first - do while (associated(berg)) ! loop over all bergs + ! Saving all the iceberg variables. + berg%axn=axn !Alon + berg%ayn=ayn !Alon + berg%bxn=bxn !Alon + berg%byn=byn !Alon + berg%lon=lonn + berg%lat=latn + berg%uvel=uveln + berg%vvel=vveln + berg%ine=i + berg%jne=j + berg%xi=xi + berg%yj=yj + !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) + !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') + if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') - !Updating iceberg positions and velocities - berg%lon_old=berg%lon - berg%lat_old=berg%lat - berg%uvel_old=berg%uvel - berg%vvel_old=berg%vvel berg=>berg%next - enddo ! loop over all bergs - + enddo ! loop over all bergs + enddo ; enddo + + ! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) + if (interactive_icebergs_on) then + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + + !Updating iceberg positions and velocities + berg%lon_old=berg%lon + berg%lat_old=berg%lat + berg%uvel_old=berg%uvel + berg%vvel_old=berg%vvel + + berg=>berg%next + enddo ! loop over all bergs + enddo ; enddo + endif - endif - contains +contains subroutine rotpos_to_tang(lon, lat, x, y) ! Arguments @@ -2640,12 +2648,12 @@ subroutine icebergs_stock_pe(bergs, index, value) select case (index) case (ISTOCK_WATER) - berg_mass=sum_mass(bergs%first) + berg_mass=sum_mass(bergs) stored_mass=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) value=stored_mass+berg_mass case (ISTOCK_HEAT) - berg_mass=sum_mass(bergs%first) + berg_mass=sum_mass(bergs) stored_mass=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) value=-(stored_mass+berg_mass)*HLF ! HLF is in (J/kg) from constants_mod diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 30066d1..2766f65 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -157,9 +157,13 @@ module ice_bergs_framework real, dimension(:,:), pointer :: data end type buffer +type :: linked_list + type(iceberg), pointer :: first=>null() +end type linked_list + type :: icebergs !; private!Niki: Ask Alistair why this is private. ice_bergs_io cannot compile if this is private! type(icebergs_gridded), pointer :: grd - type(iceberg), pointer :: first=>null() + type(linked_list), dimension(:,:), allocatable :: list type(xyt), pointer :: trajectories=>null() real :: dt ! Time-step between iceberg calls (should make adaptive?) integer :: current_year @@ -375,6 +379,11 @@ subroutine ice_bergs_framework_init(bergs, & ! ' [lon|lat][min|max]=', minval(ice_lon),maxval(ice_lon),minval(ice_lat),maxval(ice_lat) !write(stderrunit,*) 'diamonds, int args = ', mpp_pe(),gni, gnj, layout, axes + ! Allocate grid of pointers + allocate( bergs%list(grd%isd:grd%ied, grd%jsd:grd%jed) ) + do j = grd%jsd,grd%jed ; do i = grd%isd,grd%ied + bergs%list(i,j)%first => null() + enddo ; enddo !write(stderrunit,*) 'diamonds: allocating grid' allocate( grd%lon(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lon(:,:)=999. @@ -672,19 +681,19 @@ subroutine offset_berg_dates(bergs,Time) type(iceberg), pointer :: this integer :: iyr, imon, iday, ihr, imin, isec, yr_offset real :: latest_start_year, berg_start_year +integer :: grdi, grdj call get_date(Time, iyr, imon, iday, ihr, imin, isec) - latest_start_year=iyr-99999 + latest_start_year=iyr-999999. - this=>bergs%first - if (associated(this)) then - latest_start_year=float(this%start_year)+this%start_day/367. - endif - do while (associated(this)) - berg_start_year=float(this%start_year)+this%start_day/367. - if (berg_start_year>latest_start_year) latest_start_year=berg_start_year - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + berg_start_year=float(this%start_year)+this%start_day/367. + if (berg_start_year>latest_start_year) latest_start_year=berg_start_year + this=>this%next + enddo + enddo ; enddo call mpp_max(latest_start_year) if (latest_start_year<=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367.) return ! No conflicts! @@ -693,11 +702,13 @@ subroutine offset_berg_dates(bergs,Time) if (mpp_pe().eq.mpp_root_pe()) write(*,'(a,i8,a)') & 'diamonds: Bergs found with creation dates after model date! Adjusting berg dates by ',yr_offset,' years' call bergs_chksum(bergs, 'before adjusting start dates') - this=>bergs%first - do while (associated(this)) - this%start_year=this%start_year-yr_offset - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + this%start_year=this%start_year-yr_offset + this=>this%next + enddo + enddo ; enddo call bergs_chksum(bergs, 'after adjusting start dates') end subroutine offset_berg_dates @@ -716,6 +727,7 @@ subroutine send_bergs_to_other_pes(bergs) type(icebergs_gridded), pointer :: grd integer :: i, nbergs_start, nbergs_end integer :: stderrunit +integer :: grdi, grdj ! Get the stderr unit number stderrunit = stderr() @@ -730,8 +742,8 @@ subroutine send_bergs_to_other_pes(bergs) ! Find number of bergs that headed east/west nbergs_to_send_e=0 nbergs_to_send_w=0 - if (associated(bergs%first)) then - this=>bergs%first + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first do while (associated(this)) if (this%ine.gt.bergs%grd%iec) then kick_the_bucket=>this @@ -739,19 +751,19 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_to_send_e=nbergs_to_send_e+1 call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%first,kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) elseif (this%ine.lt.bergs%grd%isc) then kick_the_bucket=>this this=>this%next nbergs_to_send_w=nbergs_to_send_w+1 call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%first,kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) else this=>this%next endif enddo - endif + enddo ; enddo ! Send bergs east if (grd%pe_E.ne.NULL_PE) then @@ -780,7 +792,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w - call unpack_berg_from_buffer2(bergs%first, bergs%ibuffer_w, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd) enddo endif else @@ -798,7 +810,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e - call unpack_berg_from_buffer2(bergs%first, bergs%ibuffer_e, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd) enddo endif else @@ -811,8 +823,8 @@ subroutine send_bergs_to_other_pes(bergs) ! here to accomodate diagonal transfer of bergs between PEs -AJA) nbergs_to_send_n=0 nbergs_to_send_s=0 - if (associated(bergs%first)) then - this=>bergs%first + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + this=>bergs%list(grdi,grdj)%first do while (associated(this)) if (this%jne.gt.bergs%grd%jec) then kick_the_bucket=>this @@ -820,19 +832,19 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_to_send_n=nbergs_to_send_n+1 call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%first,kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) elseif (this%jne.lt.bergs%grd%jsc) then kick_the_bucket=>this this=>this%next nbergs_to_send_s=nbergs_to_send_s+1 call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%first,kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) else this=>this%next endif enddo - endif + enddo ; enddo ! Send bergs north if (grd%pe_N.ne.NULL_PE) then @@ -869,7 +881,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s - call unpack_berg_from_buffer2(bergs%first, bergs%ibuffer_s, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd) enddo endif else @@ -895,7 +907,7 @@ subroutine send_bergs_to_other_pes(bergs) call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) endif do i=1, nbergs_rcvd_from_n - call unpack_berg_from_buffer2(bergs%first, bergs%ibuffer_n, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd) enddo endif else @@ -925,15 +937,17 @@ subroutine send_bergs_to_other_pes(bergs) if (debug) then i=0 - this=>bergs%first - do while (associated(this)) - call check_position(grd, this, 'exchange (bot)') - if (this%ine.lt.bergs%grd%isc .or. & - this%ine.gt.bergs%grd%iec .or. & - this%jne.lt.bergs%grd%jsc .or. & - this%jne.gt.bergs%grd%jec) i=i+1 - this=>this%next - enddo ! while + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + call check_position(grd, this, 'exchange (bot)') + if (this%ine.lt.bergs%grd%isc .or. & + this%ine.gt.bergs%grd%iec .or. & + this%jne.lt.bergs%grd%jsc .or. & + this%jne.gt.bergs%grd%jec) i=i+1 + this=>this%next + enddo ! while + enddo ; enddo call mpp_sum(i) if (i>0 .and. mpp_pe()==mpp_root_pe()) then write(stderrunit,'(a,i4)') 'diamonds, send_bergs_to_other_pes: # of bergs outside computational domain = ',i @@ -1012,13 +1026,12 @@ subroutine increase_buffer(old,delta) end subroutine increase_buffer - subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) + subroutine unpack_berg_from_buffer2(bergs, buff, n,grd) ! Arguments - type(iceberg), pointer :: first + type(icebergs), pointer :: bergs type(buffer), pointer :: buff integer, intent(in) :: n type(icebergs_gridded), pointer :: grd - logical, optional :: force_append ! Local variables !real :: lon, lat, uvel, vvel, xi, yj @@ -1031,71 +1044,63 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) ! Get the stderr unit number stderrunit = stderr() - if(present(force_append)) force_app = force_append - - localberg%lon=buff%data(1,n) - localberg%lat=buff%data(2,n) - localberg%uvel=buff%data(3,n) - localberg%vvel=buff%data(4,n) - localberg%xi=buff%data(5,n) - localberg%yj=buff%data(6,n) - localberg%start_lon=buff%data(7,n) - localberg%start_lat=buff%data(8,n) - localberg%start_year=nint(buff%data(9,n)) - localberg%start_day=buff%data(10,n) - localberg%start_mass=buff%data(11,n) - localberg%mass=buff%data(12,n) - localberg%thickness=buff%data(13,n) - localberg%width=buff%data(14,n) - localberg%length=buff%data(15,n) - localberg%mass_scaling=buff%data(16,n) - localberg%mass_of_bits=buff%data(17,n) - localberg%heat_density=buff%data(18,n) - - if(force_app) then !force append with origin ine,jne (for I/O) - localberg%ine=buff%data(19,n) - localberg%jne=buff%data(20,n) - call add_new_berg_to_list(first, localberg) - else - - localberg%axn=buff%data(21,n) !Alon - localberg%ayn=buff%data(22,n) !Alon - localberg%bxn=buff%data(23,n) !Alon - localberg%byn=buff%data(24,n) !Alon - localberg%uvel_old=buff%data(25,n) !Alon - localberg%vvel_old=buff%data(26,n) !Alon - localberg%lon_old=buff%data(27,n) !Alon - localberg%lat_old=buff%data(28,n) !Alon - - lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + localberg%lon=buff%data(1,n) + localberg%lat=buff%data(2,n) + localberg%uvel=buff%data(3,n) + localberg%vvel=buff%data(4,n) + localberg%xi=buff%data(5,n) + localberg%yj=buff%data(6,n) + localberg%start_lon=buff%data(7,n) + localberg%start_lat=buff%data(8,n) + localberg%start_year=nint(buff%data(9,n)) + localberg%start_day=buff%data(10,n) + localberg%start_mass=buff%data(11,n) + localberg%mass=buff%data(12,n) + localberg%thickness=buff%data(13,n) + localberg%width=buff%data(14,n) + localberg%length=buff%data(15,n) + localberg%mass_scaling=buff%data(16,n) + localberg%mass_of_bits=buff%data(17,n) + localberg%heat_density=buff%data(18,n) + localberg%ine=buff%data(19,n) + localberg%jne=buff%data(20,n) + localberg%axn=buff%data(21,n) !Alon + localberg%ayn=buff%data(22,n) !Alon + localberg%bxn=buff%data(23,n) !Alon + localberg%byn=buff%data(24,n) !Alon + localberg%uvel_old=buff%data(25,n) !Alon + localberg%vvel_old=buff%data(26,n) !Alon + localberg%lon_old=buff%data(27,n) !Alon + localberg%lat_old=buff%data(28,n) !Alon + + lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + if (lres) then + lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + else + lres=find_cell_wide(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - call add_new_berg_to_list(first, localberg) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) else - lres=find_cell_wide(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - if (lres) then - lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - call add_new_berg_to_list(first, localberg) - else - write(stderrunit,'("diamonds, unpack_berg_from_buffer pe=(",i3,a,2i4,a,2f8.2)')& - & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat - write(stderrunit,*) localberg%lon,localberg%lat - write(stderrunit,*) localberg%uvel,localberg%vvel - write(stderrunit,*) localberg%axn,localberg%ayn !Alon - write(stderrunit,*) localberg%bxn,localberg%byn !Alon - write(stderrunit,*) localberg%uvel_old,localberg%vvel_old !Alon - write(stderrunit,*) localberg%lon_old,localberg%lat_old !Alon - write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec - write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed - write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) - write(stderrunit,*) grd%lat(grd%isc-1,grd%jsc-1),grd%lat(grd%iec,grd%jec) - write(stderrunit,*) grd%lon(grd%isd,grd%jsd),grd%lon(grd%ied,grd%jsd) - write(stderrunit,*) grd%lat(grd%isd,grd%jsd),grd%lat(grd%ied,grd%jed) - write(stderrunit,*) lres - call error_mesg('diamonds, unpack_berg_from_buffer', 'can not find a cell to place berg in!', FATAL) - endif - endif + write(stderrunit,'("diamonds, unpack_berg_from_buffer pe=(",i3,a,2i4,a,2f8.2)')& + & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat + write(stderrunit,*) localberg%lon,localberg%lat + write(stderrunit,*) localberg%uvel,localberg%vvel + write(stderrunit,*) localberg%axn,localberg%ayn !Alon + write(stderrunit,*) localberg%bxn,localberg%byn !Alon + write(stderrunit,*) localberg%uvel_old,localberg%vvel_old !Alon + write(stderrunit,*) localberg%lon_old,localberg%lat_old !Alon + write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec + write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed + write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) + write(stderrunit,*) grd%lat(grd%isc-1,grd%jsc-1),grd%lat(grd%iec,grd%jec) + write(stderrunit,*) grd%lon(grd%isd,grd%jsd),grd%lon(grd%ied,grd%jsd) + write(stderrunit,*) grd%lat(grd%isd,grd%jsd),grd%lat(grd%ied,grd%jed) + write(stderrunit,*) lres + call error_mesg('diamonds, unpack_berg_from_buffer', 'can not find a cell to place berg in!', FATAL) endif + endif end subroutine unpack_berg_from_buffer2 @@ -1320,35 +1325,40 @@ subroutine count_out_of_order(bergs,label) ! Local variables type(iceberg), pointer :: this, next integer :: i, icnt1, icnt2, icnt3 +integer :: grdi, grdj icnt1=0; icnt3=0 - this=>bergs%first - next=>null() - if (associated(this)) then - if (associated(this%next)) next=>this%next - endif - do while (associated(next)) - if (.not. inorder(this,next)) icnt1=icnt1+1 - if (inorder(this,next).and.inorder(next,this)) icnt3=icnt3+1 - this=>next - next=>next%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + next=>null() + if (associated(this)) then + if (associated(this%next)) next=>this%next + endif + do while (associated(next)) + if (.not. inorder(this,next)) icnt1=icnt1+1 + if (inorder(this,next).and.inorder(next,this)) icnt3=icnt3+1 + this=>next + next=>next%next + enddo + enddo;enddo call mpp_sum(icnt1) i=0; icnt2=0 - this=>bergs%first - do while (associated(this)) - i=1 - if (this%inebergs%grd%iec .or. & - this%jnebergs%grd%jec) icnt2=icnt2+1 - this=>this%next - if (i>1.and..not.associated(this%prev)) then - call error_mesg('diamonds, count_out_of_order', 'Pointer %prev is unassociated. This should not happen!', FATAL) - endif - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + i=1 + if (this%inebergs%grd%iec .or. & + this%jnebergs%grd%jec) icnt2=icnt2+1 + this=>this%next + if (i>1.and..not.associated(this%prev)) then + call error_mesg('diamonds, count_out_of_order', 'Pointer %prev is unassociated. This should not happen!', FATAL) + endif + enddo + enddo; enddo call mpp_sum(icnt2) if ((debug.or.icnt1.ne.0).and.mpp_pe().eq.mpp_root_pe()) then @@ -1369,19 +1379,31 @@ subroutine check_for_duplicates(bergs,label) ! Local variables type(iceberg), pointer :: this1, next1, this2, next2 integer :: icnt_id, icnt_same +integer :: grdi, grdj +integer :: grdi_inner, grdj_inner icnt_id=0 icnt_same=0 - this1=>bergs%first - do while (associated(this1)) - this2=>this1%next - do while (associated(this2)) - if (sameid(this1,this2)) icnt_id=icnt_id+1 - if (sameberg(this1,this2)) icnt_same=icnt_same+1 - this2=>this2%next + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this1=>bergs%list(grdi,grdj)%first + do while (associated(this1)) + do grdj_inner = grdj,bergs%grd%jec ; do grdi_inner = bergs%grd%isc,bergs%grd%iec + if ( .not.(grdj_inner==grdj .and. grdi_innerthis1%next + else + this2=>bergs%list(grdi_inner,grdj_inner)%first + endif + do while (associated(this2)) + if (sameid(this1,this2)) icnt_id=icnt_id+1 + if (sameberg(this1,this2)) icnt_same=icnt_same+1 + this2=>this2%next + enddo + endif + enddo ; enddo + this1=>this1%next enddo - this1=>this1%next - enddo + enddo ; enddo call mpp_sum(icnt_id) call mpp_sum(icnt_same) @@ -1642,12 +1664,15 @@ subroutine print_bergs(iochan, bergs, label) ! Local variables integer :: nbergs, nnbergs type(iceberg), pointer :: this +integer :: grdi, grdj - this=>bergs%first - do while(associated(this)) - call print_berg(iochan, this, label) - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + call print_berg(iochan, this, label) + this=>this%next + enddo + enddo ; enddo nbergs=count_bergs(bergs) nnbergs=nbergs call mpp_sum(nnbergs) @@ -1657,18 +1682,31 @@ end subroutine print_bergs ! ############################################################################## -integer function count_bergs(bergs) +integer function count_bergs(bergs, with_halos) ! Arguments type(icebergs), pointer :: bergs +logical, optional :: with_halos ! Local variables type(iceberg), pointer :: this +integer :: grdi, grdj, is, ie, js, je +logical :: include_halos + + include_halos = .false. + if (present(with_halos)) include_halos = with_halos + if (include_halos) then + is = bergs%grd%isd ; ie = bergs%grd%ied ; js = bergs%grd%jsd ; je = bergs%grd%jed + else + is = bergs%grd%isc ; ie = bergs%grd%iec ; js = bergs%grd%jsc ; je = bergs%grd%jec + endif count_bergs=0 - this=>bergs%first - do while(associated(this)) - count_bergs=count_bergs+1 - this=>this%next - enddo + do grdj = js,je ; do grdi = is,ie + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + count_bergs=count_bergs+1 + this=>this%next + enddo + enddo ; enddo end function count_bergs @@ -1680,45 +1718,48 @@ subroutine record_posn(bergs) ! Local variables type(xyt) :: posn type(iceberg), pointer :: this +integer :: grdi, grdj - this=>bergs%first - do while (associated(this)) - posn%lon=this%lon - posn%lat=this%lat - posn%year=bergs%current_year - posn%day=bergs%current_yearday - posn%uvel=this%uvel - posn%vvel=this%vvel - posn%mass=this%mass - posn%mass_of_bits=this%mass_of_bits - posn%heat_density=this%heat_density - posn%thickness=this%thickness - posn%width=this%width - posn%length=this%length - posn%uo=this%uo - posn%vo=this%vo - posn%ui=this%ui - posn%vi=this%vi - posn%ua=this%ua - posn%va=this%va - posn%ssh_x=this%ssh_x - posn%ssh_y=this%ssh_y - posn%sst=this%sst - posn%cn=this%cn - posn%hi=this%hi - posn%axn=this%axn - posn%ayn=this%ayn - posn%bxn=this%bxn - posn%byn=this%byn - posn%uvel_old=this%uvel_old - posn%vvel_old=this%vvel_old - posn%lon_old=this%lon_old - posn%lat_old=this%lat_old - - call push_posn(this%trajectory, posn) - - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + posn%lon=this%lon + posn%lat=this%lat + posn%year=bergs%current_year + posn%day=bergs%current_yearday + posn%uvel=this%uvel + posn%vvel=this%vvel + posn%mass=this%mass + posn%mass_of_bits=this%mass_of_bits + posn%heat_density=this%heat_density + posn%thickness=this%thickness + posn%width=this%width + posn%length=this%length + posn%uo=this%uo + posn%vo=this%vo + posn%ui=this%ui + posn%vi=this%vi + posn%ua=this%ua + posn%va=this%va + posn%ssh_x=this%ssh_x + posn%ssh_y=this%ssh_y + posn%sst=this%sst + posn%cn=this%cn + posn%hi=this%hi + posn%axn=this%axn + posn%ayn=this%ayn + posn%bxn=this%bxn + posn%byn=this%byn + posn%uvel_old=this%uvel_old + posn%vvel_old=this%vvel_old + posn%lon_old=this%lon_old + posn%lat_old=this%lat_old + + call push_posn(this%trajectory, posn) + + this=>this%next + enddo + enddo ; enddo end subroutine record_posn @@ -1811,16 +1852,19 @@ subroutine move_all_trajectories(bergs, delete_bergs) ! Local variables type(iceberg), pointer :: this, next logical :: delete_bergs_after_moving_traj +integer :: grdi, grdj delete_bergs_after_moving_traj = .false. if (present(delete_bergs)) delete_bergs_after_moving_traj = delete_bergs - this=>bergs%first - do while (associated(this)) - next=>this%next - call move_trajectory(bergs, this) - ! if (delete_bergs_after_moving_traj) call destroy_iceberg(this) - this=>next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + next=>this%next + call move_trajectory(bergs, this) + ! if (delete_bergs_after_moving_traj) call destroy_iceberg(this) + this=>next + enddo + enddo ; enddo end subroutine move_all_trajectories @@ -2468,52 +2512,58 @@ end subroutine check_position ! ############################################################################## -real function sum_mass(first,justbits,justbergs) +real function sum_mass(bergs,justbits,justbergs) ! Arguments -type(iceberg), pointer :: first +type(icebergs), pointer :: bergs logical, intent(in), optional :: justbits, justbergs ! Local variables type(iceberg), pointer :: this +integer :: grdi, grdj sum_mass=0. - this=>first - do while(associated(this)) - if (present(justbergs)) then - sum_mass=sum_mass+this%mass*this%mass_scaling - elseif (present(justbits)) then - sum_mass=sum_mass+this%mass_of_bits*this%mass_scaling - else - sum_mass=sum_mass+(this%mass+this%mass_of_bits)*this%mass_scaling - endif - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + if (present(justbergs)) then + sum_mass=sum_mass+this%mass*this%mass_scaling + elseif (present(justbits)) then + sum_mass=sum_mass+this%mass_of_bits*this%mass_scaling + else + sum_mass=sum_mass+(this%mass+this%mass_of_bits)*this%mass_scaling + endif + this=>this%next + enddo + enddo ; enddo end function sum_mass ! ############################################################################## -real function sum_heat(first,justbits,justbergs) +real function sum_heat(bergs,justbits,justbergs) ! Arguments -type(iceberg), pointer :: first +type(icebergs), pointer :: bergs logical, intent(in), optional :: justbits, justbergs ! Local variables type(iceberg), pointer :: this real :: dm +integer :: grdi, grdj sum_heat=0. - this=>first - do while(associated(this)) - dm=0. - if (present(justbergs)) then - dm=this%mass*this%mass_scaling - elseif (present(justbits)) then - dm=this%mass_of_bits*this%mass_scaling - else - dm=(this%mass+this%mass_of_bits)*this%mass_scaling - endif - sum_heat=sum_heat+dm*this%heat_density - this=>this%next - enddo + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + dm=0. + if (present(justbergs)) then + dm=this%mass*this%mass_scaling + elseif (present(justbits)) then + dm=this%mass_of_bits*this%mass_scaling + else + dm=(this%mass+this%mass_of_bits)*this%mass_scaling + endif + sum_heat=sum_heat+dm*this%heat_density + this=>this%next + enddo + enddo ; enddo end function sum_heat @@ -2736,6 +2786,7 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) type(iceberg), pointer :: this type(icebergs_gridded), pointer :: grd logical :: check_halo +integer :: grdi, grdj ! For convenience grd=>bergs%grd @@ -2750,36 +2801,38 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) icnt(:,:)=0 grd%tmp(:,:)=0. - this=>bergs%first - i=0; ichk5=0 - do while(associated(this)) - i=i+1 - iberg=berg_chksum(this) - fld(i,1) = this%lon - fld(i,2) = this%lat - fld(i,3) = this%uvel - fld(i,4) = this%vvel - fld(i,5) = this%mass - fld(i,6) = this%thickness - fld(i,7) = this%width - fld(i,8) = this%length - fld(i,9) = this%axn !added by Alon - fld(i,10) = this%ayn !added by Alon - fld(i,11) = this%bxn !added by Alon - fld(i,12) = this%byn !added by Alon - fld(i,13) = this%uvel_old !added by Alon - fld(i,14) = this%vvel_old !added by Alon - fld(i,15) = this%lon_old !added by Alon - fld(i,16) = this%lat_old !added by Alon - fld(i,17) = time_hash(this) !Changed from 9 to 17 by Alon - fld(i,18) = pos_hash(this) !Changed from 10 to 18 by Alon - fld(i,19) = float(iberg) !Changed from 11 to 19 by Alon - icnt(this%ine,this%jne)=icnt(this%ine,this%jne)+1 - fld2(i,:) = fld(i,:)*float( icnt(this%ine,this%jne) ) !*float( i ) - grd%tmp(this%ine,this%jne)=grd%tmp(this%ine,this%jne)+time_hash(this)*pos_hash(this)+log(this%mass) - ichk5=ichk5+iberg - this=>this%next - enddo + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + this=>bergs%list(grdi,grdj)%first + i=0; ichk5=0 + do while(associated(this)) + i=i+1 + iberg=berg_chksum(this) + fld(i,1) = this%lon + fld(i,2) = this%lat + fld(i,3) = this%uvel + fld(i,4) = this%vvel + fld(i,5) = this%mass + fld(i,6) = this%thickness + fld(i,7) = this%width + fld(i,8) = this%length + fld(i,9) = this%axn !added by Alon + fld(i,10) = this%ayn !added by Alon + fld(i,11) = this%bxn !added by Alon + fld(i,12) = this%byn !added by Alon + fld(i,13) = this%uvel_old !added by Alon + fld(i,14) = this%vvel_old !added by Alon + fld(i,15) = this%lon_old !added by Alon + fld(i,16) = this%lat_old !added by Alon + fld(i,17) = time_hash(this) !Changed from 9 to 17 by Alon + fld(i,18) = pos_hash(this) !Changed from 10 to 18 by Alon + fld(i,19) = float(iberg) !Changed from 11 to 19 by Alon + icnt(this%ine,this%jne)=icnt(this%ine,this%jne)+1 + fld2(i,:) = fld(i,:)*float( icnt(this%ine,this%jne) ) !*float( i ) + grd%tmp(this%ine,this%jne)=grd%tmp(this%ine,this%jne)+time_hash(this)*pos_hash(this)+log(this%mass) + ichk5=ichk5+iberg + this=>this%next + enddo + enddo ; enddo ichk1=mpp_chksum( fld ) ichk2=mpp_chksum( fld2 ) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 3449158..9f9ca58 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -105,7 +105,6 @@ subroutine write_restart(bergs) integer :: stderrunit !I/O vars type(restart_file_type) :: bergs_restart -type(iceberg), pointer :: bergs4io=>NULL() integer :: nbergs type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & @@ -136,6 +135,7 @@ subroutine write_restart(bergs) jne, & start_year !uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. +integer :: grdi, grdj ! Get the stderr unit number stderrunit=stderr() @@ -145,17 +145,14 @@ subroutine write_restart(bergs) grd=>bergs%grd !First add the bergs on the io_tile_root_pe (if any) to the I/O list - nbergs = 0 - if(associated(bergs%first)) then - !bergs4io => bergs%first !This would modify the bergs and cause them to grow to include all bergs in the tile. - !Alternatively, create a new list, slow - this=>bergs%first - do while (associated(this)) - nbergs = nbergs +1 - call add_new_berg_to_list(bergs4io, this) - this=>this%next - enddo - endif + nbergs = 0 + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + nbergs = nbergs +1 + this=>this%next + enddo + enddo ; enddo allocate(lon(nbergs)) allocate(lat(nbergs)) @@ -232,24 +229,28 @@ subroutine write_restart(bergs) ! Write variables - if(associated(bergs%first)) this=>bergs%first - do i=1,nbergs - lon(i) = this%lon; lat(i) = this%lat - lon_old(i) = this%lon_old; lat_old(i) = this%lat_old !Alon - uvel(i) = this%uvel; vvel(i) = this%vvel - ine(i) = this%ine; jne(i) = this%jne - mass(i) = this%mass; thickness(i) = this%thickness - axn(i) = this%axn; ayn(i) = this%ayn !Added by Alon - uvel_old(i) = this%uvel_old; vvel_old(i) = this%vvel_old !Added by Alon - bxn(i) = this%bxn; byn(i) = this%byn !Added by Alon - width(i) = this%width; length(i) = this%length - start_lon(i) = this%start_lon; start_lat(i) = this%start_lat - start_year(i) = this%start_year; start_day(i) = this%start_day - start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling - mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density - this=>this%next - enddo - + i = 0 + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) + i = i + 1 + lon(i) = this%lon; lat(i) = this%lat + lon_old(i) = this%lon_old; lat_old(i) = this%lat_old !Alon + uvel(i) = this%uvel; vvel(i) = this%vvel + ine(i) = this%ine; jne(i) = this%jne + mass(i) = this%mass; thickness(i) = this%thickness + axn(i) = this%axn; ayn(i) = this%ayn !Added by Alon + uvel_old(i) = this%uvel_old; vvel_old(i) = this%vvel_old !Added by Alon + bxn(i) = this%bxn; byn(i) = this%byn !Added by Alon + width(i) = this%width; length(i) = this%length + start_lon(i) = this%start_lon; start_lat(i) = this%start_lat + start_year(i) = this%start_year; start_day(i) = this%start_day + start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling + mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density + this=>this%next + enddo + enddo ; enddo + call save_restart(bergs_restart) call free_restart_type(bergs_restart) @@ -471,8 +472,8 @@ subroutine read_restart_bergs_orig(bergs,Time) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) - call add_new_berg_to_list(bergs%first, localberg) - if (really_debug) call print_berg(stderrunit, bergs%first, 'read_restart_bergs, add_new_berg_to_list') + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + if (really_debug) call print_berg(stderrunit, bergs%list(localberg%ine,localberg%jne)%first, 'read_restart_bergs, add_new_berg_to_list') elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) endif @@ -500,11 +501,11 @@ subroutine read_restart_bergs_orig(bergs,Time) if (.not. found_restart .and. bergs%nbergs_start==0 .and. generate_test_icebergs) call generate_bergs(bergs,Time) - bergs%floating_mass_start=sum_mass(bergs%first) + bergs%floating_mass_start=sum_mass(bergs) call mpp_sum( bergs%floating_mass_start ) - bergs%icebergs_mass_start=sum_mass(bergs%first,justbergs=.true.) + bergs%icebergs_mass_start=sum_mass(bergs,justbergs=.true.) call mpp_sum( bergs%icebergs_mass_start ) - bergs%bergy_mass_start=sum_mass(bergs%first,justbits=.true.) + bergs%bergy_mass_start=sum_mass(bergs,justbits=.true.) call mpp_sum( bergs%bergy_mass_start ) if (mpp_pe().eq.mpp_root_pe().and.verbose) write(*,'(a)') 'diamonds, read_restart_bergs: completed' @@ -554,7 +555,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=-1. localberg%vvel=0. localberg%axn=0. !Alon @@ -563,7 +564,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=0. localberg%vvel=1. localberg%axn=0. !Alon @@ -572,7 +573,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=0. localberg%vvel=-1. localberg%axn=0. !Alon @@ -581,7 +582,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) endif enddo; enddo @@ -768,8 +769,8 @@ subroutine read_restart_bergs(bergs,Time) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) - call add_new_berg_to_list(bergs%first, localberg) - if (really_debug) call print_berg(stderrunit, bergs%first, 'read_restart_bergs, add_new_berg_to_list') + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + if (really_debug) call print_berg(stderrunit, bergs%list(localberg%ine,localberg%jne)%first, 'read_restart_bergs, add_new_berg_to_list') elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) endif @@ -807,11 +808,11 @@ subroutine read_restart_bergs(bergs,Time) call generate_bergs(bergs,Time) endif - bergs%floating_mass_start=sum_mass(bergs%first) + bergs%floating_mass_start=sum_mass(bergs) call mpp_sum( bergs%floating_mass_start ) - bergs%icebergs_mass_start=sum_mass(bergs%first,justbergs=.true.) + bergs%icebergs_mass_start=sum_mass(bergs,justbergs=.true.) call mpp_sum( bergs%icebergs_mass_start ) - bergs%bergy_mass_start=sum_mass(bergs%first,justbits=.true.) + bergs%bergy_mass_start=sum_mass(bergs,justbits=.true.) call mpp_sum( bergs%bergy_mass_start ) if (mpp_pe().eq.mpp_root_pe().and.verbose) write(*,'(a)') 'diamonds, read_restart_bergs: completed' @@ -861,7 +862,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=-1. localberg%vvel=0. localberg%axn=0. !Alon @@ -870,7 +871,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=0. localberg%vvel=1. localberg%axn=0. !Alon @@ -879,7 +880,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) localberg%uvel=0. localberg%vvel=-1. localberg%axn=0. !Alon @@ -888,7 +889,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - call add_new_berg_to_list(bergs%first, localberg) + call add_new_berg_to_list(bergs%list(i,j)%first, localberg) endif enddo; enddo @@ -967,7 +968,7 @@ subroutine read_restart_calving(bergs) call mpp_sum( bergs%stored_start ) bergs%stored_heat_start=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum( bergs%stored_heat_start ) - bergs%floating_heat_start=sum_heat(bergs%first) + bergs%floating_heat_start=sum_heat(bergs) call mpp_sum( bergs%floating_heat_start ) end subroutine read_restart_calving From a01fd33c37f7c35b425cd20d9f881a742482ebce Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 29 Jul 2015 17:29:20 -0400 Subject: [PATCH 046/361] Bug fix for restarts (post Verlet) - A few new variables (axn, any, bxn, bny, ...) added for the Verlet algorithm were being assigned the value of "mass" in the restart file. --- icebergs_io.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 3449158..5017f67 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -202,12 +202,12 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_restart,filename,'uvel',uvel,longname='zonal velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'vvel',vvel,longname='meridional velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'mass',mass,longname='mass',units='kg') - id = register_restart_field(bergs_restart,filename,'axn',mass,longname='explicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'ayn',mass,longname='explicit meridional acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'uvel_old',mass,longname='old explicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'vvel_old',mass,longname='old explicit meridional acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'bxn',mass,longname='inplicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'byn',mass,longname='implicit meridional acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'axn',axn,longname='explicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'ayn',ayn,longname='explicit meridional acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'uvel_old',uvel_old,longname='old explicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'vvel_old',vvel_old,longname='old explicit meridional acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'bxn',bxn,longname='inplicit zonal acceleration',units='m/s^2') !Alon + id = register_restart_field(bergs_restart,filename,'byn',byn,longname='implicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ine',ine,longname='i index',units='none') id = register_restart_field(bergs_restart,filename,'jne',jne,longname='j index',units='none') id = register_restart_field(bergs_restart,filename,'thickness',thickness,longname='thickness',units='m') From 6185016de0860fdc8d48d3def027e558e4a1facd Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 4 Aug 2015 11:27:00 -0400 Subject: [PATCH 047/361] Found a small bug in the subroutine which sends bergs to other PE's. The search for bergs moving north to south should be on the entire domain including the halos. This bug has been fixed. --- icebergs_framework.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 2766f65..e04ff8a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -823,7 +823,7 @@ subroutine send_bergs_to_other_pes(bergs) ! here to accomodate diagonal transfer of bergs between PEs -AJA) nbergs_to_send_n=0 nbergs_to_send_s=0 - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) if (this%jne.gt.bergs%grd%jec) then From 154dcbdf403d2e6faaa5a5b51f6efa9197f86a58 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 4 Aug 2015 15:14:31 -0400 Subject: [PATCH 048/361] Added a routine called move_berg_between_cells which makes sure that the icebergs are on the correct lists after the icebergs have been evolved. The routine checks if ine=grdi and jne=grdj, and if not, moves the berg to the correct list. I have not fully tested whether this works. --- icebergs.F90 | 4 +++- icebergs_framework.F90 | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 87a7a53..410cbb7 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -30,6 +30,7 @@ module ice_bergs use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory,move_all_trajectories +use ice_bergs_framework, only: move_berg_between_cells use ice_bergs_framework, only: record_posn,check_position,print_berg,print_bergs,print_fld use ice_bergs_framework, only: add_new_berg_to_list,delete_iceberg_from_list,destroy_iceberg use ice_bergs_framework, only: grd_chksum2,grd_chksum3 @@ -1270,6 +1271,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! For each berg, evolve call mpp_clock_begin(bergs%clock_mom) call evolve_icebergs(bergs) + !call move_berg_between_cells(bergs) !Markpoint6 if (debug) call bergs_chksum(bergs, 'run bergs (evolved)',ignore_halo_violation=.true.) if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) @@ -2342,12 +2344,12 @@ subroutine evolve_icebergs(bergs) berg%lat_old=berg%lat berg%uvel_old=berg%uvel berg%vvel_old=berg%vvel - berg=>berg%next enddo ! loop over all bergs enddo ; enddo endif + contains subroutine rotpos_to_tang(lon, lat, x, y) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e04ff8a..a4cd57e 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -66,6 +66,7 @@ module ice_bergs_framework public checksum_gridded public grd_chksum2,grd_chksum3 public fix_restart_dates, offset_berg_dates +public move_berg_between_cells type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -715,6 +716,32 @@ end subroutine offset_berg_dates ! ############################################################################# +subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists if they have moved from cell to cell. +! Arguments +type(icebergs), pointer :: bergs +type(icebergs_gridded), pointer :: grd +type(iceberg), pointer :: moving_berg, this +integer :: grdi, grdj + +do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + if ((this%ine.ne.grdi) .or. (this%jne.ne.grdj)) then + moving_berg=>this + this=>this%next + !call move_trajectory(bergs, kick_the_bucket) + call add_new_berg_to_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,moving_berg) + else + this=>this%next + endif + enddo +enddo ; enddo + +end subroutine move_berg_between_cells + +! ############################################################################# + subroutine send_bergs_to_other_pes(bergs) ! Arguments type(icebergs), pointer :: bergs From 8977c627f4e5702d6376ca372fd40cc4f99b2216 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 6 Aug 2015 11:51:42 -0400 Subject: [PATCH 049/361] Fixed the icebergs moving between cell lists subroutine. -Added initialization for grd and this pointers. -Do not allocate or deallocate memory when moving bergs from cell to cell. - This is not working quite yet. There is still a bug --- icebergs.F90 | 2 +- icebergs_framework.F90 | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 410cbb7..3621ad1 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1271,7 +1271,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! For each berg, evolve call mpp_clock_begin(bergs%clock_mom) call evolve_icebergs(bergs) - !call move_berg_between_cells(bergs) !Markpoint6 + call move_berg_between_cells(bergs) !Markpoint6 if (debug) call bergs_chksum(bergs, 'run bergs (evolved)',ignore_halo_violation=.true.) if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index a4cd57e..9f3adeb 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -719,9 +719,12 @@ end subroutine offset_berg_dates subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists if they have moved from cell to cell. ! Arguments type(icebergs), pointer :: bergs -type(icebergs_gridded), pointer :: grd -type(iceberg), pointer :: moving_berg, this +type(icebergs_gridded), pointer :: grd => null() +type(iceberg), pointer :: moving_berg => null(), this => null() integer :: grdi, grdj +logical :: quick +! For convenience +grd=>bergs%grd do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first @@ -729,9 +732,23 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists if ((this%ine.ne.grdi) .or. (this%jne.ne.grdj)) then moving_berg=>this this=>this%next - !call move_trajectory(bergs, kick_the_bucket) - call add_new_berg_to_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg) - call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,moving_berg) + + !Removing the iceberg from the old list + if (associated(moving_berg%prev)) then + moving_berg%prev%next=>moving_berg%next + else + bergs%list(grdi,grdj)%first=>moving_berg%next + endif + if (associated(moving_berg%next)) moving_berg%next%prev=>moving_berg%prev + + !Inserting the iceberg into the new list +! call insert_berg_into_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg,quick=.true.) +! call insert_berg_into_list(bergs%list(grdi,grdj)%first,moving_berg) + call insert_berg_into_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg) + + !Clear moving_berg + moving_berg=>null() + else this=>this%next endif From 277e41b27d8a0eb4ff06a0bda5f5fb0aca2e0c61 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 7 Aug 2015 11:45:18 -0400 Subject: [PATCH 050/361] Fixed a bug which was allowing the icebergs to enter an infinite loop. The problem was that when an iceberg moved onto a new list, and the new list was empty, the iceberg was assigned to first, but the next and previous of the berg were not set to null. The error has been corrected. The routine which moves icebergs between lists corresponding to cells, should now be working. The model passes a 10 day regression test. --- icebergs_framework.F90 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 9f3adeb..66c1bd1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -729,21 +729,20 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) + if ((this%ine.ne.grdi) .or. (this%jne.ne.grdj)) then moving_berg=>this this=>this%next !Removing the iceberg from the old list if (associated(moving_berg%prev)) then - moving_berg%prev%next=>moving_berg%next + moving_berg%prev%next=>moving_berg%next else - bergs%list(grdi,grdj)%first=>moving_berg%next + bergs%list(grdi,grdj)%first=>moving_berg%next endif if (associated(moving_berg%next)) moving_berg%next%prev=>moving_berg%prev !Inserting the iceberg into the new list -! call insert_berg_into_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg,quick=.true.) -! call insert_berg_into_list(bergs%list(grdi,grdj)%first,moving_berg) call insert_berg_into_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg) !Clear moving_berg @@ -1468,17 +1467,18 @@ subroutine insert_berg_into_list(first, newberg, quick) type(iceberg), pointer :: this, prev logical :: quickly = .false. -if(present(quick)) quickly = quick if (associated(first)) then if (.not. parallel_reprod .or. quickly) then newberg%next=>first + newberg%prev=>null() first%prev=>newberg first=>newberg else if (inorder(newberg,first)) then ! Insert at front of list newberg%next=>first + newberg%prev=>null() first%prev=>newberg first=>newberg else @@ -1500,6 +1500,8 @@ subroutine insert_berg_into_list(first, newberg, quick) else ! list is empty so create it first=>newberg + first%next=>null() + first%prev=>null() endif end subroutine insert_berg_into_list From 597bf993fe3e8ab48b59bca58dc00bf792458f89 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 17 Aug 2015 16:39:19 -0400 Subject: [PATCH 051/361] Minor fix for generate_test_icebergs, used in debugging - generate_test_icebergs=.true. creates 4 icebergs in every cell poleward of +-60, moving in the cardinal directions. The start location was the center of cell which meant that they were indistinguishable from each other. The insertion into the list was not determinate. - I have offset each of the four bergs within the cell in order to make each berg identifiable. - This only affects this debugging option (generate_test_icebergs). --- icebergs_io.F90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b81888c..144af01 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -863,6 +863,7 @@ subroutine generate_bergs(bergs,Time) localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%list(i,j)%first, localberg) + localberg%start_lon=localberg%lon-0.001 localberg%uvel=-1. localberg%vvel=0. localberg%axn=0. !Alon @@ -872,6 +873,7 @@ subroutine generate_bergs(bergs,Time) localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%list(i,j)%first, localberg) + localberg%start_lat=localberg%lat+0.001 localberg%uvel=0. localberg%vvel=1. localberg%axn=0. !Alon @@ -881,6 +883,7 @@ subroutine generate_bergs(bergs,Time) localberg%bxn=0. !Alon localberg%byn=0. !Alon call add_new_berg_to_list(bergs%list(i,j)%first, localberg) + localberg%start_lat=localberg%lat-0.001 localberg%uvel=0. localberg%vvel=-1. localberg%axn=0. !Alon From 2327b5696d12f103e5b51def5616eb6f930ceb44 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 17 Aug 2015 16:51:17 -0400 Subject: [PATCH 052/361] Added debugging diagnostics "bergs_per_cell" and "list_chksum" - Implemented count_bergs_in_list() and list_chksum() - count_bergs() uses count_bergs_in_list() --- icebergs.F90 | 22 +++++++++++++++--- icebergs_framework.F90 | 52 +++++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3621ad1..eec7028 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -27,8 +27,8 @@ module ice_bergs use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell use ice_bergs_framework, only: nclasses,old_bug_bilin -use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum -use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list +use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum,count_bergs_in_list +use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list,list_chksum use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory,move_all_trajectories use ice_bergs_framework, only: move_berg_between_cells use ice_bergs_framework, only: record_posn,check_position,print_berg,print_bergs,print_fld @@ -1095,6 +1095,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger +real, dimension(:,:), allocatable :: iCount integer :: stderrunit @@ -1347,7 +1348,22 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_fax, tauxa(:,:), Time) if (grd%id_fay>0) & lerr=send_data(grd%id_fay, tauya(:,:), Time) - + if (grd%id_count>0) then + allocate( iCount(grd%isc:grd%iec,grd%jsc:grd%jec) ); iCount(:,:)=0 + do j = grd%jsc, grd%jec ; do i = grd%isc, grd%iec + iCount(i,j) = count_bergs_in_list(bergs%list(i,j)%first) + enddo ; enddo + lerr=send_data(grd%id_count, iCount(:,:), Time) + deallocate( iCount ) + endif + if (grd%id_chksum>0) then + allocate( iCount(grd%isc:grd%iec,grd%jsc:grd%jec) ); iCount(:,:)=0 + do j = grd%jsc, grd%jec ; do i = grd%isc, grd%iec + iCount(i,j) = list_chksum(bergs%list(i,j)%first) + enddo ; enddo + lerr=send_data(grd%id_chksum, iCount(:,:), Time) + deallocate( iCount ) + endif ! Dump icebergs to screen if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_run, status') diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 66c1bd1..2296ba6 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -62,7 +62,7 @@ module ice_bergs_framework public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position public move_trajectory, move_all_trajectories public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell -public sum_mass,sum_heat,bilin,yearday,bergs_chksum +public sum_mass,sum_heat,bilin,yearday,bergs_chksum,list_chksum,count_bergs_in_list public checksum_gridded public grd_chksum2,grd_chksum3 public fix_restart_dates, offset_berg_dates @@ -123,6 +123,7 @@ module ice_bergs_framework integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1 + integer :: id_count=-1, id_chksum=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -608,6 +609,10 @@ subroutine ice_bergs_framework_init(bergs, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & 'Calving into iceberg class', 'kg/s') + grd%id_count=register_diag_field('icebergs', 'bergs_per_cell', axes, Time, & + 'Number of bergs per cell', '#') + grd%id_chksum=register_diag_field('icebergs', 'list_chksum', axes, Time, & + 'mpp_chksum on bergs in each cell', '#') grd%id_uo=register_diag_field('icebergs', 'uo', axes, Time, & 'Ocean zonal component of velocity', 'm s^-1') grd%id_vo=register_diag_field('icebergs', 'vo', axes, Time, & @@ -1733,7 +1738,6 @@ integer function count_bergs(bergs, with_halos) type(icebergs), pointer :: bergs logical, optional :: with_halos ! Local variables -type(iceberg), pointer :: this integer :: grdi, grdj, is, ie, js, je logical :: include_halos @@ -1747,17 +1751,30 @@ integer function count_bergs(bergs, with_halos) count_bergs=0 do grdj = js,je ; do grdi = is,ie - this=>bergs%list(grdi,grdj)%first - do while(associated(this)) - count_bergs=count_bergs+1 - this=>this%next - enddo + count_bergs=count_bergs+count_bergs_in_list(bergs%list(grdi,grdj)%first) enddo ; enddo end function count_bergs ! ############################################################################## +integer function count_bergs_in_list(first) +! Arguments +type(iceberg), pointer :: first +! Local variables +type(iceberg), pointer :: this + + count_bergs_in_list=0 + this=>first + do while(associated(this)) + count_bergs_in_list=count_bergs_in_list+1 + this=>this%next + enddo + +end function count_bergs_in_list + +! ############################################################################## + subroutine record_posn(bergs) ! Arguments type(icebergs), pointer :: bergs @@ -2921,7 +2938,26 @@ end subroutine bergs_chksum ! ############################################################################## -integer function berg_chksum(berg ) +integer function list_chksum(first) +! Arguments +type(iceberg), pointer :: first +! Local variables +integer :: i +type(iceberg), pointer :: this + + this=>first + i=0; list_chksum=0 + do while(associated(this)) + i=i+1 + list_chksum=list_chksum+berg_chksum(this)*i + this=>this%next + enddo + +end function list_chksum + +! ############################################################################## + +integer function berg_chksum(berg) ! Arguments type(iceberg), pointer :: berg ! Local variables From f720e15b3c4e4581953926b76b79068655397302 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 11 Sep 2015 15:28:32 -0400 Subject: [PATCH 053/361] For the interactive forces, I have changed the loop so that icebergs only interact with other icebergs which are in the nine grid cells immediately adjacent. The icebergs are not get stored correctly in the halos (or at all). So this will not work well at the edge of a processor. This will be done next. --- icebergs.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3621ad1..d2a75d0 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -165,11 +165,10 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i lon1=berg%lon; lat1=berg%lat call rotpos_to_tang(lon1,lat1,x1,y1) - do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 other_berg=>bergs%list(grdi,grdj)%first !Note: This summing should be made order invarient. -!Note: Need to limit how many icebergs we search over do while (associated(other_berg)) ! loop over all other bergs L2=other_berg%length W2=other_berg%width From 1f0146659394a9382eaf8734702b6f8319447e4b Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 11 Sep 2015 17:46:26 -0400 Subject: [PATCH 054/361] A new routine called update_halo has been included. This routine works in two steps. First the halos are cleared (ie: all the bergs are deleted from cells in the halos). Second, the icebergs near the the edge of the processor are copied into the halos of the other processor. The code compiles, but has not yet been tested. Also, I am not sure that the icebergs which are being moved into the halos of the other processor are being sent to the correct grid list. This will be the next update. --- icebergs.F90 | 3 +- icebergs_framework.F90 | 243 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index d2a75d0..5afee1d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -30,7 +30,7 @@ module ice_bergs use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory,move_all_trajectories -use ice_bergs_framework, only: move_berg_between_cells +use ice_bergs_framework, only: move_berg_between_cells, update_halo use ice_bergs_framework, only: record_posn,check_position,print_berg,print_bergs,print_fld use ice_bergs_framework, only: add_new_berg_to_list,delete_iceberg_from_list,destroy_iceberg use ice_bergs_framework, only: grd_chksum2,grd_chksum3 @@ -1278,6 +1278,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) call send_bergs_to_other_pes(bergs) + call update_halo(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 66c1bd1..afad18a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -54,6 +54,7 @@ module ice_bergs_framework !Public subs public ice_bergs_framework_init public send_bergs_to_other_pes +public update_halo public pack_berg_into_buffer2, unpack_berg_from_buffer2 public pack_traj_into_buffer2, unpack_traj_from_buffer2 public increase_buffer, increase_ibuffer, increase_ibuffer_traj, increase_buffer_traj @@ -756,6 +757,248 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists end subroutine move_berg_between_cells + +! ############################################################################# + +subroutine update_halo(bergs) +! Arguments +type(icebergs), pointer :: bergs +! Local variables +type(iceberg), pointer :: kick_the_bucket, this +integer :: nbergs_to_send_e, nbergs_to_send_w +integer :: nbergs_to_send_n, nbergs_to_send_s +integer :: nbergs_rcvd_from_e, nbergs_rcvd_from_w +integer :: nbergs_rcvd_from_n, nbergs_rcvd_from_s +type(icebergs_gridded), pointer :: grd +integer :: i, nbergs_start, nbergs_end +integer :: stderrunit +integer :: grdi, grdj +integer :: halo_width + + halo_width=2 ! Must be less than current halo value used for updating weight. + +! Step 1: Clear the current halos + do grdj = grd%jsd,grd%jsc-1 ; do grdi = grd%isd,grd%ied + call delete_all_bergs_in_list(bergs, grdj, grdi) + enddo ; enddo + + do grdj = grd%jec+1,grd%jed ; do grdi = grd%isd,grd%ied + call delete_all_bergs_in_list(bergs,grdj,grdi) + enddo ; enddo + + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%isc-1 + call delete_all_bergs_in_list(bergs,grdj,grdi) + enddo ; enddo + + do grdj = grd%jsd,grd%jed ; do grdi = grd%iec+1,grd%ied + call delete_all_bergs_in_list(bergs,grdj,grdi) + enddo ; enddo + + +! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes + + ! Get the stderr unit number + stderrunit = stderr() + + ! For convenience + grd=>bergs%grd + + if (debug) then + nbergs_start=count_bergs(bergs) + endif + + ! Find number of bergs that headed east/west + nbergs_to_send_e=0 + nbergs_to_send_w=0 + + !Bergs on eastern side of the processor + do grdj = grd%jsc,grd%jec ; do grdi = grd%iec+1,grd%iec+halo_width + this=>bergs%list(grdi,grdj)%first + kick_the_bucket=>this + this=>this%next + nbergs_to_send_e=nbergs_to_send_e+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + enddo; enddo + + !Bergs on the western side of the processor + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc-halo_width,grd%isc-1 + kick_the_bucket=>this + this=>this%next + nbergs_to_send_w=nbergs_to_send_w+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + enddo; enddo + + + + ! Send bergs east + if (grd%pe_E.ne.NULL_PE) then + call mpp_send(nbergs_to_send_e, plen=1, to_pe=grd%pe_E, tag=COMM_TAG_1) + if (nbergs_to_send_e.gt.0) then + call mpp_send(bergs%obuffer_e%data, nbergs_to_send_e*buffer_width, grd%pe_E, tag=COMM_TAG_2) + endif + endif + + ! Send bergs west + if (grd%pe_W.ne.NULL_PE) then + call mpp_send(nbergs_to_send_w, plen=1, to_pe=grd%pe_W, tag=COMM_TAG_3) + if (nbergs_to_send_w.gt.0) then + call mpp_send(bergs%obuffer_w%data, nbergs_to_send_w*buffer_width, grd%pe_W, tag=COMM_TAG_4) + endif + endif + + ! Receive bergs from west + if (grd%pe_W.ne.NULL_PE) then + nbergs_rcvd_from_w=-999 + call mpp_recv(nbergs_rcvd_from_w, glen=1, from_pe=grd%pe_W, tag=COMM_TAG_1) + if (nbergs_rcvd_from_w.lt.0) then + write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_w,' from',grd%pe_W,' (W) !!!!!!!!!!!!!!!!!!!!!!' + endif + if (nbergs_rcvd_from_w.gt.0) then + call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) + call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) + do i=1, nbergs_rcvd_from_w + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd) + enddo + endif + else + nbergs_rcvd_from_w=0 + endif + + ! Receive bergs from east + if (grd%pe_E.ne.NULL_PE) then + nbergs_rcvd_from_e=-999 + call mpp_recv(nbergs_rcvd_from_e, glen=1, from_pe=grd%pe_E, tag=COMM_TAG_3) + if (nbergs_rcvd_from_e.lt.0) then + write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_e,' from',grd%pe_E,' (E) !!!!!!!!!!!!!!!!!!!!!!' + endif + if (nbergs_rcvd_from_e.gt.0) then + call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) + call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) + do i=1, nbergs_rcvd_from_e + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd) + enddo + endif + else + nbergs_rcvd_from_e=0 + endif + + + + ! Find number of bergs that headed north/south + nbergs_to_send_n=0 + nbergs_to_send_s=0 + + + !Bergs on north side of the processor + do grdj = grd%jec-halo_width,grd%jec-1 ; do grdi = grd%isd,grd%ied + kick_the_bucket=>this + this=>this%next + nbergs_to_send_n=nbergs_to_send_n+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + enddo; enddo + + + !Bergs on south side of the processor + do grdj = grd%jsc+1,grd%jsc+halo_width ; do grdi = grd%isd,grd%ied + kick_the_bucket=>this + this=>this%next + nbergs_to_send_s=nbergs_to_send_s+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + enddo; enddo + + + ! Send bergs north + if (grd%pe_N.ne.NULL_PE) then + if(folded_north_on_pe) then + call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_9) + else + call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_5) + endif + if (nbergs_to_send_n.gt.0) then + if(folded_north_on_pe) then + call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) + else + call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_6) + endif + endif + endif + + ! Send bergs south + if (grd%pe_S.ne.NULL_PE) then + call mpp_send(nbergs_to_send_s, plen=1, to_pe=grd%pe_S, tag=COMM_TAG_7) + if (nbergs_to_send_s.gt.0) then + call mpp_send(bergs%obuffer_s%data, nbergs_to_send_s*buffer_width, grd%pe_S, tag=COMM_TAG_8) + endif + endif + + + ! Receive bergs from south + if (grd%pe_S.ne.NULL_PE) then + nbergs_rcvd_from_s=-999 + call mpp_recv(nbergs_rcvd_from_s, glen=1, from_pe=grd%pe_S, tag=COMM_TAG_5) + if (nbergs_rcvd_from_s.lt.0) then + write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_s,' from',grd%pe_S,' (S) !!!!!!!!!!!!!!!!!!!!!!' + endif + if (nbergs_rcvd_from_s.gt.0) then + call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) + call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) + do i=1, nbergs_rcvd_from_s + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd) + enddo + endif + else + nbergs_rcvd_from_s=0 + endif + + ! Receive bergs from north + if (grd%pe_N.ne.NULL_PE) then + nbergs_rcvd_from_n=-999 + if(folded_north_on_pe) then + call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_9) + else + call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_7) + endif + if (nbergs_rcvd_from_n.lt.0) then + write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_n,' from',grd%pe_N,' (N) !!!!!!!!!!!!!!!!!!!!!!' + endif + if (nbergs_rcvd_from_n.gt.0) then + call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n) + if(folded_north_on_pe) then + call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) + else + call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) + endif + do i=1, nbergs_rcvd_from_n + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd) + enddo + endif + else + nbergs_rcvd_from_n=0 + endif + + + + call mpp_sync_self() + + +contains + subroutine delete_all_bergs_in_list(bergs,grdj,grdi) + type(icebergs), pointer :: bergs + ! Local variables + type(iceberg), pointer :: kick_the_bucket, this + integer :: grdi, grdj + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + kick_the_bucket=>this + this=>this%next + call destroy_iceberg(kick_the_bucket) +! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + enddo + end subroutine delete_all_bergs_in_list + +end subroutine update_halo + + ! ############################################################################# subroutine send_bergs_to_other_pes(bergs) From df8a3568dd4bfca38465a71314fb2de550238859 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 17 Sep 2015 15:57:13 -0400 Subject: [PATCH 055/361] Fixed a few bugs in the subroutine halo_update. These bugs were causing segmentation faults. With these changes, the model is able to run for one day, and it returns the same answers as dev/master. It seems that the halos are now updating correctly. I am going to run a longer test so that the icebergs will have time to move between processors. --- icebergs_framework.F90 | 75 +++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index afad18a..d8af313 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -774,10 +774,21 @@ subroutine update_halo(bergs) integer :: stderrunit integer :: grdi, grdj integer :: halo_width +integer :: temp1, temp2 + +halo_width=2 ! Must be less than current halo value used for updating weight. + + ! Get the stderr unit number + stderrunit = stderr() + + ! For convenience + grd=>bergs%grd + - halo_width=2 ! Must be less than current halo value used for updating weight. ! Step 1: Clear the current halos + + do grdj = grd%jsd,grd%jsc-1 ; do grdi = grd%isd,grd%ied call delete_all_bergs_in_list(bergs, grdj, grdi) enddo ; enddo @@ -797,11 +808,9 @@ subroutine update_halo(bergs) ! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes - ! Get the stderr unit number - stderrunit = stderr() - - ! For convenience - grd=>bergs%grd +! ! Get the stderr unit number +! stderrunit = stderr() +! if (debug) then nbergs_start=count_bergs(bergs) @@ -814,18 +823,22 @@ subroutine update_halo(bergs) !Bergs on eastern side of the processor do grdj = grd%jsc,grd%jec ; do grdi = grd%iec+1,grd%iec+halo_width this=>bergs%list(grdi,grdj)%first - kick_the_bucket=>this - this=>this%next - nbergs_to_send_e=nbergs_to_send_e+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + do while (associated(this)) + kick_the_bucket=>this + this=>this%next + nbergs_to_send_e=nbergs_to_send_e+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + enddo enddo; enddo !Bergs on the western side of the processor do grdj = grd%jsc,grd%jec ; do grdi = grd%isc-halo_width,grd%isc-1 - kick_the_bucket=>this - this=>this%next - nbergs_to_send_w=nbergs_to_send_w+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + do while (associated(this)) + kick_the_bucket=>this + this=>this%next + nbergs_to_send_w=nbergs_to_send_w+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + enddo enddo; enddo @@ -891,20 +904,24 @@ subroutine update_halo(bergs) !Bergs on north side of the processor do grdj = grd%jec-halo_width,grd%jec-1 ; do grdi = grd%isd,grd%ied - kick_the_bucket=>this - this=>this%next - nbergs_to_send_n=nbergs_to_send_n+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + do while (associated(this)) + kick_the_bucket=>this + this=>this%next + nbergs_to_send_n=nbergs_to_send_n+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + enddo enddo; enddo !Bergs on south side of the processor do grdj = grd%jsc+1,grd%jsc+halo_width ; do grdi = grd%isd,grd%ied - kick_the_bucket=>this - this=>this%next - nbergs_to_send_s=nbergs_to_send_s+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) - enddo; enddo + do while (associated(this)) + kick_the_bucket=>this + this=>this%next + nbergs_to_send_s=nbergs_to_send_s+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + enddo + enddo; enddo ! Send bergs north @@ -981,8 +998,13 @@ subroutine update_halo(bergs) call mpp_sync_self() -contains - subroutine delete_all_bergs_in_list(bergs,grdj,grdi) +end subroutine update_halo + + + + +!contains +subroutine delete_all_bergs_in_list(bergs,grdj,grdi) type(icebergs), pointer :: bergs ! Local variables type(iceberg), pointer :: kick_the_bucket, this @@ -994,9 +1016,8 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) call destroy_iceberg(kick_the_bucket) ! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) enddo - end subroutine delete_all_bergs_in_list +end subroutine delete_all_bergs_in_list -end subroutine update_halo ! ############################################################################# From 08a5867919f87000789ecac09d25e2b7e1008275 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 17 Sep 2015 16:55:31 -0400 Subject: [PATCH 056/361] Added iceberg_halo to the namelist with a default =2. It is required that iceberg_halo < halo --- icebergs_framework.F90 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d8af313..c4df69b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -72,6 +72,7 @@ module ice_bergs_framework type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain integer :: halo ! Nominal halo width + integer :: iceberg_halo ! halo width used by icebergs (must be lt halo) integer :: isc, iec, jsc, jec ! Indices of computational domain integer :: isd, ied, jsd, jed ! Indices of data domain integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE identifiers @@ -269,6 +270,7 @@ subroutine ice_bergs_framework_init(bergs, & ! Namelist parameters (and defaults) integer :: halo=4 ! Width of halo region +integer :: iceberg_halo=2 ! Width of halo region for icebergs (must be lt halo) integer :: traj_sample_hrs=24 ! Period between sampling of position for trajectory storage integer :: traj_write_hrs=480 ! Period between writing sampled trajectories to disk integer :: verbose_hrs=24 ! Period between verbose messages @@ -295,7 +297,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, traj_write_hrs, & +namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & @@ -537,6 +539,10 @@ subroutine ice_bergs_framework_init(bergs, & enddo endif +if (iceberg_halo .gt. halo) then + iceberg_halo=halo +endif + ! Parameters bergs%dt=dt @@ -544,6 +550,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%traj_write_hrs=traj_write_hrs bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo + bergs%grd%iceberg_halo=iceberg_halo bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef bergs%radial_damping_coef=radial_damping_coef @@ -776,7 +783,7 @@ subroutine update_halo(bergs) integer :: halo_width integer :: temp1, temp2 -halo_width=2 ! Must be less than current halo value used for updating weight. +halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. ! Get the stderr unit number stderrunit = stderr() From 2975d34f4b71fba40708ad64ce2843e3b0942542 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 18 Sep 2015 09:11:17 -0400 Subject: [PATCH 057/361] Added an if statement that only allows you to use interactive forces when you are using Verlet time stepping. Interactive forces is now working, it seems --- icebergs.F90 | 2 -- icebergs_framework.F90 | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5afee1d..92a26c5 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -167,7 +167,6 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 other_berg=>bergs%list(grdi,grdj)%first - !Note: This summing should be made order invarient. do while (associated(other_berg)) ! loop over all other bergs L2=other_berg%length @@ -343,7 +342,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a use_new_predictive_corrective=.True. endif - !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon v_star=vvel0+(ayn*(dt/2.)) !Alon diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index c4df69b..9c6ab83 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -543,6 +543,9 @@ subroutine ice_bergs_framework_init(bergs, & iceberg_halo=halo endif +if (Runge_not_Verlet) then + interactive_icebergs_on=.false. ! Iceberg interactions only with Verlet +endif ! Parameters bergs%dt=dt From 26517ea4b1cba54dc00d209c505bb1e69a1169af Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 18 Sep 2015 11:12:21 -0400 Subject: [PATCH 058/361] Fixed a bug in the loops inside halo_update_icebergs Changed the name of halo_update to halo_update_icebergs --- icebergs.F90 | 4 ++-- icebergs_framework.F90 | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 92a26c5..427d529 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -30,7 +30,7 @@ module ice_bergs use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list use ice_bergs_framework, only: send_bergs_to_other_pes,move_trajectory,move_all_trajectories -use ice_bergs_framework, only: move_berg_between_cells, update_halo +use ice_bergs_framework, only: move_berg_between_cells, update_halo_icebergs use ice_bergs_framework, only: record_posn,check_position,print_berg,print_bergs,print_fld use ice_bergs_framework, only: add_new_berg_to_list,delete_iceberg_from_list,destroy_iceberg use ice_bergs_framework, only: grd_chksum2,grd_chksum3 @@ -1276,7 +1276,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) call send_bergs_to_other_pes(bergs) - call update_halo(bergs) + call update_halo_icebergs(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 9c6ab83..232f454 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -54,7 +54,7 @@ module ice_bergs_framework !Public subs public ice_bergs_framework_init public send_bergs_to_other_pes -public update_halo +public update_halo_icebergs public pack_berg_into_buffer2, unpack_berg_from_buffer2 public pack_traj_into_buffer2, unpack_traj_from_buffer2 public increase_buffer, increase_ibuffer, increase_ibuffer_traj, increase_buffer_traj @@ -770,7 +770,7 @@ end subroutine move_berg_between_cells ! ############################################################################# -subroutine update_halo(bergs) +subroutine update_halo_icebergs(bergs) ! Arguments type(icebergs), pointer :: bergs ! Local variables @@ -831,7 +831,7 @@ subroutine update_halo(bergs) nbergs_to_send_w=0 !Bergs on eastern side of the processor - do grdj = grd%jsc,grd%jec ; do grdi = grd%iec+1,grd%iec+halo_width + do grdj = grd%jsc,grd%jec ; do grdi = grd%iec-halo_width+1,grd%iec this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this @@ -842,7 +842,7 @@ subroutine update_halo(bergs) enddo; enddo !Bergs on the western side of the processor - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc-halo_width,grd%isc-1 + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%isc+halo_width-1 do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -913,7 +913,7 @@ subroutine update_halo(bergs) !Bergs on north side of the processor - do grdj = grd%jec-halo_width,grd%jec-1 ; do grdi = grd%isd,grd%ied + do grdj = grd%jec-halo_width+1,grd%jec ; do grdi = grd%isd,grd%ied do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -924,7 +924,7 @@ subroutine update_halo(bergs) !Bergs on south side of the processor - do grdj = grd%jsc+1,grd%jsc+halo_width ; do grdi = grd%isd,grd%ied + do grdj = grd%jsc,grd%jsc+halo_width-1 ; do grdi = grd%isd,grd%ied do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -1008,7 +1008,7 @@ subroutine update_halo(bergs) call mpp_sync_self() -end subroutine update_halo +end subroutine update_halo_icebergs From 76b48fe7ddf3d23318fe86622bc65b72496d197d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 18 Sep 2015 17:07:10 -0400 Subject: [PATCH 059/361] Adding iceberg_counter for each cell called iceberg_counter_grd. This counts the amount of icebergs created by each cell. This has been added to the write restart. I tried to add it to read restart, but it is not working yet. (And now its time for the weekend) --- icebergs.F90 | 4 +++- icebergs_framework.F90 | 21 ++++++++++++++------- icebergs_io.F90 | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d8326b9..84b987c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -582,7 +582,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a write(stderrunit,200) mpp_pe(),'Starting pars:', & 'yr0=',berg%start_year, 'day0=',berg%start_day, & 'lon0=',berg%start_lon, 'lat0=',berg%start_lat, 'mass0=',berg%start_mass, & - 'sclng=',berg%mass_scaling + 'sclng=',berg%mass_scaling, 'num0=',berg%iceberg_num write(stderrunit,100) mpp_pe(),'Geometry:', & 'M=',M, 'T=',T, 'D=',D, 'F=',F, 'W=',W, 'L=',L write(stderrunit,100) mpp_pe(),'delta U:', & @@ -1770,6 +1770,7 @@ subroutine calve_icebergs(bergs) newberg%start_lon=newberg%lon newberg%start_lat=newberg%lat newberg%start_year=bergs%current_year + newberg%iceberg_num=bergs%current_year !!!! ALon: MP: Change this!! newberg%start_day=bergs%current_yearday+ddt/86400. newberg%start_mass=bergs%initial_mass(k) newberg%mass_scaling=bergs%mass_scaling(k) @@ -1789,6 +1790,7 @@ subroutine calve_icebergs(bergs) icnt=icnt+1 bergs%nbergs_calved=bergs%nbergs_calved+1 bergs%nbergs_calved_by_class(k)=bergs%nbergs_calved_by_class(k)+1 + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 enddo icntmax=max(icntmax,icnt) enddo diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 30066d1..1ceb47d 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,7 +15,7 @@ module ice_bergs_framework implicit none ; private -integer, parameter :: buffer_width=28 !Changed from 20 to 28 by Alon +integer, parameter :: buffer_width=29 !Changed from 20 to 29 by Alon integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes @@ -115,6 +115,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: iceberg_heat_content=>null() ! Distributed heat content of bergs (J/m^2) real, dimension(:,:), pointer :: parity_x=>null() ! X component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) real, dimension(:,:), pointer :: parity_y=>null() ! Y component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) + integer, dimension(:,:), pointer :: iceberg_counter_grd=>null() ! Counts icebergs created for naming purposes ! Diagnostics handles integer :: id_uo=-1, id_vo=-1, id_calving=-1, id_stored_ice=-1, id_accum=-1, id_unused=-1, id_floating_melt=-1 integer :: id_melt_buoy=-1, id_melt_eros=-1, id_melt_conv=-1, id_virtual_area=-1, id_real_calving=-1 @@ -133,7 +134,7 @@ module ice_bergs_framework real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi real :: mass_of_bits, heat_density - integer :: year + integer :: year, iceberg_num type(xyt), pointer :: next=>null() end type xyt @@ -145,6 +146,7 @@ module ice_bergs_framework real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density integer :: start_year + integer :: iceberg_num integer :: ine, jne ! nearest index in NE direction (for convenience) real :: xi, yj ! Non-dimensional coords within current cell (0..1) ! Environment variables (as seen by the iceberg) @@ -419,6 +421,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( bergs%nbergs_calved_by_class(nclasses) ); bergs%nbergs_calved_by_class(:)=0 allocate( grd%parity_x(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%parity_x(:,:)=1. allocate( grd%parity_y(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%parity_y(:,:)=1. + allocate( grd%iceberg_counter_grd(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%iceberg_counter_grd(:,:)=0 !write(stderrunit,*) 'diamonds: copying grid' ! Copy data declared on ice model computational domain @@ -983,6 +986,7 @@ subroutine pack_berg_into_buffer2(berg, buff, n) buff%data(26,n)=berg%vvel_old !Alon buff%data(27,n)=berg%lon_old !Alon buff%data(28,n)=berg%lat_old !Alon + buff%data(29,n)=float(berg%iceberg_num) end subroutine pack_berg_into_buffer2 @@ -1066,6 +1070,7 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) localberg%vvel_old=buff%data(26,n) !Alon localberg%lon_old=buff%data(27,n) !Alon localberg%lat_old=buff%data(28,n) !Alon + localberg%iceberg_num=nint(buff%data(29,n)) lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then @@ -1440,7 +1445,7 @@ end subroutine insert_berg_into_list ! ############################################################################## -logical function inorder(berg1, berg2) +logical function inorder(berg1, berg2) !MP Alon - Change to include iceberg_num ! Arguments type(iceberg), pointer :: berg1, berg2 ! Local variables @@ -1484,7 +1489,7 @@ end function inorder ! ############################################################################## - real function time_hash(berg) + real function time_hash(berg)! Alon: Think about removing this. ! Arguments type(iceberg), pointer :: berg time_hash=berg%start_day+366.*float(berg%start_year) @@ -1500,7 +1505,7 @@ end function pos_hash ! ############################################################################## -logical function sameid(berg1, berg2) +logical function sameid(berg1, berg2) ! Alon: MP updat this. ! Arguments type(iceberg), pointer :: berg1, berg2 ! Local variables @@ -1616,7 +1621,7 @@ subroutine print_berg(iochan, berg, label) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") start lon,lat,yr,day,mass=",2f10.4,i5,f7.2,es12.4)') & label, mpp_pe(), berg%start_lon, berg%start_lat, & - berg%start_year, berg%start_day, berg%start_mass + berg%start_year, berg%iceberg_num, berg%start_day, berg%start_mass write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & label, mpp_pe(), ') i,j=',berg%ine, berg%jne, & ' xi,yj=', berg%xi, berg%yj, & @@ -1779,6 +1784,7 @@ subroutine move_trajectory(bergs, berg) vals%lon=berg%start_lon vals%lat=berg%start_lat vals%year=berg%start_year + vals%iceberg_num=berg%iceberg_num vals%day=berg%start_day vals%mass=berg%start_mass call push_posn(berg%trajectory, vals) @@ -2871,9 +2877,10 @@ integer function berg_chksum(berg ) itmp(37)=berg%start_year !Changed from 29 to 37 by Alon itmp(38)=berg%ine !Changed from 30 to 38 by Alon itmp(39)=berg%jne !Changed from 31 to 39 by Alon + itmp(40)=berg%iceberg_num !added by Alon ichk1=0; ichk2=0; ichk3=0 - do i=1,36+3 !Changd from 28 to 36 by Alon + do i=1,37+3 !Changd from 28 to 37 by Alon ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 5017f67..2e93e75 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -99,7 +99,7 @@ subroutine write_restart(bergs) ! Arguments type(icebergs), pointer :: bergs ! Local variables -integer :: i,id +integer :: i,j,id character(len=35) :: filename type(iceberg), pointer :: this=>NULL() integer :: stderrunit @@ -134,7 +134,10 @@ subroutine write_restart(bergs) integer, allocatable, dimension(:) :: ine, & jne, & + iceberg_num, & start_year + + !uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. ! Get the stderr unit number @@ -184,6 +187,7 @@ subroutine write_restart(bergs) allocate(ine(nbergs)) allocate(jne(nbergs)) allocate(start_year(nbergs)) + allocate(iceberg_num(nbergs)) call get_instance_filename("icebergs.res.nc", filename) call set_domain(bergs%grd%domain) @@ -219,6 +223,8 @@ subroutine write_restart(bergs) longname='latitude of calving location',units='degrees_N') id = register_restart_field(bergs_restart,filename,'start_year',start_year, & longname='calendar year of calving event', units='years') + id = register_restart_field(bergs_restart,filename,'iceberg_num',iceberg_num, & + longname='identification of the iceberg', units='years') id = register_restart_field(bergs_restart,filename,'start_day',start_day, & longname='year day of calving event',units='days') id = register_restart_field(bergs_restart,filename,'start_mass',start_mass, & @@ -245,11 +251,13 @@ subroutine write_restart(bergs) width(i) = this%width; length(i) = this%length start_lon(i) = this%start_lon; start_lat(i) = this%start_lat start_year(i) = this%start_year; start_day(i) = this%start_day + iceberg_num(i) = this%iceberg_num; start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density this=>this%next enddo - + + call save_restart(bergs_restart) call free_restart_type(bergs_restart) @@ -282,8 +290,10 @@ subroutine write_restart(bergs) deallocate( & ine, & jne, & + iceberg_num, & start_year ) + call nullify_domain() ! Write stored ice @@ -294,7 +304,8 @@ subroutine write_restart(bergs) call write_data(filename, 'stored_ice', bergs%grd%stored_ice, bergs%grd%domain) call grd_chksum2(bergs%grd, bergs%grd%stored_heat, 'write stored_heat') call write_data(filename, 'stored_heat', bergs%grd%stored_heat, bergs%grd%domain) - + !call grd_chksum2(bergs%grd, bergs%grd%iceberg_counter_grd, 'write iceberg_counter_grd') + call write_data(filename, 'iceberg_counter_grd', bergs%grd%iceberg_counter_grd, bergs%grd%domain) contains function last_berg(berg) @@ -323,7 +334,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer :: lonid, latid, uvelid, vvelid, ineid, jneid integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid, lon_oldid, lat_oldid !Added by Alon integer :: massid, thicknessid, widthid, lengthid -integer :: start_lonid, start_latid, start_yearid, start_dayid, start_massid +integer :: start_lonid, start_latid, start_yearid, iceberg_numid, start_dayid, start_massid integer :: scaling_id, mass_of_bits_id, heat_density_id logical :: lres, found_restart, multiPErestart real :: lon0, lon1, lat0, lat1 @@ -398,6 +409,7 @@ subroutine read_restart_bergs_orig(bergs,Time) start_lonid=inq_var(ncid, 'start_lon') start_latid=inq_var(ncid, 'start_lat') start_yearid=inq_var(ncid, 'start_year') + iceberg_numid=inq_var(ncid, 'icberg_num') start_dayid=inq_var(ncid, 'start_day') start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') @@ -455,6 +467,7 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_lon=get_double(ncid, start_lonid, k) localberg%start_lat=get_double(ncid, start_latid, k) localberg%start_year=get_int(ncid, start_yearid, k) + localberg%iceberg_num=get_int(ncid, iceberg_numid, k) localberg%start_day=get_double(ncid, start_dayid, k) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) @@ -541,6 +554,7 @@ subroutine generate_bergs(bergs,Time) localberg%start_lon=localberg%lon localberg%start_lat=localberg%lat localberg%start_year=iyr + localberg%iceberg_num=iyr !MP1!!!!Insert complex formulae here! Alon localberg%start_day=float(iday)+(float(ihr)+float(imin)/60.)/24. localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) @@ -636,8 +650,11 @@ subroutine read_restart_bergs(bergs,Time) !axn, ayn, uvel_old, vvel_old, lon_old, lat_old, bxn, byn added by Alon integer, allocatable, dimension(:) :: ine, & jne, & + iceberg_num, & start_year +!integer, allocatable, dimension(:,:) :: iceberg_counter_gre + ! Get the stderr unit number stderrunit=stderr() @@ -684,6 +701,7 @@ subroutine read_restart_bergs(bergs,Time) allocate(ine(nbergs_in_file)) allocate(jne(nbergs_in_file)) allocate(start_year(nbergs_in_file)) + allocate(iceberg_num(nbergs_in_file)) call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) @@ -712,6 +730,7 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) + call read_unlimited_axis(filename,'iceberg_num',iceberg_num,domain=grd%domain) ! Find approx outer bounds for tile lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) @@ -760,6 +779,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_lon=start_lon(k) localberg%start_lat=start_lat(k) localberg%start_year=start_year(k) + localberg%iceberg_num=iceberg_num(k) localberg%start_day=start_day(k) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) @@ -802,6 +822,7 @@ subroutine read_restart_bergs(bergs,Time) deallocate( & ine, & jne, & + iceberg_num, & start_year ) elseif(.not. found_restart .and. bergs%nbergs_start==0 .and. generate_test_icebergs) then call generate_bergs(bergs,Time) @@ -848,6 +869,7 @@ subroutine generate_bergs(bergs,Time) localberg%start_lon=localberg%lon localberg%start_lat=localberg%lat localberg%start_year=iyr + localberg%iceberg_num=iyr !Alon: MP2: insert complex formulae here!! localberg%start_day=float(iday)+(float(ihr)+float(imin)/60.)/24. localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) @@ -926,10 +948,15 @@ subroutine read_restart_calving(bergs) if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: reading stored_heat from restart file.' call read_data(filename, 'stored_heat', grd%stored_heat, grd%domain) + if (field_exist(filename, 'iceberg_counting_grd')) then + print *, 'field exitst!!!' + !call read_data(filename, 'iceberg_counting_grd', grd%iceberg_counting_grd, grd%domain) ! - why does this not work??? + endif else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: stored_heat WAS NOT FOUND in the file. Setting to 0.' grd%stored_heat(:,:)=0. + grd%iceberg_counter_grd(:,:)=0 endif bergs%restarted=.true. else From 7d000ed2bbaf7b96c35ccd95ee3534a03d3ac17d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 21 Sep 2015 11:47:55 -0400 Subject: [PATCH 060/361] Added a unique numbering for each iceberg. This number is called iceberg_num and is saved in the restart file, picksup from the restart file. The iceberg counter is now working and is saved as a gridded variable which saves to the restart file, and picksup from the restart. The iceberg num is not yet saved in the iceberg trajectory file. --- icebergs.F90 | 9 +++++++-- icebergs_framework.F90 | 10 +++++++++- icebergs_io.F90 | 38 +++++++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 84b987c..14f076a 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -97,6 +97,7 @@ subroutine icebergs_init(bergs, & call mpp_clock_begin(bergs%clock_ior) call ice_bergs_io_init(bergs,io_layout) + call read_restart_calving(bergs) !This is moved to before restart_bergs (by Alon) so that generate icebergs can have the correct counter if(orig_read) then call read_restart_bergs_orig(bergs,Time) else @@ -104,7 +105,7 @@ subroutine icebergs_init(bergs, & endif call bergs_chksum(bergs, 'read_restart bergs') if (fix_restart_dates) call offset_berg_dates(bergs,Time) - call read_restart_calving(bergs) + !call read_restart_calving(bergs) call mpp_clock_end(bergs%clock_ior) if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') @@ -1720,6 +1721,7 @@ subroutine calve_icebergs(bergs) ! Local variables type(icebergs_gridded), pointer :: grd integer :: i,j,k,icnt,icntmax +integer :: iNg, jNg !Total number of points gloablly in i and j direction type(iceberg) :: newberg logical :: lret real :: xi, yj, ddt, calving_to_bergs, calved_to_berg, heat_to_bergs, heat_to_berg @@ -1731,6 +1733,9 @@ subroutine calve_icebergs(bergs) ! For convenience grd=>bergs%grd + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction + grd%real_calving(:,:,:)=0. calving_to_bergs=0. heat_to_bergs=0. @@ -1770,7 +1775,7 @@ subroutine calve_icebergs(bergs) newberg%start_lon=newberg%lon newberg%start_lat=newberg%lat newberg%start_year=bergs%current_year - newberg%iceberg_num=bergs%current_year !!!! ALon: MP: Change this!! + newberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg newberg%start_day=bergs%current_yearday+ddt/86400. newberg%start_mass=bergs%initial_mass(k) newberg%mass_scaling=bergs%mass_scaling(k) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 1ceb47d..fafa43d 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -72,6 +72,7 @@ module ice_bergs_framework integer :: halo ! Nominal halo width integer :: isc, iec, jsc, jec ! Indices of computational domain integer :: isd, ied, jsd, jed ! Indices of data domain + integer :: isg, ieg, jsg, jeg ! Indices of global domain integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE identifiers real, dimension(:,:), pointer :: lon=>null() ! Longitude of cell corners real, dimension(:,:), pointer :: lat=>null() ! Latitude of cell corners @@ -236,7 +237,7 @@ subroutine ice_bergs_framework_init(bergs, & use mpp_parameter_mod, only: SCALAR_PAIR, CGRID_NE, BGRID_NE, CORNER, AGRID use mpp_domains_mod, only: mpp_update_domains, mpp_define_domains -use mpp_domains_mod, only: mpp_get_compute_domain, mpp_get_data_domain +use mpp_domains_mod, only: mpp_get_compute_domain, mpp_get_data_domain, mpp_get_global_domain use mpp_domains_mod, only: CYCLIC_GLOBAL_DOMAIN, FOLD_NORTH_EDGE use mpp_domains_mod, only: mpp_get_neighbor_pe, NORTH, SOUTH, EAST, WEST use mpp_domains_mod, only: mpp_define_io_domain @@ -362,12 +363,14 @@ subroutine ice_bergs_framework_init(bergs, & !write(stderrunit,*) 'diamond: get compute domain' call mpp_get_compute_domain( grd%domain, grd%isc, grd%iec, grd%jsc, grd%jec ) call mpp_get_data_domain( grd%domain, grd%isd, grd%ied, grd%jsd, grd%jed ) + call mpp_get_global_domain( grd%domain, grd%isg, grd%ieg, grd%jsg, grd%jeg ) call mpp_get_neighbor_pe(grd%domain, NORTH, grd%pe_N) call mpp_get_neighbor_pe(grd%domain, SOUTH, grd%pe_S) call mpp_get_neighbor_pe(grd%domain, EAST, grd%pe_E) call mpp_get_neighbor_pe(grd%domain, WEST, grd%pe_W) + folded_north_on_pe = ((dom_y_flags == FOLD_NORTH_EDGE) .and. (grd%jec == gnj)) !write(stderrunit,'(a,6i4)') 'diamonds, icebergs_init: pe,n,s,e,w =',mpp_pe(),grd%pe_N,grd%pe_S,grd%pe_E,grd%pe_W, NULL_PE @@ -663,6 +666,10 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_clock_end(bergs%clock_ini) call mpp_clock_end(bergs%clock) +!print *, mpp_pe(), 'Alon: global', grd%isg, grd%ieg, grd%jsg, grd%jeg +!print *, mpp_pe(), 'Alon: comp', grd%isc, grd%iec, grd%jsc, grd%jec +!print *, mpp_pe(), 'Alon: data', grd%isd, grd%ied, grd%jsd, grd%jed + end subroutine ice_bergs_framework_init ! ############################################################################## @@ -1578,6 +1585,7 @@ subroutine create_iceberg(berg, bergvals) end subroutine create_iceberg + ! ############################################################################## subroutine delete_iceberg_from_list(first, berg) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 2e93e75..53df911 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -529,11 +529,14 @@ subroutine generate_bergs(bergs,Time) type(time_type), intent(in) :: Time ! Local variables integer :: i,j + integer :: iNg, jNg !Total number of points gloablly in i and j direction type(iceberg) :: localberg ! NOT a pointer but an actual local variable integer :: iyr, imon, iday, ihr, imin, isec ! For convenience grd=>bergs%grd + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction call get_date(Time, iyr, imon, iday, ihr, imin, isec) @@ -554,7 +557,6 @@ subroutine generate_bergs(bergs,Time) localberg%start_lon=localberg%lon localberg%start_lat=localberg%lat localberg%start_year=iyr - localberg%iceberg_num=iyr !MP1!!!!Insert complex formulae here! Alon localberg%start_day=float(iday)+(float(ihr)+float(imin)/60.)/24. localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) @@ -568,6 +570,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=-1. localberg%vvel=0. @@ -577,6 +581,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=1. @@ -586,6 +592,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=-1. @@ -595,6 +603,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) endif enddo; enddo @@ -653,7 +663,7 @@ subroutine read_restart_bergs(bergs,Time) iceberg_num, & start_year -!integer, allocatable, dimension(:,:) :: iceberg_counter_gre +!integer, allocatable, dimension(:,:) :: iceberg_counter_grd ! Get the stderr unit number stderrunit=stderr() @@ -844,11 +854,14 @@ subroutine generate_bergs(bergs,Time) type(time_type), intent(in) :: Time ! Local variables integer :: i,j + integer :: iNg, jNg !Total number of points gloablly in i and j direction type(iceberg) :: localberg ! NOT a pointer but an actual local variable integer :: iyr, imon, iday, ihr, imin, isec ! For convenience grd=>bergs%grd + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction call get_date(Time, iyr, imon, iday, ihr, imin, isec) @@ -869,7 +882,6 @@ subroutine generate_bergs(bergs,Time) localberg%start_lon=localberg%lon localberg%start_lat=localberg%lat localberg%start_year=iyr - localberg%iceberg_num=iyr !Alon: MP2: insert complex formulae here!! localberg%start_day=float(iday)+(float(ihr)+float(imin)/60.)/24. localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) @@ -883,6 +895,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=-1. localberg%vvel=0. @@ -892,6 +906,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=1. @@ -901,6 +917,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) localberg%uvel=0. localberg%vvel=-1. @@ -910,6 +928,8 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) endif enddo; enddo @@ -948,14 +968,18 @@ subroutine read_restart_calving(bergs) if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: reading stored_heat from restart file.' call read_data(filename, 'stored_heat', grd%stored_heat, grd%domain) - if (field_exist(filename, 'iceberg_counting_grd')) then - print *, 'field exitst!!!' - !call read_data(filename, 'iceberg_counting_grd', grd%iceberg_counting_grd, grd%domain) ! - why does this not work??? - endif else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: stored_heat WAS NOT FOUND in the file. Setting to 0.' grd%stored_heat(:,:)=0. + endif + if (field_exist(filename, 'iceberg_counter_grd')) then + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: reading iceberg_counter_grd from restart file.' + call read_data(filename, 'iceberg_counter_grd', grd%iceberg_counter_grd, grd%domain) + else + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: iceberg_counter_grd WAS NOT FOUND in the file. Setting to 0.' grd%iceberg_counter_grd(:,:)=0 endif bergs%restarted=.true. From 8c0eb53ab70257151b06e30db0848f63c8540f74 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 21 Sep 2015 13:49:10 -0400 Subject: [PATCH 061/361] Iceberg_num now outputs into the iceberg_trajectory.nc file --- icebergs_framework.F90 | 6 ++++-- icebergs_io.F90 | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index fafa43d..f62d13f 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -16,7 +16,7 @@ module ice_bergs_framework implicit none ; private integer, parameter :: buffer_width=29 !Changed from 20 to 29 by Alon -integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon +integer, parameter :: buffer_width_traj=32 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -424,7 +424,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( bergs%nbergs_calved_by_class(nclasses) ); bergs%nbergs_calved_by_class(:)=0 allocate( grd%parity_x(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%parity_x(:,:)=1. allocate( grd%parity_y(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%parity_y(:,:)=1. - allocate( grd%iceberg_counter_grd(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%iceberg_counter_grd(:,:)=0 + allocate( grd%iceberg_counter_grd(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%iceberg_counter_grd(:,:)=1 !write(stderrunit,*) 'diamonds: copying grid' ! Copy data declared on ice model computational domain @@ -1248,6 +1248,7 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(29,n)=traj%vvel_old !Alon buff%data(30,n)=traj%lon_old !Alon buff%data(31,n)=traj%lat_old !Alon + buff%data(32,n)=float(traj%iceberg_num) end subroutine pack_traj_into_buffer2 @@ -1293,6 +1294,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%vvel_old=buff%data(29,n) !Alon traj%lon_old=buff%data(30,n) !Alon traj%lat_old=buff%data(31,n) !Alon + traj%iceberg_num=nint(buff%data(32,n)) call append_posn(first, traj) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 53df911..9ad4b85 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -224,7 +224,7 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_restart,filename,'start_year',start_year, & longname='calendar year of calving event', units='years') id = register_restart_field(bergs_restart,filename,'iceberg_num',iceberg_num, & - longname='identification of the iceberg', units='years') + longname='identification of the iceberg', units='dimensionless') id = register_restart_field(bergs_restart,filename,'start_day',start_day, & longname='year day of calving event',units='days') id = register_restart_field(bergs_restart,filename,'start_mass',start_mass, & @@ -1030,7 +1030,7 @@ subroutine write_trajectory(trajectory) type(xyt), pointer :: trajectory ! Local variables integer :: iret, ncid, i_dim, i -integer :: lonid, latid, yearid, dayid, uvelid, vvelid +integer :: lonid, latid, yearid, dayid, uvelid, vvelid, iceberg_numid !integer :: axnid, aynid, uvel_oldid, vvel_oldid, lat_oldid, lon_oldid, bxnid, bynid !Added by Alon integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid integer :: cnid, hiid @@ -1170,6 +1170,7 @@ subroutine write_trajectory(trajectory) sstid = inq_varid(ncid, 'sst') cnid = inq_varid(ncid, 'cn') hiid = inq_varid(ncid, 'hi') + iceberg_numid = inq_varid(ncid, 'iceberg_num') else ! Dimensions iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) @@ -1199,6 +1200,7 @@ subroutine write_trajectory(trajectory) sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) + iceberg_numid = def_var(ncid, 'iceberg_num', NF_INT, i_dim) ! Attributes iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) @@ -1249,6 +1251,8 @@ subroutine write_trajectory(trajectory) call put_att(ncid, cnid, 'units', 'none') call put_att(ncid, hiid, 'long_name', 'sea ice thickness') call put_att(ncid, hiid, 'units', 'm') + call put_att(ncid, iceberg_numid, 'long_name', 'iceberg id number') + call put_att(ncid, iceberg_numid, 'units', 'dimensionless') endif ! End define mode @@ -1286,6 +1290,7 @@ subroutine write_trajectory(trajectory) call put_double(ncid, sstid, i, this%sst) call put_double(ncid, cnid, i, this%cn) call put_double(ncid, hiid, i, this%hi) + call put_int(ncid, iceberg_numid, i, this%iceberg_num) next=>this%next deallocate(this) this=>next From 0c6591e98e5e7d7348a7eb5e4e21e9a0b0c64aac Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 22 Sep 2015 11:44:02 -0400 Subject: [PATCH 062/361] Fixed two bugs in halo_update scheme: 1) Editted the delete_all_icebergs_in_list subroutine, to make it point the first pointer to null. 2)Added a variable called halo_iceberg, which is a flag that says whether an iceberg is a temporary iceberg copied to a halo. This prevents the temporary icebergs begin copied back the orginal processor, which causes icebergs to multiply over and over again. --- icebergs.F90 | 1 + icebergs_framework.F90 | 113 ++++++++++++++++++++++++++--------------- icebergs_io.F90 | 17 ++++++- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 427d529..5867342 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1780,6 +1780,7 @@ subroutine calve_icebergs(bergs) newberg%start_mass=bergs%initial_mass(k) newberg%mass_scaling=bergs%mass_scaling(k) newberg%mass_of_bits=0. + newberg%halo_berg=0. newberg%heat_density=grd%stored_heat(i,j)/grd%stored_ice(i,j,k) ! This is in J/kg call add_new_berg_to_list(bergs%list(i,j)%first, newberg) calved_to_berg=bergs%initial_mass(k)*bergs%mass_scaling(k) ! Units of kg diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 232f454..a09745a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,8 +15,8 @@ module ice_bergs_framework implicit none ; private -integer, parameter :: buffer_width=28 !Changed from 20 to 28 by Alon -integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon +integer, parameter :: buffer_width=29 !Changed from 20 to 29 by Alon +integer, parameter :: buffer_width_traj=32 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -134,7 +134,7 @@ module ice_bergs_framework real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi + real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg real :: mass_of_bits, heat_density integer :: year type(xyt), pointer :: next=>null() @@ -147,6 +147,7 @@ module ice_bergs_framework real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_old, lat_old !Explicit and implicit accelerations !Alon real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density + real :: halo_berg ! Equal to zero for bergs on computational domain, and =1 for bergs on the halo integer :: start_year integer :: ine, jne ! nearest index in NE direction (for convenience) real :: xi, yj ! Non-dimensional coords within current cell (0..1) @@ -785,6 +786,7 @@ subroutine update_halo_icebergs(bergs) integer :: grdi, grdj integer :: halo_width integer :: temp1, temp2 +real :: current_halo_status halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. @@ -837,7 +839,10 @@ subroutine update_halo_icebergs(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_e=nbergs_to_send_e+1 + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -847,7 +852,10 @@ subroutine update_halo_icebergs(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_w=nbergs_to_send_w+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -918,7 +926,10 @@ subroutine update_halo_icebergs(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_n=nbergs_to_send_n+1 + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -929,7 +940,10 @@ subroutine update_halo_icebergs(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_s=nbergs_to_send_s+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -1026,6 +1040,7 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) call destroy_iceberg(kick_the_bucket) ! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) enddo + bergs%list(grdi,grdj)%first=>null() end subroutine delete_all_bergs_in_list @@ -1062,22 +1077,26 @@ subroutine send_bergs_to_other_pes(bergs) do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) - if (this%ine.gt.bergs%grd%iec) then - kick_the_bucket=>this - this=>this%next - nbergs_to_send_e=nbergs_to_send_e+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) - call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) - elseif (this%ine.lt.bergs%grd%isc) then - kick_the_bucket=>this - this=>this%next - nbergs_to_send_w=nbergs_to_send_w+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) - call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + if (this%halo_berg .lt. 0.5) then + if (this%ine.gt.bergs%grd%iec) then + kick_the_bucket=>this + this=>this%next + nbergs_to_send_e=nbergs_to_send_e+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + call move_trajectory(bergs, kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + elseif (this%ine.lt.bergs%grd%isc) then + kick_the_bucket=>this + this=>this%next + nbergs_to_send_w=nbergs_to_send_w+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + call move_trajectory(bergs, kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + else + this=>this%next + endif else - this=>this%next + this=>this%next endif enddo enddo ; enddo @@ -1143,22 +1162,26 @@ subroutine send_bergs_to_other_pes(bergs) do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) - if (this%jne.gt.bergs%grd%jec) then - kick_the_bucket=>this - this=>this%next - nbergs_to_send_n=nbergs_to_send_n+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) - call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) - elseif (this%jne.lt.bergs%grd%jsc) then - kick_the_bucket=>this - this=>this%next - nbergs_to_send_s=nbergs_to_send_s+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) - call move_trajectory(bergs, kick_the_bucket) - call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + if (this%halo_berg .lt. 0.5) then + if (this%jne.gt.bergs%grd%jec) then + kick_the_bucket=>this + this=>this%next + nbergs_to_send_n=nbergs_to_send_n+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + call move_trajectory(bergs, kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + elseif (this%jne.lt.bergs%grd%jsc) then + kick_the_bucket=>this + this=>this%next + nbergs_to_send_s=nbergs_to_send_s+1 + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + call move_trajectory(bergs, kick_the_bucket) + call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + else + this=>this%next + endif else - this=>this%next + this=>this%next endif enddo enddo ; enddo @@ -1314,6 +1337,7 @@ subroutine pack_berg_into_buffer2(berg, buff, n) buff%data(26,n)=berg%vvel_old !Alon buff%data(27,n)=berg%lon_old !Alon buff%data(28,n)=berg%lat_old !Alon + buff%data(29,n)=berg%halo_berg end subroutine pack_berg_into_buffer2 @@ -1389,6 +1413,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd) localberg%vvel_old=buff%data(26,n) !Alon localberg%lon_old=buff%data(27,n) !Alon localberg%lat_old=buff%data(28,n) !Alon + localberg%halo_berg=buff%data(29,n) !Alon lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then @@ -1558,6 +1583,7 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(29,n)=traj%vvel_old !Alon buff%data(30,n)=traj%lon_old !Alon buff%data(31,n)=traj%lat_old !Alon + buff%data(32,n)=traj%halo_berg !Alon end subroutine pack_traj_into_buffer2 @@ -1603,6 +1629,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%vvel_old=buff%data(29,n) !Alon traj%lon_old=buff%data(30,n) !Alon traj%lat_old=buff%data(31,n) !Alon + traj%halo_berg=buff%data(32,n) !Alon call append_posn(first, traj) @@ -2074,6 +2101,7 @@ subroutine record_posn(bergs) posn%vvel_old=this%vvel_old posn%lon_old=this%lon_old posn%lat_old=this%lat_old + posn%halo_berg=this%halo_berg call push_posn(this%trajectory, posn) @@ -3199,8 +3227,8 @@ integer function berg_chksum(berg ) ! Arguments type(iceberg), pointer :: berg ! Local variables -real :: rtmp(36) !Changed from 28 to 34 by Alon -integer :: itmp(36+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon +real :: rtmp(37) !Changed from 28 to 34 by Alon +integer :: itmp(37+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon integer :: i rtmp(:)=0. @@ -3239,14 +3267,15 @@ integer function berg_chksum(berg ) rtmp(34)=berg%vvel_old !Added by Alon rtmp(35)=berg%lat_old !Added by Alon rtmp(36)=berg%lon_old !Added by Alon + itmp(37)=berg%halo_berg !Changed from 31 to 40 by Alon - itmp(1:36)=transfer(rtmp,i8) !Changed from 28 to 36 by Alon - itmp(37)=berg%start_year !Changed from 29 to 37 by Alon - itmp(38)=berg%ine !Changed from 30 to 38 by Alon - itmp(39)=berg%jne !Changed from 31 to 39 by Alon + itmp(1:37)=transfer(rtmp,i8) !Changed from 28 to 37 by Alon + itmp(38)=berg%start_year !Changed from 29 to 38 by Alon + itmp(39)=berg%ine !Changed from 30 to 39 by Alon + itmp(40)=berg%jne !Changed from 31 to 40 by Alon ichk1=0; ichk2=0; ichk3=0 - do i=1,36+3 !Changd from 28 to 36 by Alon + do i=1,37+3 !Changd from 28 to 36 by Alon ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 144af01..d5d4c89 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -129,6 +129,7 @@ subroutine write_restart(bergs) start_mass, & mass_scaling, & mass_of_bits, & + halo_berg, & heat_density integer, allocatable, dimension(:) :: ine, & @@ -177,6 +178,7 @@ subroutine write_restart(bergs) allocate(mass_scaling(nbergs)) allocate(mass_of_bits(nbergs)) allocate(heat_density(nbergs)) + allocate(halo_berg(nbergs)) allocate(ine(nbergs)) allocate(jne(nbergs)) @@ -226,6 +228,8 @@ subroutine write_restart(bergs) longname='mass of bergy bits',units='kg') id = register_restart_field(bergs_restart,filename,'heat_density',heat_density, & longname='heat density',units='J/kg') + id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & + longname='halo_berg',units='dimensionless') ! Write variables @@ -246,6 +250,7 @@ subroutine write_restart(bergs) start_lon(i) = this%start_lon; start_lat(i) = this%start_lat start_year(i) = this%start_year; start_day(i) = this%start_day start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling + halo_berg(i) = this%halo_berg mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density this=>this%next enddo @@ -277,6 +282,7 @@ subroutine write_restart(bergs) start_mass, & mass_scaling, & mass_of_bits, & + halo_berg, & heat_density ) !axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon @@ -325,7 +331,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid, lon_oldid, lat_oldid !Added by Alon integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, start_dayid, start_massid -integer :: scaling_id, mass_of_bits_id, heat_density_id +integer :: scaling_id, mass_of_bits_id, heat_density_id, halo_bergid logical :: lres, found_restart, multiPErestart real :: lon0, lon1, lat0, lat1 character(len=33) :: filename, filename_base @@ -402,6 +408,7 @@ subroutine read_restart_bergs_orig(bergs,Time) start_dayid=inq_var(ncid, 'start_day') start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') + halo_bergid=inq_var(ncid, 'halo_berg') mass_of_bits_id=inq_var(ncid, 'mass_of_bits',unsafe=.true.) heat_density_id=inq_var(ncid, 'heat_density',unsafe=.true.) ineid=inq_var(ncid, 'ine',unsafe=.true.) @@ -459,6 +466,7 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_day=get_double(ncid, start_dayid, k) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) + localberg%halo_berg=get_double(ncid, halo_bergid, k) if (mass_of_bits_id>0) then ! Allow reading of older restart with no bergy bits localberg%mass_of_bits=get_double(ncid, mass_of_bits_id, k) else @@ -546,6 +554,7 @@ subroutine generate_bergs(bergs,Time) localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. + localberg%halo_berg=0. localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. @@ -633,6 +642,7 @@ subroutine read_restart_bergs(bergs,Time) start_mass, & mass_scaling, & mass_of_bits, & + halo_berg, & heat_density !axn, ayn, uvel_old, vvel_old, lon_old, lat_old, bxn, byn added by Alon integer, allocatable, dimension(:) :: ine, & @@ -680,6 +690,7 @@ subroutine read_restart_bergs(bergs,Time) allocate(start_mass(nbergs_in_file)) allocate(mass_scaling(nbergs_in_file)) allocate(mass_of_bits(nbergs_in_file)) + allocate(halo_berg(nbergs_in_file)) allocate(heat_density(nbergs_in_file)) allocate(ine(nbergs_in_file)) @@ -708,6 +719,7 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) + call read_unlimited_axis(filename,'halo_berg',halo_berg,domain=grd%domain) call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) @@ -765,6 +777,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) localberg%mass_of_bits=mass_of_bits(k) + localberg%halo_berg=halo_berg(k) localberg%heat_density=heat_density(k) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) @@ -798,6 +811,7 @@ subroutine read_restart_bergs(bergs,Time) start_mass, & mass_scaling, & mass_of_bits, & + halo_berg, & heat_density ) !axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon. deallocate( & @@ -853,6 +867,7 @@ subroutine generate_bergs(bergs,Time) localberg%start_mass=localberg%mass localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. + localberg%halo_berg=0. localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. From 82b58d9ccfd8ebf012433ca99e356df2204905b1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 22 Sep 2015 11:51:14 -0400 Subject: [PATCH 063/361] I am not sure if the changes I commited in the previous commit, actually got saved. This is a repeat of the previous commit. --- icebergs_framework.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index a09745a..a8eb46e 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1040,7 +1040,6 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) call destroy_iceberg(kick_the_bucket) ! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) enddo - bergs%list(grdi,grdj)%first=>null() end subroutine delete_all_bergs_in_list From cdd81cc98fdc3156fee165f9da16cd96e4f8f5d8 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 22 Sep 2015 11:58:48 -0400 Subject: [PATCH 064/361] I tried to commit this before, but the wrong files got included. Here I repeat this commit: Fixed two bugs in halo_update scheme: 1) Editted the delete_all_icebergs_in_list subroutine, to make it point the first pointer to null. 2)Added a variable called halo_iceberg, which is a flag that says whether an iceberg is a temporary iceberg copied to a halo. This prevents the temporary icebergs begin copied back the orginal processor, which causes icebergs to multiply over and over again. --- icebergs_framework.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index a8eb46e..c76ec82 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1039,6 +1039,7 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) this=>this%next call destroy_iceberg(kick_the_bucket) ! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + bergs%list(grdi,grdj)%first=>null() enddo end subroutine delete_all_bergs_in_list From 720361d5c10b400031b372f70761a6a3bd3a0911 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 23 Sep 2015 17:52:33 -0400 Subject: [PATCH 065/361] Added a new type called bond, which corresponds to bonds between icebergs Created a submodule which initially established bonds between icebergs close to one another (for testing purposes) Created a submodule which checks whether the bonds are health, and can also count the total number of bounds. There are still some bugs, and everyone is not quite working, but it is now time to go home. --- icebergs.F90 | 280 +++++++++++++++++++++++++++++------------ icebergs_framework.F90 | 18 ++- 2 files changed, 219 insertions(+), 79 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2c2fe69..8642781 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -23,7 +23,7 @@ module ice_bergs use diag_manager_mod, only: diag_axis_init use ice_bergs_framework, only: ice_bergs_framework_init -use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer +use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer, bond use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell use ice_bergs_framework, only: nclasses,old_bug_bilin @@ -111,10 +111,155 @@ subroutine icebergs_init(bergs, & if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') + if (bergs%iceberg_bonds_on) call initialize_iceberg_bonds(bergs) + end subroutine icebergs_init +! ############################################################################## + +subroutine initialize_iceberg_bonds(bergs) + +type(icebergs), pointer :: bergs +type(iceberg), pointer :: berg +type(iceberg), pointer :: other_berg +type(icebergs_gridded), pointer :: grd + + + +real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg +real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg +real :: r_dist_x, r_dist_y, r_dist +integer :: grdi_outer, grdj_outer +integer :: grdi_inner, grdj_inner + + ! For convenience + grd=>bergs%grd + !Should update halos before doing this + do grdj_outer = grd%jsc,grd%jec ; do grdi_outer = grd%isc,grd%iec !Should you be on the data domain?? + berg=>bergs%list(grdi_outer,grdj_outer)%first + do while (associated(berg)) ! loop over all bergs + + lon1=berg%lon; lat1=berg%lat + call rotpos_to_tang(lon1,lat1,x1,y1) + + do grdj_inner = berg%jne-1,berg%jne+1 ; do grdi_inner = berg%ine-1,berg%ine+1 !Only looping through adjacent cells. + other_berg=>bergs%list(grdi_inner,grdj_inner)%first + do while (associated(other_berg)) ! loop over all other bergs + + if (berg%iceberg_num .ne. other_berg%iceberg_num) then + lon2=other_berg%lon; lat2=other_berg%lat + call rotpos_to_tang(lon2,lat2,x2,y2) + r_dist_x=x1-x2 ; r_dist_y=y1-y2 + r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + + !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond + call form_a_bond(berg, other_berg) + !endif + other_berg=>other_berg%next + endif + enddo ! End of looping through all other bergs in the inner list + enddo ; enddo; !End of inner loop + berg=>berg%next + enddo ! End of looping through all bergs in the outer list + enddo ; enddo; !End of outer loop. + + call check_if_all_bonds_are_present(bergs) + + + +end subroutine initialize_iceberg_bonds + +! ############################################################################## + +subroutine form_a_bond(berg, other_berg) + +type(iceberg), pointer :: berg +type(iceberg), pointer :: other_berg +type(bond) , pointer :: new_bond, first_bond +print *, 'Forming a bond!!!' + + +! Step 1: Create a new bond +allocate(new_bond) +new_bond%berg_num_of_current_bond=other_berg%iceberg_num +new_bond%berg_in_current_bond=>other_berg + +! Step 2: Put this new bond at the start of the bond list + first_bond=>berg%first_bond + if (associated(first_bond)) then + new_bond%next_bond=>first_bond + new_bond%prev_bond=>null() !This should not be needed + first_bond%prev_bond=>new_bond + berg%first_bond=>new_bond + else + new_bond%next_bond=>null() !This should not be needed + new_bond%prev_bond=>null() !This should not be needed + berg%first_bond=>new_bond + endif + +end subroutine form_a_bond + +! ############################################################################# + +subroutine check_if_all_bonds_are_present(bergs) + +type(icebergs), pointer :: bergs +type(iceberg), pointer :: berg +type(iceberg), pointer :: other_berg +type(icebergs_gridded), pointer :: grd +type(bond) , pointer :: current_bond, other_berg_bond +integer :: grdi, grdj +logical :: bond_is_good + +print *, "starting bond_check" + + ! For convenience + grd=>bergs%grd + + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + bond_is_good=.False. + other_berg=>current_bond%berg_in_current_bond + if (associated(other_berg)) then + other_berg_bond=>other_berg%first_bond + + do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list + if (associated(other_berg_bond%berg_in_current_bond)) then + if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then + bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found + endif + endif + if (bond_is_good) then + other_berg_bond=>null() + else + other_berg_bond=>other_berg_bond%next_bond + endif + enddo ! End of loop over the other berg's bonds. + + ! Now we assess how we did + + if (bond_is_good) then + print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond + else + print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond + endif + + else + print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num + endif + current_bond=>current_bond%next_bond + enddo !End of loop over current bonds + enddo ! End of loop over all bergs + enddo; enddo !End of loop over all grid cells + +print *, "starting bond_check" +end subroutine check_if_all_bonds_are_present + ! ############################################################################## subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 @@ -167,28 +312,29 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i call rotpos_to_tang(lon1,lat1,x1,y1) do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 - other_berg=>bergs%list(grdi,grdj)%first -!Note: This summing should be made order invarient. - do while (associated(other_berg)) ! loop over all other bergs - L2=other_berg%length - W2=other_berg%width - T2=other_berg%thickness - u2=other_berg%uvel_old !Old values are used to make it order invariant - v2=other_berg%vvel_old !Old values are used to make it order invariant - A2=L2*W2 - R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - lon2=berg%lon_old; lat2=berg%lat_old !Old values are used to make it order invariant - call rotpos_to_tang(lon2,lat2,x2,y2) - - r_dist_x=x1-x2 ; r_dist_y=y1-y2 - r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - - call overlap_area(R1,R2,r_dist,A_o,trapped) - T_min=min(T1,T2) - - !Calculating spring force (later this should only be done on the first time around) - accel_spring=spring_coef*(T_min/T1)*(A_o/A1) - if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then + other_berg=>bergs%list(grdi,grdj)%first + !Note: This summing should be made order invarient. + do while (associated(other_berg)) ! loop over all other bergs + if (berg%iceberg_num .ne. other_berg%iceberg_num) then + L2=other_berg%length + W2=other_berg%width + T2=other_berg%thickness + u2=other_berg%uvel_old !Old values are used to make it order invariant + v2=other_berg%vvel_old !Old values are used to make it order invariant + A2=L2*W2 + R2=sqrt(A2/pi) ! Interaction radius of the other iceberg + lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant + call rotpos_to_tang(lon2,lat2,x2,y2) + + r_dist_x=x1-x2 ; r_dist_y=y1-y2 + r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + + call overlap_area(R1,R2,r_dist,A_o,trapped) + T_min=min(T1,T2) + + !Calculating spring force (later this should only be done on the first time around) + accel_spring=spring_coef*(T_min/T1)*(A_o/A1) + if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) @@ -225,12 +371,11 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !print *, 'P_21',P_21 !print *, 'P_12',P_12 !print *, 'P_22',P_22 - + endif endif - - other_berg=>other_berg%next + other_berg=>other_berg%next enddo ! loop over all bergs - enddo ; enddo +enddo ; enddo contains @@ -262,30 +407,6 @@ subroutine overlap_area(R1,R2,d,A,trapped) end subroutine overlap_area - subroutine rotpos_to_tang(lon, lat, x, y) - ! Arguments - real, intent(in) :: lon, lat - real, intent(out) :: x, y - ! Local variables - real :: r,colat,clon,slon - - if (lat>90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat - call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) - endif - if (lat==90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat - call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) - endif - - colat=90.-lat - r=Rearth*(colat*pi_180) - clon=cos(lon*pi_180) - slon=sin(lon*pi_180) - x=r*clon - y=r*slon - - end subroutine rotpos_to_tang end subroutine interactive_force @@ -2358,31 +2479,6 @@ subroutine evolve_icebergs(bergs) contains - subroutine rotpos_to_tang(lon, lat, x, y) - ! Arguments - real, intent(in) :: lon, lat - real, intent(out) :: x, y - ! Local variables - real :: r,colat,clon,slon - - if (lat>90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat - call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) - endif - if (lat==90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat - call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) - endif - - colat=90.-lat - r=Rearth*(colat*pi_180) - clon=cos(lon*pi_180) - slon=sin(lon*pi_180) - x=r*clon - y=r*slon - - end subroutine rotpos_to_tang - subroutine rotpos_from_tang(x, y, lon, lat) ! Arguments real, intent(in) :: x, y @@ -2631,11 +2727,41 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (debug) error=.true. endif -end subroutine adjust_index_and_ground + end subroutine adjust_index_and_ground end subroutine evolve_icebergs +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +subroutine rotpos_to_tang(lon, lat, x, y) + ! Arguments + real, intent(in) :: lon, lat + real, intent(out) :: x, y + ! Local variables + real :: r,colat,clon,slon + real :: Rearth + integer :: stderrunit + + stderrunit = stderr() + Rearth=6360.e3 + + if (lat>90.) then + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat + call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) + endif + if (lat==90.) then + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat + call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) + endif + + colat=90.-lat + r=Rearth*(colat*pi_180) + clon=cos(lon*pi_180) + slon=sin(lon*pi_180) + x=r*clon + y=r*slon + end subroutine rotpos_to_tang ! ############################################################################## diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 4ab69cf..45c4fd4 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -49,7 +49,7 @@ module ice_bergs_framework !Public types -public icebergs_gridded, xyt, iceberg, icebergs, buffer +public icebergs_gridded, xyt, iceberg, icebergs, buffer, bond !Public subs public ice_bergs_framework_init @@ -157,8 +157,15 @@ module ice_bergs_framework ! Environment variables (as seen by the iceberg) real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi type(xyt), pointer :: trajectory=>null() + type(bond), pointer :: first_bond=>null() !First element of bond list. end type iceberg +type :: bond + type(bond), pointer :: prev_bond=>null(), next_bond=>null() + type(iceberg), pointer :: berg_in_current_bond=>null() + integer :: berg_num_of_current_bond +end type bond + type :: buffer integer :: size=0 real, dimension(:,:), pointer :: data @@ -194,6 +201,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon @@ -292,6 +300,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon @@ -303,7 +312,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & - rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & + rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -553,6 +562,10 @@ subroutine ice_bergs_framework_init(bergs, & if (Runge_not_Verlet) then interactive_icebergs_on=.false. ! Iceberg interactions only with Verlet endif +if (.not.interactive_icebergs_on) then + !iceberg_bonds_on=.false. ! This line needs to included later, but is omitted for testing +endif + ! Parameters bergs%dt=dt @@ -573,6 +586,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%iceberg_bonds_on=iceberg_bonds_on !Alon bergs%critical_interaction_damping_on=critical_interaction_damping_on !Alon bergs%interactive_icebergs_on=interactive_icebergs_on !Alon bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon From 6feebfb42c75a00c9c1c5823bab4e493863c286a Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 23 Sep 2015 18:08:02 -0400 Subject: [PATCH 066/361] Found a couple of bugs which were putting the code into an infinite loop. These have been corrected. --- icebergs.F90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 8642781..c28773c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -157,8 +157,8 @@ subroutine initialize_iceberg_bonds(bergs) !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond call form_a_bond(berg, other_berg) !endif - other_berg=>other_berg%next endif + other_berg=>other_berg%next enddo ! End of looping through all other bergs in the inner list enddo ; enddo; !End of inner loop berg=>berg%next @@ -213,7 +213,7 @@ subroutine check_if_all_bonds_are_present(bergs) integer :: grdi, grdj logical :: bond_is_good -print *, "starting bond_check" +!print *, "starting bond_check" ! For convenience grd=>bergs%grd @@ -254,10 +254,11 @@ subroutine check_if_all_bonds_are_present(bergs) endif current_bond=>current_bond%next_bond enddo !End of loop over current bonds + berg=>berg%next enddo ! End of loop over all bergs enddo; enddo !End of loop over all grid cells -print *, "starting bond_check" +! print *, "ending bond_check" end subroutine check_if_all_bonds_are_present ! ############################################################################## From aa62514524a10994cb36f032cc65e53e9e57b6c8 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 24 Sep 2015 10:59:33 -0400 Subject: [PATCH 067/361] The bond counter and bond quality control submodules are not working. The bond counter counts up the number of bonds. The bond quality control makes sure that each bond matches up with the corresponding bond saved on the bonded berg. --- icebergs.F90 | 90 ++++++++++++++++++++++++++++++------------ icebergs_framework.F90 | 1 + 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c28773c..dd098e6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -133,6 +133,8 @@ subroutine initialize_iceberg_bonds(bergs) real :: r_dist_x, r_dist_y, r_dist integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner +logical :: check_bond_quality + ! For convenience grd=>bergs%grd @@ -144,7 +146,8 @@ subroutine initialize_iceberg_bonds(bergs) lon1=berg%lon; lat1=berg%lat call rotpos_to_tang(lon1,lat1,x1,y1) - do grdj_inner = berg%jne-1,berg%jne+1 ; do grdi_inner = berg%ine-1,berg%ine+1 !Only looping through adjacent cells. + do grdj_inner = grd%jsc,grd%jec ; do grdi_inner = grd%isc,grd%iec !This line uses n^2 steps +! do grdj_inner = berg%jne-1,berg%jne+1 ; do grdi_inner = berg%ine-1,berg%ine+1 !Only looping through adjacent cells. other_berg=>bergs%list(grdi_inner,grdj_inner)%first do while (associated(other_berg)) ! loop over all other bergs @@ -165,7 +168,9 @@ subroutine initialize_iceberg_bonds(bergs) enddo ! End of looping through all bergs in the outer list enddo ; enddo; !End of outer loop. - call check_if_all_bonds_are_present(bergs) + + check_bond_quality=.True. + call check_if_all_bonds_are_present(bergs,check_bond_quality) @@ -203,62 +208,95 @@ end subroutine form_a_bond ! ############################################################################# -subroutine check_if_all_bonds_are_present(bergs) +subroutine check_if_all_bonds_are_present(bergs, check_bond_quality) type(icebergs), pointer :: bergs type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd type(bond) , pointer :: current_bond, other_berg_bond +!integer, intent(out) :: number_of_bonds +integer :: number_of_bonds, number_of_bonds_all_pe integer :: grdi, grdj logical :: bond_is_good +logical, optional :: check_bond_quality +logical :: quality_check +logical :: all_bonds_matching +integer :: stderrunit -!print *, "starting bond_check" + print *, "starting bond_check" + quality_check=.false. + if(present(check_bond_quality)) quality_check = check_bond_quality ! For convenience grd=>bergs%grd + number_of_bonds=0 ! This is a bond counter. + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds - bond_is_good=.False. - other_berg=>current_bond%berg_in_current_bond - if (associated(other_berg)) then - other_berg_bond=>other_berg%first_bond + number_of_bonds=number_of_bonds+1 + + ! ##### Beginning Quality Check on Bonds ###### + if (quality_check) then + all_bonds_matching=.True. + bond_is_good=.False. + other_berg=>current_bond%berg_in_current_bond + if (associated(other_berg)) then + other_berg_bond=>other_berg%first_bond - do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list - if (associated(other_berg_bond%berg_in_current_bond)) then - if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then - bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found + do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list + if (associated(other_berg_bond%berg_in_current_bond)) then + if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then + bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found + endif + endif + if (bond_is_good) then + other_berg_bond=>null() + else + other_berg_bond=>other_berg_bond%next_bond endif - endif + enddo ! End of loop over the other berg's bonds. + if (bond_is_good) then - other_berg_bond=>null() + print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond else - other_berg_bond=>other_berg_bond%next_bond + print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond + all_bonds_matching=.false. endif - enddo ! End of loop over the other berg's bonds. - - ! Now we assess how we did - - if (bond_is_good) then - print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond else - print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond + print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num + all_bonds_matching=.false. endif - - else - print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num endif + ! ##### Ending Quality Check on Bonds ###### + current_bond=>current_bond%next_bond enddo !End of loop over current bonds berg=>berg%next enddo ! End of loop over all bergs enddo; enddo !End of loop over all grid cells -! print *, "ending bond_check" + number_of_bonds_all_pe=number_of_bonds + call mpp_sum(number_of_bonds_all_pe) + + bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's + if (number_of_bonds .gt. 0) then + print *, "Number of bonds on pe, out of a total of: ", number_of_bonds, number_of_bonds_all_pe + endif + + if (quality_check) then + if (.not. all_bonds_matching) then + stderrunit = stderr() + write(stderrunit,*) 'diamonds, Bonds are not matching!!!! PE=',mpp_pe() + call error_mesg('diamonds, bonds', 'Bonds are not matching!', FATAL) + endif + endif + + print *, "ending bond_check" end subroutine check_if_all_bonds_are_present ! ############################################################################## diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 45c4fd4..4780300 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -228,6 +228,7 @@ module ice_bergs_framework real :: net_melt=0., berg_melt=0., bergy_src=0., bergy_melt=0. integer :: nbergs_calved=0, nbergs_melted=0, nbergs_start=0, nbergs_end=0 integer :: nspeeding_tickets=0 + integer :: nbonds=0 integer, dimension(:), pointer :: nbergs_calved_by_class=>null() end type icebergs From 2c8a08c3ddc9ee2f096cec187bab52476f2a779d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 24 Sep 2015 18:46:32 -0400 Subject: [PATCH 068/361] Iceberg bonds can now be initialized, saved to a restart file. Some of the code for reading bonds from the restart file has been written, but this needs a little more work. --- icebergs.F90 | 141 +++------------------------ icebergs_framework.F90 | 142 ++++++++++++++++++++++++++- icebergs_io.F90 | 215 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 361 insertions(+), 137 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index dd098e6..0f51e60 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -26,6 +26,7 @@ module ice_bergs use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer, bond use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell +use ice_bergs_framework, only: count_bonds, form_a_bond use ice_bergs_framework, only: nclasses,old_bug_bilin use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list @@ -39,6 +40,7 @@ module ice_bergs use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving +use ice_bergs_io, only: read_restart_bonds implicit none ; private @@ -111,8 +113,13 @@ subroutine icebergs_init(bergs, & if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') - if (bergs%iceberg_bonds_on) call initialize_iceberg_bonds(bergs) - + if (bergs%iceberg_bonds_on) then + if (bergs%manually_initialize_bonds) then + call initialize_iceberg_bonds(bergs) + else + call read_restart_bonds(bergs,Time) + endif + endif end subroutine icebergs_init @@ -125,7 +132,7 @@ subroutine initialize_iceberg_bonds(bergs) type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd - + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg @@ -133,6 +140,7 @@ subroutine initialize_iceberg_bonds(bergs) real :: r_dist_x, r_dist_y, r_dist integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner +integer :: nbonds logical :: check_bond_quality @@ -158,7 +166,7 @@ subroutine initialize_iceberg_bonds(bergs) r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond - call form_a_bond(berg, other_berg) + call form_a_bond(berg, other_berg%iceberg_num, other_berg) !endif endif other_berg=>other_berg%next @@ -170,7 +178,7 @@ subroutine initialize_iceberg_bonds(bergs) check_bond_quality=.True. - call check_if_all_bonds_are_present(bergs,check_bond_quality) + call count_bonds(bergs, nbonds,check_bond_quality) @@ -178,129 +186,6 @@ end subroutine initialize_iceberg_bonds ! ############################################################################## -subroutine form_a_bond(berg, other_berg) - -type(iceberg), pointer :: berg -type(iceberg), pointer :: other_berg -type(bond) , pointer :: new_bond, first_bond -print *, 'Forming a bond!!!' - - -! Step 1: Create a new bond -allocate(new_bond) -new_bond%berg_num_of_current_bond=other_berg%iceberg_num -new_bond%berg_in_current_bond=>other_berg - -! Step 2: Put this new bond at the start of the bond list - first_bond=>berg%first_bond - if (associated(first_bond)) then - new_bond%next_bond=>first_bond - new_bond%prev_bond=>null() !This should not be needed - first_bond%prev_bond=>new_bond - berg%first_bond=>new_bond - else - new_bond%next_bond=>null() !This should not be needed - new_bond%prev_bond=>null() !This should not be needed - berg%first_bond=>new_bond - endif - -end subroutine form_a_bond - -! ############################################################################# - -subroutine check_if_all_bonds_are_present(bergs, check_bond_quality) - -type(icebergs), pointer :: bergs -type(iceberg), pointer :: berg -type(iceberg), pointer :: other_berg -type(icebergs_gridded), pointer :: grd -type(bond) , pointer :: current_bond, other_berg_bond -!integer, intent(out) :: number_of_bonds -integer :: number_of_bonds, number_of_bonds_all_pe -integer :: grdi, grdj -logical :: bond_is_good -logical, optional :: check_bond_quality -logical :: quality_check -logical :: all_bonds_matching -integer :: stderrunit - - print *, "starting bond_check" - quality_check=.false. - if(present(check_bond_quality)) quality_check = check_bond_quality - - ! For convenience - grd=>bergs%grd - - number_of_bonds=0 ! This is a bond counter. - - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec - berg=>bergs%list(grdi,grdj)%first - do while (associated(berg)) ! loop over all bergs - current_bond=>berg%first_bond - do while (associated(current_bond)) ! loop over all bonds - number_of_bonds=number_of_bonds+1 - - ! ##### Beginning Quality Check on Bonds ###### - if (quality_check) then - all_bonds_matching=.True. - bond_is_good=.False. - other_berg=>current_bond%berg_in_current_bond - if (associated(other_berg)) then - other_berg_bond=>other_berg%first_bond - - do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list - if (associated(other_berg_bond%berg_in_current_bond)) then - if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then - bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found - endif - endif - if (bond_is_good) then - other_berg_bond=>null() - else - other_berg_bond=>other_berg_bond%next_bond - endif - enddo ! End of loop over the other berg's bonds. - - if (bond_is_good) then - print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond - else - print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond - all_bonds_matching=.false. - endif - else - print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num - all_bonds_matching=.false. - endif - endif - ! ##### Ending Quality Check on Bonds ###### - - current_bond=>current_bond%next_bond - enddo !End of loop over current bonds - berg=>berg%next - enddo ! End of loop over all bergs - enddo; enddo !End of loop over all grid cells - - number_of_bonds_all_pe=number_of_bonds - call mpp_sum(number_of_bonds_all_pe) - - bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's - if (number_of_bonds .gt. 0) then - print *, "Number of bonds on pe, out of a total of: ", number_of_bonds, number_of_bonds_all_pe - endif - - if (quality_check) then - if (.not. all_bonds_matching) then - stderrunit = stderr() - write(stderrunit,*) 'diamonds, Bonds are not matching!!!! PE=',mpp_pe() - call error_mesg('diamonds, bonds', 'Bonds are not matching!', FATAL) - endif - endif - - print *, "ending bond_check" -end subroutine check_if_all_bonds_are_present - -! ############################################################################## - subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 type(icebergs), pointer :: bergs type(iceberg), pointer :: berg diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 4780300..cd2dd54 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -62,7 +62,8 @@ module ice_bergs_framework public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position public move_trajectory, move_all_trajectories -public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell +public form_a_bond +public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell, count_bonds public sum_mass,sum_heat,bilin,yearday,bergs_chksum public checksum_gridded public grd_chksum2,grd_chksum3 @@ -202,6 +203,7 @@ module ice_bergs_framework logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. + logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon @@ -302,6 +304,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. +logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon @@ -313,7 +316,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & - rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, & + rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -588,6 +591,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon bergs%iceberg_bonds_on=iceberg_bonds_on !Alon + bergs%manually_initialize_bonds=manually_initialize_bonds !Alon bergs%critical_interaction_damping_on=critical_interaction_damping_on !Alon bergs%interactive_icebergs_on=interactive_icebergs_on !Alon bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon @@ -2065,6 +2069,140 @@ subroutine print_bergs(iochan, bergs, label) end subroutine print_bergs + +! ############################################################################## + +subroutine form_a_bond(berg, other_berg_num, other_berg) + +type(iceberg), pointer :: berg +type(iceberg), optional, pointer :: other_berg +type(bond) , pointer :: new_bond, first_bond +integer, intent(in) :: other_berg_num +print *, 'Forming a bond!!!' + + +! Step 1: Create a new bond +allocate(new_bond) +new_bond%berg_num_of_current_bond=other_berg_num +if(present(other_berg)) then + new_bond%berg_in_current_bond=>other_berg +else + new_bond%berg_in_current_bond=>null() +endif + +! Step 2: Put this new bond at the start of the bond list + first_bond=>berg%first_bond + if (associated(first_bond)) then + new_bond%next_bond=>first_bond + new_bond%prev_bond=>null() !This should not be needed + first_bond%prev_bond=>new_bond + berg%first_bond=>new_bond + else + new_bond%next_bond=>null() !This should not be needed + new_bond%prev_bond=>null() !This should not be needed + berg%first_bond=>new_bond + endif + +end subroutine form_a_bond + +! ############################################################################# +! ############################################################################# +subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) + +type(icebergs), pointer :: bergs +type(iceberg), pointer :: berg +type(iceberg), pointer :: other_berg +type(icebergs_gridded), pointer :: grd +type(bond) , pointer :: current_bond, other_berg_bond +!integer, intent(out) :: number_of_bonds +integer, intent(out) :: number_of_bonds +integer :: number_of_bonds_all_pe +integer :: grdi, grdj +logical :: bond_is_good +logical, optional :: check_bond_quality +logical :: quality_check +logical :: all_bonds_matching +integer :: stderrunit + + print *, "starting bond_check" + quality_check=.false. + all_bonds_matching=.True. + if(present(check_bond_quality)) quality_check = check_bond_quality + + ! For convenience + grd=>bergs%grd + + number_of_bonds=0 ! This is a bond counter. + + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + number_of_bonds=number_of_bonds+1 + + ! ##### Beginning Quality Check on Bonds ###### + if (quality_check) then + all_bonds_matching=.True. + bond_is_good=.False. + other_berg=>current_bond%berg_in_current_bond + if (associated(other_berg)) then + other_berg_bond=>other_berg%first_bond + + do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list + if (associated(other_berg_bond%berg_in_current_bond)) then + if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then + bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found + endif + endif + if (bond_is_good) then + other_berg_bond=>null() + else + other_berg_bond=>other_berg_bond%next_bond + endif + enddo ! End of loop over the other berg's bonds. + + if (bond_is_good) then + print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond + else + print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond + all_bonds_matching=.false. + endif + else + print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num + all_bonds_matching=.false. + endif + endif + ! ##### Ending Quality Check on Bonds ###### + + current_bond=>current_bond%next_bond + enddo !End of loop over current bonds + berg=>berg%next + enddo ! End of loop over all bergs + enddo; enddo !End of loop over all grid cells + + number_of_bonds_all_pe=number_of_bonds + call mpp_sum(number_of_bonds_all_pe) + + bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's + if (number_of_bonds .gt. 0) then + print *, "Number of bonds on pe, out of a total of: ", number_of_bonds, number_of_bonds_all_pe + endif + + if (quality_check) then + if (.not.all_bonds_matching) then + stderrunit = stderr() + write(stderrunit,*) 'diamonds, Bonds are not matching!!!! PE=',mpp_pe() + call error_mesg('diamonds, bonds', 'Bonds are not matching!', FATAL) + endif + endif + + print *, "ending bond_check" + +end subroutine count_bonds + + + ! ############################################################################## integer function count_bergs(bergs, with_halos) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index c093c6a..6044c6c 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -22,10 +22,11 @@ module ice_bergs_io use time_manager_mod, only: time_type, get_date, get_time, set_date, operator(-) -use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer +use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer, bond use ice_bergs_framework, only: pack_berg_into_buffer2,unpack_berg_from_buffer2 use ice_bergs_framework, only: pack_traj_into_buffer2,unpack_traj_from_buffer2 use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell,append_posn +use ice_bergs_framework, only: count_bonds, form_a_bond use ice_bergs_framework, only: push_posn use ice_bergs_framework, only: add_new_berg_to_list,destroy_iceberg use ice_bergs_framework, only: increase_ibuffer,increase_ibuffer_traj,grd_chksum2,grd_chksum3 @@ -42,7 +43,7 @@ module ice_bergs_io public ice_bergs_io_init public read_restart_bergs,read_restart_bergs_orig,write_restart,write_trajectory -public read_restart_calving +public read_restart_calving, read_restart_bonds !Local Vars integer, parameter :: file_format_major_version=0 @@ -98,14 +99,17 @@ end subroutine ice_bergs_io_init subroutine write_restart(bergs) ! Arguments type(icebergs), pointer :: bergs +type(bond), pointer :: current_bond ! Local variables integer :: i,j,id character(len=35) :: filename +character(len=35) :: filename_bonds type(iceberg), pointer :: this=>NULL() integer :: stderrunit !I/O vars type(restart_file_type) :: bergs_restart -integer :: nbergs +type(restart_file_type) :: bergs_bond_restart +integer :: nbergs, nbonds type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & lat, & @@ -132,10 +136,16 @@ subroutine write_restart(bergs) halo_berg, & heat_density -integer, allocatable, dimension(:) :: ine, & - jne, & - iceberg_num, & - start_year +integer, allocatable, dimension(:) :: ine, & + jne, & + iceberg_num, & + start_year, & + bond_first_num, & + bond_second_num, & + bond_first_jne, & + bond_first_ine, & + bond_second_jne, & + bond_second_ine !uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. @@ -188,6 +198,7 @@ subroutine write_restart(bergs) allocate(start_year(nbergs)) allocate(iceberg_num(nbergs)) + call get_instance_filename("icebergs.res.nc", filename) call set_domain(bergs%grd%domain) call register_restart_axis(bergs_restart,filename,'i',nbergs) @@ -237,6 +248,7 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & longname='halo_berg',units='dimensionless') + ! Write variables i = 0 @@ -263,6 +275,7 @@ subroutine write_restart(bergs) enddo enddo ; enddo + call save_restart(bergs_restart) call free_restart_type(bergs_restart) @@ -299,9 +312,79 @@ subroutine write_restart(bergs) iceberg_num, & start_year ) + call nullify_domain() + +!########## Creating bond restart file ###################### + + !Allocating restart memory for bond related variables. + nbonds=0 + if (bergs%iceberg_bonds_on) then + call count_bonds(bergs, nbonds) + endif + + allocate(bond_first_num(nbonds)) + allocate(bond_second_num(nbonds)) + allocate(bond_first_ine(nbonds)) + allocate(bond_first_jne(nbonds)) + allocate(bond_second_ine(nbonds)) + allocate(bond_second_jne(nbonds)) + + call get_instance_filename("bonds_iceberg.res.nc", filename_bonds) + call set_domain(bergs%grd%domain) + call register_restart_axis(bergs_bond_restart,filename,'i',nbonds) + call set_meta_global(bergs_bond_restart,'file_format_major_version',ival=(/file_format_major_version/)) + call set_meta_global(bergs_bond_restart,'file_format_minor_version',ival=(/file_format_minor_version/)) + call set_meta_global(bergs_bond_restart,'time_axis',ival=(/0/)) + + !Now start writing in the io_tile_root_pe if there are any bergs in the I/O list + + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_ine',bond_first_ine,longname='iceberg ine of first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_jne',bond_first_jne,longname='iceberg jne of first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_ine',bond_second_ine,longname='iceberg ine of second berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_jne',bond_second_jne,longname='iceberg jne of second berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_num',bond_first_num,longname='iceberg id first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_num',bond_second_num,longname='iceberg id second berg in bond',units='dimensionless') + + + ! Write variables + + i = 0 + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while(associated(this)) !Loops over all bergs + current_bond=>this%first_bond + do while (associated(current_bond)) ! loop over all bonds + i = i + 1 + bond_first_ine(i)=this%ine + bond_first_jne(i)=this%jne + bond_first_num(i)= this%iceberg_num + bond_second_num(i)=current_bond%berg_num_of_current_bond + bond_second_ine(i)=current_bond%berg_in_current_bond%ine + bond_second_jne(i)=current_bond%berg_in_current_bond%jne + + current_bond=>current_bond%next_bond + enddo !End of loop over bonds + this=>this%next + enddo!End of loop over bergs + enddo; enddo !End of loop over grid + + call save_restart(bergs_bond_restart) + call free_restart_type(bergs_bond_restart) + + + deallocate( & + bond_first_num, & + bond_second_num, & + bond_first_ine, & + bond_first_jne, & + bond_second_ine, & + bond_second_jne ) + call nullify_domain() +!############################################################################################# + ! Write stored ice filename='RESTART/calving.res.nc' if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(stderrunit,'(2a)') 'diamonds, write_restart: writing ',filename @@ -960,6 +1043,124 @@ subroutine generate_bergs(bergs,Time) end subroutine generate_bergs end subroutine read_restart_bergs + + +! ############################################################################## +subroutine read_restart_bonds(bergs,Time) +! Arguments +type(icebergs), pointer :: bergs +type(time_type), intent(in) :: Time +! Local variables +integer :: k, siz(4), nbonds_in_file +logical :: lres, found_restart, found +logical :: first_berg_found, second_berg_found +logical :: multiPErestart ! Not needed with new restart read; currently kept for compatibility +real :: lon0, lon1, lat0, lat1 +character(len=33) :: filename, filename_base +type(icebergs_gridded), pointer :: grd +type(iceberg) :: localberg ! NOT a pointer but an actual local variable +type(iceberg) , pointer :: this, first_berg, second_berg +type(bond) , pointer :: current_bond +integer :: stderrunit + +integer, allocatable, dimension(:) :: bond_first_num, & + bond_second_num, & + bond_first_jne, & + bond_first_ine, & + bond_second_jne, & + bond_second_ine +!integer, allocatable, dimension(:,:) :: iceberg_counter_grd + + ! Get the stderr unit number + stderrunit=stderr() + + ! For convenience + grd=>bergs%grd + + ! Zero out nbergs_in_file + nbonds_in_file = 0 + + filename_base=trim(restart_input_dir)//'bonds_iceberg.res.nc' + + found_restart = find_restart_file(filename_base, filename, multiPErestart, io_tile_id(1)) + call error_mesg('read_restart_bonds_bergs_new', 'Using new icebergs restart read', NOTE) + + filename = filename_base + call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) + nbonds_in_file = siz(1) + + if (nbonds_in_file .gt. 0) then + + allocate(bond_first_num(nbonds_in_file)) + allocate(bond_second_num(nbonds_in_file)) + allocate(bond_first_jne(nbonds_in_file)) + allocate(bond_first_ine(nbonds_in_file)) + allocate(bond_second_ine(nbonds_in_file)) + allocate(bond_second_jne(nbonds_in_file)) + + + call read_unlimited_axis(filename,'bond_first_num',bond_first_num,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_num',bond_second_num,domain=grd%domain) + call read_unlimited_axis(filename,'bond_first_jne',bond_first_jne,domain=grd%domain) + call read_unlimited_axis(filename,'bond_first_ine',bond_first_ine,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_jne',bond_second_jne,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_ine',bond_second_ine,domain=grd%domain) + + ! Find approx outer bounds for tile + lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lon1=maxval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lat0=minval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lat1=maxval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + do k=1, nbonds_in_file + + + ! Search for the first berg, which the bond belongs to + first_berg_found=.false. + first_berg=>null() + this=>bergs%list(bond_first_ine(k),bond_first_jne(k))%first + do while(associated(this)) + if (this%iceberg_num == bond_first_num(k)) then + first_berg_found=.true. + first_berg=>this + this=>null() + else + this=>this%next + endif + enddo + + ! Search for the second berg, which the bond belongs to + second_berg_found=.false. + second_berg=>null() + this=>bergs%list(bond_second_ine(k),bond_second_jne(k))%first + do while(associated(this)) + if (this%iceberg_num == bond_second_num(k)) then + second_berg_found=.true. + second_berg=>this + this=>null() + else + this=>this%next + endif + enddo + + if (first_berg_found .and. second_berg_found) then + call form_a_bond(first_berg, bond_second_num(k),second_berg) + + else + !I need to create an option to slowly search for the icebergs + print *, 'The bergs and bonds do not match!!!', k, nbonds_in_file + call error_mesg('read_restart_bonds_bergs_new', 'Failure with reading bonds: bergs and bonds do not match', FATAL) + endif + enddo + + deallocate( & + bond_first_num, & + bond_second_num, & + bond_first_ine, & + bond_first_jne, & + bond_second_ine, & + bond_second_jne ) + endif +end subroutine read_restart_bonds ! ############################################################################## subroutine read_restart_calving(bergs) From 5f3bb1aaf8af92154e2d5b2a7dd6b7e232f4a442 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 25 Sep 2015 10:57:42 -0400 Subject: [PATCH 069/361] Iceberg bonds can now be read from a restart file. This seems to be working well. --- icebergs_io.F90 | 173 +++++++++++++++++++++++++++++------------------- 1 file changed, 106 insertions(+), 67 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 6044c6c..3752e84 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1062,7 +1062,12 @@ subroutine read_restart_bonds(bergs,Time) type(iceberg) , pointer :: this, first_berg, second_berg type(bond) , pointer :: current_bond integer :: stderrunit - +integer :: number_first_bonds_matched !How many first bond bergs found on pe +integer :: number_second_bonds_matched !How many second bond bergs found on pe +integer :: number_perfect_bonds ! How many complete bonds formed +integer :: number_partial_bonds ! How many either complete/partial bonds formed. +integer :: all_pe_number_perfect_bonds, all_pe_number_partial_bonds +integer :: all_pe_number_first_bonds_matched, all_pe_number_second_bonds_matched integer, allocatable, dimension(:) :: bond_first_num, & bond_second_num, & bond_first_jne, & @@ -1091,75 +1096,109 @@ subroutine read_restart_bonds(bergs,Time) if (nbonds_in_file .gt. 0) then - allocate(bond_first_num(nbonds_in_file)) - allocate(bond_second_num(nbonds_in_file)) - allocate(bond_first_jne(nbonds_in_file)) - allocate(bond_first_ine(nbonds_in_file)) - allocate(bond_second_ine(nbonds_in_file)) - allocate(bond_second_jne(nbonds_in_file)) - - - call read_unlimited_axis(filename,'bond_first_num',bond_first_num,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_num',bond_second_num,domain=grd%domain) - call read_unlimited_axis(filename,'bond_first_jne',bond_first_jne,domain=grd%domain) - call read_unlimited_axis(filename,'bond_first_ine',bond_first_ine,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_jne',bond_second_jne,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_ine',bond_second_ine,domain=grd%domain) - - ! Find approx outer bounds for tile - lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lon1=maxval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lat0=minval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lat1=maxval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - do k=1, nbonds_in_file - + allocate(bond_first_num(nbonds_in_file)) + allocate(bond_second_num(nbonds_in_file)) + allocate(bond_first_jne(nbonds_in_file)) + allocate(bond_first_ine(nbonds_in_file)) + allocate(bond_second_ine(nbonds_in_file)) + allocate(bond_second_jne(nbonds_in_file)) + + + call read_unlimited_axis(filename,'bond_first_num',bond_first_num,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_num',bond_second_num,domain=grd%domain) + call read_unlimited_axis(filename,'bond_first_jne',bond_first_jne,domain=grd%domain) + call read_unlimited_axis(filename,'bond_first_ine',bond_first_ine,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_jne',bond_second_jne,domain=grd%domain) + call read_unlimited_axis(filename,'bond_second_ine',bond_second_ine,domain=grd%domain) + + number_first_bonds_matched=0 + number_second_bonds_matched=0 + number_perfect_bonds=0 + number_partial_bonds=0 + do k=1, nbonds_in_file + + ! Decide whether the first iceberg is on the processeor + if ( bond_first_ine(k)>=grd%isc .and. bond_first_ine(k)<=grd%iec .and. & + bond_first_jne(k)>=grd%jsc .and.bond_first_jne(k)<=grd%jec ) then + number_first_bonds_matched=number_first_bonds_matched+1 - ! Search for the first berg, which the bond belongs to - first_berg_found=.false. - first_berg=>null() - this=>bergs%list(bond_first_ine(k),bond_first_jne(k))%first - do while(associated(this)) - if (this%iceberg_num == bond_first_num(k)) then - first_berg_found=.true. - first_berg=>this - this=>null() - else - this=>this%next - endif - enddo - - ! Search for the second berg, which the bond belongs to - second_berg_found=.false. - second_berg=>null() - this=>bergs%list(bond_second_ine(k),bond_second_jne(k))%first - do while(associated(this)) - if (this%iceberg_num == bond_second_num(k)) then - second_berg_found=.true. - second_berg=>this - this=>null() - else - this=>this%next - endif - enddo + ! Search for the first berg, which the bond belongs to + first_berg_found=.false. + first_berg=>null() + this=>bergs%list(bond_first_ine(k),bond_first_jne(k))%first + do while(associated(this)) + if (this%iceberg_num == bond_first_num(k)) then + first_berg_found=.true. + first_berg=>this + this=>null() + else + this=>this%next + endif + enddo - if (first_berg_found .and. second_berg_found) then - call form_a_bond(first_berg, bond_second_num(k),second_berg) - - else - !I need to create an option to slowly search for the icebergs - print *, 'The bergs and bonds do not match!!!', k, nbonds_in_file - call error_mesg('read_restart_bonds_bergs_new', 'Failure with reading bonds: bergs and bonds do not match', FATAL) - endif - enddo + ! Decide whether the second iceberg is on the processeor (data domain) + second_berg_found=.false. + if ( bond_second_ine(k)>=grd%isd .and. bond_second_ine(k)<=grd%ied .and. & + bond_second_jne(k)>=grd%jsd .and.bond_second_jne(k)<=grd%jed ) then + number_second_bonds_matched=number_second_bonds_matched+1 + + ! Search for the second berg, which the bond belongs to + second_berg=>null() + this=>bergs%list(bond_second_ine(k),bond_second_jne(k))%first + do while(associated(this)) + if (this%iceberg_num == bond_second_num(k)) then + second_berg_found=.true. + second_berg=>this + this=>null() + else + this=>this%next + endif + enddo + endif + + if (first_berg_found) then + number_partial_bonds=number_partial_bonds+1 + if (second_berg_found) then + call form_a_bond(first_berg, bond_second_num(k),second_berg) + number_perfect_bonds=number_perfect_bonds+1 + else + call form_a_bond(first_berg, bond_second_num(k)) + endif + else + write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', k, mpp_pe(), nbonds_in_file + call error_mesg('read_restart_bonds_bergs_new', 'Failure with reading bonds: First bond not found on pe', FATAL) + endif + endif + enddo - deallocate( & - bond_first_num, & - bond_second_num, & - bond_first_ine, & - bond_first_jne, & - bond_second_ine, & - bond_second_jne ) - endif + !Analyse how many bonds were created and take appropriate action + all_pe_number_perfect_bonds=number_perfect_bonds + all_pe_number_partial_bonds=number_partial_bonds + all_pe_number_first_bonds_matched=number_first_bonds_matched + all_pe_number_second_bonds_matched=number_second_bonds_matched + call mpp_sum(all_pe_number_perfect_bonds) + call mpp_sum(all_pe_number_partial_bonds) + call mpp_sum(all_pe_number_first_bonds_matched) + call mpp_sum(all_pe_number_second_bonds_matched) + + if (all_pe_number_partial_bonds .lt. nbonds_in_file) then + write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file + call error_mesg('read_restart_bonds_bergs_new', 'Not enough partial bonds formed', FATAL) + endif + + if (all_pe_number_perfect_bonds .lt. nbonds_in_file) then + write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Warning, some bonds are not fully formed', all_pe_number_perfect_bonds , nbonds_in_file + call error_mesg('read_restart_bonds_bergs_new', 'Not enough perfect bonds formed', NOTE) + endif + + deallocate( & + bond_first_num, & + bond_second_num, & + bond_first_ine, & + bond_first_jne, & + bond_second_ine, & + bond_second_jne ) + endif end subroutine read_restart_bonds ! ############################################################################## From 97933556c1abca30a0d0553b25dcf526d5245dad Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 25 Sep 2015 16:27:14 -0400 Subject: [PATCH 070/361] Icebergs bonds can now move from one processor to another. After the bond has moved, it is reconstructed on the other processor. I still need to write a scheme which locates the partner bergs on the other processor. However, this will be simple, since the berg stores the address of the partner berg in the bond, and moves it to the other processor. I have also introduced a namelist parameter called max_bonds, which is the maximum amount of bonds that one iceberg can have when it is moved from one processor to another. This all seems to be working for now. --- icebergs.F90 | 2 +- icebergs_framework.F90 | 160 ++++++++++++++++++++++++++++++----------- icebergs_io.F90 | 137 +++++++++++++++++------------------ 3 files changed, 189 insertions(+), 110 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 0f51e60..43f3610 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -166,7 +166,7 @@ subroutine initialize_iceberg_bonds(bergs) r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond - call form_a_bond(berg, other_berg%iceberg_num, other_berg) + call form_a_bond(berg, other_berg%iceberg_num, other_berg%ine, other_berg%jne, other_berg) !endif endif other_berg=>other_berg%next diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index cd2dd54..8df3610 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -163,8 +163,8 @@ module ice_bergs_framework type :: bond type(bond), pointer :: prev_bond=>null(), next_bond=>null() - type(iceberg), pointer :: berg_in_current_bond=>null() - integer :: berg_num_of_current_bond + type(iceberg), pointer :: other_berg=>null() + integer :: other_berg_num, other_berg_ine, other_berg_jne end type bond type :: buffer @@ -185,6 +185,7 @@ module ice_bergs_framework real :: current_yearday ! 1.00-365.99 integer :: traj_sample_hrs, traj_write_hrs integer :: verbose_hrs + integer :: max_bonds integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers integer :: clock_trw, clock_trp real :: rho_bergs ! Density of icebergs [kg/m^3] @@ -289,6 +290,7 @@ subroutine ice_bergs_framework_init(bergs, & integer :: traj_sample_hrs=24 ! Period between sampling of position for trajectory storage integer :: traj_write_hrs=480 ! Period between writing sampled trajectories to disk integer :: verbose_hrs=24 ! Period between verbose messages +integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs real :: spring_coef=1.e-4 ! Spring contant for iceberg interactions - Alon real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon @@ -314,7 +316,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, & +namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & @@ -569,6 +571,9 @@ subroutine ice_bergs_framework_init(bergs, & if (.not.interactive_icebergs_on) then !iceberg_bonds_on=.false. ! This line needs to included later, but is omitted for testing endif +if (.not. iceberg_bonds_on) then + max_bonds=0 +endif ! Parameters @@ -577,6 +582,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%traj_write_hrs=traj_write_hrs bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo + bergs%max_bonds=max_bonds bergs%grd%iceberg_halo=iceberg_halo bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef @@ -816,7 +822,9 @@ subroutine update_halo_icebergs(bergs) integer :: halo_width integer :: temp1, temp2 real :: current_halo_status - +logical :: force_app + +force_app =.false. halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. ! Get the stderr unit number @@ -870,7 +878,7 @@ subroutine update_halo_icebergs(bergs) nbergs_to_send_e=nbergs_to_send_e+1 current_halo_status=kick_the_bucket%halo_berg kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e, bergs%max_bonds) kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -883,7 +891,7 @@ subroutine update_halo_icebergs(bergs) nbergs_to_send_w=nbergs_to_send_w+1 current_halo_status=kick_the_bucket%halo_berg kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w, bergs%max_bonds) kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -917,7 +925,7 @@ subroutine update_halo_icebergs(bergs) call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, force_app, bergs%max_bonds ) enddo endif else @@ -935,7 +943,7 @@ subroutine update_halo_icebergs(bergs) call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, force_app, bergs%max_bonds ) enddo endif else @@ -957,7 +965,7 @@ subroutine update_halo_icebergs(bergs) nbergs_to_send_n=nbergs_to_send_n+1 current_halo_status=kick_the_bucket%halo_berg kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n, bergs%max_bonds ) kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -971,7 +979,7 @@ subroutine update_halo_icebergs(bergs) nbergs_to_send_s=nbergs_to_send_s+1 current_halo_status=kick_the_bucket%halo_berg kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s,bergs%max_bonds ) kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo @@ -1013,7 +1021,7 @@ subroutine update_halo_icebergs(bergs) call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd,force_app, bergs%max_bonds ) enddo endif else @@ -1039,7 +1047,7 @@ subroutine update_halo_icebergs(bergs) call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) endif do i=1, nbergs_rcvd_from_n - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd, force_app, bergs%max_bonds ) enddo endif else @@ -1089,6 +1097,9 @@ subroutine send_bergs_to_other_pes(bergs) integer :: i, nbergs_start, nbergs_end integer :: stderrunit integer :: grdi, grdj +logical :: force_app + +force_app=.false. ! Get the stderr unit number stderrunit = stderr() @@ -1111,14 +1122,14 @@ subroutine send_bergs_to_other_pes(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_e=nbergs_to_send_e+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e, bergs%max_bonds ) call move_trajectory(bergs, kick_the_bucket) call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) elseif (this%ine.lt.bergs%grd%isc) then kick_the_bucket=>this this=>this%next nbergs_to_send_w=nbergs_to_send_w+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w, bergs%max_bonds ) call move_trajectory(bergs, kick_the_bucket) call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) else @@ -1157,7 +1168,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, force_app, bergs%max_bonds ) enddo endif else @@ -1175,7 +1186,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, force_app, bergs%max_bonds) enddo endif else @@ -1196,14 +1207,14 @@ subroutine send_bergs_to_other_pes(bergs) kick_the_bucket=>this this=>this%next nbergs_to_send_n=nbergs_to_send_n+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_n, nbergs_to_send_n,bergs%max_bonds) call move_trajectory(bergs, kick_the_bucket) call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) elseif (this%jne.lt.bergs%grd%jsc) then kick_the_bucket=>this this=>this%next nbergs_to_send_s=nbergs_to_send_s+1 - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s) + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s,bergs%max_bonds) call move_trajectory(bergs, kick_the_bucket) call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) else @@ -1250,7 +1261,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd, force_app, bergs%max_bonds ) enddo endif else @@ -1276,7 +1287,7 @@ subroutine send_bergs_to_other_pes(bergs) call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) endif do i=1, nbergs_rcvd_from_n - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd,force_app, bergs%max_bonds) enddo endif else @@ -1328,12 +1339,20 @@ subroutine send_bergs_to_other_pes(bergs) end subroutine send_bergs_to_other_pes - subroutine pack_berg_into_buffer2(berg, buff, n) + subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) ! Arguments type(iceberg), pointer :: berg type(buffer), pointer :: buff integer, intent(in) :: n + integer, optional :: max_bonds_in + !integer, intent(in) :: max_bonds ! Change this later ! Local variables + integer :: counter, k, max_bonds + type(bond), pointer :: current_bond + + max_bonds=0 + if (present(max_bonds_in)) max_bonds=max_bonds_in + if (.not.associated(buff)) call increase_buffer(buff,delta_buf) if (n>buff%size) call increase_buffer(buff,delta_buf) @@ -1362,12 +1381,30 @@ subroutine pack_berg_into_buffer2(berg, buff, n) buff%data(22,n)=berg%ayn !Alon buff%data(23,n)=berg%bxn !Alon buff%data(24,n)=berg%byn !Alon - buff%data(25,n)=berg%uvel_old !Alon + buff%data(25,n)=berg%uvel_old !Alon buff%data(26,n)=berg%vvel_old !Alon buff%data(27,n)=berg%lon_old !Alon buff%data(28,n)=berg%lat_old !Alon buff%data(29,n)=float(berg%iceberg_num) - buff%data(30,n)=berg%halo_berg + buff%data(30,n)=berg%halo_berg + + if (max_bonds .gt. 0) then + counter=30 !how many data points being passed so far (must match above) + do k = 1,max_bonds + current_bond=>berg%first_bond + if (associated(current_bond)) then + buff%data(counter+(3*(k-1)+1),n)=float(current_bond%other_berg_num) + buff%data(counter+(3*(k-1)+2),n)=float(current_bond%other_berg_ine) + buff%data(counter+(3*(k-1)+3),n)=float(current_bond%other_berg_jne) + current_bond=>current_bond%next_bond + else + buff%data(counter+(3*(k-1)+1),n)=0. + buff%data(counter+(3*(k-1)+2),n)=0. + buff%data(counter+(3*(k-1)+3),n)=0. + endif + enddo + endif + end subroutine pack_berg_into_buffer2 @@ -1397,13 +1434,14 @@ subroutine increase_buffer(old,delta) end subroutine increase_buffer - subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append) + subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_in) ! Arguments type(icebergs), pointer :: bergs type(buffer), pointer :: buff integer, intent(in) :: n type(icebergs_gridded), pointer :: grd logical, optional :: force_append + integer, optional :: max_bonds_in ! Local variables !real :: lon, lat, uvel, vvel, xi, yj @@ -1411,11 +1449,19 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append) !integer :: ine, jne, start_year logical :: lres type(iceberg) :: localberg + type(iceberg), pointer :: this + integer :: other_berg_num, other_berg_ine, other_berg_jne + integer :: counter, k, max_bonds integer :: stderrunit logical :: force_app = .false. + logical :: quick + ! Get the stderr unit number stderrunit = stderr() - + + quick=.false. + max_bonds=0 + if (present(max_bonds_in)) max_bonds=max_bonds_in if(present(force_append)) force_app = force_append localberg%lon=buff%data(1,n) @@ -1449,19 +1495,20 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append) localberg%halo_berg=buff%data(30,n) if(force_app) then !force append with origin ine,jne (for I/O) + localberg%ine=buff%data(19,n) localberg%jne=buff%data(20,n) - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) else lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) else lres=find_cell_wide(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) else write(stderrunit,'("diamonds, unpack_berg_from_buffer pe=(",i3,a,2i4,a,2f8.2)')& & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat @@ -1481,8 +1528,24 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append) call error_mesg('diamonds, unpack_berg_from_buffer', 'can not find a cell to place berg in!', FATAL) endif endif - - endif + endif + + !# Do stuff to do with bonds here MP1 + + if (max_bonds .gt. 0) then + counter=30 !how many data points being passed so far (must match above) + do k = 1,max_bonds + other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) + other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) + other_berg_jne=nint(buff%data(counter+(3*(k-1)+3),n)) + if (other_berg_num .gt. 0) then + call form_a_bond(this, other_berg_num, other_berg_ine, other_berg_jne) + endif + enddo + endif + + !############################## + end subroutine unpack_berg_from_buffer2 subroutine increase_ibuffer(old,delta) @@ -1679,10 +1742,11 @@ end subroutine unpack_traj_from_buffer2 ! ############################################################################## -subroutine add_new_berg_to_list(first, bergvals, quick) +subroutine add_new_berg_to_list(first, bergvals, quick, newberg_return) ! Arguments type(iceberg), pointer :: first type(iceberg), intent(in) :: bergvals +type(iceberg), intent(out), pointer, optional :: newberg_return logical, intent(in), optional :: quick ! Local variables type(iceberg), pointer :: new=>null() @@ -1690,12 +1754,18 @@ subroutine add_new_berg_to_list(first, bergvals, quick) new=>null() call create_iceberg(new, bergvals) + if (present(newberg_return)) then + newberg_return=>new + !newberg_return=>null() + endif + if (present(quick)) then if(quick) call insert_berg_into_list(first, new, quick=.true.) else call insert_berg_into_list(first, new) endif + !Clear new new=>null() @@ -2072,22 +2142,30 @@ end subroutine print_bergs ! ############################################################################## -subroutine form_a_bond(berg, other_berg_num, other_berg) +subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, other_berg) type(iceberg), pointer :: berg type(iceberg), optional, pointer :: other_berg type(bond) , pointer :: new_bond, first_bond integer, intent(in) :: other_berg_num +integer, optional :: other_berg_ine, other_berg_jne + print *, 'Forming a bond!!!' ! Step 1: Create a new bond allocate(new_bond) -new_bond%berg_num_of_current_bond=other_berg_num +new_bond%other_berg_num=other_berg_num if(present(other_berg)) then - new_bond%berg_in_current_bond=>other_berg + new_bond%other_berg=>other_berg + new_bond%other_berg_ine=other_berg%ine + new_bond%other_berg_jne=other_berg%jne else - new_bond%berg_in_current_bond=>null() + new_bond%other_berg=>null() + if (present(other_berg_ine)) then + new_bond%other_berg_ine=other_berg_ine + new_bond%other_berg_jne=other_berg_jne + endif endif ! Step 2: Put this new bond at the start of the bond list @@ -2145,13 +2223,13 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) if (quality_check) then all_bonds_matching=.True. bond_is_good=.False. - other_berg=>current_bond%berg_in_current_bond + other_berg=>current_bond%other_berg if (associated(other_berg)) then other_berg_bond=>other_berg%first_bond do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list - if (associated(other_berg_bond%berg_in_current_bond)) then - if (other_berg_bond%berg_in_current_bond%iceberg_num==berg%iceberg_num) then + if (associated(other_berg_bond%other_berg)) then + if (other_berg_bond%other_berg%iceberg_num==berg%iceberg_num) then bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found endif endif @@ -2163,13 +2241,13 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) enddo ! End of loop over the other berg's bonds. if (bond_is_good) then - print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%berg_num_of_current_bond + print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num else - print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%berg_num_of_current_bond + print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%other_berg_num all_bonds_matching=.false. endif else - print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%berg_in_current_bond%iceberg_num + print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%other_berg%iceberg_num all_bonds_matching=.false. endif endif diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 3752e84..9b6d4e0 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -140,12 +140,12 @@ subroutine write_restart(bergs) jne, & iceberg_num, & start_year, & - bond_first_num, & - bond_second_num, & - bond_first_jne, & - bond_first_ine, & - bond_second_jne, & - bond_second_ine + first_berg_num, & + other_berg_num, & + first_berg_jne, & + first_berg_ine, & + other_berg_jne, & + other_berg_ine !uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. @@ -322,12 +322,12 @@ subroutine write_restart(bergs) call count_bonds(bergs, nbonds) endif - allocate(bond_first_num(nbonds)) - allocate(bond_second_num(nbonds)) - allocate(bond_first_ine(nbonds)) - allocate(bond_first_jne(nbonds)) - allocate(bond_second_ine(nbonds)) - allocate(bond_second_jne(nbonds)) + allocate(first_berg_num(nbonds)) + allocate(other_berg_num(nbonds)) + allocate(first_berg_ine(nbonds)) + allocate(first_berg_jne(nbonds)) + allocate(other_berg_ine(nbonds)) + allocate(other_berg_jne(nbonds)) call get_instance_filename("bonds_iceberg.res.nc", filename_bonds) call set_domain(bergs%grd%domain) @@ -338,12 +338,12 @@ subroutine write_restart(bergs) !Now start writing in the io_tile_root_pe if there are any bergs in the I/O list - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_ine',bond_first_ine,longname='iceberg ine of first berg in bond',units='dimensionless') - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_jne',bond_first_jne,longname='iceberg jne of first berg in bond',units='dimensionless') - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_ine',bond_second_ine,longname='iceberg ine of second berg in bond',units='dimensionless') - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_jne',bond_second_jne,longname='iceberg jne of second berg in bond',units='dimensionless') - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_first_num',bond_first_num,longname='iceberg id first berg in bond',units='dimensionless') - id = register_restart_field(bergs_bond_restart,filename_bonds,'bond_second_num',bond_second_num,longname='iceberg id second berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'first_berg_ine',first_berg_ine,longname='iceberg ine of first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'first_berg_jne',first_berg_jne,longname='iceberg jne of first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'first_berg_num',first_berg_num,longname='iceberg id first berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_ine',other_berg_ine,longname='iceberg ine of second berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_jne',other_berg_jne,longname='iceberg jne of second berg in bond',units='dimensionless') + id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_num',other_berg_num,longname='iceberg id second berg in bond',units='dimensionless') ! Write variables @@ -355,12 +355,12 @@ subroutine write_restart(bergs) current_bond=>this%first_bond do while (associated(current_bond)) ! loop over all bonds i = i + 1 - bond_first_ine(i)=this%ine - bond_first_jne(i)=this%jne - bond_first_num(i)= this%iceberg_num - bond_second_num(i)=current_bond%berg_num_of_current_bond - bond_second_ine(i)=current_bond%berg_in_current_bond%ine - bond_second_jne(i)=current_bond%berg_in_current_bond%jne + first_berg_ine(i)=this%ine + first_berg_jne(i)=this%jne + first_berg_num(i)= this%iceberg_num + other_berg_num(i)=current_bond%other_berg_num + other_berg_ine(i)=current_bond%other_berg%ine + other_berg_jne(i)=current_bond%other_berg%jne current_bond=>current_bond%next_bond enddo !End of loop over bonds @@ -373,12 +373,12 @@ subroutine write_restart(bergs) deallocate( & - bond_first_num, & - bond_second_num, & - bond_first_ine, & - bond_first_jne, & - bond_second_ine, & - bond_second_jne ) + first_berg_num, & + other_berg_num, & + first_berg_ine, & + first_berg_jne, & + other_berg_ine, & + other_berg_jne ) call nullify_domain() @@ -1068,12 +1068,12 @@ subroutine read_restart_bonds(bergs,Time) integer :: number_partial_bonds ! How many either complete/partial bonds formed. integer :: all_pe_number_perfect_bonds, all_pe_number_partial_bonds integer :: all_pe_number_first_bonds_matched, all_pe_number_second_bonds_matched -integer, allocatable, dimension(:) :: bond_first_num, & - bond_second_num, & - bond_first_jne, & - bond_first_ine, & - bond_second_jne, & - bond_second_ine +integer, allocatable, dimension(:) :: first_berg_num, & + other_berg_num, & + first_berg_jne, & + first_berg_ine, & + other_berg_jne, & + other_berg_ine !integer, allocatable, dimension(:,:) :: iceberg_counter_grd ! Get the stderr unit number @@ -1088,7 +1088,7 @@ subroutine read_restart_bonds(bergs,Time) filename_base=trim(restart_input_dir)//'bonds_iceberg.res.nc' found_restart = find_restart_file(filename_base, filename, multiPErestart, io_tile_id(1)) - call error_mesg('read_restart_bonds_bergs_new', 'Using new icebergs restart read', NOTE) + call error_mesg('read_restart_bonds_bergs_new', 'Using new icebergs bond restart read', NOTE) filename = filename_base call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) @@ -1096,20 +1096,20 @@ subroutine read_restart_bonds(bergs,Time) if (nbonds_in_file .gt. 0) then - allocate(bond_first_num(nbonds_in_file)) - allocate(bond_second_num(nbonds_in_file)) - allocate(bond_first_jne(nbonds_in_file)) - allocate(bond_first_ine(nbonds_in_file)) - allocate(bond_second_ine(nbonds_in_file)) - allocate(bond_second_jne(nbonds_in_file)) + allocate(first_berg_num(nbonds_in_file)) + allocate(other_berg_num(nbonds_in_file)) + allocate(first_berg_jne(nbonds_in_file)) + allocate(first_berg_ine(nbonds_in_file)) + allocate(other_berg_ine(nbonds_in_file)) + allocate(other_berg_jne(nbonds_in_file)) - call read_unlimited_axis(filename,'bond_first_num',bond_first_num,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_num',bond_second_num,domain=grd%domain) - call read_unlimited_axis(filename,'bond_first_jne',bond_first_jne,domain=grd%domain) - call read_unlimited_axis(filename,'bond_first_ine',bond_first_ine,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_jne',bond_second_jne,domain=grd%domain) - call read_unlimited_axis(filename,'bond_second_ine',bond_second_ine,domain=grd%domain) + call read_unlimited_axis(filename,'first_berg_num',first_berg_num,domain=grd%domain) + call read_unlimited_axis(filename,'other_berg_num',other_berg_num,domain=grd%domain) + call read_unlimited_axis(filename,'first_berg_jne',first_berg_jne,domain=grd%domain) + call read_unlimited_axis(filename,'first_berg_ine',first_berg_ine,domain=grd%domain) + call read_unlimited_axis(filename,'other_berg_jne',other_berg_jne,domain=grd%domain) + call read_unlimited_axis(filename,'other_berg_ine',other_berg_ine,domain=grd%domain) number_first_bonds_matched=0 number_second_bonds_matched=0 @@ -1118,16 +1118,16 @@ subroutine read_restart_bonds(bergs,Time) do k=1, nbonds_in_file ! Decide whether the first iceberg is on the processeor - if ( bond_first_ine(k)>=grd%isc .and. bond_first_ine(k)<=grd%iec .and. & - bond_first_jne(k)>=grd%jsc .and.bond_first_jne(k)<=grd%jec ) then + if ( first_berg_ine(k)>=grd%isc .and. first_berg_ine(k)<=grd%iec .and. & + first_berg_jne(k)>=grd%jsc .and.first_berg_jne(k)<=grd%jec ) then number_first_bonds_matched=number_first_bonds_matched+1 ! Search for the first berg, which the bond belongs to first_berg_found=.false. first_berg=>null() - this=>bergs%list(bond_first_ine(k),bond_first_jne(k))%first + this=>bergs%list(first_berg_ine(k),first_berg_jne(k))%first do while(associated(this)) - if (this%iceberg_num == bond_first_num(k)) then + if (this%iceberg_num == first_berg_num(k)) then first_berg_found=.true. first_berg=>this this=>null() @@ -1138,15 +1138,15 @@ subroutine read_restart_bonds(bergs,Time) ! Decide whether the second iceberg is on the processeor (data domain) second_berg_found=.false. - if ( bond_second_ine(k)>=grd%isd .and. bond_second_ine(k)<=grd%ied .and. & - bond_second_jne(k)>=grd%jsd .and.bond_second_jne(k)<=grd%jed ) then + if ( other_berg_ine(k)>=grd%isd .and. other_berg_ine(k)<=grd%ied .and. & + other_berg_jne(k)>=grd%jsd .and.other_berg_jne(k)<=grd%jed ) then number_second_bonds_matched=number_second_bonds_matched+1 ! Search for the second berg, which the bond belongs to second_berg=>null() - this=>bergs%list(bond_second_ine(k),bond_second_jne(k))%first + this=>bergs%list(other_berg_ine(k),other_berg_jne(k))%first do while(associated(this)) - if (this%iceberg_num == bond_second_num(k)) then + if (this%iceberg_num == other_berg_num(k)) then second_berg_found=.true. second_berg=>this this=>null() @@ -1159,10 +1159,10 @@ subroutine read_restart_bonds(bergs,Time) if (first_berg_found) then number_partial_bonds=number_partial_bonds+1 if (second_berg_found) then - call form_a_bond(first_berg, bond_second_num(k),second_berg) + call form_a_bond(first_berg, other_berg_num(k), other_berg_ine(k), other_berg_jne(k), second_berg) number_perfect_bonds=number_perfect_bonds+1 else - call form_a_bond(first_berg, bond_second_num(k)) + call form_a_bond(first_berg, other_berg_num(k),other_berg_ine(k),other_berg_jne(k)) endif else write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', k, mpp_pe(), nbonds_in_file @@ -1178,8 +1178,6 @@ subroutine read_restart_bonds(bergs,Time) all_pe_number_second_bonds_matched=number_second_bonds_matched call mpp_sum(all_pe_number_perfect_bonds) call mpp_sum(all_pe_number_partial_bonds) - call mpp_sum(all_pe_number_first_bonds_matched) - call mpp_sum(all_pe_number_second_bonds_matched) if (all_pe_number_partial_bonds .lt. nbonds_in_file) then write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file @@ -1187,17 +1185,20 @@ subroutine read_restart_bonds(bergs,Time) endif if (all_pe_number_perfect_bonds .lt. nbonds_in_file) then - write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Warning, some bonds are not fully formed', all_pe_number_perfect_bonds , nbonds_in_file + call mpp_sum(all_pe_number_first_bonds_matched) + call mpp_sum(all_pe_number_second_bonds_matched) + write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Warning, some bonds are not fully formed', all_pe_number_first_bonds_matched , nbonds_in_file + write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Number of first and second bonds matched:', all_pe_number_second_bonds_matched , nbonds_in_file call error_mesg('read_restart_bonds_bergs_new', 'Not enough perfect bonds formed', NOTE) endif deallocate( & - bond_first_num, & - bond_second_num, & - bond_first_ine, & - bond_first_jne, & - bond_second_ine, & - bond_second_jne ) + first_berg_num, & + other_berg_num, & + first_berg_ine, & + first_berg_jne, & + other_berg_ine, & + other_berg_jne ) endif end subroutine read_restart_bonds ! ############################################################################## From 1bb0ff17fd78d73cbe034c7b87e2b5755c131d01 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 25 Sep 2015 17:05:43 -0400 Subject: [PATCH 071/361] Written a submodule which reconnects bonds after bergs have been sent between processors. This seems to be working, but has not yet been tested properly. --- icebergs.F90 | 4 +++- icebergs_framework.F90 | 53 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 43f3610..2eab323 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -26,7 +26,7 @@ module ice_bergs use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer, bond use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell -use ice_bergs_framework, only: count_bonds, form_a_bond +use ice_bergs_framework, only: count_bonds, form_a_bond,connect_all_bonds use ice_bergs_framework, only: nclasses,old_bug_bilin use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list @@ -1322,7 +1322,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) call send_bergs_to_other_pes(bergs) + call connect_all_bonds(bergs) call update_halo_icebergs(bergs) + call connect_all_bonds(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 8df3610..2b93f6e 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -62,7 +62,7 @@ module ice_bergs_framework public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position public move_trajectory, move_all_trajectories -public form_a_bond +public form_a_bond, connect_all_bonds public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell, count_bonds public sum_mass,sum_heat,bilin,yearday,bergs_chksum public checksum_gridded @@ -2184,6 +2184,57 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth end subroutine form_a_bond ! ############################################################################# + +subroutine connect_all_bonds(bergs) +type(icebergs), pointer :: bergs +type(iceberg), pointer :: other_berg, berg +type(icebergs_gridded), pointer :: grd +integer :: grdi, grdj +type(bond) , pointer :: current_bond, other_berg_bond +logical :: bond_matched, missing_bond + +missing_bond=.false. + + ! For convenience + grd=>bergs%grd + + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + + !code to find parter bond goes here + if (.not.associated(current_bond%other_berg)) then + other_berg=>bergs%list(current_bond%other_berg_ine,current_bond%other_berg_jne)%first + do while (associated(current_bond)) ! loop over all bonds + bond_matched=.false. + if (other_berg%iceberg_num == current_bond%other_berg_num) then + current_bond%other_berg=>other_berg + other_berg=>null() + bond_matched=.true. + else + other_berg=>other_berg%next + endif + enddo + if (.not.bond_matched) then + if (berg%halo_berg .lt. 0.5) then + missing_bond=.true. + call error_mesg('diamonds, connect_all_bonds', 'A non halo bond is missing!!!', WARNING) + endif + endif + endif + + current_bond=>current_bond%next_bond + enddo + berg=>berg%next + enddo + enddo;enddo + + +end subroutine connect_all_bonds + + ! ############################################################################# subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) From d1d855550e065f9bb88f705db437cbc27f333150 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 29 Sep 2015 13:37:07 -0400 Subject: [PATCH 072/361] 1) Bonds quality control has been added to the code. This subrouting (inside count_bonds()) makes sure that all the bonds are connneted correctly. 2) Halos now update before bonds are formed, so that the bonds get formed correctly. The structure is now in place for bonds. We just need to add the bonding force. --- icebergs.F90 | 23 +++++++++-------- icebergs_framework.F90 | 57 ++++++++++++++++++++++++++++++------------ icebergs_io.F90 | 4 ++- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2eab323..d90ec41 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -85,6 +85,8 @@ subroutine icebergs_init(bergs, & real, dimension(:,:), intent(in), optional :: ocean_depth logical, intent(in), optional :: maskmap(:,:) logical, intent(in), optional :: fractional_area +integer :: nbonds +logical :: check_bond_quality integer :: stdlogunit, stderrunit @@ -119,6 +121,10 @@ subroutine icebergs_init(bergs, & else call read_restart_bonds(bergs,Time) endif + call update_halo_icebergs(bergs) + call connect_all_bonds(bergs) + check_bond_quality=.True. + call count_bonds(bergs, nbonds,check_bond_quality) endif end subroutine icebergs_init @@ -132,16 +138,11 @@ subroutine initialize_iceberg_bonds(bergs) type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd - - - real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg real :: r_dist_x, r_dist_y, r_dist integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner -integer :: nbonds -logical :: check_bond_quality ! For convenience @@ -177,11 +178,6 @@ subroutine initialize_iceberg_bonds(bergs) enddo ; enddo; !End of outer loop. - check_bond_quality=.True. - call count_bonds(bergs, nbonds,check_bond_quality) - - - end subroutine initialize_iceberg_bonds ! ############################################################################## @@ -1132,12 +1128,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd -logical :: lerr, sample_traj, write_traj, lbudget, lverbose +logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger +integer :: nbonds integer :: stderrunit @@ -1549,6 +1546,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%berg_melt=0. bergs%bergy_melt=0. bergs%bergy_src=0. + + check_bond_quality=.true. + call count_bonds(bergs, nbonds,check_bond_quality) + if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect: ',check_bond_quality endif if (debug) call bergs_chksum(bergs, 'run bergs (bot)') diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 2b93f6e..e00df91 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2191,7 +2191,8 @@ subroutine connect_all_bonds(bergs) type(icebergs_gridded), pointer :: grd integer :: grdi, grdj type(bond) , pointer :: current_bond, other_berg_bond -logical :: bond_matched, missing_bond +logical :: bond_matched, missing_bond, check_bond_quality +integer nbonds missing_bond=.false. @@ -2207,7 +2208,7 @@ subroutine connect_all_bonds(bergs) !code to find parter bond goes here if (.not.associated(current_bond%other_berg)) then other_berg=>bergs%list(current_bond%other_berg_ine,current_bond%other_berg_jne)%first - do while (associated(current_bond)) ! loop over all bonds + do while (associated(other_berg)) ! loop over all other bergs bond_matched=.false. if (other_berg%iceberg_num == current_bond%other_berg_num) then current_bond%other_berg=>other_berg @@ -2231,6 +2232,10 @@ subroutine connect_all_bonds(bergs) enddo enddo;enddo + if (debug) then + check_bond_quality=.true. + call count_bonds(bergs, nbonds,check_bond_quality) + endif end subroutine connect_all_bonds @@ -2248,15 +2253,19 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) integer :: number_of_bonds_all_pe integer :: grdi, grdj logical :: bond_is_good -logical, optional :: check_bond_quality +logical, intent(inout), optional :: check_bond_quality logical :: quality_check -logical :: all_bonds_matching +integer :: num_unmatched_bonds,num_unmatched_bonds_all_pe +integer :: num_unassosiated_bond_pairs, num_unassosiated_bond_pairs_all_pe integer :: stderrunit - print *, "starting bond_check" +! print *, "starting bond_check" + stderrunit = stderr() quality_check=.false. - all_bonds_matching=.True. if(present(check_bond_quality)) quality_check = check_bond_quality + check_bond_quality=.false. + num_unmatched_bonds=0 + num_unassosiated_bond_pairs=0 ! For convenience grd=>bergs%grd @@ -2272,7 +2281,8 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) ! ##### Beginning Quality Check on Bonds ###### if (quality_check) then - all_bonds_matching=.True. + num_unmatched_bonds=0 + num_unassosiated_bond_pairs=0 bond_is_good=.False. other_berg=>current_bond%other_berg if (associated(other_berg)) then @@ -2292,14 +2302,14 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) enddo ! End of loop over the other berg's bonds. if (bond_is_good) then - print*, 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num + !if (debug) write(stderrunit,*) 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num else - print*, 'Non-matching bond...:', berg%iceberg_num, current_bond%other_berg_num - all_bonds_matching=.false. + if (debug) write(stderrunit,*) 'Non-matching bond...:', berg%iceberg_num, current_bond%other_berg_num + num_unmatched_bonds=num_unmatched_bonds+1 endif else - print *, 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%other_berg%iceberg_num - all_bonds_matching=.false. + if (debug) write(stderrunit,*) 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%other_berg%iceberg_num + num_unassosiated_bond_pairs=0 endif endif ! ##### Ending Quality Check on Bonds ###### @@ -2319,14 +2329,29 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) endif if (quality_check) then - if (.not.all_bonds_matching) then - stderrunit = stderr() - write(stderrunit,*) 'diamonds, Bonds are not matching!!!! PE=',mpp_pe() + num_unmatched_bonds_all_pe=num_unmatched_bonds + num_unassosiated_bond_pairs_all_pe = num_unassosiated_bond_pairs + call mpp_sum(num_unmatched_bonds_all_pe) + call mpp_sum(num_unassosiated_bond_pairs_all_pe) + + if (num_unmatched_bonds_all_pe .gt. 0) then call error_mesg('diamonds, bonds', 'Bonds are not matching!', FATAL) endif + if (num_unassosiated_bond_pairs_all_pe .ne. 0) then + call error_mesg('diamonds, bonds', 'Bonds partners not located!', Warning) + if (num_unassosiated_bond_pairs .ne. 0) then + write(*,'(2a)') 'diamonds, Bonds parnters not located!!!! PE=', mpp_pe() + endif + endif + if ((num_unmatched_bonds_all_pe == 0) .and. (num_unassosiated_bond_pairs_all_pe == 0)) then + if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds: All iceberg bonds are connected and working well.' + check_bond_quality=.true. + else + if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds: Warning, Broken Bonds! ' + endif endif - print *, "ending bond_check" +! print *, "ending bond_check" end subroutine count_bonds diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 9b6d4e0..b3b2c52 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -110,6 +110,7 @@ subroutine write_restart(bergs) type(restart_file_type) :: bergs_restart type(restart_file_type) :: bergs_bond_restart integer :: nbergs, nbonds +logical :: check_bond_quality type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & lat, & @@ -319,7 +320,8 @@ subroutine write_restart(bergs) !Allocating restart memory for bond related variables. nbonds=0 if (bergs%iceberg_bonds_on) then - call count_bonds(bergs, nbonds) + check_bond_quality=.true. + call count_bonds(bergs, nbonds,check_bond_quality) endif allocate(first_berg_num(nbonds)) From 25885a5cdaf6936c131480fa13b6e27b7e102e8c Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 29 Sep 2015 15:07:43 -0400 Subject: [PATCH 073/361] Added bond interactions. The bond interactions only take place is the distance between the two icebergs is greater than R1+R2. At the moment, this is a spring force, which does not depend on the mass of the icebergs. This requires that all bonds are broken before the iceberg becomes very small, or else the berg will become unstable. This should be revisited. The iceberg bond interactions have not been tested yet. Before testing I need to find the bug in the verlet code. --- icebergs.F90 | 169 +++++++++++++++++++++++++---------------- icebergs_framework.F90 | 7 +- 2 files changed, 107 insertions(+), 69 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d90ec41..a24e5d8 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -186,6 +186,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i type(icebergs), pointer :: bergs type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg +type(bond), pointer :: current_bond real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg real :: r_dist_x, r_dist_y, r_dist, A_o, trapped, T_min @@ -194,18 +195,21 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real :: u2, v2 real :: Rearth logical :: critical_interaction_damping_on -real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef +real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y integer :: stderrunit integer :: grdi, grdj - +logical :: iceberg_bonds_on Rearth=6360.e3 !spring_coef=1.e-4 spring_coef=bergs%spring_coef +bond_coef=bergs%bond_coef radial_damping_coef=bergs%radial_damping_coef tangental_damping_coef=bergs%tangental_damping_coef critical_interaction_damping_on=bergs%critical_interaction_damping_on +iceberg_bonds_on=bergs%iceberg_bonds_on + !Using critical values for damping rather than manually setting the damping. if (critical_interaction_damping_on) then @@ -255,78 +259,109 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !Calculating spring force (later this should only be done on the first time around) accel_spring=spring_coef*(T_min/T1)*(A_o/A1) if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then - IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) - IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - - - !Working out the damping - - !Paralel velocity - P_11=(r_dist_x*r_dist_x)/(r_dist**2) - P_12=(r_dist_x*r_dist_y)/(r_dist**2) - P_21=(r_dist_x*r_dist_y)/(r_dist**2) - P_22=(r_dist_y*r_dist_y)/(r_dist**2) - p_ia_coef=radial_damping_coef*(T_min/T1)*(A_o/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - - !Normal velocities - P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_o/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2))+sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - -!print *, 'P_11',P_11 -!print *, 'P_21',P_21 -!print *, 'P_12',P_12 -!print *, 'P_22',P_22 + IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) + IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) + + + !Working out the damping + + !Paralel velocity + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_21=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + p_ia_coef=radial_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 + p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + !print *, 'P_11',P_11 + !print *, 'P_21',P_21 + !print *, 'P_12',P_12 + !print *, 'P_22',P_22 + endif endif - endif - other_berg=>other_berg%next - enddo ! loop over all bergs -enddo ; enddo + other_berg=>other_berg%next + enddo ! loop over all bergs + enddo ; enddo - contains + !Interactions due to iceberg bonds + if (iceberg_bonds_on) then ! MP1 + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + other_berg=>current_bond%other_berg + if (.not. associated(current_bond)) then + call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) + else + L2=other_berg%length + W2=other_berg%width + !T2=other_berg%thickness ! Note, that it is not dependent on thickness This means that it might go unstable for small icebergs + !u2=other_berg%uvel_old + !v2=other_berg%vvel_old + A2=L2*W2 + R2=sqrt(A2/pi) ! Interaction radius of the other iceberg + lon2=other_berg%lon_old; lat2=other_berg%lat_old + call rotpos_to_tang(lon2,lat2,x2,y2) + r_dist_x=x1-x2 ; r_dist_y=y1-y2 + r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - subroutine overlap_area(R1,R2,d,A,trapped) - real, intent(in) :: R1, R2, d - real, intent(out) :: A, Trapped - real :: R1_sq, R2_sq, d_sq - R1_sq=R1**2 - R2_sq=R2**2 - d_sq=d**2 - Trapped=0. - -if (d>0.) then - if (d<(R1+R2)) then - if (d>abs(R1-R2)) then - A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) - else - A=min(pi*R1_sq,pi*R2_sq) - Trapped=1. - endif - else - A=0. - endif -else - A=0. ! No area of perfectly overlapping bergs (ie: a berg interacting with itself) -endif + ! Think about doing bonds using an "inverse overlap area, or some type" + if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then + accel_spring=bond_coef*(r_dist-(R1+R2)) + IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) + IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) + endif !Note, no damping on bond force has been added yet + endif + current_bond=>current_bond%next_bond + enddo + endif - end subroutine overlap_area + contains + subroutine overlap_area(R1,R2,d,A,trapped) + real, intent(in) :: R1, R2, d + real, intent(out) :: A, Trapped + real :: R1_sq, R2_sq, d_sq + R1_sq=R1**2 + R2_sq=R2**2 + d_sq=d**2 + Trapped=0. + + if (d>0.) then + if (d<(R1+R2)) then + if (d>abs(R1-R2)) then + A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) + else + A=min(pi*R1_sq,pi*R2_sq) + Trapped=1. + endif + else + A=0. + endif + else + A=0. ! No area of perfectly overlapping bergs (ie: a berg interacting with itself) + endif + end subroutine overlap_area end subroutine interactive_force diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e00df91..c360657 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -189,7 +189,8 @@ module ice_bergs_framework integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers integer :: clock_trw, clock_trp real :: rho_bergs ! Density of icebergs [kg/m^3] - real :: spring_coef ! Spring contant for iceberg interactions - Alon + real :: spring_coef ! Spring contant for iceberg interactions + real :: bond_coef ! Spring contant for iceberg bonds real :: radial_damping_coef ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs @@ -293,6 +294,7 @@ subroutine ice_bergs_framework_init(bergs, & integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs real :: spring_coef=1.e-4 ! Spring contant for iceberg interactions - Alon +real :: bond_coef=100000.0 ! Spring contant for iceberg bonds - Alon real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs @@ -317,7 +319,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, & - distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & + distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & @@ -586,6 +588,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%grd%iceberg_halo=iceberg_halo bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef + bergs%bond_coef=bond_coef bergs%radial_damping_coef=radial_damping_coef bergs%tangental_damping_coef=tangental_damping_coef bergs%LoW_ratio=LoW_ratio From dfa63240e3ce7e3f1a1c0e72607953e056a843da Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 30 Sep 2015 10:40:49 -0400 Subject: [PATCH 074/361] Not too many changes. But want to change branches now. --- icebergs.F90 | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d8326b9..024c301 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -290,7 +290,7 @@ end subroutine interactive_force ! ############################################################################## -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon MP1 !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments type(icebergs), pointer :: bergs @@ -2200,7 +2200,7 @@ subroutine evolve_icebergs(bergs) axn=berg%axn; ayn=berg%ayn !Alon bxn=berg%bxn; byn=berg%byn !Alon - +print *, 'first', axn, bxn, lon1, lat1, uvel1, i, j ,xi, yj ! Velocities used to update the position uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon @@ -2219,7 +2219,7 @@ subroutine evolve_icebergs(bergs) endif dxdln=r180_pi/(Rearth*cos(latn*pi_180)) -! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) +! Turn the velocities into u_star, v_star.(uvel3 is v_star) uvel3=uvel1+(dt_2*axn) !Alon vvel3=vvel1+(dt_2*ayn) !Alon @@ -2228,14 +2228,25 @@ subroutine evolve_icebergs(bergs) i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" ! call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + +if (bounced) then !This is the case when the iceberg changes direction due to topography + axn=0. + ayn=0. + bxn=0. + byn=0. +endif + + i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) +print *, 'second', axn, bxn, lon1, lat1, uvel1, i , j , xi, yj !Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon +print *, 'third', axn, bxn, lon1, lat1, uvel1, i, j, xi, yj !Solving for the new velocity if (on_tangential_plane) then call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) @@ -2249,6 +2260,7 @@ subroutine evolve_icebergs(bergs) uveln=uvel4 vveln=vvel4 +print *, 'forth', axn, bxn, lon1, lat1, uvel1, i, j, xi, yj, uveln !Debugging if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. @@ -2299,6 +2311,7 @@ subroutine evolve_icebergs(bergs) endif +print *, 'fifth', axn, bxn, lon1, lat1, uvel1, i, j, xi, yj, uveln endif ! End of the Verlet Stepiing -added by Alon !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! From 8eac08b5b695bceeceb0aff584df65d738fee1e7 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 30 Sep 2015 10:56:37 -0400 Subject: [PATCH 075/361] Two small changes to the verlet algorithm 1) lon1 changed to lonn. This was a typo from before 2) After iceberg is bounced in the Verlet algorithm, the acceleration and velocity is set to zero. This has not been done for the RK algorithm because I do not want to change the answers. --- icebergs.F90 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index a24e5d8..2925127 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2326,7 +2326,16 @@ subroutine evolve_icebergs(bergs) ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" - ! call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + + ! If the iceberg bounces off the land, then its velocity and acceleration are set to zero + if (bounced) then + axn=0. ; ayn=0. + bxn=0. ; byn=0. + uvel3=0.; vvel3=0. + uvel1=0.; vvel1=0. + endif + i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) @@ -2338,7 +2347,7 @@ subroutine evolve_icebergs(bergs) !Solving for the new velocity if (on_tangential_plane) then call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) - call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) else From f2b98720ceac8b66d8b58c4a04bfd3d1c55b79b7 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 30 Sep 2015 12:00:43 -0400 Subject: [PATCH 076/361] lat_old, lon_old, uvel_old, vvel_old do not need to be passed between processors, or passed to the IO. I have removed these, which should speed things up a little. I have also changed buffer_width so that it is no longer a parameter. This allows us to define buffer_width in terms of the namelist variable max_bonds. This assigns the correct amount of memory for passing bonds. At a later stage we will perhaps adjust the size of the buffer depending on the amount of bonds. --- icebergs_framework.F90 | 53 +++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index c360657..704b8fe 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,8 +15,9 @@ module ice_bergs_framework implicit none ; private -integer, parameter :: buffer_width=30 !Changed from 20 to 30 by Alon -integer, parameter :: buffer_width_traj=33 !Changed from 23 by Alon +integer :: buffer_width=26 !Changed from 20 to 26 by Alon +!integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon +integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -575,9 +576,12 @@ subroutine ice_bergs_framework_init(bergs, & endif if (.not. iceberg_bonds_on) then max_bonds=0 +else + buffer_width=buffer_width+(max_bonds*3) ! Increase buffer width to include bonds being passed between processors endif + ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs @@ -1384,15 +1388,11 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) buff%data(22,n)=berg%ayn !Alon buff%data(23,n)=berg%bxn !Alon buff%data(24,n)=berg%byn !Alon - buff%data(25,n)=berg%uvel_old !Alon - buff%data(26,n)=berg%vvel_old !Alon - buff%data(27,n)=berg%lon_old !Alon - buff%data(28,n)=berg%lat_old !Alon - buff%data(29,n)=float(berg%iceberg_num) - buff%data(30,n)=berg%halo_berg + buff%data(25,n)=float(berg%iceberg_num) + buff%data(26,n)=berg%halo_berg if (max_bonds .gt. 0) then - counter=30 !how many data points being passed so far (must match above) + counter=26 !how many data points being passed so far (must match above) do k = 1,max_bonds current_bond=>berg%first_bond if (associated(current_bond)) then @@ -1490,13 +1490,16 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%ayn=buff%data(22,n) !Alon localberg%bxn=buff%data(23,n) !Alon localberg%byn=buff%data(24,n) !Alon - localberg%uvel_old=buff%data(25,n) !Alon - localberg%vvel_old=buff%data(26,n) !Alon - localberg%lon_old=buff%data(27,n) !Alon - localberg%lat_old=buff%data(28,n) !Alon - localberg%iceberg_num=nint(buff%data(29,n)) - localberg%halo_berg=buff%data(30,n) - + localberg%iceberg_num=nint(buff%data(25,n)) + localberg%halo_berg=buff%data(26,n) + + !These quantities no longer need to be passed between processors + localberg%uvel_old=localberg%uvel + localberg%vvel_old=localberg%vvel + localberg%lon_old=localberg%lon + localberg%lat_old=localberg%lat + + if(force_app) then !force append with origin ine,jne (for I/O) localberg%ine=buff%data(19,n) @@ -1536,7 +1539,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ !# Do stuff to do with bonds here MP1 if (max_bonds .gt. 0) then - counter=30 !how many data points being passed so far (must match above) + counter=26 !how many data points being passed so far (must match above) do k = 1,max_bonds other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) @@ -1684,12 +1687,8 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(25,n)=traj%ayn !Alon buff%data(26,n)=traj%bxn !Alon buff%data(27,n)=traj%byn !Alon - buff%data(28,n)=traj%uvel_old !Alon - buff%data(29,n)=traj%vvel_old !Alon - buff%data(30,n)=traj%lon_old !Alon - buff%data(31,n)=traj%lat_old !Alon - buff%data(32,n)=float(traj%iceberg_num) - buff%data(33,n)=traj%halo_berg !Alon + buff%data(28,n)=float(traj%iceberg_num) + buff%data(29,n)=traj%halo_berg !Alon end subroutine pack_traj_into_buffer2 @@ -1731,12 +1730,8 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%ayn=buff%data(25,n) !Alon traj%bxn=buff%data(26,n) !Alon traj%byn=buff%data(27,n) !Alon - traj%uvel_old=buff%data(28,n) !Alon - traj%vvel_old=buff%data(29,n) !Alon - traj%lon_old=buff%data(30,n) !Alon - traj%lat_old=buff%data(31,n) !Alon - traj%iceberg_num=nint(buff%data(32,n)) - traj%halo_berg=buff%data(33,n) !Alon + traj%iceberg_num=nint(buff%data(28,n)) + traj%halo_berg=buff%data(29,n) !Alon call append_posn(first, traj) From 2a5141f5701451294a87856e1ae4c098cb526927 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 30 Sep 2015 13:31:46 -0400 Subject: [PATCH 077/361] Iceberg bond health is only checked if iceberg bonds are active. --- icebergs.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2925127..c7b93e6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1582,9 +1582,11 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%bergy_melt=0. bergs%bergy_src=0. - check_bond_quality=.true. - call count_bonds(bergs, nbonds,check_bond_quality) - if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect: ',check_bond_quality + if (bergs%iceberg_bonds_on) then + check_bond_quality=.true. + call count_bonds(bergs, nbonds,check_bond_quality) + if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect: ',check_bond_quality + endif endif if (debug) call bergs_chksum(bergs, 'run bergs (bot)') From 7ed59dddc5c9122d7812d6dacb110d18af599443 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 30 Sep 2015 15:21:50 -0400 Subject: [PATCH 078/361] Added a namelist flag called save_short_traj (default to true). When this is true, the iceberg_trajectory.nc file only keeps the lat, lon, day, year, iceberg_num. This reduces the amount of time spent on writing this file, which may allow us to keep the trajectory files during long simulations. --- icebergs.F90 | 4 +- icebergs_framework.F90 | 121 +++++++++++++----------- icebergs_io.F90 | 205 +++++++++++++++++++++-------------------- 3 files changed, 174 insertions(+), 156 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c7b93e6..598f25b 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1373,7 +1373,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (sample_traj) call record_posn(bergs) if (write_traj) then call move_all_trajectories(bergs) - call write_trajectory(bergs%trajectories) + call write_trajectory(bergs%trajectories, bergs%save_short_traj) endif ! Gridded diagnostics @@ -2807,7 +2807,7 @@ subroutine icebergs_end(bergs) ! Delete bergs and structures call move_all_trajectories(bergs, delete_bergs=.true.) - call write_trajectory(bergs%trajectories) + call write_trajectory(bergs%trajectories, bergs%save_short_traj) deallocate(bergs%grd%lon) deallocate(bergs%grd%lat) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 704b8fe..076eba4 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -16,8 +16,9 @@ module ice_bergs_framework implicit none ; private integer :: buffer_width=26 !Changed from 20 to 26 by Alon +integer :: buffer_width_traj=29 !Changed from 23 by Alon !integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon -integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon +!integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars @@ -205,6 +206,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon @@ -308,6 +310,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon @@ -319,7 +322,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, & +namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & @@ -579,13 +582,14 @@ subroutine ice_bergs_framework_init(bergs, & else buffer_width=buffer_width+(max_bonds*3) ! Increase buffer width to include bonds being passed between processors endif - +if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs bergs%traj_write_hrs=traj_write_hrs + bergs%save_short_traj=save_short_traj bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo bergs%max_bonds=max_bonds @@ -1650,11 +1654,12 @@ subroutine increase_buffer_traj(old,delta) end subroutine increase_buffer_traj - subroutine pack_traj_into_buffer2(traj, buff, n) + subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) ! Arguments type(xyt), pointer :: traj type(buffer), pointer :: buff integer, intent(in) :: n + logical, intent(in) :: save_short_traj ! Local variables if (.not.associated(buff)) call increase_buffer_traj(buff,delta_buf) @@ -1664,35 +1669,37 @@ subroutine pack_traj_into_buffer2(traj, buff, n) buff%data(2,n)=traj%lat buff%data(3,n)=float(traj%year) buff%data(4,n)=traj%day - buff%data(5,n)=traj%uvel - buff%data(6,n)=traj%vvel - buff%data(7,n)=traj%mass - buff%data(8,n)=traj%mass_of_bits - buff%data(9,n)=traj%heat_density - buff%data(10,n)=traj%thickness - buff%data(11,n)=traj%width - buff%data(12,n)=traj%length - buff%data(13,n)=traj%uo - buff%data(14,n)=traj%vo - buff%data(15,n)=traj%ui - buff%data(16,n)=traj%vi - buff%data(17,n)=traj%ua - buff%data(18,n)=traj%va - buff%data(19,n)=traj%ssh_x - buff%data(20,n)=traj%ssh_y - buff%data(21,n)=traj%sst - buff%data(22,n)=traj%cn - buff%data(23,n)=traj%hi - buff%data(24,n)=traj%axn !Alon - buff%data(25,n)=traj%ayn !Alon - buff%data(26,n)=traj%bxn !Alon - buff%data(27,n)=traj%byn !Alon - buff%data(28,n)=float(traj%iceberg_num) - buff%data(29,n)=traj%halo_berg !Alon + buff%data(5,n)=float(traj%iceberg_num) + if (.not. save_short_traj) then + buff%data(6,n)=traj%uvel + buff%data(7,n)=traj%vvel + buff%data(8,n)=traj%mass + buff%data(9,n)=traj%mass_of_bits + buff%data(10,n)=traj%heat_density + buff%data(11,n)=traj%thickness + buff%data(12,n)=traj%width + buff%data(13,n)=traj%length + buff%data(14,n)=traj%uo + buff%data(15,n)=traj%vo + buff%data(16,n)=traj%ui + buff%data(17,n)=traj%vi + buff%data(18,n)=traj%ua + buff%data(19,n)=traj%va + buff%data(20,n)=traj%ssh_x + buff%data(21,n)=traj%ssh_y + buff%data(22,n)=traj%sst + buff%data(23,n)=traj%cn + buff%data(24,n)=traj%hi + buff%data(25,n)=traj%axn !Alon + buff%data(26,n)=traj%ayn !Alon + buff%data(27,n)=traj%bxn !Alon + buff%data(28,n)=traj%byn !Alon + buff%data(29,n)=traj%halo_berg !Alon + endif end subroutine pack_traj_into_buffer2 - subroutine unpack_traj_from_buffer2(first, buff, n) + subroutine unpack_traj_from_buffer2(first, buff, n, save_short_traj) ! Arguments type(xyt), pointer :: first type(buffer), pointer :: buff @@ -1700,6 +1707,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n) ! Local variables type(xyt) :: traj integer :: stderrunit + logical, intent(in) :: save_short_traj ! Get the stderr unit number stderrunit = stderr() @@ -1707,32 +1715,33 @@ subroutine unpack_traj_from_buffer2(first, buff, n) traj%lat=buff%data(2,n) traj%year=nint(buff%data(3,n)) traj%day=buff%data(4,n) - traj%uvel=buff%data(5,n) - traj%vvel=buff%data(6,n) - traj%mass=buff%data(7,n) - traj%mass_of_bits=buff%data(8,n) - traj%heat_density=buff%data(9,n) - traj%thickness=buff%data(10,n) - traj%width=buff%data(11,n) - traj%length=buff%data(12,n) - traj%uo=buff%data(13,n) - traj%vo=buff%data(14,n) - traj%ui=buff%data(15,n) - traj%vi=buff%data(16,n) - traj%ua=buff%data(17,n) - traj%va=buff%data(18,n) - traj%ssh_x=buff%data(19,n) - traj%ssh_y=buff%data(20,n) - traj%sst=buff%data(21,n) - traj%cn=buff%data(22,n) - traj%hi=buff%data(23,n) - traj%axn=buff%data(24,n) !Alon - traj%ayn=buff%data(25,n) !Alon - traj%bxn=buff%data(26,n) !Alon - traj%byn=buff%data(27,n) !Alon - traj%iceberg_num=nint(buff%data(28,n)) - traj%halo_berg=buff%data(29,n) !Alon - + traj%iceberg_num=nint(buff%data(5,n)) + if (.not. save_short_traj) then + traj%uvel=buff%data(6,n) + traj%vvel=buff%data(7,n) + traj%mass=buff%data(8,n) + traj%mass_of_bits=buff%data(9,n) + traj%heat_density=buff%data(10,n) + traj%thickness=buff%data(11,n) + traj%width=buff%data(12,n) + traj%length=buff%data(13,n) + traj%uo=buff%data(14,n) + traj%vo=buff%data(15,n) + traj%ui=buff%data(16,n) + traj%vi=buff%data(17,n) + traj%ua=buff%data(18,n) + traj%va=buff%data(19,n) + traj%ssh_x=buff%data(20,n) + traj%ssh_y=buff%data(21,n) + traj%sst=buff%data(22,n) + traj%cn=buff%data(23,n) + traj%hi=buff%data(24,n) + traj%axn=buff%data(25,n) !Alon + traj%ayn=buff%data(26,n) !Alon + traj%bxn=buff%data(27,n) !Alon + traj%byn=buff%data(28,n) !Alon + traj%halo_berg=buff%data(29,n) !Alon + endif call append_posn(first, traj) end subroutine unpack_traj_from_buffer2 diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b3b2c52..d7ec695 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1286,7 +1286,7 @@ end subroutine read_restart_calving ! ############################################################################## -subroutine write_trajectory(trajectory) +subroutine write_trajectory(trajectory, save_short_traj) ! Arguments type(xyt), pointer :: trajectory ! Local variables @@ -1300,7 +1300,7 @@ subroutine write_trajectory(trajectory) character(len=7) :: pe_name type(xyt), pointer :: this, next integer :: stderrunit - +logical, intent(in) :: save_short_traj !I/O vars type(xyt), pointer :: traj4io=>null() integer :: ntrajs_sent_io,ntrajs_rcvd_io @@ -1344,7 +1344,7 @@ subroutine write_trajectory(trajectory) call increase_ibuffer_traj(ibuffer_io, ntrajs_rcvd_io) call mpp_recv(ibuffer_io%data, ntrajs_rcvd_io*buffer_width_traj,from_pe=from_pe, tag=COMM_TAG_12) do i=1, ntrajs_rcvd_io - call unpack_traj_from_buffer2(traj4io, ibuffer_io, i) + call unpack_traj_from_buffer2(traj4io, ibuffer_io, i, save_short_traj) enddo endif enddo @@ -1352,7 +1352,7 @@ subroutine write_trajectory(trajectory) ! Pack and send trajectories to the root PE for this I/O tile do while (associated(trajectory)) ntrajs_sent_io = ntrajs_sent_io +1 - call pack_traj_into_buffer2(trajectory, obuffer_io, ntrajs_sent_io) + call pack_traj_into_buffer2(trajectory, obuffer_io, ntrajs_sent_io, save_short_traj) this => trajectory ! Need to keep pointer in order to free up the links memory trajectory => trajectory%next ! This will eventually result in trajectory => null() deallocate(this) ! Delete the link from memory @@ -1412,26 +1412,28 @@ subroutine write_trajectory(trajectory) latid = inq_varid(ncid, 'lat') yearid = inq_varid(ncid, 'year') dayid = inq_varid(ncid, 'day') - uvelid = inq_varid(ncid, 'uvel') - vvelid = inq_varid(ncid, 'vvel') - uoid = inq_varid(ncid, 'uo') - void = inq_varid(ncid, 'vo') - uiid = inq_varid(ncid, 'ui') - viid = inq_varid(ncid, 'vi') - uaid = inq_varid(ncid, 'ua') - vaid = inq_varid(ncid, 'va') - mid = inq_varid(ncid, 'mass') - mbid = inq_varid(ncid, 'mass_of_bits') - hdid = inq_varid(ncid, 'heat_density') - did = inq_varid(ncid, 'thickness') - wid = inq_varid(ncid, 'width') - lid = inq_varid(ncid, 'length') - sshxid = inq_varid(ncid, 'ssh_x') - sshyid = inq_varid(ncid, 'ssh_y') - sstid = inq_varid(ncid, 'sst') - cnid = inq_varid(ncid, 'cn') - hiid = inq_varid(ncid, 'hi') iceberg_numid = inq_varid(ncid, 'iceberg_num') + if (.not.save_short_traj) then + uvelid = inq_varid(ncid, 'uvel') + vvelid = inq_varid(ncid, 'vvel') + uoid = inq_varid(ncid, 'uo') + void = inq_varid(ncid, 'vo') + uiid = inq_varid(ncid, 'ui') + viid = inq_varid(ncid, 'vi') + uaid = inq_varid(ncid, 'ua') + vaid = inq_varid(ncid, 'va') + mid = inq_varid(ncid, 'mass') + mbid = inq_varid(ncid, 'mass_of_bits') + hdid = inq_varid(ncid, 'heat_density') + did = inq_varid(ncid, 'thickness') + wid = inq_varid(ncid, 'width') + lid = inq_varid(ncid, 'length') + sshxid = inq_varid(ncid, 'ssh_x') + sshyid = inq_varid(ncid, 'ssh_y') + sstid = inq_varid(ncid, 'sst') + cnid = inq_varid(ncid, 'cn') + hiid = inq_varid(ncid, 'hi') + endif else ! Dimensions iret = nf_def_dim(ncid, 'i', NF_UNLIMITED, i_dim) @@ -1442,26 +1444,28 @@ subroutine write_trajectory(trajectory) latid = def_var(ncid, 'lat', NF_DOUBLE, i_dim) yearid = def_var(ncid, 'year', NF_INT, i_dim) dayid = def_var(ncid, 'day', NF_DOUBLE, i_dim) - uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) - vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) - uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) - void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) - uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) - viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) - uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) - vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) - mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) - mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) - hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) - did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) - wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) - lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) - sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) - sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) - sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) - cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) - hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) iceberg_numid = def_var(ncid, 'iceberg_num', NF_INT, i_dim) + if (.not. save_short_traj) then + uvelid = def_var(ncid, 'uvel', NF_DOUBLE, i_dim) + vvelid = def_var(ncid, 'vvel', NF_DOUBLE, i_dim) + uoid = def_var(ncid, 'uo', NF_DOUBLE, i_dim) + void = def_var(ncid, 'vo', NF_DOUBLE, i_dim) + uiid = def_var(ncid, 'ui', NF_DOUBLE, i_dim) + viid = def_var(ncid, 'vi', NF_DOUBLE, i_dim) + uaid = def_var(ncid, 'ua', NF_DOUBLE, i_dim) + vaid = def_var(ncid, 'va', NF_DOUBLE, i_dim) + mid = def_var(ncid, 'mass', NF_DOUBLE, i_dim) + mbid = def_var(ncid, 'mass_of_bits', NF_DOUBLE, i_dim) + hdid = def_var(ncid, 'heat_density', NF_DOUBLE, i_dim) + did = def_var(ncid, 'thickness', NF_DOUBLE, i_dim) + wid = def_var(ncid, 'width', NF_DOUBLE, i_dim) + lid = def_var(ncid, 'length', NF_DOUBLE, i_dim) + sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) + sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) + sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) + cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) + hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) + endif ! Attributes iret = nf_put_att_int(ncid, NCGLOBAL, 'file_format_major_version', NF_INT, 1, 0) @@ -1474,46 +1478,49 @@ subroutine write_trajectory(trajectory) call put_att(ncid, yearid, 'units', 'years') call put_att(ncid, dayid, 'long_name', 'year day') call put_att(ncid, dayid, 'units', 'days') - call put_att(ncid, uvelid, 'long_name', 'zonal spped') - call put_att(ncid, uvelid, 'units', 'm/s') - call put_att(ncid, vvelid, 'long_name', 'meridional spped') - call put_att(ncid, vvelid, 'units', 'm/s') - call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') - call put_att(ncid, uoid, 'units', 'm/s') - call put_att(ncid, void, 'long_name', 'ocean meridional spped') - call put_att(ncid, void, 'units', 'm/s') - call put_att(ncid, uiid, 'long_name', 'ice zonal spped') - call put_att(ncid, uiid, 'units', 'm/s') - call put_att(ncid, viid, 'long_name', 'ice meridional spped') - call put_att(ncid, viid, 'units', 'm/s') - call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') - call put_att(ncid, uaid, 'units', 'm/s') - call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') - call put_att(ncid, vaid, 'units', 'm/s') - call put_att(ncid, mid, 'long_name', 'mass') - call put_att(ncid, mid, 'units', 'kg') - call put_att(ncid, mbid, 'long_name', 'mass_of_bits') - call put_att(ncid, mbid, 'units', 'kg') - call put_att(ncid, hdid, 'long_name', 'heat_density') - call put_att(ncid, hdid, 'units', 'J/kg') - call put_att(ncid, did, 'long_name', 'thickness') - call put_att(ncid, did, 'units', 'm') - call put_att(ncid, wid, 'long_name', 'width') - call put_att(ncid, wid, 'units', 'm') - call put_att(ncid, lid, 'long_name', 'length') - call put_att(ncid, lid, 'units', 'm') - call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') - call put_att(ncid, sshxid, 'units', 'non-dim') - call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') - call put_att(ncid, sshyid, 'units', 'non-dim') - call put_att(ncid, sstid, 'long_name', 'sea surface temperature') - call put_att(ncid, sstid, 'units', 'degrees_C') - call put_att(ncid, cnid, 'long_name', 'sea ice concentration') - call put_att(ncid, cnid, 'units', 'none') - call put_att(ncid, hiid, 'long_name', 'sea ice thickness') - call put_att(ncid, hiid, 'units', 'm') call put_att(ncid, iceberg_numid, 'long_name', 'iceberg id number') call put_att(ncid, iceberg_numid, 'units', 'dimensionless') + + if (.not. save_short_traj) then + call put_att(ncid, uvelid, 'long_name', 'zonal spped') + call put_att(ncid, uvelid, 'units', 'm/s') + call put_att(ncid, vvelid, 'long_name', 'meridional spped') + call put_att(ncid, vvelid, 'units', 'm/s') + call put_att(ncid, uoid, 'long_name', 'ocean zonal spped') + call put_att(ncid, uoid, 'units', 'm/s') + call put_att(ncid, void, 'long_name', 'ocean meridional spped') + call put_att(ncid, void, 'units', 'm/s') + call put_att(ncid, uiid, 'long_name', 'ice zonal spped') + call put_att(ncid, uiid, 'units', 'm/s') + call put_att(ncid, viid, 'long_name', 'ice meridional spped') + call put_att(ncid, viid, 'units', 'm/s') + call put_att(ncid, uaid, 'long_name', 'atmos zonal spped') + call put_att(ncid, uaid, 'units', 'm/s') + call put_att(ncid, vaid, 'long_name', 'atmos meridional spped') + call put_att(ncid, vaid, 'units', 'm/s') + call put_att(ncid, mid, 'long_name', 'mass') + call put_att(ncid, mid, 'units', 'kg') + call put_att(ncid, mbid, 'long_name', 'mass_of_bits') + call put_att(ncid, mbid, 'units', 'kg') + call put_att(ncid, hdid, 'long_name', 'heat_density') + call put_att(ncid, hdid, 'units', 'J/kg') + call put_att(ncid, did, 'long_name', 'thickness') + call put_att(ncid, did, 'units', 'm') + call put_att(ncid, wid, 'long_name', 'width') + call put_att(ncid, wid, 'units', 'm') + call put_att(ncid, lid, 'long_name', 'length') + call put_att(ncid, lid, 'units', 'm') + call put_att(ncid, sshxid, 'long_name', 'sea surface height gradient_x') + call put_att(ncid, sshxid, 'units', 'non-dim') + call put_att(ncid, sshyid, 'long_name', 'sea surface height gradient_y') + call put_att(ncid, sshyid, 'units', 'non-dim') + call put_att(ncid, sstid, 'long_name', 'sea surface temperature') + call put_att(ncid, sstid, 'units', 'degrees_C') + call put_att(ncid, cnid, 'long_name', 'sea ice concentration') + call put_att(ncid, cnid, 'units', 'none') + call put_att(ncid, hiid, 'long_name', 'sea ice thickness') + call put_att(ncid, hiid, 'units', 'm') + endif endif ! End define mode @@ -1533,25 +1540,27 @@ subroutine write_trajectory(trajectory) call put_double(ncid, latid, i, this%lat) call put_int(ncid, yearid, i, this%year) call put_double(ncid, dayid, i, this%day) - call put_double(ncid, uvelid, i, this%uvel) - call put_double(ncid, vvelid, i, this%vvel) - call put_double(ncid, uoid, i, this%uo) - call put_double(ncid, void, i, this%vo) - call put_double(ncid, uiid, i, this%ui) - call put_double(ncid, viid, i, this%vi) - call put_double(ncid, uaid, i, this%ua) - call put_double(ncid, vaid, i, this%va) - call put_double(ncid, mid, i, this%mass) - call put_double(ncid, hdid, i, this%heat_density) - call put_double(ncid, did, i, this%thickness) - call put_double(ncid, wid, i, this%width) - call put_double(ncid, lid, i, this%length) - call put_double(ncid, sshxid, i, this%ssh_x) - call put_double(ncid, sshyid, i, this%ssh_y) - call put_double(ncid, sstid, i, this%sst) - call put_double(ncid, cnid, i, this%cn) - call put_double(ncid, hiid, i, this%hi) call put_int(ncid, iceberg_numid, i, this%iceberg_num) + if (.not. save_short_traj) then + call put_double(ncid, uvelid, i, this%uvel) + call put_double(ncid, vvelid, i, this%vvel) + call put_double(ncid, uoid, i, this%uo) + call put_double(ncid, void, i, this%vo) + call put_double(ncid, uiid, i, this%ui) + call put_double(ncid, viid, i, this%vi) + call put_double(ncid, uaid, i, this%ua) + call put_double(ncid, vaid, i, this%va) + call put_double(ncid, mid, i, this%mass) + call put_double(ncid, hdid, i, this%heat_density) + call put_double(ncid, did, i, this%thickness) + call put_double(ncid, wid, i, this%width) + call put_double(ncid, lid, i, this%length) + call put_double(ncid, sshxid, i, this%ssh_x) + call put_double(ncid, sshyid, i, this%ssh_y) + call put_double(ncid, sstid, i, this%sst) + call put_double(ncid, cnid, i, this%cn) + call put_double(ncid, hiid, i, this%hi) + endif next=>this%next deallocate(this) this=>next From bca6646bd0c89c4cc94c0b12c90b85974d589136 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 1 Oct 2015 11:00:58 -0400 Subject: [PATCH 079/361] A few more changes to the iceberg interactions. Made bonding force proportional the mass so that it is more similar to the attractive force. Preliminary tests indicate that this is working, but much more testing is needed. Made a few other cosmetic changes. --- icebergs.F90 | 24 ++++++++++++++++++------ icebergs_framework.F90 | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 598f25b..eacf371 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -198,6 +198,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y +real :: L_dist integer :: stderrunit integer :: grdi, grdj logical :: iceberg_bonds_on @@ -313,7 +314,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i else L2=other_berg%length W2=other_berg%width - !T2=other_berg%thickness ! Note, that it is not dependent on thickness This means that it might go unstable for small icebergs + T2=other_berg%thickness ! Note, that it is not dependent on thickness This means that it might go unstable for small icebergs !u2=other_berg%uvel_old !v2=other_berg%vvel_old A2=L2*W2 @@ -325,10 +326,14 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) ! Think about doing bonds using an "inverse overlap area, or some type" - if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then - accel_spring=bond_coef*(r_dist-(R1+R2)) - IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) - IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) + if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then + L_dist = min( (r_dist-(R1+R2) ),min(R1,R2) ) + call overlap_area(R1,R2,L_dist,A_o,trapped) + T_min=min(T1,T2) + accel_spring=bond_coef*(T_min/T1)*(A_o/A1) + !accel_spring=bond_coef*(r_dist-(R1+R2)) + IA_x=IA_x-(accel_spring*(r_dist_x/r_dist)) !Note: negative sign is an attractive force. + IA_y=IA_y-(accel_spring*(r_dist_y/r_dist)) endif !Note, no damping on bond force has been added yet endif current_bond=>current_bond%next_bond @@ -1585,7 +1590,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%iceberg_bonds_on) then check_bond_quality=.true. call count_bonds(bergs, nbonds,check_bond_quality) - if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect: ',check_bond_quality + if (mpp_pe().eq.mpp_root_pe()) + if (check_bond_quality) then + write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect' + else + write(*,'(2a)') 'diamonds, Bond check complete. Bonds are not perfect' + endif endif endif @@ -2032,6 +2042,7 @@ subroutine evolve_icebergs(bergs) uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj + !print *, 'Alon: look here!', lon2, lat2, uvel2, vvel2, i, j, xi, yj call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & @@ -2327,6 +2338,7 @@ subroutine evolve_icebergs(bergs) ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj + !print *, 'Alon: look here!', lonn, latn, uvel3, vvel3, i, j, xi, yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 076eba4..e9e871c 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -297,7 +297,7 @@ subroutine ice_bergs_framework_init(bergs, & integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs real :: spring_coef=1.e-4 ! Spring contant for iceberg interactions - Alon -real :: bond_coef=100000.0 ! Spring contant for iceberg bonds - Alon +real :: bond_coef=1.e-4 ! Spring contant for iceberg bonds - Alon real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs From 47b51e96a41b5add01d11cc948dc36a7fc29caec Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 1 Oct 2015 18:02:08 -0400 Subject: [PATCH 080/361] A bug has been fixed. This bug was inside pack_icebergs_in_buffer, and had to do with the way the bonds were included in the buffer. (ie: the definition of current_bond was inside the loop and had to be moved outside). There is another bond related bug which is giving rise to a segmentation fault after 72 days of the model running with bonds on. I will find this tomorrow --- icebergs.F90 | 12 ++++++------ icebergs_framework.F90 | 44 ++++++++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index eacf371..3d29f17 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1590,12 +1590,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%iceberg_bonds_on) then check_bond_quality=.true. call count_bonds(bergs, nbonds,check_bond_quality) - if (mpp_pe().eq.mpp_root_pe()) - if (check_bond_quality) then - write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect' - else - write(*,'(2a)') 'diamonds, Bond check complete. Bonds are not perfect' - endif + !if (mpp_pe().eq.mpp_root_pe()) then + !if (check_bond_quality) then + ! write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect' + !else + ! write(*,'(2a)') 'diamonds, Bond check complete. Bonds are not perfect' + !endif endif endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e9e871c..7816a8a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1361,6 +1361,7 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) integer :: counter, k, max_bonds type(bond), pointer :: current_bond + !print *, 'Packing berg', berg%iceberg_num, mpp_pe(), berg%halo_berg max_bonds=0 if (present(max_bonds_in)) max_bonds=max_bonds_in @@ -1397,8 +1398,8 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) if (max_bonds .gt. 0) then counter=26 !how many data points being passed so far (must match above) + current_bond=>berg%first_bond do k = 1,max_bonds - current_bond=>berg%first_bond if (associated(current_bond)) then buff%data(counter+(3*(k-1)+1),n)=float(current_bond%other_berg_num) buff%data(counter+(3*(k-1)+2),n)=float(current_bond%other_berg_ine) @@ -1503,6 +1504,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%lon_old=localberg%lon localberg%lat_old=localberg%lat + !print *, 'Unpacking berg', localberg%iceberg_num, mpp_pe(), localberg%halo_berg if(force_app) then !force append with origin ine,jne (for I/O) @@ -1548,11 +1550,12 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) other_berg_jne=nint(buff%data(counter+(3*(k-1)+3),n)) - if (other_berg_num .gt. 0) then + if (other_berg_num .gt. 1) then call form_a_bond(this, other_berg_num, other_berg_ine, other_berg_jne) endif enddo endif + this=>null() !############################## @@ -2156,26 +2159,25 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth type(bond) , pointer :: new_bond, first_bond integer, intent(in) :: other_berg_num integer, optional :: other_berg_ine, other_berg_jne - -print *, 'Forming a bond!!!' - -! Step 1: Create a new bond -allocate(new_bond) -new_bond%other_berg_num=other_berg_num -if(present(other_berg)) then - new_bond%other_berg=>other_berg - new_bond%other_berg_ine=other_berg%ine - new_bond%other_berg_jne=other_berg%jne -else - new_bond%other_berg=>null() - if (present(other_berg_ine)) then - new_bond%other_berg_ine=other_berg_ine - new_bond%other_berg_jne=other_berg_jne +if (berg%iceberg_num .ne. other_berg_num) then + print *, 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg + ! Step 1: Create a new bond + allocate(new_bond) + new_bond%other_berg_num=other_berg_num + if(present(other_berg)) then + new_bond%other_berg=>other_berg + new_bond%other_berg_ine=other_berg%ine + new_bond%other_berg_jne=other_berg%jne + else + new_bond%other_berg=>null() + if (present(other_berg_ine)) then + new_bond%other_berg_ine=other_berg_ine + new_bond%other_berg_jne=other_berg_jne + endif endif -endif -! Step 2: Put this new bond at the start of the bond list + ! Step 2: Put this new bond at the start of the bond list first_bond=>berg%first_bond if (associated(first_bond)) then new_bond%next_bond=>first_bond @@ -2187,6 +2189,10 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth new_bond%prev_bond=>null() !This should not be needed berg%first_bond=>new_bond endif + new_bond=>null() + else + call error_mesg('diamonds, bonds', 'An iceberg is trying to bond with itself!!!', FATAL) + endif end subroutine form_a_bond From d114b9155900b51648a2c16f9e1840f8a37c3524 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 5 Oct 2015 16:54:00 -0400 Subject: [PATCH 081/361] A series of corrections have been made to the way that bonds are passed from processor to processor in order to get rid of segmentation faults. The bonds now seem to be working, although longer simulations are needed in order to properly debug the code. We have added: 1) Iceberg addresses are clear from bonds when the partner iceberg leaves the processor 2) Iceberg search for their bonded pairs in the 9 cells around the last known location 3) The subroutine show_all_bonds(bergs) displays all the bonds for debugging purposes 4) The subroutine bond_address_update, puts the last known address inside the bonds (this actually only has to be done for icebergs near the edge of a processor) --- icebergs.F90 | 21 +++-- icebergs_framework.F90 | 192 ++++++++++++++++++++++++++++++++++------- 2 files changed, 173 insertions(+), 40 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3d29f17..7f6dd8b 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -26,7 +26,7 @@ module ice_bergs use ice_bergs_framework, only: icebergs_gridded, xyt, iceberg, icebergs, buffer, bond use ice_bergs_framework, only: verbose, really_debug,debug,old_bug_rotated_weights,budget,use_roundoff_fix use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell -use ice_bergs_framework, only: count_bonds, form_a_bond,connect_all_bonds +use ice_bergs_framework, only: count_bonds, form_a_bond,connect_all_bonds,show_all_bonds, bond_address_update use ice_bergs_framework, only: nclasses,old_bug_bilin use ice_bergs_framework, only: sum_mass,sum_heat,bilin,yearday,count_bergs,bergs_chksum use ice_bergs_framework, only: checksum_gridded,add_new_berg_to_list @@ -124,6 +124,7 @@ subroutine icebergs_init(bergs, & call update_halo_icebergs(bergs) call connect_all_bonds(bergs) check_bond_quality=.True. + nbonds=0 call count_bonds(bergs, nbonds,check_bond_quality) endif @@ -1328,6 +1329,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call bergs_chksum(bergs, 'run bergs (top)') if (debug) call checksum_gridded(bergs%grd, 'top of s/r run') + ! Accumulate ice from calving call accumulate_calving(bergs) @@ -1356,12 +1358,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) + ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) + if (bergs%iceberg_bonds_on) call bond_address_update(bergs) call send_bergs_to_other_pes(bergs) - call connect_all_bonds(bergs) call update_halo_icebergs(bergs) - call connect_all_bonds(bergs) + if (bergs%iceberg_bonds_on) call connect_all_bonds(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) @@ -1373,6 +1376,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) + ! For each berg, record call mpp_clock_begin(bergs%clock_dia) if (sample_traj) call record_posn(bergs) @@ -1434,6 +1438,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Dump icebergs to screen if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_run, status') + + ! Dump icebergs bonds to screen + if (really_debug) call show_all_bonds(bergs) + call mpp_clock_end(bergs%clock_dia) ! Return what ever calving we did not use and additional icebergs melt @@ -1589,13 +1597,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%iceberg_bonds_on) then check_bond_quality=.true. + nbonds=0 call count_bonds(bergs, nbonds,check_bond_quality) - !if (mpp_pe().eq.mpp_root_pe()) then - !if (check_bond_quality) then - ! write(*,'(2a)') 'diamonds, Bond check complete. Bonds are perfect' - !else - ! write(*,'(2a)') 'diamonds, Bond check complete. Bonds are not perfect' - !endif endif endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 7816a8a..af6f023 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -64,7 +64,7 @@ module ice_bergs_framework public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position public move_trajectory, move_all_trajectories -public form_a_bond, connect_all_bonds +public form_a_bond, connect_all_bonds, show_all_bonds, bond_address_update public find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell, count_bonds public sum_mass,sum_heat,bilin,yearday,bergs_chksum public checksum_gridded @@ -724,10 +724,6 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_clock_end(bergs%clock_ini) call mpp_clock_end(bergs%clock) -!print *, mpp_pe(), 'Alon: global', grd%isg, grd%ieg, grd%jsg, grd%jeg -!print *, mpp_pe(), 'Alon: comp', grd%isc, grd%iec, grd%jsc, grd%jec -!print *, mpp_pe(), 'Alon: data', grd%isd, grd%ied, grd%jsd, grd%jed - end subroutine ice_bergs_framework_init ! ############################################################################## @@ -844,8 +840,6 @@ subroutine update_halo_icebergs(bergs) ! For convenience grd=>bergs%grd - - ! Step 1: Clear the current halos @@ -896,6 +890,7 @@ subroutine update_halo_icebergs(bergs) !Bergs on the western side of the processor do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%isc+halo_width-1 + this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -970,6 +965,7 @@ subroutine update_halo_icebergs(bergs) !Bergs on north side of the processor do grdj = grd%jec-halo_width+1,grd%jec ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -984,6 +980,7 @@ subroutine update_halo_icebergs(bergs) !Bergs on south side of the processor do grdj = grd%jsc,grd%jsc+halo_width-1 ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next @@ -1361,7 +1358,6 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) integer :: counter, k, max_bonds type(bond), pointer :: current_bond - !print *, 'Packing berg', berg%iceberg_num, mpp_pe(), berg%halo_berg max_bonds=0 if (present(max_bonds_in)) max_bonds=max_bonds_in @@ -1412,10 +1408,47 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) endif enddo endif - + + ! Clearing berg pointer from partner bonds + !if (berg%halo_berg .lt. 0.5) then + ! call clear_berg_from_partners_bonds(berg) + !endif end subroutine pack_berg_into_buffer2 + +!###########################################################################3 + + subroutine clear_berg_from_partners_bonds(berg) + !Arguments + type(iceberg), intent(in), pointer :: berg + type(iceberg), pointer :: other_berg + type(bond), pointer :: current_bond, matching_bond + + current_bond=>berg%first_bond + do while (associated(current_bond)) !Looping over bonds + other_berg=>current_bond%other_berg + if (associated(other_berg)) then + matching_bond=>other_berg%first_bond + do while (associated(matching_bond)) ! Looping over possible matching bonds in other_berg + if (matching_bond%other_berg_num .eq. berg%iceberg_num) then + matching_bond%other_berg=>null() + matching_bond=>null() + else + matching_bond=>matching_bond%next_bond + endif + enddo + else + ! Note: This is meant to be unmatched after you have cleared the first berg + ! call error_mesg('diamonds, clear berg from partners', 'The bond you are trying to clear is unmatched!', WARNING) + endif + current_bond=>current_bond%next_bond + enddo !End loop over bonds + + end subroutine clear_berg_from_partners_bonds + + + subroutine increase_buffer(old,delta) ! Arguments type(buffer), pointer :: old @@ -1504,8 +1537,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%lon_old=localberg%lon localberg%lat_old=localberg%lat - !print *, 'Unpacking berg', localberg%iceberg_num, mpp_pe(), localberg%halo_berg - + ! force_app=.true. if(force_app) then !force append with origin ine,jne (for I/O) localberg%ine=buff%data(19,n) @@ -1544,6 +1576,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ !# Do stuff to do with bonds here MP1 + this%first_bond=>null() if (max_bonds .gt. 0) then counter=26 !how many data points being passed so far (must match above) do k = 1,max_bonds @@ -1770,12 +1803,15 @@ subroutine add_new_berg_to_list(first, bergvals, quick, newberg_return) endif if (present(quick)) then - if(quick) call insert_berg_into_list(first, new, quick=.true.) + if(quick) then + call insert_berg_into_list(first, new, quick=.true.) + else + call insert_berg_into_list(first, new) + endif else call insert_berg_into_list(first, new) endif - !Clear new new=>null() @@ -2091,6 +2127,9 @@ subroutine destroy_iceberg(berg) type(iceberg), pointer :: berg ! Local variables + ! Clears all matching bonds before deallocint memory + call clear_berg_from_partners_bonds(berg) + ! Bye-bye berg deallocate(berg) @@ -2161,7 +2200,8 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth integer, optional :: other_berg_ine, other_berg_jne if (berg%iceberg_num .ne. other_berg_num) then - print *, 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg + !print *, 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg, berg%ine, berg%jne + ! Step 1: Create a new bond allocate(new_bond) new_bond%other_berg_num=other_berg_num @@ -2198,47 +2238,139 @@ end subroutine form_a_bond ! ############################################################################# +subroutine bond_address_update(bergs) +type(icebergs), pointer :: bergs +type(iceberg), pointer :: other_berg, berg +type(icebergs_gridded), pointer :: grd +integer :: grdi, grdj, nbonds +type(bond) , pointer :: current_bond + + ! For convenience + grd=>bergs%grd + + ! This could be done for only the bergs near the halos + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + if (associated(current_bond%other_berg)) then + current_bond%other_berg_ine=current_bond%other_berg%ine + current_bond%other_berg_jne=current_bond%other_berg%jne + current_bond=>current_bond%next_bond + else + if (berg%halo_berg .lt. 0.5) then + call error_mesg('diamonds, bond address update', 'other berg in bond not assosiated!', FATAL) + endif + current_bond=>current_bond%next_bond + endif + enddo + berg=>berg%next + enddo + enddo; enddo + + call mpp_sync_self() + +end subroutine bond_address_update + +!################################################################################################### + +subroutine show_all_bonds(bergs) +type(icebergs), pointer :: bergs +type(iceberg), pointer :: other_berg, berg +type(icebergs_gridded), pointer :: grd +integer :: grdi, grdj, nbonds +type(bond) , pointer :: current_bond + + ! For convenience + grd=>bergs%grd + + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + + print *, 'Show Bond1 :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine, current_bond%other_berg_jne, mpp_pe() + if (associated(current_bond%other_berg)) then + print *, 'Show Bond2 :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg%ine, current_bond%other_berg%jne, mpp_pe() + print *, 'Bond matching', current_bond%other_berg%iceberg_num, current_bond%other_berg_num, mpp_pe() + endif + current_bond=>current_bond%next_bond + enddo + berg=>berg%next + enddo + enddo; enddo + +end subroutine show_all_bonds + + subroutine connect_all_bonds(bergs) type(icebergs), pointer :: bergs type(iceberg), pointer :: other_berg, berg type(icebergs_gridded), pointer :: grd +integer :: i, j integer :: grdi, grdj +integer :: grdi_inner, grdj_inner type(bond) , pointer :: current_bond, other_berg_bond logical :: bond_matched, missing_bond, check_bond_quality integer nbonds missing_bond=.false. +bond_matched=.false. - ! For convenience +! For convenience grd=>bergs%grd do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied +! do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec ! Don't connect halo bergs berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds - !code to find parter bond goes here if (.not.associated(current_bond%other_berg)) then - other_berg=>bergs%list(current_bond%other_berg_ine,current_bond%other_berg_jne)%first + bond_matched=.false. + i = current_bond%other_berg_ine ; j = current_bond%other_berg_jne + other_berg=>bergs%list(i,j)%first do while (associated(other_berg)) ! loop over all other bergs - bond_matched=.false. if (other_berg%iceberg_num == current_bond%other_berg_num) then current_bond%other_berg=>other_berg other_berg=>null() - bond_matched=.true. + bond_matched=.true. else other_berg=>other_berg%next endif enddo if (.not.bond_matched) then - if (berg%halo_berg .lt. 0.5) then - missing_bond=.true. - call error_mesg('diamonds, connect_all_bonds', 'A non halo bond is missing!!!', WARNING) - endif + ! If you are stil not matched, then search adjacent cells + do grdj_inner = j-1,j+1 ; do grdi_inner = i-1,i+1 + if (.not. bond_matched) then + if ((grdj_inner .gt. grd%jsd-1) .and. (grdj_inner .lt. grd%jed+1) & + .and. (grdi_inner .gt. grd%isd-1) .and. (grdi_inner .lt. grd%ied+1) & + .and. ((grdi_inner .ne. i) .or. (grdj_inner .ne. j)) ) then + other_berg=>bergs%list(grdi_inner,grdj_inner)%first + do while (associated(other_berg)) ! loop over all other bergs + if (other_berg%iceberg_num == current_bond%other_berg_num) then + current_bond%other_berg=>other_berg + other_berg=>null() + bond_matched=.true. + else + other_berg=>other_berg%next + endif + enddo + endif + endif + enddo;enddo + endif + if (.not.bond_matched) then + if (berg%halo_berg .lt. 0.5) then + missing_bond=.true. + print * , berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine + call error_mesg('diamonds, connect_all_bonds', 'A non-halo bond is missing!!!', FATAL) + endif endif endif - current_bond=>current_bond%next_bond enddo berg=>berg%next @@ -2247,6 +2379,7 @@ subroutine connect_all_bonds(bergs) if (debug) then check_bond_quality=.true. + nbonds=0 call count_bonds(bergs, nbonds,check_bond_quality) endif @@ -2261,7 +2394,6 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd type(bond) , pointer :: current_bond, other_berg_bond -!integer, intent(out) :: number_of_bonds integer, intent(out) :: number_of_bonds integer :: number_of_bonds_all_pe integer :: grdi, grdj @@ -2284,7 +2416,6 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) grd=>bergs%grd number_of_bonds=0 ! This is a bond counter. - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs @@ -2293,6 +2424,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) number_of_bonds=number_of_bonds+1 ! ##### Beginning Quality Check on Bonds ###### +! print *, 'Quality check', mpp_pe(), berg%iceberg_num if (quality_check) then num_unmatched_bonds=0 num_unassosiated_bond_pairs=0 @@ -2301,7 +2433,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) if (associated(other_berg)) then other_berg_bond=>other_berg%first_bond - do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list + do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list if (associated(other_berg_bond%other_berg)) then if (other_berg_bond%other_berg%iceberg_num==berg%iceberg_num) then bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found @@ -2315,7 +2447,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) enddo ! End of loop over the other berg's bonds. if (bond_is_good) then - !if (debug) write(stderrunit,*) 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num + if (debug) write(stderrunit,*) 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num else if (debug) write(stderrunit,*) 'Non-matching bond...:', berg%iceberg_num, current_bond%other_berg_num num_unmatched_bonds=num_unmatched_bonds+1 @@ -2338,7 +2470,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's if (number_of_bonds .gt. 0) then - print *, "Number of bonds on pe, out of a total of: ", number_of_bonds, number_of_bonds_all_pe + print *, "Number of bonds on pe:", mpp_pe(), "out of a total of: ", number_of_bonds, number_of_bonds_all_pe endif if (quality_check) then @@ -2364,8 +2496,6 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) endif endif -! print *, "ending bond_check" - end subroutine count_bonds From ad09701241a512f84d6d54af652e119e41873feb Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 6 Oct 2015 11:15:01 -0400 Subject: [PATCH 082/361] Two bugs have been fixed: 1) The amount of memory allocated in berg_checksum has been corrected 2) IA_x and IA_y were not initialized correctly, which was causing errors sometimes. Both of these bugs have been fixed --- icebergs.F90 | 13 +++++++++---- icebergs_framework.F90 | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7f6dd8b..4b0a338 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -425,6 +425,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a use_new_predictive_corrective=.True. endif + !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon v_star=vvel0+(ayn*(dt/2.)) !Alon @@ -509,7 +510,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=bxn + IA_x byn=byn + IA_y endif -!print *,'IA_x=',IA_x !print *,'IA_x=',IA_x,'IA_y',IA_y !print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 !print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y @@ -621,8 +621,12 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a axn=0. ayn=0. if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave + IA_x - ayn=-gravity*ssh_y +wave_rad*vwave + IA_y + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave + if (interactive_icebergs_on) then + axn=axn + IA_x + ayn=ayn + IA_y + endif endif if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon axn=axn+f_cori*vveln @@ -2342,11 +2346,13 @@ subroutine evolve_icebergs(bergs) ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj !print *, 'Alon: look here!', lonn, latn, uvel3, vvel3, i, j, xi, yj + !print *, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" ! If the iceberg bounces off the land, then its velocity and acceleration are set to zero if (bounced) then + !print *, 'you have been bounce: big time!',lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag axn=0. ; ayn=0. bxn=0. ; byn=0. uvel3=0.; vvel3=0. @@ -2443,7 +2449,6 @@ subroutine evolve_icebergs(bergs) !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') - berg=>berg%next enddo ! loop over all bergs enddo ; enddo diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index af6f023..0c7c109 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3702,7 +3702,7 @@ integer function berg_chksum(berg ) type(iceberg), pointer :: berg ! Local variables real :: rtmp(37) !Changed from 28 to 34 by Alon -integer :: itmp(37+3), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon +integer :: itmp(37+4), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon integer :: i rtmp(:)=0. From 59a0dece34f5b26dee00a4e6966adf043da7b082 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 8 Oct 2015 11:21:45 -0400 Subject: [PATCH 083/361] Tabular icebergs can now be initiated by manually designing them in the restart file. A subroutine has been written which allows you to read in iceberg bonds while ignoring the ine, jne values of the bonds. This is done by searching through all grid boxes for the position of the iceberg which matched the iceberg id in the bond. There also exists a python script to initialize tabular iceberg restart files (both for bonds and icebergs). A small amount of work was also done on improving the bonding force (to make it stable in the limit of small icebergs). This is still work in progress. --- icebergs.F90 | 10 ++++-- icebergs_framework.F90 | 76 +++++++++++++++++++++++++++++++++++++++++- icebergs_io.F90 | 47 ++++++++++++++++++++++++-- 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 4b0a338..441f728 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -197,6 +197,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i real :: Rearth logical :: critical_interaction_damping_on real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef +real :: mult_factor real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y real :: L_dist @@ -327,11 +328,14 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) ! Think about doing bonds using an "inverse overlap area, or some type" + mult_factor=((r_dist/(R1+R2))-1) if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then - L_dist = min( (r_dist-(R1+R2) ),min(R1,R2) ) - call overlap_area(R1,R2,L_dist,A_o,trapped) T_min=min(T1,T2) - accel_spring=bond_coef*(T_min/T1)*(A_o/A1) + A_o = min((pi*R1**R1),(pi*R2*R2)) !New idea - force increase with distance + !L_dist = min( (r_dist-(R1+R2) ),min(R1,R2) ) + !call overlap_area(R1,R2,L_dist,A_o,trapped) + !accel_spring=bond_coef*(T_min/T1)*(A_o/A1) + accel_spring=bond_coef*mult_factor*(T_min/T1)*(A_o/A1) !accel_spring=bond_coef*(r_dist-(R1+R2)) IA_x=IA_x-(accel_spring*(r_dist_x/r_dist)) !Note: negative sign is an attractive force. IA_y=IA_y-(accel_spring*(r_dist_y/r_dist)) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 0c7c109..3b7e87e 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -71,6 +71,8 @@ module ice_bergs_framework public grd_chksum2,grd_chksum3 public fix_restart_dates, offset_berg_dates public move_berg_between_cells +public find_individual_iceberg + type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -840,6 +842,18 @@ subroutine update_halo_icebergs(bergs) ! For convenience grd=>bergs%grd + +!For debugging +do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + print *, 'A', this%iceberg_num, mpp_pe(), this%halo_berg + this=>this%next + enddo +enddo; enddo + + + ! Step 1: Clear the current halos @@ -859,6 +873,20 @@ subroutine update_halo_icebergs(bergs) call delete_all_bergs_in_list(bergs,grdj,grdi) enddo ; enddo +!############################## + +!For debugging +do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + print *, 'B', this%iceberg_num, mpp_pe(), this%halo_berg + this=>this%next + enddo +enddo; enddo + + +!####################################################### + ! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes @@ -1067,6 +1095,18 @@ subroutine update_halo_icebergs(bergs) call mpp_sync_self() +!For debugging +do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + print *, 'C', this%iceberg_num, mpp_pe(), this%halo_berg + this=>this%next + enddo +enddo; enddo + + + + end subroutine update_halo_icebergs @@ -2470,7 +2510,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's if (number_of_bonds .gt. 0) then - print *, "Number of bonds on pe:", mpp_pe(), "out of a total of: ", number_of_bonds, number_of_bonds_all_pe + print *, "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() endif if (quality_check) then @@ -2893,6 +2933,40 @@ end function find_cell_loc end function find_cell_by_search + +! ############################################################################## + +subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found) +type(icebergs), pointer :: bergs +type(iceberg), pointer :: this +type(icebergs_gridded), pointer :: grd +integer :: grdi, grdj +integer, intent(in) :: iceberg_num +integer, intent(out) :: ine, jne +real, intent(out) :: berg_found + +berg_found=0.0 +ine=999 +jne=999 + ! For convenience + grd=>bergs%grd + + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + if (iceberg_num .eq. this%iceberg_num) then + ine=this%ine + jne=this%jne + berg_found=1.0 + !print *, 'found this one' + return + endif + this=>this%next + enddo + enddo ; enddo +end subroutine find_individual_iceberg + + ! ############################################################################## logical function find_cell(grd, x, y, oi, oj) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index d7ec695..e29006d 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -26,7 +26,7 @@ module ice_bergs_io use ice_bergs_framework, only: pack_berg_into_buffer2,unpack_berg_from_buffer2 use ice_bergs_framework, only: pack_traj_into_buffer2,unpack_traj_from_buffer2 use ice_bergs_framework, only: find_cell,find_cell_by_search,count_bergs,is_point_in_cell,pos_within_cell,append_posn -use ice_bergs_framework, only: count_bonds, form_a_bond +use ice_bergs_framework, only: count_bonds, form_a_bond, find_individual_iceberg use ice_bergs_framework, only: push_posn use ice_bergs_framework, only: add_new_berg_to_list,destroy_iceberg use ice_bergs_framework, only: increase_ibuffer,increase_ibuffer_traj,grd_chksum2,grd_chksum3 @@ -726,6 +726,7 @@ subroutine read_restart_bergs(bergs,Time) character(len=33) :: filename, filename_base type(icebergs_gridded), pointer :: grd type(iceberg) :: localberg ! NOT a pointer but an actual local variable +real :: pos_is_good, pos_is_good_all_pe integer :: stderrunit real, allocatable, dimension(:) :: lon, & @@ -863,6 +864,16 @@ subroutine read_restart_bergs(bergs,Time) lres=find_cell_by_search(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) endif endif + ! The next few lines are a check to see whether the icebergs are all found. + pos_is_good=0.0 + if (lres) then + pos_is_good=1.0 + endif + pos_is_good_all_pe=pos_is_good + call mpp_sum(pos_is_good_all_pe) + if (pos_is_good_all_pe .lt. 0.5) then + call error_mesg('diamonds, read_restart_bergs', 'One of the iceberg positions was not found', FATAL) + endif if (really_debug) then write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& & ' on PE ',mpp_pe() @@ -1070,6 +1081,8 @@ subroutine read_restart_bonds(bergs,Time) integer :: number_partial_bonds ! How many either complete/partial bonds formed. integer :: all_pe_number_perfect_bonds, all_pe_number_partial_bonds integer :: all_pe_number_first_bonds_matched, all_pe_number_second_bonds_matched +integer :: ine, jne +real :: berg_found, berg_found_all_pe integer, allocatable, dimension(:) :: first_berg_num, & other_berg_num, & first_berg_jne, & @@ -1118,7 +1131,36 @@ subroutine read_restart_bonds(bergs,Time) number_perfect_bonds=0 number_partial_bonds=0 do k=1, nbonds_in_file - + + + ! If i,j in restart files are not good, then we find the berg position of the bond addresses manually: + if (ignore_ij_restart) then + !Finding first iceberg in bond + ine=999 ; jne=999 ; berg_found=0.0 + call find_individual_iceberg(bergs,first_berg_num(k), ine, jne,berg_found) + berg_found_all_pe=berg_found + call mpp_sum(berg_found_all_pe) + !print *, mpp_pe(), berg_found_all_pe, berg_found, first_berg_num(k),'here' + if (berg_found_all_pe .gt. 0.5) then + first_berg_ine(k)=ine + first_berg_jne(k)=jne + else + call error_mesg('read_restart_bonds_bergs_new', 'First iceberg in bond not found on any pe', FATAL) + endif + + !Finding other iceberg other iceberg + ine=999 ; jne=999 ; berg_found=0.0 + call find_individual_iceberg(bergs,other_berg_num(k), ine, jne, berg_found) + call mpp_sum(berg_found) + if (berg_found .gt. 0.5) then + other_berg_ine(k)=ine + other_berg_jne(k)=jne + else + call error_mesg('read_restart_bonds_bergs_new', 'Other iceberg in bond not found on any pe', FATAL) + endif + endif + + ! Decide whether the first iceberg is on the processeor if ( first_berg_ine(k)>=grd%isc .and. first_berg_ine(k)<=grd%iec .and. & first_berg_jne(k)>=grd%jsc .and.first_berg_jne(k)<=grd%jec ) then @@ -1203,6 +1245,7 @@ subroutine read_restart_bonds(bergs,Time) other_berg_jne ) endif end subroutine read_restart_bonds + ! ############################################################################## subroutine read_restart_calving(bergs) From 734864f9f17e1e6479e870c0dabc0d0c7ce88059 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 8 Oct 2015 18:21:28 -0400 Subject: [PATCH 084/361] 1) Damping added to iceberg bonds. 2) A bug was fixed in the accel subroutine. The interactive_forces call was using a u_s,v_s, which was not defined. This has been corrected. --- icebergs.F90 | 95 ++++++++++++++++++++++++++++-------------- icebergs_framework.F90 | 43 ++++++++++--------- 2 files changed, 85 insertions(+), 53 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 441f728..4058eec 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -190,14 +190,14 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i type(bond), pointer :: current_bond real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg -real :: r_dist_x, r_dist_y, r_dist, A_o, trapped, T_min +real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min real, intent(in) :: u0,v0, u1, v1 real :: P_11, P_12, P_21, P_22 real :: u2, v2 real :: Rearth logical :: critical_interaction_damping_on real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef -real :: mult_factor +real :: mult_factor, damping_factor real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y real :: L_dist @@ -213,12 +213,12 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i critical_interaction_damping_on=bergs%critical_interaction_damping_on iceberg_bonds_on=bergs%iceberg_bonds_on - !Using critical values for damping rather than manually setting the damping. if (critical_interaction_damping_on) then radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping - tangental_damping_coef=(2.*sqrt(spring_coef)/5) ! Critical damping /5 (just a guess) + tangental_damping_coef=(2.*sqrt(spring_coef)) ! Critical damping (just a guess) endif +print *, radial_damping_coef ! Get the stderr unit number. Not sure what this does @@ -258,22 +258,23 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i call overlap_area(R1,R2,r_dist,A_o,trapped) T_min=min(T1,T2) + A_min = min((pi*R1**R1),(pi*R2*R2)) !Calculating spring force (later this should only be done on the first time around) - accel_spring=spring_coef*(T_min/T1)*(A_o/A1) if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then + !Spring force + accel_spring=spring_coef*(T_min/T1)*(A_o/A1) IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - - !Working out the damping + !Damping force: !Paralel velocity P_11=(r_dist_x*r_dist_x)/(r_dist**2) P_12=(r_dist_x*r_dist_y)/(r_dist**2) P_21=(r_dist_x*r_dist_y)/(r_dist**2) P_22=(r_dist_y*r_dist_y)/(r_dist**2) - p_ia_coef=radial_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) P_ia_11=P_ia_11+p_ia_coef*P_11 @@ -286,7 +287,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !Normal velocities P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_o/A1) + p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) P_ia_11=P_ia_11+p_ia_coef*P_11 @@ -317,8 +318,8 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i L2=other_berg%length W2=other_berg%width T2=other_berg%thickness ! Note, that it is not dependent on thickness This means that it might go unstable for small icebergs - !u2=other_berg%uvel_old - !v2=other_berg%vvel_old + u2=other_berg%uvel_old + v2=other_berg%vvel_old A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg lon2=other_berg%lon_old; lat2=other_berg%lat_old @@ -326,25 +327,60 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i r_dist_x=x1-x2 ; r_dist_y=y1-y2 r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - - ! Think about doing bonds using an "inverse overlap area, or some type" - mult_factor=((r_dist/(R1+R2))-1) - if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then - T_min=min(T1,T2) - A_o = min((pi*R1**R1),(pi*R2*R2)) !New idea - force increase with distance - !L_dist = min( (r_dist-(R1+R2) ),min(R1,R2) ) - !call overlap_area(R1,R2,L_dist,A_o,trapped) - !accel_spring=bond_coef*(T_min/T1)*(A_o/A1) - accel_spring=bond_coef*mult_factor*(T_min/T1)*(A_o/A1) - !accel_spring=bond_coef*(r_dist-(R1+R2)) + T_min=min(T1,T2) + A_min = min((pi*R1**R1),(pi*R2*R2)) + + !Spring force + if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then + mult_factor=((r_dist/(R1+R2))-1) + accel_spring=bond_coef*mult_factor*(T_min/T1)*(A_min/A1) IA_x=IA_x-(accel_spring*(r_dist_x/r_dist)) !Note: negative sign is an attractive force. IA_y=IA_y-(accel_spring*(r_dist_y/r_dist)) - endif !Note, no damping on bond force has been added yet + endif !Note, no damping on bond force has been added yet + + damping_factor=2.0 + !Spring damping + if ((r_dist>0.) .AND. (r_dist> (R1+R2)) .AND. (r_dist< (damping_factor*(R1+R2))) ) then + !Paralel velocity + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_21=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 + p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + + endif + endif + + + current_bond=>current_bond%next_bond enddo endif +!print *,'IA_x=',IA_x,'IA_y',IA_y +!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 +!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y contains subroutine overlap_area(R1,R2,d,A,trapped) @@ -514,9 +550,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn=bxn + IA_x byn=byn + IA_y endif -!print *,'IA_x=',IA_x,'IA_y',IA_y -!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 -!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y endif @@ -540,8 +573,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a uveln=uvel; vveln=vvel endif + us=uvel0 ; vs=vvel0 do itloop=1,2 ! Iterate on drag coefficients - + if (itloop .eq. 2) then + us=uveln ; vs=vveln + endif if (use_new_predictive_corrective) then !Alon's proposed change - using Bob's improved scheme. drag_ocn=c_ocn*0.5*(sqrt( (uveln-uo)**2+(vveln-vo)**2 )+sqrt( (uvel0-uo)**2+(vvel0-vo)**2 )) @@ -580,8 +616,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a endif - - ! Solve for implicit accelerations if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice @@ -2350,7 +2384,6 @@ subroutine evolve_icebergs(bergs) ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj !print *, 'Alon: look here!', lonn, latn, uvel3, vvel3, i, j, xi, yj - !print *, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" @@ -2367,7 +2400,6 @@ subroutine evolve_icebergs(bergs) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -2536,6 +2568,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lon0=lon; lat0=lat ! original position i0=i; j0=j ! original i,j lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) +! print *, 'Alon:', lon, lat, i, j, xi, yj, lret xi0=xi; yj0=yj ! original xi,yj if (debug) then !Sanity check lret, xi and yj diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3b7e87e..22b9165 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -842,15 +842,14 @@ subroutine update_halo_icebergs(bergs) ! For convenience grd=>bergs%grd - !For debugging -do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - print *, 'A', this%iceberg_num, mpp_pe(), this%halo_berg - this=>this%next - enddo -enddo; enddo +!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied +! this=>bergs%list(grdi,grdj)%first +! do while (associated(this)) +! print *, 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj +! this=>this%next +! enddo +!enddo; enddo @@ -876,13 +875,13 @@ subroutine update_halo_icebergs(bergs) !############################## !For debugging -do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - print *, 'B', this%iceberg_num, mpp_pe(), this%halo_berg - this=>this%next - enddo -enddo; enddo +!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied +! this=>bergs%list(grdi,grdj)%first +! do while (associated(this)) +! print *, 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj +! this=>this%next +! enddo +!enddo; enddo !####################################################### @@ -1096,13 +1095,13 @@ subroutine update_halo_icebergs(bergs) !For debugging -do grdj = grd%jsd,grd%jsd ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - print *, 'C', this%iceberg_num, mpp_pe(), this%halo_berg - this=>this%next - enddo -enddo; enddo +!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied +! this=>bergs%list(grdi,grdj)%first +! do while (associated(this)) +! print *, 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj +! this=>this%next +! enddo +!enddo; enddo From 8869339f7e829b9dde6a93e11a0ee88f25d23da4 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 12 Oct 2015 17:05:16 -0400 Subject: [PATCH 085/361] A few bugs related to iceberg bonds have been fixed. 1) lat_old, lon_old, vvel_old, uvel_old have been removed from the restart files, and are initialized to equal lon,lat,vvel and uvel, respectively. 2) Interactive_forces subroutine has been edited so that it has less repitition. Also, the calculation of the distance between icebergs has been corrected. 3) A small bug has been corrected which allows iceberg bonds to form for all iceberg_num greater than 0 (rather than greater than 1). 4) The force between icebergs now depends on the distance between the icebergs rather than the overlap of the iceberg areas. This is stable in the limit of small icebergs, unlike the area overlap The bonds appear to be working --- icebergs.F90 | 234 +++++++++++++++++++---------------------- icebergs_framework.F90 | 67 ++++++------ icebergs_io.F90 | 57 +--------- 3 files changed, 148 insertions(+), 210 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 4058eec..10eb565 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -188,93 +188,142 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond -real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg -real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg -real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min real, intent(in) :: u0,v0, u1, v1 -real :: P_11, P_12, P_21, P_22 real :: u2, v2 -real :: Rearth logical :: critical_interaction_damping_on -real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef -real :: mult_factor, damping_factor real, intent(out) :: IA_x, IA_y real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y -real :: L_dist -integer :: stderrunit integer :: grdi, grdj logical :: iceberg_bonds_on -Rearth=6360.e3 -!spring_coef=1.e-4 -spring_coef=bergs%spring_coef -bond_coef=bergs%bond_coef -radial_damping_coef=bergs%radial_damping_coef -tangental_damping_coef=bergs%tangental_damping_coef -critical_interaction_damping_on=bergs%critical_interaction_damping_on +logical :: bonded iceberg_bonds_on=bergs%iceberg_bonds_on -!Using critical values for damping rather than manually setting the damping. -if (critical_interaction_damping_on) then - radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping - tangental_damping_coef=(2.*sqrt(spring_coef)) ! Critical damping (just a guess) -endif -print *, radial_damping_coef + IA_x=0. + IA_y=0. + P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. + P_ia_times_u_x=0. ; P_ia_times_u_y=0. + bonded=.false. !Unbonded iceberg interactions + do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 + other_berg=>bergs%list(grdi,grdj)%first + do while (associated(other_berg)) ! loop over all other bergs + call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) + other_berg=>other_berg%next + enddo ! loop over all bergs + enddo ; enddo -! Get the stderr unit number. Not sure what this does - stderrunit = stderr() + bonded=.true. !Interactions due to iceberg bonds + if (iceberg_bonds_on) then ! MP1 + current_bond=>berg%first_bond + do while (associated(current_bond)) ! loop over all bonds + other_berg=>current_bond%other_berg + if (.not. associated(current_bond)) then + call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) + else + call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) + endif + current_bond=>current_bond%next_bond + enddo + endif -IA_x=0. -IA_y=0. -P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. -P_ia_times_u_x=0. ; P_ia_times_u_y=0. +!print *,'IA_x=',IA_x,'IA_y',IA_y, berg%iceberg_num +!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 +!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y + contains -L1=berg%length -W1=berg%width -T1=berg%thickness -A1=L1*W1 -R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) -lon1=berg%lon; lat1=berg%lat -call rotpos_to_tang(lon1,lat1,x1,y1) + subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) + !Arguments + type(icebergs), pointer :: bergs + type(iceberg), pointer :: berg + type(iceberg), pointer :: other_berg + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg + real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg + real :: dlon, dlat + real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min + real, intent(in) :: u0,v0, u1, v1 + real :: P_11, P_12, P_21, P_22 + real :: M1, M2, M_min + real :: u2, v2 + real :: Rearth + logical :: critical_interaction_damping_on + real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef + real, intent(inout) :: IA_x, IA_y + real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y + logical ,intent(in) :: bonded + + Rearth=6360.e3 + spring_coef=bergs%spring_coef + !bond_coef=bergs%bond_coef + radial_damping_coef=bergs%radial_damping_coef + tangental_damping_coef=bergs%tangental_damping_coef + critical_interaction_damping_on=bergs%critical_interaction_damping_on + + !Using critical values for damping rather than manually setting the damping. + if (critical_interaction_damping_on) then + radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping + tangental_damping_coef=(2.*sqrt(spring_coef)) ! Critical damping (just a guess) + endif - do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 - other_berg=>bergs%list(grdi,grdj)%first - !Note: This summing should be made order invarient. - do while (associated(other_berg)) ! loop over all other bergs if (berg%iceberg_num .ne. other_berg%iceberg_num) then + !From Berg 1 + L1=berg%length + W1=berg%width + T1=berg%thickness + M1=berg%mass + A1=L1*W1 + R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) + lon1=berg%lon; lat1=berg%lat + !call rotpos_to_tang(lon1,lat1,x1,y1) + + + !From Berg 1 L2=other_berg%length W2=other_berg%width T2=other_berg%thickness + M2=other_berg%mass u2=other_berg%uvel_old !Old values are used to make it order invariant v2=other_berg%vvel_old !Old values are used to make it order invariant A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant - call rotpos_to_tang(lon2,lat2,x2,y2) - - r_dist_x=x1-x2 ; r_dist_y=y1-y2 - r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - - call overlap_area(R1,R2,r_dist,A_o,trapped) - T_min=min(T1,T2) - A_min = min((pi*R1**R1),(pi*R2*R2)) + !call rotpos_to_tang(lon2,lat2,x2,y2) + dlon=lon1-lon2 + dlat=lat1-lat2 + + !Note that this is not the exact distance along a great circle. + !Approximation for small distances. Should be fine. + !r_dist_x=x1-x2 ; r_dist_y=y1-y2 + !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) + r_dist_y=dlat*(pi/180)*Rearth + r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) + + !print *, 'outside the loop',R1, R2,r_dist, bonded + !call overlap_area(R1,R2,r_dist,A_o,trapped) + !T_min=min(T1,T2) + !A_min = min((pi*R1**R1),(pi*R2*R2)) + M_min=min(M1,M2) !Calculating spring force (later this should only be done on the first time around) - if ((r_dist>0.) .AND. (r_dist< (R1+R2)) ) then + if ((r_dist>0.) .AND. ((r_dist< (R1+R2)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then !Spring force - accel_spring=spring_coef*(T_min/T1)*(A_o/A1) + !accel_spring=spring_coef*(T_min/T1)*(A_o/A1) ! Old version dependent on area + accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - !Working out the damping + !MP1 + !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) + !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist !Damping force: !Paralel velocity P_11=(r_dist_x*r_dist_x)/(r_dist**2) P_12=(r_dist_x*r_dist_y)/(r_dist**2) P_21=(r_dist_x*r_dist_y)/(r_dist**2) P_22=(r_dist_y*r_dist_y)/(r_dist**2) - p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) + !p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=radial_damping_coef*(M_min/M1) p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) P_ia_11=P_ia_11+p_ia_coef*P_11 @@ -287,7 +336,8 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !Normal velocities P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) + !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=tangental_damping_coef*(M_min/M1) p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) P_ia_11=P_ia_11+p_ia_coef*P_11 @@ -303,85 +353,10 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !print *, 'P_22',P_22 endif endif - other_berg=>other_berg%next - enddo ! loop over all bergs - enddo ; enddo - - !Interactions due to iceberg bonds - if (iceberg_bonds_on) then ! MP1 - current_bond=>berg%first_bond - do while (associated(current_bond)) ! loop over all bonds - other_berg=>current_bond%other_berg - if (.not. associated(current_bond)) then - call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) - else - L2=other_berg%length - W2=other_berg%width - T2=other_berg%thickness ! Note, that it is not dependent on thickness This means that it might go unstable for small icebergs - u2=other_berg%uvel_old - v2=other_berg%vvel_old - A2=L2*W2 - R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - lon2=other_berg%lon_old; lat2=other_berg%lat_old - call rotpos_to_tang(lon2,lat2,x2,y2) - - r_dist_x=x1-x2 ; r_dist_y=y1-y2 - r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - T_min=min(T1,T2) - A_min = min((pi*R1**R1),(pi*R2*R2)) - - !Spring force - if ((r_dist>0.) .AND. (r_dist> (R1+R2)) ) then - mult_factor=((r_dist/(R1+R2))-1) - accel_spring=bond_coef*mult_factor*(T_min/T1)*(A_min/A1) - IA_x=IA_x-(accel_spring*(r_dist_x/r_dist)) !Note: negative sign is an attractive force. - IA_y=IA_y-(accel_spring*(r_dist_y/r_dist)) - endif !Note, no damping on bond force has been added yet - - damping_factor=2.0 - !Spring damping - if ((r_dist>0.) .AND. (r_dist> (R1+R2)) .AND. (r_dist< (damping_factor*(R1+R2))) ) then - !Paralel velocity - P_11=(r_dist_x*r_dist_x)/(r_dist**2) - P_12=(r_dist_x*r_dist_y)/(r_dist**2) - P_21=(r_dist_x*r_dist_y)/(r_dist**2) - P_22=(r_dist_y*r_dist_y)/(r_dist**2) - p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - !Normal velocities - P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - endif - - endif + end subroutine calculate_force - current_bond=>current_bond%next_bond - enddo - endif - -!print *,'IA_x=',IA_x,'IA_y',IA_y -!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 -!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y - contains subroutine overlap_area(R1,R2,d,A,trapped) real, intent(in) :: R1, R2, d @@ -409,6 +384,9 @@ subroutine overlap_area(R1,R2,d,A,trapped) end subroutine overlap_area + + + end subroutine interactive_force diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 22b9165..cb2a16b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -298,8 +298,8 @@ subroutine ice_bergs_framework_init(bergs, & integer :: verbose_hrs=24 ! Period between verbose messages integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs -real :: spring_coef=1.e-4 ! Spring contant for iceberg interactions - Alon -real :: bond_coef=1.e-4 ! Spring contant for iceberg bonds - Alon +real :: spring_coef=1.e-8 ! Spring contant for iceberg interactions - Alon +real :: bond_coef=1.e-8 ! Spring contant for iceberg bonds - Alon real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs @@ -833,7 +833,7 @@ subroutine update_halo_icebergs(bergs) real :: current_halo_status logical :: force_app -force_app =.false. +force_app =.true. halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. ! Get the stderr unit number @@ -846,16 +846,18 @@ subroutine update_halo_icebergs(bergs) !do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! this=>bergs%list(grdi,grdj)%first ! do while (associated(this)) -! print *, 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj +! write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj ! this=>this%next ! enddo !enddo; enddo +! Use when debugging: +!call show_all_bonds(bergs) ! Step 1: Clear the current halos - + call mpp_sync_self() do grdj = grd%jsd,grd%jsc-1 ; do grdi = grd%isd,grd%ied call delete_all_bergs_in_list(bergs, grdj, grdi) enddo ; enddo @@ -872,30 +874,26 @@ subroutine update_halo_icebergs(bergs) call delete_all_bergs_in_list(bergs,grdj,grdi) enddo ; enddo + call mpp_sync_self() !############################## !For debugging !do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! this=>bergs%list(grdi,grdj)%first ! do while (associated(this)) -! print *, 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj +! write(stderrunit,*) 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj ! this=>this%next ! enddo !enddo; enddo + if (debug) then + nbergs_start=count_bergs(bergs) + endif !####################################################### - ! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes -! ! Get the stderr unit number -! stderrunit = stderr() -! - - if (debug) then - nbergs_start=count_bergs(bergs) - endif ! Find number of bergs that headed east/west nbergs_to_send_e=0 @@ -905,6 +903,7 @@ subroutine update_halo_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%iec-halo_width+1,grd%iec this=>bergs%list(grdi,grdj)%first do while (associated(this)) + !write(stderrunit,*) 'sending east', this%iceberg_num, this%ine, this%jne, mpp_pe() kick_the_bucket=>this this=>this%next nbergs_to_send_e=nbergs_to_send_e+1 @@ -947,6 +946,7 @@ subroutine update_halo_icebergs(bergs) endif endif + call mpp_sync_self() ! Receive bergs from west if (grd%pe_W.ne.NULL_PE) then nbergs_rcvd_from_w=-999 @@ -984,7 +984,6 @@ subroutine update_halo_icebergs(bergs) endif - ! Find number of bergs that headed north/south nbergs_to_send_n=0 nbergs_to_send_s=0 @@ -1089,19 +1088,17 @@ subroutine update_halo_icebergs(bergs) nbergs_rcvd_from_n=0 endif - - call mpp_sync_self() !For debugging -!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied -! this=>bergs%list(grdi,grdj)%first -! do while (associated(this)) -! print *, 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj -! this=>this%next -! enddo -!enddo; enddo +do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo +enddo; enddo @@ -1123,8 +1120,8 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) this=>this%next call destroy_iceberg(kick_the_bucket) ! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) - bergs%list(grdi,grdj)%first=>null() enddo + bergs%list(grdi,grdj)%first=>null() end subroutine delete_all_bergs_in_list @@ -1146,7 +1143,7 @@ subroutine send_bergs_to_other_pes(bergs) integer :: grdi, grdj logical :: force_app -force_app=.false. +force_app=.true. ! Get the stderr unit number stderrunit = stderr() @@ -1463,14 +1460,19 @@ subroutine clear_berg_from_partners_bonds(berg) type(iceberg), intent(in), pointer :: berg type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond, matching_bond - + integer :: stderrunit + ! Get the stderr unit number + stderrunit = stderr() + current_bond=>berg%first_bond do while (associated(current_bond)) !Looping over bonds other_berg=>current_bond%other_berg if (associated(other_berg)) then + !write(stderrunit,*) , 'Other berg', berg%iceberg_num, other_berg%iceberg_num, mpp_pe() matching_bond=>other_berg%first_bond do while (associated(matching_bond)) ! Looping over possible matching bonds in other_berg if (matching_bond%other_berg_num .eq. berg%iceberg_num) then + !write(stderrunit,*) , 'Clearing', berg%iceberg_num, matching_bond%other_berg_num,other_berg%iceberg_num, mpp_pe() matching_bond%other_berg=>null() matching_bond=>null() else @@ -1622,7 +1624,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) other_berg_jne=nint(buff%data(counter+(3*(k-1)+3),n)) - if (other_berg_num .gt. 1) then + if (other_berg_num .gt. 0.5) then call form_a_bond(this, other_berg_num, other_berg_ine, other_berg_jne) endif enddo @@ -2237,9 +2239,13 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth type(bond) , pointer :: new_bond, first_bond integer, intent(in) :: other_berg_num integer, optional :: other_berg_ine, other_berg_jne +integer :: stderrunit + + stderrunit = stderr() if (berg%iceberg_num .ne. other_berg_num) then - !print *, 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg, berg%ine, berg%jne + + !write (stderrunit,*) , 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg, berg%ine, berg%jne ! Step 1: Create a new bond allocate(new_bond) @@ -2403,6 +2409,7 @@ subroutine connect_all_bonds(bergs) enddo;enddo endif if (.not.bond_matched) then + print * , berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine if (berg%halo_berg .lt. 0.5) then missing_bond=.true. print * , berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine @@ -2968,7 +2975,7 @@ end subroutine find_individual_iceberg ! ############################################################################## -logical function find_cell(grd, x, y, oi, oj) +logical function find_cell(grd, x, y, oi, oj) !MP1 ! Arguments type(icebergs_gridded), intent(in) :: grd real, intent(in) :: x, y diff --git a/icebergs_io.F90 b/icebergs_io.F90 index e29006d..b231d41 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -114,15 +114,11 @@ subroutine write_restart(bergs) type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & lat, & - lon_old, & - lat_old, & uvel, & vvel, & mass, & axn, & ayn, & - uvel_old, & - vvel_old, & bxn, & byn, & thickness, & @@ -149,7 +145,6 @@ subroutine write_restart(bergs) other_berg_ine -!uvel_old, vvel_old, lon_old, lat_old, axn, ayn, bxn, byn added by Alon. integer :: grdi, grdj ! Get the stderr unit number @@ -171,15 +166,11 @@ subroutine write_restart(bergs) allocate(lon(nbergs)) allocate(lat(nbergs)) - allocate(lon_old(nbergs)) !Alon - allocate(lat_old(nbergs)) !Alon allocate(uvel(nbergs)) allocate(vvel(nbergs)) allocate(mass(nbergs)) allocate(axn(nbergs)) !Alon allocate(ayn(nbergs)) !Alon - allocate(uvel_old(nbergs)) !Alon - allocate(vvel_old(nbergs)) !Alon allocate(bxn(nbergs)) !Alon allocate(byn(nbergs)) !Alon allocate(thickness(nbergs)) @@ -212,15 +203,11 @@ subroutine write_restart(bergs) ! Define Variables id = register_restart_field(bergs_restart,filename,'lon',lon,longname='longitude',units='degrees_E') id = register_restart_field(bergs_restart,filename,'lat',lat,longname='latitude',units='degrees_N') - id = register_restart_field(bergs_restart,filename,'lon_old',lon_old,longname='longitude',units='degrees_E') !Alon - id = register_restart_field(bergs_restart,filename,'lat_old',lat_old,longname='latitude',units='degrees_N') !Alon id = register_restart_field(bergs_restart,filename,'uvel',uvel,longname='zonal velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'vvel',vvel,longname='meridional velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'mass',mass,longname='mass',units='kg') id = register_restart_field(bergs_restart,filename,'axn',axn,longname='explicit zonal acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ayn',ayn,longname='explicit meridional acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'uvel_old',uvel_old,longname='old explicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'vvel_old',vvel_old,longname='old explicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'bxn',bxn,longname='inplicit zonal acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'byn',byn,longname='implicit meridional acceleration',units='m/s^2') !Alon id = register_restart_field(bergs_restart,filename,'ine',ine,longname='i index',units='none') @@ -258,12 +245,10 @@ subroutine write_restart(bergs) do while(associated(this)) i = i + 1 lon(i) = this%lon; lat(i) = this%lat - lon_old(i) = this%lon_old; lat_old(i) = this%lat_old !Alon uvel(i) = this%uvel; vvel(i) = this%vvel ine(i) = this%ine; jne(i) = this%jne mass(i) = this%mass; thickness(i) = this%thickness axn(i) = this%axn; ayn(i) = this%ayn !Added by Alon - uvel_old(i) = this%uvel_old; vvel_old(i) = this%vvel_old !Added by Alon bxn(i) = this%bxn; byn(i) = this%byn !Added by Alon width(i) = this%width; length(i) = this%length start_lon(i) = this%start_lon; start_lat(i) = this%start_lat @@ -283,15 +268,11 @@ subroutine write_restart(bergs) deallocate( & lon, & lat, & - lon_old, & - lat_old, & uvel, & vvel, & mass, & axn, & ayn, & - uvel_old, & - vvel_old, & bxn, & byn, & thickness, & @@ -305,7 +286,6 @@ subroutine write_restart(bergs) mass_of_bits, & halo_berg, & heat_density ) -!axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon deallocate( & ine, & @@ -423,7 +403,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer, dimension(:), allocatable :: found_restart_int integer :: k, ierr, ncid, dimid, nbergs_in_file integer :: lonid, latid, uvelid, vvelid, ineid, jneid -integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid, lon_oldid, lat_oldid !Added by Alon +integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, iceberg_numid, start_dayid, start_massid integer :: scaling_id, mass_of_bits_id, heat_density_id, halo_bergid @@ -483,15 +463,11 @@ subroutine read_restart_bergs_orig(bergs,Time) lonid=inq_var(ncid, 'lon') latid=inq_var(ncid, 'lat') - lon_oldid=inq_var(ncid, 'lon_old') !Alon - lat_oldid=inq_var(ncid, 'lat_old') !Alon uvelid=inq_var(ncid, 'uvel') vvelid=inq_var(ncid, 'vvel') massid=inq_var(ncid, 'mass') axnid=inq_var(ncid, 'axn') !Alon aynid=inq_var(ncid, 'ayn') !Alon - uvel_oldid=inq_var(ncid, 'uvel_old') !Alon - vvel_oldid=inq_var(ncid, 'vvel_old') !Alon bxnid=inq_var(ncid, 'bxn') !Alon bynid=inq_var(ncid, 'byn') !Alon thicknessid=inq_var(ncid, 'thickness') @@ -547,10 +523,6 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%mass=get_double(ncid, massid, k) localberg%axn=get_double(ncid, axnid, k) !Alon localberg%ayn=get_double(ncid, aynid, k) !Alon - localberg%uvel_old=get_double(ncid, uvel_oldid, k) !Alon - localberg%vvel_old=get_double(ncid, vvel_oldid, k) !Alon - localberg%lon_old=get_double(ncid, lon_oldid, k) !Alon - localberg%lat_old=get_double(ncid, lat_oldid, k) !Alon localberg%bxn=get_double(ncid, bxnid, k) !Alon localberg%byn=get_double(ncid, bynid, k) !Alon localberg%thickness=get_double(ncid, thicknessid, k) @@ -731,15 +703,11 @@ subroutine read_restart_bergs(bergs,Time) real, allocatable, dimension(:) :: lon, & lat, & - lon_old, & - lat_old, & uvel, & vvel, & mass, & axn, & ayn, & - uvel_old, & - vvel_old, & bxn, & byn, & thickness, & @@ -753,7 +721,6 @@ subroutine read_restart_bergs(bergs,Time) mass_of_bits, & halo_berg, & heat_density -!axn, ayn, uvel_old, vvel_old, lon_old, lat_old, bxn, byn added by Alon integer, allocatable, dimension(:) :: ine, & jne, & iceberg_num, & @@ -782,15 +749,11 @@ subroutine read_restart_bergs(bergs,Time) if(nbergs_in_file > 0) then allocate(lon(nbergs_in_file)) allocate(lat(nbergs_in_file)) - allocate(lon_old(nbergs_in_file)) !Alon - allocate(lat_old(nbergs_in_file)) !Alon allocate(uvel(nbergs_in_file)) allocate(vvel(nbergs_in_file)) allocate(mass(nbergs_in_file)) allocate(axn(nbergs_in_file)) !Alon allocate(ayn(nbergs_in_file)) !Alon - allocate(uvel_old(nbergs_in_file)) !Alon - allocate(vvel_old(nbergs_in_file)) !Alon allocate(bxn(nbergs_in_file)) !Alon allocate(byn(nbergs_in_file)) !Alon allocate(thickness(nbergs_in_file)) @@ -812,15 +775,11 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) - call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) @@ -885,10 +844,10 @@ subroutine read_restart_bergs(bergs,Time) localberg%mass=mass(k) localberg%axn=axn(k) !Alon localberg%ayn=ayn(k) !Alon - localberg%uvel_old=uvel_old(k) !Alon - localberg%vvel_old=vvel_old(k) !Alon - localberg%lon_old=lon_old(k) !Alon - localberg%lat_old=lat_old(k) !Alon + localberg%uvel_old=uvel(k) !Alon + localberg%vvel_old=vvel(k) !Alon + localberg%lon_old=lon(k) !Alon + localberg%lat_old=lat(k) !Alon localberg%bxn=bxn(k) !Alon localberg%byn=byn(k) !Alon localberg%thickness=thickness(k) @@ -916,15 +875,11 @@ subroutine read_restart_bergs(bergs,Time) deallocate( & lon, & lat, & - lon_old, & - lat_old, & uvel, & vvel, & mass, & axn, & ayn, & - uvel_old, & - vvel_old, & bxn, & byn, & thickness, & @@ -938,7 +893,6 @@ subroutine read_restart_bergs(bergs,Time) mass_of_bits, & halo_berg, & heat_density ) -!axn, ayn, uvel_old, vvel_old, lat_old, lon_old, bxn, byn above added by Alon. deallocate( & ine, & jne, & @@ -1335,7 +1289,6 @@ subroutine write_trajectory(trajectory, save_short_traj) ! Local variables integer :: iret, ncid, i_dim, i integer :: lonid, latid, yearid, dayid, uvelid, vvelid, iceberg_numid -!integer :: axnid, aynid, uvel_oldid, vvel_oldid, lat_oldid, lon_oldid, bxnid, bynid !Added by Alon integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid integer :: cnid, hiid integer :: mid, did, wid, lid, mbid, hdid From a6c47baaeaa4d10c6d0e48b4b87e8a01e794bb75 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Oct 2015 15:37:45 -0400 Subject: [PATCH 086/361] Two more bugs fixed in the never ending stream of bugs related to iceberg interactions: 1) A segmentation fault was removed by editing the subroutine connect_all_bonds. Here we had to tell bergs in halos not to search for bonded bergs on other processors 2) A bug was fixed inside the interactive_forces subroutine. Icebergs were interacting with one another more than once per time step. This was fixed by specifically asking whether we are considering a bonded or unbonded interaction. There are still more details to be worked out with the tabular icebergs. They not working yet for very large icebergs, but appear to work for icebergs made up of 4 smaller icebergs. --- icebergs.F90 | 10 +++-- icebergs_framework.F90 | 92 +++++++++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 10eb565..2305a33 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -306,7 +306,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i !A_min = min((pi*R1**R1),(pi*R2*R2)) M_min=min(M1,M2) !Calculating spring force (later this should only be done on the first time around) - if ((r_dist>0.) .AND. ((r_dist< (R1+R2)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then + if ((r_dist>0.) .AND. ((r_dist< (R1+R2).AND. (.not. bonded)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then !Spring force !accel_spring=spring_coef*(T_min/T1)*(A_o/A1) ! Old version dependent on area accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) @@ -314,8 +314,9 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) !MP1 + !print *, 'in the loop1', berg%iceberg_num, other_berg%iceberg_num,r_dist, bonded !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) - !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist + !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num !Damping force: !Paralel velocity P_11=(r_dist_x*r_dist_x)/(r_dist**2) @@ -591,6 +592,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a RHS_x=RHS_x - (((P_ia_11*uvel)+(P_ia_12*vvel))-P_ia_times_u_x) RHS_y=RHS_y - (((P_ia_21*uvel)+(P_ia_22*vvel))-P_ia_times_u_y) endif + !print *,'Before calculation:', berg%iceberg_num, IA_x, IA_y, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y + !print *,'Before calculation:', berg%iceberg_num, itloop, IA_x, IA_y endif @@ -2048,6 +2051,8 @@ subroutine evolve_icebergs(bergs) uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl + + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) @@ -2361,7 +2366,6 @@ subroutine evolve_icebergs(bergs) ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) i=i1;j=j1;xi=berg%xi;yj=berg%yj - !print *, 'Alon: look here!', lonn, latn, uvel3, vvel3, i, j, xi, yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index cb2a16b..5200b3f 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -208,6 +208,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. @@ -298,8 +299,8 @@ subroutine ice_bergs_framework_init(bergs, & integer :: verbose_hrs=24 ! Period between verbose messages integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs -real :: spring_coef=1.e-8 ! Spring contant for iceberg interactions - Alon -real :: bond_coef=1.e-8 ! Spring contant for iceberg bonds - Alon +real :: spring_coef=3.e-9 ! Spring contant for iceberg interactions (this seems to be the highest stable value) +real :: bond_coef=3.e-9 ! Spring contant for iceberg bonds - not being used right now real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs @@ -312,6 +313,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. @@ -327,7 +329,7 @@ subroutine ice_bergs_framework_init(bergs, & namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & - parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & + parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -609,6 +611,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon bergs%manually_initialize_bonds=manually_initialize_bonds !Alon bergs%critical_interaction_damping_on=critical_interaction_damping_on !Alon @@ -832,9 +835,11 @@ subroutine update_halo_icebergs(bergs) integer :: temp1, temp2 real :: current_halo_status logical :: force_app +logical :: halo_debugging force_app =.true. halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. +halo_debugging=bergs%halo_debugging ! Must be less than current halo value used for updating weight. ! Get the stderr unit number stderrunit = stderr() @@ -842,16 +847,20 @@ subroutine update_halo_icebergs(bergs) ! For convenience grd=>bergs%grd + + !For debugging -!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied -! this=>bergs%list(grdi,grdj)%first -! do while (associated(this)) -! write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj -! this=>this%next -! enddo -!enddo; enddo -! Use when debugging: -!call show_all_bonds(bergs) +if (halo_debugging) then + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo + enddo; enddo + ! Use when debugging: + call show_all_bonds(bergs) +endif @@ -878,14 +887,15 @@ subroutine update_halo_icebergs(bergs) !############################## !For debugging -!do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied -! this=>bergs%list(grdi,grdj)%first -! do while (associated(this)) -! write(stderrunit,*) 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj -! this=>this%next -! enddo -!enddo; enddo - +if (halo_debugging) then + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo + enddo; enddo +endif if (debug) then nbergs_start=count_bergs(bergs) endif @@ -1092,14 +1102,15 @@ subroutine update_halo_icebergs(bergs) !For debugging -do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied +if (halo_debugging) then + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) write(stderrunit,*) 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj this=>this%next enddo -enddo; enddo - + enddo; enddo +endif @@ -2377,16 +2388,18 @@ subroutine connect_all_bonds(bergs) if (.not.associated(current_bond%other_berg)) then bond_matched=.false. i = current_bond%other_berg_ine ; j = current_bond%other_berg_jne - other_berg=>bergs%list(i,j)%first - do while (associated(other_berg)) ! loop over all other bergs - if (other_berg%iceberg_num == current_bond%other_berg_num) then - current_bond%other_berg=>other_berg - other_berg=>null() - bond_matched=.true. - else - other_berg=>other_berg%next - endif - enddo + if ( (i.gt. grd%isd-1) .and. (i .lt. grd%ied+1) .and. (j .gt. grd%jsd-1) .and. (j .lt. grd%jed+1)) then + other_berg=>bergs%list(i,j)%first + do while (associated(other_berg)) ! loop over all other bergs + if (other_berg%iceberg_num == current_bond%other_berg_num) then + current_bond%other_berg=>other_berg + other_berg=>null() + bond_matched=.true. + else + other_berg=>other_berg%next + endif + enddo + endif if (.not.bond_matched) then ! If you are stil not matched, then search adjacent cells do grdj_inner = j-1,j+1 ; do grdi_inner = i-1,i+1 @@ -2408,12 +2421,17 @@ subroutine connect_all_bonds(bergs) endif enddo;enddo endif - if (.not.bond_matched) then - print * , berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine + if (.not.bond_matched) then if (berg%halo_berg .lt. 0.5) then missing_bond=.true. - print * , berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine + print * ,'non-halo berg unmatched: ', berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine call error_mesg('diamonds, connect_all_bonds', 'A non-halo bond is missing!!!', FATAL) + else ! This is not a problem if the partner berg is not yet in the halo + if ( (current_bond%other_berg_ine .gt.grd%isd-1) .and. (current_bond%other_berg_ine .lt.grd%ied+1) & + .and. (current_bond%other_berg_jne .gt.grd%jsd-1) .and. (current_bond%other_berg_jne .lt.grd%jed+1) ) then + print * ,'halo berg unmatched: ',mpp_pe(), berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine,current_bond%other_berg_jne + call error_mesg('diamonds, connect_all_bonds', 'A halo bond is missing!!!', WARNING) + endif endif endif endif @@ -2516,7 +2534,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's if (number_of_bonds .gt. 0) then - print *, "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() + write(stderrunit,*) "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() endif if (quality_check) then From 73f4e76244495af407285b63399b8f85015d3bd4 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 15 Oct 2015 17:19:57 -0400 Subject: [PATCH 087/361] Two bugs in the iceberg interactions fixed: 1) Damping coefitients must be multiplied by dt before entering the matrix A (which solves for the updated acceleration. 2) P_21 was not being correctly undated when applying the damping to perpendicular motion. This has been corrected. Also, the perpendicular damping is set to 4 times less than the parralel. This is just a guess for now, and needs to be investigated further. Also, a flag has been added whihc allows the user to use icebergs which only feel interaction forces, and do not feel the environment. Fixing these two bugs allows the model to run with more than 4 bonded icebergs. More testing is needed to see if this is sufficiently robust --- icebergs.F90 | 120 ++++++++++++++++++++++++----------------- icebergs_framework.F90 | 7 ++- 2 files changed, 77 insertions(+), 50 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2305a33..6907b4c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -262,7 +262,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i !Using critical values for damping rather than manually setting the damping. if (critical_interaction_damping_on) then radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping - tangental_damping_coef=(2.*sqrt(spring_coef)) ! Critical damping (just a guess) + tangental_damping_coef=(2.*sqrt(spring_coef))/4 ! Critical damping (just a guess) endif if (berg%iceberg_num .ne. other_berg%iceberg_num) then @@ -312,46 +312,50 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) + - !MP1 - !print *, 'in the loop1', berg%iceberg_num, other_berg%iceberg_num,r_dist, bonded - !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) - !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num - !Damping force: - !Paralel velocity - P_11=(r_dist_x*r_dist_x)/(r_dist**2) - P_12=(r_dist_x*r_dist_y)/(r_dist**2) - P_21=(r_dist_x*r_dist_y)/(r_dist**2) - P_22=(r_dist_y*r_dist_y)/(r_dist**2) - !p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=radial_damping_coef*(M_min/M1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - - !Normal velocities - P_11=1-P_11 ; P_12=-P_12 ; P_22=1-P_22 - !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=tangental_damping_coef*(M_min/M1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - - !print *, 'P_11',P_11 - !print *, 'P_21',P_21 - !print *, 'P_12',P_12 - !print *, 'P_22',P_22 + if (r_dist < 5*(R1+R2)) then + !MP1 + !print *, 'in the loop1', berg%iceberg_num, other_berg%iceberg_num,r_dist, bonded, IA_x, IA_y + !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) + !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num + !Damping force: + !Paralel velocity + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_21=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + !p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=radial_damping_coef*(M_min/M1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + !print *, 'Paralel: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_21= -P_21 ; P_22=1-P_22 + !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=tangental_damping_coef*(M_min/M1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + !print *, 'Perp: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 + !print *, 'P_11',P_11 + !print *, 'P_21',P_21 + !print *, 'P_12',P_12 + !print *, 'P_22',P_22 + endif endif endif @@ -521,7 +525,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interactive spring acceleration - (Does the spring part need to be called twice?) if (interactive_icebergs_on) then - call Interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. if (.not.Runge_not_Verlet) then axn=axn + IA_x ayn=ayn + IA_y @@ -583,7 +587,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a if (interactive_icebergs_on) then if (itloop>1) then - call Interactive_force(bergs, berg, IA_x, IA_y, us, vs, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, us,vs, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. endif if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest RHS_x=RHS_x -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) @@ -593,7 +597,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a RHS_y=RHS_y - (((P_ia_21*uvel)+(P_ia_22*vvel))-P_ia_times_u_y) endif !print *,'Before calculation:', berg%iceberg_num, IA_x, IA_y, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y - !print *,'Before calculation:', berg%iceberg_num, itloop, IA_x, IA_y endif @@ -612,12 +615,25 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a endif if (interactive_icebergs_on) then - A11=A11+P_ia_11 - A12=A12+P_ia_12 - A21=A21+P_ia_21 - A22=A22+P_ia_22 + A11=A11+(dt*P_ia_11) + A12=A12+(dt*P_ia_12) + A21=A21+(dt*P_ia_21) + A22=A22+(dt*P_ia_22) endif + !This is for testing the code using only interactive forces + if (bergs%only_interactive_forces) then + RHS_x=(IA_x/2) -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) + RHS_y=(IA_y/2) -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) + A11=1+(dt*P_ia_11) + A12=(dt*P_ia_12) + A21=(dt*P_ia_21) + A22=1+(dt*P_ia_22) + !print *,'Other', berg%iceberg_num, P_ia_12,u_star, P_ia_times_u_x, P_ia_11, dt + endif + + + detA=1./((A11*A22)-(A12*A21)) ax=detA*(A22*RHS_x-A12*RHS_y) ay=detA*(A11*RHS_y-A21*RHS_x) @@ -633,8 +649,8 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a uveln=u_star+dt*ax ! Alon vveln=v_star+dt*ay ! Alon + !print *,'IN loop', berg%iceberg_num, RHS_x, A11, A12, A21, A22, ax, itloop, uveln enddo ! itloop - !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon axn=0. @@ -651,9 +667,17 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a axn=axn+f_cori*vveln ayn=ayn-f_cori*uveln endif + + !This is for testing the code using only interactive forces + if (bergs%only_interactive_forces) then + axn=IA_x/2 + ayn=IA_y/2 + endif + bxn= ax-(axn/2) !Alon byn= ay-(ayn/2) !Alon + !print *,'After1', berg%iceberg_num, axn, bxn, uveln ! Limit speed of bergs based on a CFL criteria if (bergs%speed_limit>0.) then diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 5200b3f..6c04300 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -208,6 +208,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. @@ -313,6 +314,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. @@ -327,7 +329,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj, & - distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, & + distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & @@ -610,7 +612,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%passive_mode=passive_mode bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit - bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon bergs%manually_initialize_bonds=manually_initialize_bonds !Alon From f7a6a37cd256febe321572d96cf2f1397849f8af Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 16 Oct 2015 18:03:35 -0400 Subject: [PATCH 088/361] Fixed two bugs related to iceberg interactions: 1) The interactions were taking place based on old positions. They should rather use the updated position, r_np1, for stability. To do this meant updating the position at the end of the time step rather than beginning. This has been done. There are still remaining issues related to the fact that this means we have to search a wider range of grid cells to find hippy bergs. I will sort this out on Monday. 1b) lat_new and lon_new have to be passed between processor. They also have to be stored in the restart file (which has not been done yet). 2) Another bug is fixed, which related to the damping matrix, P, having to be multiplied by dt before being part of the inversion. This has been fixed. --- icebergs.F90 | 147 +++++++++++++++++++++++++++++++++++------ icebergs_framework.F90 | 38 ++++++----- icebergs_io.F90 | 12 ++-- 3 files changed, 151 insertions(+), 46 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 6907b4c..81c7af5 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -204,7 +204,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i P_ia_times_u_x=0. ; P_ia_times_u_y=0. bonded=.false. !Unbonded iceberg interactions - do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 + do grdj = berg%jne-2,berg%jne+2 ; do grdi = berg%ine-2,berg%ine+2 !Note: need to make sure this is wide enough, but less than the halo width other_berg=>bergs%list(grdi,grdj)%first do while (associated(other_berg)) ! loop over all other bergs call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) @@ -273,7 +273,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i M1=berg%mass A1=L1*W1 R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) - lon1=berg%lon; lat1=berg%lat + lon1=berg%lon_new; lat1=berg%lat_new !call rotpos_to_tang(lon1,lat1,x1,y1) @@ -286,7 +286,8 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i v2=other_berg%vvel_old !Old values are used to make it order invariant A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant + lon2=other_berg%lon_new; lat2=other_berg%lat_new !Old values are used to make it order invariant + !call rotpos_to_tang(lon2,lat2,x2,y2) dlon=lon1-lon2 @@ -300,6 +301,12 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i r_dist_y=dlat*(pi/180)*Rearth r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) + + if (berg%iceberg_num .eq. 1) then + print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist + print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded + print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg + endif !print *, 'outside the loop',R1, R2,r_dist, bonded !call overlap_area(R1,R2,r_dist,A_o,trapped) !T_min=min(T1,T2) @@ -315,8 +322,12 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i if (r_dist < 5*(R1+R2)) then + !MP1 - !print *, 'in the loop1', berg%iceberg_num, other_berg%iceberg_num,r_dist, bonded, IA_x, IA_y + if (berg%iceberg_num .eq. 1) then + print *, '************************************************************' + print *, 'INSIDE, r_dist', berg%iceberg_num, r_dist, bonded + endif !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num !Damping force: @@ -629,7 +640,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a A12=(dt*P_ia_12) A21=(dt*P_ia_21) A22=1+(dt*P_ia_22) - !print *,'Other', berg%iceberg_num, P_ia_12,u_star, P_ia_times_u_x, P_ia_11, dt endif @@ -648,8 +658,15 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a uveln=u_star+dt*ax ! Alon vveln=v_star+dt*ay ! Alon - - !print *,'IN loop', berg%iceberg_num, RHS_x, A11, A12, A21, A22, ax, itloop, uveln +!MP4 + ! if (berg%iceberg_num .eq. 1) then + ! print *, '***************************************************' + ! print *,'Iceberg_num, itloop', berg%iceberg_num, itloop + ! print *, 'P matrix:', P_ia_11, P_ia_12,P_ia_21,P_ia_22,P_ia_times_u_x, P_ia_times_u_x + ! print *,'A_matrix', A11, A12, A21, A22 + ! print *,'IA_x IA_y', IA_x, IA_y + ! print *, 'RHS, ustar, uvel,ax: ', RHS_x, u_star,uveln, ax + ! endif enddo ! itloop !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon @@ -670,14 +687,14 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !This is for testing the code using only interactive forces if (bergs%only_interactive_forces) then - axn=IA_x/2 - ayn=IA_y/2 + axn=IA_x + ayn=IA_y endif bxn= ax-(axn/2) !Alon byn= ay-(ayn/2) !Alon - !print *,'After1', berg%iceberg_num, axn, bxn, uveln + if (berg%iceberg_num .eq. 1) print *,'axn, bxn, uveln:', axn, bxn, uveln ! Limit speed of bergs based on a CFL criteria if (bergs%speed_limit>0.) then @@ -2351,20 +2368,21 @@ subroutine evolve_icebergs(bergs) ! Positions and velocity is updated by ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax - + + !*************************************************************************************************** !print *, 'you are here!' - +!MP5 + !call update_verlet_position(bergs,berg,i1,j1) + lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel - + ! Loading past acceleartions - Alon axn=berg%axn; ayn=berg%ayn !Alon - bxn=berg%bxn; byn=berg%byn !Alon - - + bxn=berg%bxn; byn=berg%byn !Alon ! Velocities used to update the position uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon @@ -2373,7 +2391,6 @@ subroutine evolve_icebergs(bergs) if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) u2=uvel2*dxdl1; v2=vvel2*dydl - ! Solving for new position if (on_tangential_plane) then xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon @@ -2382,20 +2399,24 @@ subroutine evolve_icebergs(bergs) lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon endif dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - + +! print *, 'TEST2: ', lonn, latn, berg%iceberg_num + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon vvel3=vvel1+(dt_2*ayn) !Alon ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) + !MP3 + !print *, 'before the bounce.!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" ! If the iceberg bounces off the land, then its velocity and acceleration are set to zero if (bounced) then - !print *, 'you have been bounce: big time!',lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag + print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag axn=0. ; ayn=0. bxn=0. ; byn=0. uvel3=0.; vvel3=0. @@ -2421,7 +2442,10 @@ subroutine evolve_icebergs(bergs) ! uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. (Perhaps this should not be here) uveln=uvel4 vveln=vvel4 - + + print *, 'New velocity: ', uveln, vveln + + ! Debugging if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. @@ -2500,10 +2524,20 @@ subroutine evolve_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs + + lonn=0. ; latn =0. + call update_verlet_position(bergs,berg,lonn, latn) + + if (berg%iceberg_num .eq. 1) then + print *, 'TEST2:' , berg%lon, berg%lat + print *, 'test1: ', lonn, latn + endif !Updating iceberg positions and velocities - berg%lon_old=berg%lon - berg%lat_old=berg%lat + berg%lon_new=lonn ! This is the t=n+1 position (one step ahead) + berg%lat_new=latn + !berg%lon_new=berg%lon + !berg%lat_new=berg%lat berg%uvel_old=berg%uvel berg%vvel_old=berg%vvel berg=>berg%next @@ -2514,6 +2548,75 @@ subroutine evolve_icebergs(bergs) contains +!####################################################################### +!MP6 +subroutine update_verlet_position(bergs,berg,lonn, latn) +type(icebergs), intent(in), pointer :: bergs +type(iceberg), intent(in), pointer :: berg +real, intent(out) :: lonn, latn +!Local variable +real :: uvel3, vvel3 +real :: lon1, lat1, dxdl1, dydl +real :: uvel1, vvel1, uvel2, vvel2 +real :: axn, ayn, bxn, byn +real :: u2, v2, x1, y1, xn, yn +integer :: i_temp, j_temp +integer :: i1, j1 +real :: xi_temp, yj_temp, dx +logical :: on_tangential_plane + + i1=berg%ine + j1=berg%jne + + on_tangential_plane=.false. + if (berg%lat>89.) on_tangential_plane=.true. + + + lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + dydl=r180_pi/Rearth + uvel1=berg%uvel; vvel1=berg%vvel + + + ! Loading past acceleartions - Alon + axn=berg%axn; ayn=berg%ayn !Alon + bxn=berg%bxn; byn=berg%byn !Alon + + ! Velocities used to update the position + uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon + vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon + + dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) + print *, 'dx= ' ,dx, dt, dt_2 + + + if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) + u2=uvel2*dxdl1; v2=vvel2*dydl + + ! Solving for new position + if (on_tangential_plane) then + xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + else + lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon + endif + dxdln=r180_pi/(Rearth*cos(latn*pi_180)) + + + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon + + ! Adjusting mass... + !MP3 + i_temp=i1; j_temp=j1; xi_temp = berg%xi; yj_temp = berg%yj + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i_temp, j_temp, xi_temp, yj_temp, bounced, error_flag) !Alon:"unclear which velocity to use here?" + +end subroutine update_verlet_position + +!####################################################################### + subroutine rotpos_from_tang(x, y, lon, lat) ! Arguments real, intent(in) :: x, y diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 6c04300..39d36d6 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,7 +15,7 @@ module ice_bergs_framework implicit none ; private -integer :: buffer_width=26 !Changed from 20 to 26 by Alon +integer :: buffer_width=28 !Changed from 20 to 28 by Alon integer :: buffer_width_traj=29 !Changed from 23 by Alon !integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon !integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon @@ -140,7 +140,7 @@ module ice_bergs_framework type :: xyt real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_new, lon_new !Explicit and implicit accelerations !Alon real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg real :: mass_of_bits, heat_density integer :: year, iceberg_num @@ -151,7 +151,7 @@ module ice_bergs_framework type(iceberg), pointer :: prev=>null(), next=>null() ! State variables (specific to the iceberg, needed for restarts) real :: lon, lat, uvel, vvel, mass, thickness, width, length - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_old, lat_old !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_new, lat_new !Explicit and implicit accelerations !Alon real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density real :: halo_berg ! Equal to zero for bergs on computational domain, and =1 for bergs on the halo @@ -1441,9 +1441,11 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) buff%data(24,n)=berg%byn !Alon buff%data(25,n)=float(berg%iceberg_num) buff%data(26,n)=berg%halo_berg + buff%data(27,n)=berg%lon_new + buff%data(28,n)=berg%lat_new if (max_bonds .gt. 0) then - counter=26 !how many data points being passed so far (must match above) + counter=28 !how many data points being passed so far (must match above) current_bond=>berg%first_bond do k = 1,max_bonds if (associated(current_bond)) then @@ -1585,12 +1587,12 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%byn=buff%data(24,n) !Alon localberg%iceberg_num=nint(buff%data(25,n)) localberg%halo_berg=buff%data(26,n) + localberg%lon_new=buff%data(27,n) + localberg%lat_new=buff%data(28,n) !These quantities no longer need to be passed between processors localberg%uvel_old=localberg%uvel localberg%vvel_old=localberg%vvel - localberg%lon_old=localberg%lon - localberg%lat_old=localberg%lat ! force_app=.true. if(force_app) then !force append with origin ine,jne (for I/O) @@ -1615,8 +1617,8 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ write(stderrunit,*) localberg%uvel,localberg%vvel write(stderrunit,*) localberg%axn,localberg%ayn !Alon write(stderrunit,*) localberg%bxn,localberg%byn !Alon - write(stderrunit,*) localberg%uvel_old,localberg%vvel_old !Alon - write(stderrunit,*) localberg%lon_old,localberg%lat_old !Alon + write(stderrunit,*) localberg%uvel_old,localberg%vvel_old + write(stderrunit,*) localberg%lon_new,localberg%lat_new write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) @@ -1633,7 +1635,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ this%first_bond=>null() if (max_bonds .gt. 0) then - counter=26 !how many data points being passed so far (must match above) + counter=28 !how many data points being passed so far (must match above) do k = 1,max_bonds other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) @@ -2116,8 +2118,8 @@ logical function sameberg(berg1, berg2) if (berg1%byn.ne.berg2%byn) return !Alon if (berg1%uvel_old.ne.berg2%uvel_old) return !Alon if (berg1%vvel_old.ne.berg2%vvel_old) return !Alon - if (berg1%lon_old.ne.berg2%lon_old) return !Alon - if (berg1%lat_old.ne.berg2%lat_old) return !Alon + if (berg1%lon_new.ne.berg2%lon_new) return !Alon + if (berg1%lat_new.ne.berg2%lat_new) return !Alon sameberg=.true. ! passing the above tests mean that bergs 1 and 2 are identical end function sameberg @@ -2210,7 +2212,7 @@ subroutine print_berg(iochan, berg, label) ' axn,ayn=', berg%axn, berg%ayn, & ' bxn,byn=', berg%bxn, berg%byn, & ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old, & - ' lon_old,lat_old=', berg%lon_old, berg%lat_old, & + ' lon_new,lat_new=', berg%lon_new, berg%lat_new, & ' p,n=', associated(berg%prev), associated(berg%next) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f10.4))') & label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi @@ -2639,8 +2641,8 @@ subroutine record_posn(bergs) posn%byn=this%byn posn%uvel_old=this%uvel_old posn%vvel_old=this%vvel_old - posn%lon_old=this%lon_old - posn%lat_old=this%lat_old + posn%lon_new=this%lon_new + posn%lat_new=this%lat_new posn%halo_berg=this%halo_berg call push_posn(this%trajectory, posn) @@ -3744,8 +3746,8 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) fld(i,12) = this%byn !added by Alon fld(i,13) = this%uvel_old !added by Alon fld(i,14) = this%vvel_old !added by Alon - fld(i,15) = this%lon_old !added by Alon - fld(i,16) = this%lat_old !added by Alon + fld(i,15) = this%lon_new !added by Alon + fld(i,16) = this%lat_new !added by Alon fld(i,17) = time_hash(this) !Changed from 9 to 17 by Alon fld(i,18) = pos_hash(this) !Changed from 10 to 18 by Alon fld(i,19) = float(iberg) !Changed from 11 to 19 by Alon @@ -3840,8 +3842,8 @@ integer function berg_chksum(berg ) rtmp(32)=berg%byn !Added by Alon rtmp(33)=berg%uvel_old !Added by Alon rtmp(34)=berg%vvel_old !Added by Alon - rtmp(35)=berg%lat_old !Added by Alon - rtmp(36)=berg%lon_old !Added by Alon + rtmp(35)=berg%lat_new !Added by Alon + rtmp(36)=berg%lon_new !Added by Alon itmp(37)=berg%halo_berg !Changed from 31 to 40 by Alon itmp(1:37)=transfer(rtmp,i8) !Changed from 28 to 37 by Alon itmp(38)=berg%start_year !Changed from 29 to 38 by Alon diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b231d41..9d291a8 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -613,8 +613,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) - localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon - localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon + localberg%lon_new=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_new=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) @@ -846,8 +846,8 @@ subroutine read_restart_bergs(bergs,Time) localberg%ayn=ayn(k) !Alon localberg%uvel_old=uvel(k) !Alon localberg%vvel_old=vvel(k) !Alon - localberg%lon_old=lon(k) !Alon - localberg%lat_old=lat(k) !Alon + localberg%lon_new=lon(k) !Alon + localberg%lat_new=lat(k) !Alon localberg%bxn=bxn(k) !Alon localberg%byn=byn(k) !Alon localberg%thickness=thickness(k) @@ -937,8 +937,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) - localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon - localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon + localberg%lon_new=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_new=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) From 223184afef2cb22a5f628ddfe72390625b775b0c Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 19 Oct 2015 13:23:24 -0400 Subject: [PATCH 089/361] Verlet position is now updated at the end of each time step. At the end of the time step, (uvel,vvel=u_n), while lon, lat)=r_np1. Making this change allows us to change the interaction distance to one grid cell in the interactive_forces subroutine. The verlet time stepping has been significantly cleaned up. --- icebergs.F90 | 223 +++++++++++++++++------------------------ icebergs_framework.F90 | 36 ++++--- icebergs_io.F90 | 12 +-- 3 files changed, 114 insertions(+), 157 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 81c7af5..88168fd 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -204,7 +204,7 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i P_ia_times_u_x=0. ; P_ia_times_u_y=0. bonded=.false. !Unbonded iceberg interactions - do grdj = berg%jne-2,berg%jne+2 ; do grdi = berg%ine-2,berg%ine+2 !Note: need to make sure this is wide enough, but less than the halo width + do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 !Note: need to make sure this is wide enough, but less than the halo width other_berg=>bergs%list(grdi,grdj)%first do while (associated(other_berg)) ! loop over all other bergs call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) @@ -273,7 +273,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i M1=berg%mass A1=L1*W1 R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) - lon1=berg%lon_new; lat1=berg%lat_new + lon1=berg%lon_old; lat1=berg%lat_old !call rotpos_to_tang(lon1,lat1,x1,y1) @@ -286,7 +286,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i v2=other_berg%vvel_old !Old values are used to make it order invariant A2=L2*W2 R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - lon2=other_berg%lon_new; lat2=other_berg%lat_new !Old values are used to make it order invariant + lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant !call rotpos_to_tang(lon2,lat2,x2,y2) @@ -302,11 +302,12 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) - if (berg%iceberg_num .eq. 1) then - print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist - print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded - print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg - endif + !if (berg%iceberg_num .eq. 1) then + !print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist + !print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist + !print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded + !print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg + !endif !print *, 'outside the loop',R1, R2,r_dist, bonded !call overlap_area(R1,R2,r_dist,A_o,trapped) !T_min=min(T1,T2) @@ -324,10 +325,10 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i if (r_dist < 5*(R1+R2)) then !MP1 - if (berg%iceberg_num .eq. 1) then - print *, '************************************************************' - print *, 'INSIDE, r_dist', berg%iceberg_num, r_dist, bonded - endif + !if (berg%iceberg_num .eq. 1) then + ! !print *, '************************************************************' + ! print *, 'INSIDE, r_dist', berg%iceberg_num, other_berg%iceberg_num, r_dist, bonded + !endif !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num !Damping force: @@ -416,7 +417,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a type(iceberg), pointer :: berg integer, intent(in) :: i, j real, intent(in) :: xi, yj, lat, uvel, vvel, uvel0, vvel0, dt -real, intent(inout) :: ax, ay +real, intent(out) :: ax, ay real, intent(inout) :: axn, ayn, bxn, byn ! Added implicit and explicit accelerations to output -Alon logical, optional :: debug_flag ! Local variables @@ -694,8 +695,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a bxn= ax-(axn/2) !Alon byn= ay-(ayn/2) !Alon - if (berg%iceberg_num .eq. 1) print *,'axn, bxn, uveln:', axn, bxn, uveln - ! Limit speed of bergs based on a CFL criteria if (bergs%speed_limit>0.) then speed=sqrt(uveln*uveln+vveln*vveln) ! Speed of berg @@ -2022,6 +2021,11 @@ subroutine evolve_icebergs(bergs) ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 ! Get the stderr unit number + + + !Initialize variables + ax1=0. ;ax2 =0.; ax3=0.; ax4=0.; + ay1=0. ;ay2 =0.; ay3=0.; ay4=0.; stderrunit = stderr() ! For convenience @@ -2062,28 +2066,25 @@ subroutine evolve_icebergs(bergs) if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - i=berg%ine - j=berg%jne - xi=berg%xi - yj=berg%yj - bounced=.false. - on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. - i1=i;j1=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - - - - if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop -Added by Alon, MP2 + !########################################################################################################### + if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop + + i=berg%ine + j=berg%jne + xi=berg%xi + yj=berg%yj + bounced=.false. + on_tangential_plane=.false. + if (berg%lat>89.) on_tangential_plane=.true. + i1=i;j1=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon axn1=axn; axn2=axn; axn3=axn; axn4=axn ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn - - - + ! A1 = A(X1) lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) @@ -2093,7 +2094,6 @@ subroutine evolve_icebergs(bergs) if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) @@ -2111,7 +2111,6 @@ subroutine evolve_icebergs(bergs) uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - !print *, 'Alon: look here!', lon2, lat2, uvel2, vvel2, i, j, xi, yj call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & @@ -2369,84 +2368,40 @@ subroutine evolve_icebergs(bergs) ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax - !*************************************************************************************************** - !print *, 'you are here!' -!MP5 - !call update_verlet_position(bergs,berg,i1,j1) - - lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - dydl=r180_pi/Rearth - uvel1=berg%uvel; vvel1=berg%vvel - - ! Loading past acceleartions - Alon - axn=berg%axn; ayn=berg%ayn !Alon - bxn=berg%bxn; byn=berg%byn !Alon - - ! Velocities used to update the position - uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon - vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon - - if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) - u2=uvel2*dxdl1; v2=vvel2*dydl - - ! Solving for new position - if (on_tangential_plane) then - xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon - call rotpos_from_tang(xn,yn,lonn,latn) - else - lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon - endif - dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - -! print *, 'TEST2: ', lonn, latn, berg%iceberg_num + !*************************************************************************************************!MP5 + lonn = berg%lon ; latn = berg%lat + axn = berg%axn ; ayn = berg%ayn + bxn= berg%bxn ; byn = berg%byn + uvel1=berg%uvel ; vvel1=berg%vvel + i=berg%ine ; j=berg%jne + xi=berg%xi ; yj=berg%yj ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon vvel3=vvel1+(dt_2*ayn) !Alon - - - ! Adjusting mass... Alon decided to move this before calculating the new velocities (so that acceleration can be a fn(r_np1) - !MP3 - !print *, 'before the bounce.!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" - !call adjust_index_and_ground(grd, lonn, latn, uvel1, vvel1, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" - ! If the iceberg bounces off the land, then its velocity and acceleration are set to zero - if (bounced) then - print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag - axn=0. ; ayn=0. - bxn=0. ; byn=0. - uvel3=0.; vvel3=0. - uvel1=0.; vvel1=0. - endif - - i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - + ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - !Solving for the new velocity + !Solving for the new velocity + on_tangential_plane=.false. + if (berg%lat>89.) on_tangential_plane=.true. if (on_tangential_plane) then call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) else - uvel4=uvel3+(dt*ax1); vvel4=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + uveln=uvel3+(dt*ax1); vveln=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln endif - ! uveln=uvel4*dxdln; vveln=vvel4*dydl !Converted to degrees. (Perhaps this should not be here) - uveln=uvel4 - vveln=vvel4 - - print *, 'New velocity: ', uveln, vveln - - ! Debugging + !if (berg%iceberg_num .eq. 1) print *, 'New velocity: ', uveln, vveln + !*************************************************************************************************!MP5 + !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! + error_flag=.false. if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. endif @@ -2457,10 +2412,10 @@ subroutine evolve_icebergs(bergs) call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lonn=',lon1,lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,latn=',lat1,latn,berg%lat + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i=',i1,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j=',j1,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lonn=',lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& @@ -2477,8 +2432,8 @@ subroutine evolve_icebergs(bergs) & dt*v1,dt*vveln write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + error_flag=pos_within_cell(grd, lonn, latn, i1, j1, xi, yj) + call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) @@ -2499,18 +2454,21 @@ subroutine evolve_icebergs(bergs) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Saving all the iceberg variables. - berg%axn=axn !Alon - berg%ayn=ayn !Alon - berg%bxn=bxn !Alon - berg%byn=byn !Alon - berg%lon=lonn - berg%lat=latn + berg%axn=axn + berg%ayn=ayn + berg%bxn=bxn + berg%byn=byn berg%uvel=uveln berg%vvel=vveln - berg%ine=i - berg%jne=j - berg%xi=xi - berg%yj=yj + + if (Runge_not_Verlet) then + berg%lon=lonn ; berg%lat=latn + berg%ine=i ; berg%jne=j + berg%xi=xi ; berg%yj=yj + else + if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) + endif + !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') @@ -2525,21 +2483,14 @@ subroutine evolve_icebergs(bergs) berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs - lonn=0. ; latn =0. - call update_verlet_position(bergs,berg,lonn, latn) - - if (berg%iceberg_num .eq. 1) then - print *, 'TEST2:' , berg%lon, berg%lat - print *, 'test1: ', lonn, latn - endif - - !Updating iceberg positions and velocities - berg%lon_new=lonn ! This is the t=n+1 position (one step ahead) - berg%lat_new=latn - !berg%lon_new=berg%lon - !berg%lat_new=berg%lat + if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) + + !Updating old velocities (for use in iceberg interactions) berg%uvel_old=berg%uvel berg%vvel_old=berg%vvel + berg%lon_old=berg%lon ! lon_old, lat_old are not really needed for Verlet. But are needed for RK + berg%lat_old=berg%lat + berg=>berg%next enddo ! loop over all bergs enddo ; enddo @@ -2550,19 +2501,20 @@ subroutine evolve_icebergs(bergs) !####################################################################### !MP6 -subroutine update_verlet_position(bergs,berg,lonn, latn) +subroutine update_verlet_position(bergs,berg) type(icebergs), intent(in), pointer :: bergs type(iceberg), intent(in), pointer :: berg -real, intent(out) :: lonn, latn !Local variable +real :: lonn, latn +integer :: i_temp, j_temp +real :: xi_temp, yj_temp real :: uvel3, vvel3 real :: lon1, lat1, dxdl1, dydl real :: uvel1, vvel1, uvel2, vvel2 real :: axn, ayn, bxn, byn real :: u2, v2, x1, y1, xn, yn -integer :: i_temp, j_temp integer :: i1, j1 -real :: xi_temp, yj_temp, dx +real :: dx logical :: on_tangential_plane i1=berg%ine @@ -2571,14 +2523,12 @@ subroutine update_verlet_position(bergs,berg,lonn, latn) on_tangential_plane=.false. if (berg%lat>89.) on_tangential_plane=.true. - lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel - ! Loading past acceleartions - Alon axn=berg%axn; ayn=berg%ayn !Alon bxn=berg%bxn; byn=berg%byn !Alon @@ -2588,8 +2538,6 @@ subroutine update_verlet_position(bergs,berg,lonn, latn) vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) - print *, 'dx= ' ,dx, dt, dt_2 - if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) u2=uvel2*dxdl1; v2=vvel2*dydl @@ -2603,7 +2551,6 @@ subroutine update_verlet_position(bergs,berg,lonn, latn) endif dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon vvel3=vvel1+(dt_2*ayn) !Alon @@ -2613,6 +2560,18 @@ subroutine update_verlet_position(bergs,berg,lonn, latn) i_temp=i1; j_temp=j1; xi_temp = berg%xi; yj_temp = berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i_temp, j_temp, xi_temp, yj_temp, bounced, error_flag) !Alon:"unclear which velocity to use here?" + if (bounced) then + print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag + berg%axn=0.0 ; berg%ayn=0.0 + berg%bxn=0.0 ; berg%byn=0.0 + berg%uvel=0.0 ; berg%vvel=0.0 + endif + + !Updating positions and index + berg%lon=lonn ; berg%lat=latn + berg%ine=i_temp ; berg%jne=j_temp + berg%xi=xi_temp ; berg%yj=yj_temp + end subroutine update_verlet_position !####################################################################### diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 39d36d6..f6ae90d 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,7 +15,7 @@ module ice_bergs_framework implicit none ; private -integer :: buffer_width=28 !Changed from 20 to 28 by Alon +integer :: buffer_width=26 !Changed from 20 to 28 by Alon integer :: buffer_width_traj=29 !Changed from 23 by Alon !integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon !integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon @@ -140,7 +140,7 @@ module ice_bergs_framework type :: xyt real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_new, lon_new !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg real :: mass_of_bits, heat_density integer :: year, iceberg_num @@ -151,7 +151,7 @@ module ice_bergs_framework type(iceberg), pointer :: prev=>null(), next=>null() ! State variables (specific to the iceberg, needed for restarts) real :: lon, lat, uvel, vvel, mass, thickness, width, length - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_new, lat_new !Explicit and implicit accelerations !Alon + real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_old, lat_old !Explicit and implicit accelerations !Alon real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density real :: halo_berg ! Equal to zero for bergs on computational domain, and =1 for bergs on the halo @@ -1441,11 +1441,9 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) buff%data(24,n)=berg%byn !Alon buff%data(25,n)=float(berg%iceberg_num) buff%data(26,n)=berg%halo_berg - buff%data(27,n)=berg%lon_new - buff%data(28,n)=berg%lat_new if (max_bonds .gt. 0) then - counter=28 !how many data points being passed so far (must match above) + counter=26 !how many data points being passed so far (must match above) current_bond=>berg%first_bond do k = 1,max_bonds if (associated(current_bond)) then @@ -1587,12 +1585,12 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%byn=buff%data(24,n) !Alon localberg%iceberg_num=nint(buff%data(25,n)) localberg%halo_berg=buff%data(26,n) - localberg%lon_new=buff%data(27,n) - localberg%lat_new=buff%data(28,n) !These quantities no longer need to be passed between processors localberg%uvel_old=localberg%uvel localberg%vvel_old=localberg%vvel + localberg%lon_old=localberg%lon + localberg%lat_old=localberg%lat ! force_app=.true. if(force_app) then !force append with origin ine,jne (for I/O) @@ -1618,7 +1616,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ write(stderrunit,*) localberg%axn,localberg%ayn !Alon write(stderrunit,*) localberg%bxn,localberg%byn !Alon write(stderrunit,*) localberg%uvel_old,localberg%vvel_old - write(stderrunit,*) localberg%lon_new,localberg%lat_new + write(stderrunit,*) localberg%lon_old,localberg%lat_old write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) @@ -1635,7 +1633,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ this%first_bond=>null() if (max_bonds .gt. 0) then - counter=28 !how many data points being passed so far (must match above) + counter=26 !how many data points being passed so far (must match above) do k = 1,max_bonds other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) @@ -2118,8 +2116,8 @@ logical function sameberg(berg1, berg2) if (berg1%byn.ne.berg2%byn) return !Alon if (berg1%uvel_old.ne.berg2%uvel_old) return !Alon if (berg1%vvel_old.ne.berg2%vvel_old) return !Alon - if (berg1%lon_new.ne.berg2%lon_new) return !Alon - if (berg1%lat_new.ne.berg2%lat_new) return !Alon + if (berg1%lon_old .ne.berg2%lon_old) return !Alon + if (berg1%lat_old.ne.berg2%lat_old) return !Alon sameberg=.true. ! passing the above tests mean that bergs 1 and 2 are identical end function sameberg @@ -2212,7 +2210,7 @@ subroutine print_berg(iochan, berg, label) ' axn,ayn=', berg%axn, berg%ayn, & ' bxn,byn=', berg%bxn, berg%byn, & ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old, & - ' lon_new,lat_new=', berg%lon_new, berg%lat_new, & + ' lon_old,lat_old=', berg%lon_old, berg%lat_old, & ' p,n=', associated(berg%prev), associated(berg%next) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f10.4))') & label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi @@ -2641,8 +2639,8 @@ subroutine record_posn(bergs) posn%byn=this%byn posn%uvel_old=this%uvel_old posn%vvel_old=this%vvel_old - posn%lon_new=this%lon_new - posn%lat_new=this%lat_new + posn%lon_old=this%lon_old + posn%lat_old=this%lat_old posn%halo_berg=this%halo_berg call push_posn(this%trajectory, posn) @@ -3746,8 +3744,8 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) fld(i,12) = this%byn !added by Alon fld(i,13) = this%uvel_old !added by Alon fld(i,14) = this%vvel_old !added by Alon - fld(i,15) = this%lon_new !added by Alon - fld(i,16) = this%lat_new !added by Alon + fld(i,15) = this%lon_old !added by Alon + fld(i,16) = this%lat_old !added by Alon fld(i,17) = time_hash(this) !Changed from 9 to 17 by Alon fld(i,18) = pos_hash(this) !Changed from 10 to 18 by Alon fld(i,19) = float(iberg) !Changed from 11 to 19 by Alon @@ -3842,8 +3840,8 @@ integer function berg_chksum(berg ) rtmp(32)=berg%byn !Added by Alon rtmp(33)=berg%uvel_old !Added by Alon rtmp(34)=berg%vvel_old !Added by Alon - rtmp(35)=berg%lat_new !Added by Alon - rtmp(36)=berg%lon_new !Added by Alon + rtmp(35)=berg%lat_old !Added by Alon + rtmp(36)=berg%lon_old !Added by Alon itmp(37)=berg%halo_berg !Changed from 31 to 40 by Alon itmp(1:37)=transfer(rtmp,i8) !Changed from 28 to 37 by Alon itmp(38)=berg%start_year !Changed from 29 to 38 by Alon diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 9d291a8..b231d41 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -613,8 +613,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) - localberg%lon_new=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon - localberg%lat_new=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon + localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) @@ -846,8 +846,8 @@ subroutine read_restart_bergs(bergs,Time) localberg%ayn=ayn(k) !Alon localberg%uvel_old=uvel(k) !Alon localberg%vvel_old=vvel(k) !Alon - localberg%lon_new=lon(k) !Alon - localberg%lat_new=lat(k) !Alon + localberg%lon_old=lon(k) !Alon + localberg%lat_old=lat(k) !Alon localberg%bxn=bxn(k) !Alon localberg%byn=byn(k) !Alon localberg%thickness=thickness(k) @@ -937,8 +937,8 @@ subroutine generate_bergs(bergs,Time) localberg%jne=j localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) - localberg%lon_new=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon - localberg%lat_new=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon + localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon + localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) From 5128472dc10faba21f72f02d1fdb8b4dd938e482 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 19 Oct 2015 15:30:24 -0400 Subject: [PATCH 090/361] The evolve_iceberg subroutine has been cleaned up and put in order. Subroutines have been created for the verlet_stepping and Runge_Kutta_stepping to make the code easier to read. All sub-sub-routines inside evolve_icebergs have been made into subroutines, which again makes the code easier to read. This commit should not change the answers. --- icebergs.F90 | 456 +++++++++++++++++++++++++++------------------------ 1 file changed, 244 insertions(+), 212 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 88168fd..6f427ae 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -47,7 +47,9 @@ module ice_bergs public icebergs_init, icebergs_end, icebergs_run, icebergs_stock_pe, icebergs public icebergs_incr_mass, icebergs_save_restart -real, parameter :: pi_180=pi/180. ! Converts degrees to radians +real, parameter :: pi_180=pi/180. ! Converts degrees to radians +real, parameter :: r180_pi=180./pi ! Converts radians to degrees +real, parameter :: Rearth=6360000. ! Radius of earth (m) real, parameter :: rho_ice=916.7 ! Density of fresh ice @ 0oC (kg/m^3) real, parameter :: rho_water=999.8 ! Density of fresh water @ 0oC (kg/m^3) real, parameter :: rho_air=1.1 ! Density of air @ 0oC (kg/m^3) ??? @@ -245,14 +247,12 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i real :: P_11, P_12, P_21, P_22 real :: M1, M2, M_min real :: u2, v2 - real :: Rearth logical :: critical_interaction_damping_on real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef real, intent(inout) :: IA_x, IA_y real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y logical ,intent(in) :: bonded - Rearth=6360.e3 spring_coef=bergs%spring_coef !bond_coef=bergs%bond_coef radial_damping_coef=bergs%radial_damping_coef @@ -1984,70 +1984,30 @@ subroutine evolve_icebergs(bergs) type(icebergs), pointer :: bergs ! Local variables type(icebergs_gridded), pointer :: grd -real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axn1, ayn1 -real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axn2, ayn2 -real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axn3, ayn3 -real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axn4, ayn4 -real :: uveln, vveln, lonn, latn, un, vn, dxdln -real :: x1, xdot1, xddot1, y1, ydot1, yddot1, xddot1n, yddot1n -real :: x2, xdot2, xddot2, y2, ydot2, yddot2, xddot2n, yddot2n -real :: x3, xdot3, xddot3, y3, ydot3, yddot3, xddot3n, yddot3n -real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n -real :: xn, xdotn, yn, ydotn, xddotn, yddotn -real :: bxddot, byddot ! Added by Alon +type(iceberg), pointer :: berg +real :: uveln, vveln, lonn, latn real :: axn, ayn, bxn, byn ! Added by Alon - explicit and implicit accelations from the previous step -real :: r180_pi, dt, dt_2, dt_6, dydl, Rearth -integer :: i, j -integer :: i1,j1,i2,j2,i3,j3,i4,j4 real :: xi, yj -logical :: bounced, on_tangential_plane, error_flag -logical :: Runge_not_Verlet ! Runge_not_Verlet=1 for Runge Kutta, =0 for Verlet method. Added by Alon -type(iceberg), pointer :: berg -integer :: stderrunit -logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. +integer :: i, j integer :: grdi, grdj - - ! 4th order Runge-Kutta to solve: - ! d/dt X = V, d/dt V = A - ! with I.C.'s: - ! X=X1 and V=V1 - ! - ! A1 = A(X1) - ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) - ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) - ! X4 = X1+ dt*V3 ; V4 = V1+ dt*A3; A4=A(X4) - ! - ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 - ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 +integer :: stderrunit +logical :: bounced, interactive_icebergs_on, Runge_not_Verlet ! Get the stderr unit number - - - !Initialize variables - ax1=0. ;ax2 =0.; ax3=0.; ax4=0.; - ay1=0. ;ay2 =0.; ay3=0.; ay4=0.; stderrunit = stderr() ! For convenience grd=>bergs%grd - interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon + interactive_icebergs_on=bergs%interactive_icebergs_on + Runge_not_Verlet=bergs%Runge_not_Verlet - ! Common constants - r180_pi=1./pi_180 - dt=bergs%dt - dt_2=0.5*dt - dt_6=dt/6. - Rearth=6360.e3 - - !Choosing time stepping scheme - Alon - !Runge_not_Verlet=.False. !Loading manually: true=Runge Kutta, False=Verlet , Alon - Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs - + + !Checking it everything is ok: if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 @@ -2063,11 +2023,217 @@ subroutine evolve_icebergs(bergs) berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) endif - if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - !########################################################################################################### - if (Runge_not_Verlet) then !Start of the Runge-Kutta Loop + + !Time stepping schemes: + if (Runge_not_Verlet) then + call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) + endif + if (.not.Runge_not_Verlet) then + call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) + endif + + ! Saving all the iceberg variables. + berg%axn=axn + berg%ayn=ayn + berg%bxn=bxn + berg%byn=byn + berg%uvel=uveln + berg%vvel=vveln + + if (Runge_not_Verlet) then + berg%lon=lonn ; berg%lat=latn + berg%ine=i ; berg%jne=j + berg%xi=xi ; berg%yj=yj + else + if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) + endif + + !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) + !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') + if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') + + berg=>berg%next + enddo ! loop over all bergs + enddo ; enddo + + ! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) + if (interactive_icebergs_on) then + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + berg=>bergs%list(grdi,grdj)%first + do while (associated(berg)) ! loop over all bergs + + if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) + + !Updating old velocities (for use in iceberg interactions) + berg%uvel_old=berg%uvel + berg%vvel_old=berg%vvel + berg%lon_old=berg%lon ! lon_old, lat_old are not really needed for Verlet. But are needed for RK + berg%lat_old=berg%lat + + berg=>berg%next + enddo ! loop over all bergs + enddo ; enddo + endif + +!contains +end subroutine evolve_icebergs + +!###################################################################### + +subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) +type(icebergs), pointer :: bergs +type(iceberg), pointer, intent(inout) :: berg +type(icebergs_gridded), pointer :: grd +! Local variables +real, intent(out) :: axn, ayn, bxn, byn, uveln, vveln +real :: lonn, latn +real :: uvel1, vvel1, uvel2, vvel2, uvel3, vvel3 +real :: ax1, ay1 +real :: x1, y1, xddot1, yddot1, xi, yj +real :: xdot3, ydot3 +real :: xdotn, ydotn +real :: dt, dt_2, dt_6, dydl +logical :: bounced, on_tangential_plane, error_flag +integer :: i, j +integer :: stderrunit + + !Initialize variables + + ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step + ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting + ! Positions and velocity is updated by + ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n + ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax + + !************************************************************************************************* + + ! Get the stderr unit number + stderrunit = stderr() + ! For convenience + grd=>bergs%grd + ! Common constants + dt=bergs%dt + dt_2=0.5*dt + + lonn = berg%lon ; latn = berg%lat + axn = berg%axn ; ayn = berg%ayn + bxn= berg%bxn ; byn = berg%byn + uvel1=berg%uvel ; vvel1=berg%vvel + i=berg%ine ; j=berg%jne + xi=berg%xi ; yj=berg%yj + + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon + + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + + ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + + !Solving for the new velocity + on_tangential_plane=.false. + if (berg%lat>89.) on_tangential_plane=.true. + if (on_tangential_plane) then + call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) + call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) + xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + else + uveln=uvel3+(dt*ax1); vveln=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + endif + + !if (berg%iceberg_num .eq. 1) print *, 'New velocity: ', uveln, vveln + + + !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! + error_flag=.false. + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lonn=',lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& + & dt*ax1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& + & dt*ay1 + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj) + call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif + +end subroutine verlet_stepping + +!###################################################################### + +subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) +type(icebergs), pointer :: bergs +type(iceberg), pointer, intent(inout) :: berg +type(icebergs_gridded), pointer :: grd +real , intent(out) :: axn, ayn, bxn, byn, uveln, vveln,lonn, latn, xi, yj +integer, intent(out) :: i, j +real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axn1, ayn1 +real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axn2, ayn2 +real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axn3, ayn3 +real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axn4, ayn4 +real :: x1, xdot1, xddot1, y1, ydot1, yddot1, xddot1n, yddot1n +real :: x2, xdot2, xddot2, y2, ydot2, yddot2, xddot2n, yddot2n +real :: x3, xdot3, xddot3, y3, ydot3, yddot3, xddot3n, yddot3n +real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n +real :: xn, xdotn, xddotn, yn, ydotn, yddotn, xddotnn, yddotnn +real :: dt, dt_2, dt_6, dydl +integer :: i1,j1,i2,j2,i3,j3,i4,j4 +integer :: stderrunit +logical :: bounced, on_tangential_plane, error_flag + ! 4th order Runge-Kutta to solve: + ! d/dt X = V, d/dt V = A + ! with I.C.'s: + ! X=X1 and V=V1 + ! + ! A1 = A(X1) + ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) + ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) + ! X4 = X1+ dt*V3 ; V4 = V1+ dt*A3; A4=A(X4) + ! + ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 + ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 + + + ! Get the stderr unit number + stderrunit = stderr() + ! For convenience + grd=>bergs%grd + ! Common constants + dt=bergs%dt + dt_2=0.5*dt + dt_6=dt/6. i=berg%ine j=berg%jne @@ -2355,170 +2521,34 @@ subroutine evolve_icebergs(bergs) write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) enddo endif - - endif ! End of the Runge-Kutta Loop -added by Alon - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (.not.Runge_not_Verlet) then !Start of the Verlet time_stepping -Whole loop added by Alon - - ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step - ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting - ! Positions and velocity is updated by - ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n - ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax - - !*************************************************************************************************!MP5 - lonn = berg%lon ; latn = berg%lat - axn = berg%axn ; ayn = berg%ayn - bxn= berg%bxn ; byn = berg%byn - uvel1=berg%uvel ; vvel1=berg%vvel - i=berg%ine ; j=berg%jne - xi=berg%xi ; yj=berg%yj - - ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) - uvel3=uvel1+(dt_2*axn) !Alon - vvel3=vvel1+(dt_2*ayn) !Alon - - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) - - ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) - call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - - !Solving for the new velocity - on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. - if (on_tangential_plane) then - call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) - call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) - xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon - call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) - else - uveln=uvel3+(dt*ax1); vveln=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln - endif - - !if (berg%iceberg_num .eq. 1) print *, 'New velocity: ', uveln, vveln - !*************************************************************************************************!MP5 - !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! - error_flag=.false. - if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i=',i1,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j=',j1,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lonn=',lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& - & dt*ax1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& - & dt*ay1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u3,un,u0=',& - & dt*uvel3,dt*uveln,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v3,vn,v0=',& - & dt*vvel3,dt*vveln,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u_n (deg)=',& - & dt*u1,dt*uveln - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v_n (deg)=',& - & dt*v1,dt*vveln - write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lonn, latn, i1, j1, xi, yj) - call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - endif - - endif ! End of the Verlet Stepiing -added by Alon -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - ! Saving all the iceberg variables. - berg%axn=axn - berg%ayn=ayn - berg%bxn=bxn - berg%byn=byn - berg%uvel=uveln - berg%vvel=vveln - if (Runge_not_Verlet) then - berg%lon=lonn ; berg%lat=latn - berg%ine=i ; berg%jne=j - berg%xi=xi ; berg%yj=yj - else - if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) - endif - - !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) - !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') - if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') - - berg=>berg%next - enddo ! loop over all bergs - enddo ; enddo - - ! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) - if (interactive_icebergs_on) then - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec - berg=>bergs%list(grdi,grdj)%first - do while (associated(berg)) ! loop over all bergs - - if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) - - !Updating old velocities (for use in iceberg interactions) - berg%uvel_old=berg%uvel - berg%vvel_old=berg%vvel - berg%lon_old=berg%lon ! lon_old, lat_old are not really needed for Verlet. But are needed for RK - berg%lat_old=berg%lat - - berg=>berg%next - enddo ! loop over all bergs - enddo ; enddo - endif - - -contains + end subroutine Runge_Kutta_stepping !####################################################################### !MP6 subroutine update_verlet_position(bergs,berg) type(icebergs), intent(in), pointer :: bergs type(iceberg), intent(in), pointer :: berg +type(icebergs_gridded), pointer :: grd !Local variable real :: lonn, latn -integer :: i_temp, j_temp -real :: xi_temp, yj_temp +real :: xi, yj real :: uvel3, vvel3 real :: lon1, lat1, dxdl1, dydl real :: uvel1, vvel1, uvel2, vvel2 -real :: axn, ayn, bxn, byn +real :: axn, ayn, bxn, byn +real :: xdot2, ydot2, dxdln real :: u2, v2, x1, y1, xn, yn -integer :: i1, j1 -real :: dx -logical :: on_tangential_plane +real :: dx, dt, dt_2 +integer :: i, j +logical :: on_tangential_plane, error_flag, bounced + + ! For convenience + grd=>bergs%grd + ! Common constants + dt=bergs%dt + dt_2=0.5*dt - i1=berg%ine - j1=berg%jne on_tangential_plane=.false. if (berg%lat>89.) on_tangential_plane=.true. @@ -2557,8 +2587,8 @@ subroutine update_verlet_position(bergs,berg) ! Adjusting mass... !MP3 - i_temp=i1; j_temp=j1; xi_temp = berg%xi; yj_temp = berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i_temp, j_temp, xi_temp, yj_temp, bounced, error_flag) !Alon:"unclear which velocity to use here?" + i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" if (bounced) then print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag @@ -2569,8 +2599,8 @@ subroutine update_verlet_position(bergs,berg) !Updating positions and index berg%lon=lonn ; berg%lat=latn - berg%ine=i_temp ; berg%jne=j_temp - berg%xi=xi_temp ; berg%yj=yj_temp + berg%ine=i ; berg%jne=j + berg%xi=xi ; berg%yj=yj end subroutine update_verlet_position @@ -2630,6 +2660,10 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun real, parameter :: posn_eps=0.05 integer :: icount, i0, j0, inm, jnm real :: xi0, yj0, lon0, lat0 +integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() bounced=.false. error=.false. @@ -2827,7 +2861,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun end subroutine adjust_index_and_ground -end subroutine evolve_icebergs +!end subroutine evolve_icebergs !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -2837,11 +2871,9 @@ subroutine rotpos_to_tang(lon, lat, x, y) real, intent(out) :: x, y ! Local variables real :: r,colat,clon,slon - real :: Rearth integer :: stderrunit stderrunit = stderr() - Rearth=6360.e3 if (lat>90.) then write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat From f7419054f4e768e04cbd15c34e6d5d0fe1701c72 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 21 Oct 2015 11:39:41 -0400 Subject: [PATCH 091/361] Two and a half bugs fixed: 1) Bug in the subroutine which reads the bond files. The write(' ') command was causing the model to crash when very large tabular icebergs were being loaded. The bug is fixed by using the write(stderrunit). 2) A bug is fixed involving the reading restart files of iceberg bonds where the tabular iceberg extends over more than one processor. The bug is fixed by updating the halos before reading the iceberg bonds. Then reading the bonds restart file, and forming all bonds which have one half of the bond in a processor. Note: it is neccesary to form the bonds where the first iceberg in the iceberg pair is in the halo, and the other bond is in the computational domain. This is because when the halo is cleared, all the iceberg bonds are in that halo are cleared too. If the halo bonds are not formed properly, they causes issues to the other bonds even though they are cleared. On the other hand, halo-halo bonds, and halo-(other PE) bonds can be left unformed and this does not cause any problems. 3) A bug was occuring which caused the model to enter an infinite loop when a 10 by 10 tabular iceberg was used. After a lot of time trying to debug, this bug miraculouly disappeared by itself, and now I can not make it come back. Perhaps it will reemerge in the future, but for now it does not seem to be an issue. The tabular icebergs now seem to be working quite well. A 10 by 10 berg can advect for a month. A 4 by 4 iceberg has been advecting for 5 months. --- icebergs.F90 | 1 + icebergs_framework.F90 | 55 ++++++++++++++++++--------------- icebergs_io.F90 | 69 ++++++++++++++++++++++++++++-------------- 3 files changed, 78 insertions(+), 47 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 6f427ae..9cbb581 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -118,6 +118,7 @@ subroutine icebergs_init(bergs, & if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') if (bergs%iceberg_bonds_on) then + call update_halo_icebergs(bergs) if (bergs%manually_initialize_bonds) then call initialize_iceberg_bonds(bergs) else diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index f6ae90d..edefdce 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -300,8 +300,8 @@ subroutine ice_bergs_framework_init(bergs, & integer :: verbose_hrs=24 ! Period between verbose messages integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs -real :: spring_coef=3.e-9 ! Spring contant for iceberg interactions (this seems to be the highest stable value) -real :: bond_coef=3.e-9 ! Spring contant for iceberg bonds - not being used right now +real :: spring_coef=1.e-8 ! Spring contant for iceberg interactions (this seems to be the highest stable value) +real :: bond_coef=1.e-8 ! Spring contant for iceberg bonds - not being used right now real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs @@ -851,7 +851,6 @@ subroutine update_halo_icebergs(bergs) grd=>bergs%grd - !For debugging if (halo_debugging) then do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied @@ -866,7 +865,6 @@ subroutine update_halo_icebergs(bergs) endif - ! Step 1: Clear the current halos call mpp_sync_self() @@ -903,6 +901,7 @@ subroutine update_halo_icebergs(bergs) nbergs_start=count_bergs(bergs) endif + call mpp_sync_self() !####################################################### ! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes @@ -911,7 +910,6 @@ subroutine update_halo_icebergs(bergs) ! Find number of bergs that headed east/west nbergs_to_send_e=0 nbergs_to_send_w=0 - !Bergs on eastern side of the processor do grdj = grd%jsc,grd%jec ; do grdi = grd%iec-halo_width+1,grd%iec this=>bergs%list(grdi,grdj)%first @@ -927,6 +925,7 @@ subroutine update_halo_icebergs(bergs) enddo enddo; enddo + !Bergs on the western side of the processor do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%isc+halo_width-1 this=>bergs%list(grdi,grdj)%first @@ -942,7 +941,6 @@ subroutine update_halo_icebergs(bergs) enddo; enddo - ! Send bergs east if (grd%pe_E.ne.NULL_PE) then call mpp_send(nbergs_to_send_e, plen=1, to_pe=grd%pe_E, tag=COMM_TAG_1) @@ -959,7 +957,6 @@ subroutine update_halo_icebergs(bergs) endif endif - call mpp_sync_self() ! Receive bergs from west if (grd%pe_W.ne.NULL_PE) then nbergs_rcvd_from_w=-999 @@ -1101,11 +1098,11 @@ subroutine update_halo_icebergs(bergs) nbergs_rcvd_from_n=0 endif - call mpp_sync_self() !For debugging if (halo_debugging) then + call mpp_sync_self() do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) @@ -1115,8 +1112,6 @@ subroutine update_halo_icebergs(bergs) enddo; enddo endif - - end subroutine update_halo_icebergs @@ -2316,13 +2311,12 @@ subroutine bond_address_update(bergs) if (associated(current_bond%other_berg)) then current_bond%other_berg_ine=current_bond%other_berg%ine current_bond%other_berg_jne=current_bond%other_berg%jne - current_bond=>current_bond%next_bond else if (berg%halo_berg .lt. 0.5) then call error_mesg('diamonds, bond address update', 'other berg in bond not assosiated!', FATAL) endif - current_bond=>current_bond%next_bond endif + current_bond=>current_bond%next_bond enddo berg=>berg%next enddo @@ -2349,13 +2343,16 @@ subroutine show_all_bonds(bergs) do while (associated(berg)) ! loop over all bergs current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds - print *, 'Show Bond1 :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine, current_bond%other_berg_jne, mpp_pe() if (associated(current_bond%other_berg)) then - print *, 'Show Bond2 :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg%ine, current_bond%other_berg%jne, mpp_pe() - print *, 'Bond matching', current_bond%other_berg%iceberg_num, current_bond%other_berg_num, mpp_pe() + if (current_bond%other_berg%iceberg_num .ne. current_bond%other_berg_num) then + print *, 'Bond matching', berg%iceberg_num,current_bond%other_berg%iceberg_num, current_bond%other_berg_num, mpp_pe() + call error_mesg('diamonds, show all bonds:', 'The bonds are not matching properly!', FATAL) + endif + else + print *, 'This bond has an non-assosiated other berg :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine, current_bond%other_berg_jne, mpp_pe() endif - current_bond=>current_bond%next_bond + current_bond=>current_bond%next_bond enddo berg=>berg%next enddo @@ -2430,11 +2427,11 @@ subroutine connect_all_bonds(bergs) print * ,'non-halo berg unmatched: ', berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine call error_mesg('diamonds, connect_all_bonds', 'A non-halo bond is missing!!!', FATAL) else ! This is not a problem if the partner berg is not yet in the halo - if ( (current_bond%other_berg_ine .gt.grd%isd-1) .and. (current_bond%other_berg_ine .lt.grd%ied+1) & - .and. (current_bond%other_berg_jne .gt.grd%jsd-1) .and. (current_bond%other_berg_jne .lt.grd%jed+1) ) then - print * ,'halo berg unmatched: ',mpp_pe(), berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine,current_bond%other_berg_jne - call error_mesg('diamonds, connect_all_bonds', 'A halo bond is missing!!!', WARNING) - endif + !if ( (current_bond%other_berg_ine .gt.grd%isd-1) .and. (current_bond%other_berg_ine .lt.grd%ied+1) & + !.and. (current_bond%other_berg_jne .gt.grd%jsd-1) .and. (current_bond%other_berg_jne .lt.grd%jed+1) ) then + !print * ,'halo berg unmatched: ',mpp_pe(), berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine,current_bond%other_berg_jne + !call error_mesg('diamonds, connect_all_bonds', 'A halo bond is missing!!!', WARNING) + !endif endif endif endif @@ -2449,7 +2446,6 @@ subroutine connect_all_bonds(bergs) nbonds=0 call count_bonds(bergs, nbonds,check_bond_quality) endif - end subroutine connect_all_bonds @@ -2963,14 +2959,16 @@ end function find_cell_by_search ! ############################################################################## -subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found) +subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found, search_data_domain) type(icebergs), pointer :: bergs type(iceberg), pointer :: this type(icebergs_gridded), pointer :: grd integer :: grdi, grdj integer, intent(in) :: iceberg_num +logical, intent(in) :: search_data_domain integer, intent(out) :: ine, jne real, intent(out) :: berg_found +integer :: ilim1, ilim2, jlim1, jlim2 berg_found=0.0 ine=999 @@ -2978,7 +2976,16 @@ subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found) ! For convenience grd=>bergs%grd - do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + if (search_data_domain) then + ilim1 = grd%isd ; ilim2=grd%ied ; jlim1 = grd%jsd ; jlim2=grd%jed + else + ilim1 = grd%isc ; ilim2=grd%iec ; jlim1 = grd%jsc ; jlim2=grd%jec + endif + + + do grdj = jlim1, jlim2 ; do grdi = ilim1, ilim2 + !do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + !do grdj = bergs%grd%jsd,bergs%grd%jed ; do grdi = bergs%grd%isd,bergs%grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) if (iceberg_num .eq. this%iceberg_num) then diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b231d41..150948a 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -863,6 +863,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%mass_of_bits=mass_of_bits(k) localberg%halo_berg=halo_berg(k) localberg%heat_density=heat_density(k) + localberg%first_bond=>null() if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) @@ -1036,9 +1037,10 @@ subroutine read_restart_bonds(bergs,Time) integer :: all_pe_number_perfect_bonds, all_pe_number_partial_bonds integer :: all_pe_number_first_bonds_matched, all_pe_number_second_bonds_matched integer :: ine, jne +logical :: search_data_domain real :: berg_found, berg_found_all_pe integer, allocatable, dimension(:) :: first_berg_num, & - other_berg_num, & + other_berg_num, & first_berg_jne, & first_berg_ine, & other_berg_jne, & @@ -1084,40 +1086,54 @@ subroutine read_restart_bonds(bergs,Time) number_second_bonds_matched=0 number_perfect_bonds=0 number_partial_bonds=0 + do k=1, nbonds_in_file ! If i,j in restart files are not good, then we find the berg position of the bond addresses manually: if (ignore_ij_restart) then !Finding first iceberg in bond - ine=999 ; jne=999 ; berg_found=0.0 - call find_individual_iceberg(bergs,first_berg_num(k), ine, jne,berg_found) + ine=999 ; jne=999 ; berg_found=0.0 ; search_data_domain=.true. + call find_individual_iceberg(bergs,first_berg_num(k), ine, jne,berg_found,search_data_domain) berg_found_all_pe=berg_found call mpp_sum(berg_found_all_pe) - !print *, mpp_pe(), berg_found_all_pe, berg_found, first_berg_num(k),'here' if (berg_found_all_pe .gt. 0.5) then - first_berg_ine(k)=ine - first_berg_jne(k)=jne + first_berg_ine(k)=ine + first_berg_jne(k)=jne + !endif else call error_mesg('read_restart_bonds_bergs_new', 'First iceberg in bond not found on any pe', FATAL) endif + if (berg_found_all_pe .lt. 0.5) then + print * , 'First bond berg not located: ', first_berg_num(k),berg_found, mpp_pe(),ine, jne + call error_mesg('read_restart_bonds_bergs_new', 'First bond iceberg not located', FATAL) + endif + !else !Finding other iceberg other iceberg - ine=999 ; jne=999 ; berg_found=0.0 - call find_individual_iceberg(bergs,other_berg_num(k), ine, jne, berg_found) - call mpp_sum(berg_found) - if (berg_found .gt. 0.5) then - other_berg_ine(k)=ine - other_berg_jne(k)=jne + ine=999 ; jne=999 ; berg_found=0.0 ; search_data_domain =.true. + call find_individual_iceberg(bergs,other_berg_num(k), ine, jne, berg_found,search_data_domain) + berg_found_all_pe=berg_found + call mpp_sum(berg_found_all_pe) + if (berg_found_all_pe .gt. 0.5) then + !if (berg_found_all_pe .gt. 1.5) then + ! call error_mesg('read_restart_bonds_bergs_new', 'Other iceberg bond found on more than one pe', FATAL) + !else + other_berg_ine(k)=ine + other_berg_jne(k)=jne + !endif else call error_mesg('read_restart_bonds_bergs_new', 'Other iceberg in bond not found on any pe', FATAL) endif + if (berg_found_all_pe .lt. 0.5) then + print * , 'First bond berg not located: ', other_berg_num(k),berg_found, mpp_pe(),ine, jne + call error_mesg('read_restart_bonds_bergs_new', 'First bond iceberg not located', FATAL) + endif endif - ! Decide whether the first iceberg is on the processeor - if ( first_berg_ine(k)>=grd%isc .and. first_berg_ine(k)<=grd%iec .and. & - first_berg_jne(k)>=grd%jsc .and.first_berg_jne(k)<=grd%jec ) then + if ( (first_berg_ine(k)>=grd%isd) .and. (first_berg_ine(k)<=grd%ied) .and. & + (first_berg_jne(k)>=grd%jsd) .and. (first_berg_jne(k)<=grd%jed) ) then number_first_bonds_matched=number_first_bonds_matched+1 ! Search for the first berg, which the bond belongs to @@ -1128,16 +1144,21 @@ subroutine read_restart_bonds(bergs,Time) if (this%iceberg_num == first_berg_num(k)) then first_berg_found=.true. first_berg=>this + if (first_berg%halo_berg.gt.0.5) print *, 'bonding halo berg:', first_berg_num(k), first_berg_ine(k),first_berg_jne(k) ,grd%isc, grd%iec, mpp_pe() this=>null() else this=>this%next endif enddo - + +!Note, this is a bug since there are no bergs in the halos up to here, are there? + ! Decide whether the second iceberg is on the processeor (data domain) second_berg_found=.false. - if ( other_berg_ine(k)>=grd%isd .and. other_berg_ine(k)<=grd%ied .and. & - other_berg_jne(k)>=grd%jsd .and.other_berg_jne(k)<=grd%jed ) then + !if ( other_berg_ine(k)>=grd%isc-1 .and. other_berg_ine(k)<=grd%iec+1 .and. & + ! other_berg_jne(k)>=grd%jsc-1 .and.other_berg_jne(k)<=grd%jec+1 ) then + if ( (other_berg_ine(k)>=grd%isd) .and. (other_berg_ine(k)<=grd%ied) .and. & + (other_berg_jne(k)>=grd%jsd) .and.(other_berg_jne(k)<=grd%jed) ) then number_second_bonds_matched=number_second_bonds_matched+1 ! Search for the second berg, which the bond belongs to @@ -1160,10 +1181,11 @@ subroutine read_restart_bonds(bergs,Time) call form_a_bond(first_berg, other_berg_num(k), other_berg_ine(k), other_berg_jne(k), second_berg) number_perfect_bonds=number_perfect_bonds+1 else - call form_a_bond(first_berg, other_berg_num(k),other_berg_ine(k),other_berg_jne(k)) + !print *, 'Forming a bond of the second type', mpp_pe(), first_berg_num(k), other_berg_num(k) + !call form_a_bond(first_berg, other_berg_num(k),other_berg_ine(k),other_berg_jne(k)) endif else - write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', k, mpp_pe(), nbonds_in_file + write(stderrunit,*) 'diamonds, bond read restart : ','Not enough partial bonds formed', k, mpp_pe(), nbonds_in_file call error_mesg('read_restart_bonds_bergs_new', 'Failure with reading bonds: First bond not found on pe', FATAL) endif endif @@ -1178,15 +1200,15 @@ subroutine read_restart_bonds(bergs,Time) call mpp_sum(all_pe_number_partial_bonds) if (all_pe_number_partial_bonds .lt. nbonds_in_file) then - write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file + write(stderrunit,*) 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file call error_mesg('read_restart_bonds_bergs_new', 'Not enough partial bonds formed', FATAL) endif if (all_pe_number_perfect_bonds .lt. nbonds_in_file) then call mpp_sum(all_pe_number_first_bonds_matched) call mpp_sum(all_pe_number_second_bonds_matched) - write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Warning, some bonds are not fully formed', all_pe_number_first_bonds_matched , nbonds_in_file - write(*,'(a,i8,a)') 'diamonds, bond read restart : ','Number of first and second bonds matched:', all_pe_number_second_bonds_matched , nbonds_in_file + write(stderrunit,*) 'diamonds, bond read restart : ','Warning, some bonds are not fully formed', all_pe_number_first_bonds_matched , nbonds_in_file + write(stderrunit,*) 'diamonds, bond read restart : ','Number of first and second bonds matched:', all_pe_number_second_bonds_matched , nbonds_in_file call error_mesg('read_restart_bonds_bergs_new', 'Not enough perfect bonds formed', NOTE) endif @@ -1198,6 +1220,7 @@ subroutine read_restart_bonds(bergs,Time) other_berg_ine, & other_berg_jne ) endif + end subroutine read_restart_bonds ! ############################################################################## From 301faee463b899a335e4050fe05141c0e4d9ab71 Mon Sep 17 00:00:00 2001 From: Zhi Liang Date: Tue, 12 Jan 2016 16:11:55 -0500 Subject: [PATCH 092/361] fix the crash issue when reading from distributed file and some file has zero bergs. Fix on print format bug --- icebergs_framework.F90 | 2 +- icebergs_io.F90 | 165 +++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 82 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 30066d1..4d255d5 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1617,7 +1617,7 @@ subroutine print_berg(iochan, berg, label) write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") start lon,lat,yr,day,mass=",2f10.4,i5,f7.2,es12.4)') & label, mpp_pe(), berg%start_lon, berg%start_lat, & berg%start_year, berg%start_day, berg%start_mass - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,7(a,2f10.4),a,2l2)') & label, mpp_pe(), ') i,j=',berg%ine, berg%jne, & ' xi,yj=', berg%xi, berg%yj, & ' lon,lat=', berg%lon, berg%lat, & diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 5017f67..63315ad 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -684,88 +684,89 @@ subroutine read_restart_bergs(bergs,Time) allocate(ine(nbergs_in_file)) allocate(jne(nbergs_in_file)) allocate(start_year(nbergs_in_file)) + endif - call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) - call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) - call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) - call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) - call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) - call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) - call read_unlimited_axis(filename,'width',width,domain=grd%domain) - call read_unlimited_axis(filename,'length',length,domain=grd%domain) - call read_unlimited_axis(filename,'start_lon',start_lon,domain=grd%domain) - call read_unlimited_axis(filename,'start_lat',start_lat,domain=grd%domain) - call read_unlimited_axis(filename,'start_day',start_day,domain=grd%domain) - call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) - call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) - call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) - call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) - - call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) - call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) - call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) - - ! Find approx outer bounds for tile - lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lon1=maxval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lat0=minval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - lat1=maxval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - do k=1, nbergs_in_file - localberg%lon=lon(k) - localberg%lat=lat(k) - if (.not. ignore_ij_restart) then ! read i,j position and avoid the "find" step - localberg%ine=ine(k) - localberg%jne=jne(k) - if ( localberg%ine>=grd%isc .and. localberg%ine<=grd%iec .and. & - localberg%jne>=grd%jsc .and.localberg%jne<=grd%jec ) then - lres=.true. - else - lres=.false. - endif - else ! i,j are not available from the file so we search the grid to find out if we reside on this PE - if (use_slow_find) then - lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - else - lres=find_cell_by_search(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - endif - endif - if (really_debug) then - write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& - & ' on PE ',mpp_pe() - write(stderrunit,*) 'diamonds, read_restart_bergs: lres = ',lres - endif - if (lres) then ! true if we reside on this PE grid - localberg%uvel=uvel(k) - localberg%vvel=vvel(k) - localberg%mass=mass(k) - localberg%axn=axn(k) !Alon - localberg%ayn=ayn(k) !Alon - localberg%uvel_old=uvel_old(k) !Alon - localberg%vvel_old=vvel_old(k) !Alon - localberg%lon_old=lon_old(k) !Alon - localberg%lat_old=lat_old(k) !Alon - localberg%bxn=bxn(k) !Alon - localberg%byn=byn(k) !Alon - localberg%thickness=thickness(k) - localberg%width=width(k) - localberg%length=length(k) - localberg%start_lon=start_lon(k) - localberg%start_lat=start_lat(k) - localberg%start_year=start_year(k) - localberg%start_day=start_day(k) - localberg%start_mass=start_mass(k) - localberg%mass_scaling=mass_scaling(k) - localberg%mass_of_bits=mass_of_bits(k) - localberg%heat_density=heat_density(k) - if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) + call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) + call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) + call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) + call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) + call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) + call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) + call read_unlimited_axis(filename,'width',width,domain=grd%domain) + call read_unlimited_axis(filename,'length',length,domain=grd%domain) + call read_unlimited_axis(filename,'start_lon',start_lon,domain=grd%domain) + call read_unlimited_axis(filename,'start_lat',start_lat,domain=grd%domain) + call read_unlimited_axis(filename,'start_day',start_day,domain=grd%domain) + call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) + call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) + call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) + call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) + + call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) + call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) + call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) + + ! Find approx outer bounds for tile + lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lon1=maxval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lat0=minval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + lat1=maxval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) + do k=1, nbergs_in_file + localberg%lon=lon(k) + localberg%lat=lat(k) + if (.not. ignore_ij_restart) then ! read i,j position and avoid the "find" step + localberg%ine=ine(k) + localberg%jne=jne(k) + if ( localberg%ine>=grd%isc .and. localberg%ine<=grd%iec .and. & + localberg%jne>=grd%jsc .and.localberg%jne<=grd%jec ) then + lres=.true. + else + lres=.false. + endif + else ! i,j are not available from the file so we search the grid to find out if we reside on this PE + if (use_slow_find) then + lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + else + lres=find_cell_by_search(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + endif + endif + if (really_debug) then + write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& + & ' on PE ',mpp_pe() + write(stderrunit,*) 'diamonds, read_restart_bergs: lres = ',lres + endif + if (lres) then ! true if we reside on this PE grid + localberg%uvel=uvel(k) + localberg%vvel=vvel(k) + localberg%mass=mass(k) + localberg%axn=axn(k) !Alon + localberg%ayn=ayn(k) !Alon + localberg%uvel_old=uvel_old(k) !Alon + localberg%vvel_old=vvel_old(k) !Alon + localberg%lon_old=lon_old(k) !Alon + localberg%lat_old=lat_old(k) !Alon + localberg%bxn=bxn(k) !Alon + localberg%byn=byn(k) !Alon + localberg%thickness=thickness(k) + localberg%width=width(k) + localberg%length=length(k) + localberg%start_lon=start_lon(k) + localberg%start_lat=start_lat(k) + localberg%start_year=start_year(k) + localberg%start_day=start_day(k) + localberg%start_mass=start_mass(k) + localberg%mass_scaling=mass_scaling(k) + localberg%mass_of_bits=mass_of_bits(k) + localberg%heat_density=heat_density(k) + if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) call add_new_berg_to_list(bergs%first, localberg) @@ -774,6 +775,8 @@ subroutine read_restart_bergs(bergs,Time) call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) endif enddo + + if(nbergs_in_file > 0) then deallocate( & lon, & lat, & From 173ed258c98b78a77ebca1673b1f473214a433f3 Mon Sep 17 00:00:00 2001 From: Zhi Liang Date: Wed, 13 Jan 2016 14:49:03 -0500 Subject: [PATCH 093/361] fix for cold restart of icebergs --- icebergs_io.F90 | 80 ++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 63315ad..268760d 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -652,9 +652,11 @@ subroutine read_restart_bergs(bergs,Time) found_restart = find_restart_file(filename_base, filename, multiPErestart, io_tile_id(1)) call error_mesg('read_restart_bergs_new', 'Using new icebergs restart read', NOTE) - filename = filename_base - call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) - nbergs_in_file = siz(1) + if (found_restart) then + filename = filename_base + call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) + nbergs_in_file = siz(1) + endif if(nbergs_in_file > 0) then allocate(lon(nbergs_in_file)) @@ -686,33 +688,35 @@ subroutine read_restart_bergs(bergs,Time) allocate(start_year(nbergs_in_file)) endif - call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) - call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) - call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) - call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) - call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) - call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) - call read_unlimited_axis(filename,'width',width,domain=grd%domain) - call read_unlimited_axis(filename,'length',length,domain=grd%domain) - call read_unlimited_axis(filename,'start_lon',start_lon,domain=grd%domain) - call read_unlimited_axis(filename,'start_lat',start_lat,domain=grd%domain) - call read_unlimited_axis(filename,'start_day',start_day,domain=grd%domain) - call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) - call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) - call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) - call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) - - call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) - call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) - call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) + if (found_restart) then + call read_unlimited_axis(filename,'lon',lon,domain=grd%domain) + call read_unlimited_axis(filename,'lat',lat,domain=grd%domain) + call read_unlimited_axis(filename,'lon_old',lon_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'lat_old',lat_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) + call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) + call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) + call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'uvel_old',uvel_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'vvel_old',vvel_old,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon + call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) + call read_unlimited_axis(filename,'width',width,domain=grd%domain) + call read_unlimited_axis(filename,'length',length,domain=grd%domain) + call read_unlimited_axis(filename,'start_lon',start_lon,domain=grd%domain) + call read_unlimited_axis(filename,'start_lat',start_lat,domain=grd%domain) + call read_unlimited_axis(filename,'start_day',start_day,domain=grd%domain) + call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) + call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) + call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) + call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) + + call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) + call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) + call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) + endif ! Find approx outer bounds for tile lon0=minval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) @@ -767,14 +771,14 @@ subroutine read_restart_bergs(bergs,Time) localberg%mass_of_bits=mass_of_bits(k) localberg%heat_density=heat_density(k) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) - lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) - call add_new_berg_to_list(bergs%first, localberg) - if (really_debug) call print_berg(stderrunit, bergs%first, 'read_restart_bergs, add_new_berg_to_list') - elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then - call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) - endif - enddo + lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) + !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) + call add_new_berg_to_list(bergs%first, localberg) + if (really_debug) call print_berg(stderrunit, bergs%first, 'read_restart_bergs, add_new_berg_to_list') + elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then + call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) + endif + enddo if(nbergs_in_file > 0) then deallocate( & From 0957ce0d01727ef54e8833070944b37f1d165cba Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 16 Mar 2016 16:03:50 -0400 Subject: [PATCH 094/361] There were a few bugs in the iceberg tipping sheme: 1) The icebergs should tip if their shortest horizonal length (W) is small compared to the iceberg depth (model was using the large horizonal length L ) - this bug was copied from Bigg et al 1997 2) There was an error in copying from Bigg et al 1997. The tipping scheme used the iceberg draft instead of the iceberg thickness. 3) In the Weeks and Mellor paper, there was an error which meant that the plus sign in front of the 58.32 should have been a minus sign Instead of correcting these errors a flag has been added so that a different rolling criteria is used where icebergs roll when W/Th>tip_parameter. The tip parameter can be added at runtime, or else is calculated directly from the iceberg and ocean density. This is the formula given in Burton et al 2012, equation 27, or equivolently it is the same as the Weeks and Mellor 1978 result, using an iceberg of constant density. When run with the standard configuration, the old (incorrect) rolling scheme is used, and the code does not change the answers --- icebergs.F90 | 29 ++++++++++++++++++++++++++--- icebergs_framework.F90 | 10 ++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 024c301..58f08ad 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -727,6 +727,7 @@ subroutine thermodynamics(bergs) real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb +real :: tip_parameter integer :: i,j, stderrunit type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. @@ -857,15 +858,37 @@ subroutine thermodynamics(bergs) call error_mesg('diamonds, thermodynamics', 'berg appears to have grounded!', FATAL) endif - ! Rolling + ! Rolling - The corrected scheme has been included. The old scheme is here for legacy reasons Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) if ( Dn>0. ) then - if ( max(Wn,Ln)0.) then + tip_parameter=bergs%tip_parameter + else + ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density + tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 + endif + !print *, 'tip_parameter',tip_parameter + if (Th<(tip_parameter* min(Wn,Ln))) then !note that we use the Thickness instead of the Draft + if (WnW) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 30066d1..ab8ea06 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -182,11 +182,13 @@ module ice_bergs_framework logical :: add_weight_to_ocean=.true. ! Add weight of bergs to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean + logical :: use_updated_rolling_scheme=.false. ! Use the corrected Rolling Scheme rather than the erronios one logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon real :: speed_limit=0. ! CFL speed limit for a berg [m/s] + real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() type(buffer), pointer :: obuffer_s=>null(), ibuffer_s=>null() @@ -278,8 +280,10 @@ subroutine ice_bergs_framework_init(bergs, & logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean real :: speed_limit=0. ! CFL speed limit for a berg +real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: use_updated_rolling_scheme=.false. ! Use the corrected Rolling Scheme rather than the erronios one logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon @@ -291,8 +295,8 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, traj_write_hrs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef, radial_damping_coef, tangental_damping_coef, & - rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & - parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & + rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, use_updated_rolling_scheme, & + parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, tip_parameter, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -544,7 +548,9 @@ subroutine ice_bergs_framework_init(bergs, & bergs%passive_mode=passive_mode bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit + bergs%tip_parameter=tip_parameter bergs%Runge_not_Verlet=Runge_not_Verlet !Alon + bergs%use_updated_rolling_scheme=use_updated_rolling_scheme !Alon bergs%critical_interaction_damping_on=critical_interaction_damping_on !Alon bergs%interactive_icebergs_on=interactive_icebergs_on !Alon bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon From a2af07727ffd219945decbe6a6512d718393a318 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 16 Mar 2016 16:29:55 -0400 Subject: [PATCH 095/361] 1) Fixed a bug in the Rolling scheme by changing Th to Tn 2) Added the possibility of running the Rolling code using the corrected Weeks and Mellor 1978 scheme. This is done by setting run parameters use_updated_rolling_scheme=.false and run_parameter=1000. --- icebergs.F90 | 37 +++++++++++++++++++++++++++---------- icebergs_framework.F90 | 4 ++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 58f08ad..71ed399 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -858,10 +858,14 @@ subroutine thermodynamics(bergs) call error_mesg('diamonds, thermodynamics', 'berg appears to have grounded!', FATAL) endif - ! Rolling - The corrected scheme has been included. The old scheme is here for legacy reasons + ! Rolling + !There are now 3 iceberg rolling schemes: + !1) Rolling based on aspect ratio threshold (iceberg of constant density) + !2) Rolling based on corrected Weeks and Mellor scheme + !3) Rolling based on incorrect Weeks and Mellor scheme - kept for legacy reasons Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) if ( Dn>0. ) then - if (bergs%use_updated_rolling_scheme) then + if (bergs%use_updated_rolling_scheme) then !Use Rolling Scheme 1 if (bergs%tip_parameter>0.) then tip_parameter=bergs%tip_parameter else @@ -869,7 +873,7 @@ subroutine thermodynamics(bergs) tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 endif !print *, 'tip_parameter',tip_parameter - if (Th<(tip_parameter* min(Wn,Ln))) then !note that we use the Thickness instead of the Draft + if (Tn<(tip_parameter* min(Wn,Ln))) then !note that we use the Thickness instead of the Draft if (Wn999.) then !Use Rolling Scheme 2 + if ( min(Wn,Ln)null(), ibuffer_n=>null() type(buffer), pointer :: obuffer_s=>null(), ibuffer_s=>null() From 93c56c458032eba3c5e1d9b748be832a666b78f6 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 16 Mar 2016 17:18:03 -0400 Subject: [PATCH 096/361] Add a swap functions to swap width and thickness when iceberg rolls (This simplifies the code, but does not change the answers) --- icebergs.F90 | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 71ed399..151135f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -875,33 +875,23 @@ subroutine thermodynamics(bergs) !print *, 'tip_parameter',tip_parameter if (Tn<(tip_parameter* min(Wn,Ln))) then !note that we use the Thickness instead of the Draft if (Wn999.) then !Use Rolling Scheme 2 if ( min(Wn,Ln)next enddo + contains + + subroutine swap_variables(x,y) + ! Arguments + real, intent(inout) :: x, y + real :: temp + temp=x + x=y + y=temp + end subroutine swap_variables + end subroutine thermodynamics ! ############################################################################## From 2b47f3f0072073bb91088c2604b85c9dfffbad2b Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 16 Mar 2016 17:38:17 -0400 Subject: [PATCH 097/361] Refactored the iceberg rolling code to make it shorter and easier to read. It should still do the same thing. Note that the width is set to be the shortest horizontal dimension. This is down after Rolling Scheme 3 (ie the old scheme) so that the code will not have answers changed in default mode --- icebergs.F90 | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 151135f..c038011 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -858,43 +858,38 @@ subroutine thermodynamics(bergs) call error_mesg('diamonds, thermodynamics', 'berg appears to have grounded!', FATAL) endif - ! Rolling + ! Rolling !There are now 3 iceberg rolling schemes: !1) Rolling based on aspect ratio threshold (iceberg of constant density) !2) Rolling based on corrected Weeks and Mellor scheme !3) Rolling based on incorrect Weeks and Mellor scheme - kept for legacy reasons Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) if ( Dn>0. ) then - if (bergs%use_updated_rolling_scheme) then !Use Rolling Scheme 1 - if (bergs%tip_parameter>0.) then - tip_parameter=bergs%tip_parameter - else - ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density - tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 - endif - !print *, 'tip_parameter',tip_parameter - if (Tn<(tip_parameter* min(Wn,Ln))) then !note that we use the Thickness instead of the Draft - if (Wn999.) then !Use Rolling Scheme 2 - if ( min(Wn,Ln)Ln) call swap_variables(Ln,Wn) !Make sure that Wn is the smaller dimension + + if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter>=999.) ) then !Use Rolling Scheme 2 + if ( Wn0.) then + tip_parameter=bergs%tip_parameter + else + ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density + tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 + endif + if (Tn<(tip_parameter* Wn)) then !note that we use the Thickness instead of the Draft + call swap_variables(Tn,Wn) endif endif - end if + endif Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) for grounding endif From 2ef3f4f3096a6d095a61090f0f8dd5cf63dfe144 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 25 Mar 2016 17:22:39 -0400 Subject: [PATCH 098/361] Commented out one line which was printing every bouncing iceberg to the screen --- icebergs.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9cbb581..c7b5ec3 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2591,12 +2591,12 @@ subroutine update_verlet_position(bergs,berg) i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" - if (bounced) then - print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag - berg%axn=0.0 ; berg%ayn=0.0 - berg%bxn=0.0 ; berg%byn=0.0 - berg%uvel=0.0 ; berg%vvel=0.0 - endif + !if (bounced) then + ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag + ! berg%axn=0.0 ; berg%ayn=0.0 + ! berg%bxn=0.0 ; berg%byn=0.0 + ! berg%uvel=0.0 ; berg%vvel=0.0 + !endif !Updating positions and index berg%lon=lonn ; berg%lat=latn From 9eddc06c592ad8822b4371f2b78ea0cdbcb9be9d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Apr 2016 10:19:10 -0400 Subject: [PATCH 099/361] 1) Added a Static_icebergs flag to the namelist. When this flag is true, the evolve_icebergs submodule does not get called, and the icebergs do not move. This is useful for construcing iceshelves 2) Added a ignore_missing_restart_bergs flag to namelist. This allows the model not to crash when the position of an iceberg in the restart file is not found. This is useful when constructing an iceshelf, and one of the icebergs in the restart file is not in the model domain. 3) Added iceberg_num output in some error messages, which helps with debugging --- .icebergs.F90.swo | Bin 0 -> 20480 bytes icebergs.F90 | 41 +++++++++++++++++++++++++---------------- icebergs_framework.F90 | 13 ++++++++++--- icebergs_io.F90 | 9 ++++++++- 4 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 .icebergs.F90.swo diff --git a/.icebergs.F90.swo b/.icebergs.F90.swo new file mode 100644 index 0000000000000000000000000000000000000000..ddfd693b44f034bd69bd80bd09917230ed1d2d10 GIT binary patch literal 20480 zcmeHPS&Sq{5iN6H28-(hfynX7Y3M3>D_aOubiSvv5w2iq>!Hdl7>gt}Eowb1vP__2; zR7Ye)Mn*C_GSjpzuK9 zfx-iY2mVhyAp6g>UWKtd%#5dH{$4fr_n+o-hoPUG<3Gaup77r_$Nz_sKV#^RFda<# z`McrYY4|Ui>MCUrhS{x#3SfOA7@#20Sx%)V=e2|KneH}o{QcFtN=g8GuV3pA9yVA7~o@guDcDm6?i^y z0(bz=nx6tb3A_q80^Ez|+xGw)z~g}r;{ohe;40wVc(z{$zKAh@0r(*BTHxitS>QBq z3OE6fUz)%kA2$jm_rt`p4v5h6+ZJPPm&e>i)kG-}VY9J(q|A;TV*?Q zb`-NjaE3aH1r`e)*sKo&djb}cVJ*+`yUlvFUT-Y31y(wh$(PwlQs73S-S%BygpzFu zITRwqUsPl;9(tsD394D?MA_Oy`vBUHlImMTEPa;;{~^W0f5Ys^6+FC*(Zh#k^nPl& zHu>=3hu~>0dr@*3llh?8s2+OIe!i^QPRs|s95;_vk3jKF>KB)YV?-BsT@i?wezH=p zmfXI)YXrpI$U%?{IpVF^s4pL`LeomWA4j7q^F)|HKa1KdN#iz0AW^KU#_aj59<^9$ zyHo4kerQkK+=tp~14>U$m4P@X&Q6>-v0H$WdD^z4NA)OkYTB_#x(~`4EQRLL#`V=3 zX6@06Xr1gosJ`zsj?|ldzlJ~LtX32vd&mUd>cm1MOhzo`p3f=m^wX`tcWHI2HR<@F z8#_IoB=(e+@PTkJ6v<<`i-0e4ZIQ)tzv48^{YqryZaaN3B_TJXTnouTBK3rV-N^c} zKfqL5R+?IDjn zljPN^ql>QK(xx~F?Xf^;@UiVisTpfx>lL9VYCpZ98(=MCP*H%frX5GA-A}6R!!yXv zft_7BTVqPYvD=-o#ZNFFG!1^J1u#3#(3f5Fd%vELn6{z>8G-Ko!PxNxj70Fz_r&Bl zk_c$e84ADCl^B2Ob%eArElv!#c!+Zc;lE#3S&Ey?6B~`EnQNMpY_^rQ+akUKeI|Oc zkWiUIrvjwc4rVmuSi(*(LQ>RuK+*XKext0S`q-;!EIL?85LXS_z6hWtBO)7PGlYRF zvWjIaa;`K=zbAIhK*b2gckMb#vH|^rLt1k>-QZm>d{U$KNupD zqL5~0E28CNvyIJj7f#vi{N_dav$}Hrg3T_ip1*J*y5F=Ow5)$U;` zqr45|5jaZn5Vx#v2kw`CyI#^!P6ET$F3rnRZ642IGF08C$eXN|@IK6SxZic7@u9a)+J3+L?1BXlL z40w?48d+Gsp+jLu_hJ=;Hl8c#?iuz1M;QP@fXu6ys$Y16Vph)B-uIEXdZL2?pITqT zV|wJJL2hGa(ewY;@m&9VfS&)&vA6Y4L;D@ki%;Q!!UKf|3J(+>C_GSjpzuK9fx-iY z2MP}q9wS6jtfTf=QpMep4^eTMe`Tq_xnh)T)|8C$FzyaU~IPZTe&@P6QK;AOy_z_q})P%H2T;5EPz;C|Ez`~;x-flmN$2U6fR z-~_M$Tm}39wFBP)J_CFlpxT0W0&fKF0$vJG9r_w@9dIw|3cdvlfoB0QIPy;pLNjBkJ8Gz2ca~LiUpA{UPDK?hh~LK%BP2@d?Z0mK zZ`(#zNgTc5Exfi%j9if4$t!ccvH6B8;$@J6i0JjryA3sa4FcU`)SR@+!Z2gEoe^6uX9i+XZ(yk*{jFUWOJN6L11F|T-mtt-c>9?6NSHBQG9 zco}t1oVC{0nM;T8vCp9q{}8HPgwA{!L{Xo@n6YW7)fX{ye5|O`$kEi1Zk&&GK5Fuj zxRLR3laHyY3i@?<6v38T!UrsONj zid{j$3+ZMIjhj5^cXZTMg;Jq!68=n5rq$({Za>GS+fpQ#u zf#Xiqjy$h)D<##AtjfA`G7yUyTJhX=&1Rr9^ID8boEL zX|Q5K;}aSTn$Y~oz~MpidQK6|)KWUDNYiE&X_`?qGf}&lR^QDw5NCDLAVA#5y83SB zfjFy+>;uv0(%~<87V(JM)9uXRHlrE?I)q&c1O$*)*foLkAE{#B%prjM`EAmmeNZ;if*}xEK%0hKNDO2V_hS&MM*|4d= z^fYb&SP67bAVc%zr3soVm1>UwjigC!J0RDJ`ePiyqJ)h$7}U&G4X6(l(%9(1Ba5`R zgFC9?PL(K?(_k%H=}Rj3gC7}vYG*3y#!EG@gUY2!*H`51i~Oma*d!?`Dx^(RjXB1pi5;dx>9Y3svzbkDA7~Sw;=}p03om< AAOHXW literal 0 HcmV?d00001 diff --git a/icebergs.F90 b/icebergs.F90 index c7b5ec3..c99b26d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1416,7 +1416,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! For each berg, evolve call mpp_clock_begin(bergs%clock_mom) - call evolve_icebergs(bergs) + + if (.not.bergs%Static_icebergs) then + call evolve_icebergs(bergs) + endif call move_berg_between_cells(bergs) !Markpoint6 if (debug) call bergs_chksum(bergs, 'run bergs (evolved)',ignore_halo_violation=.true.) if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') @@ -2026,14 +2029,13 @@ subroutine evolve_icebergs(bergs) endif if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - - !Time stepping schemes: - if (Runge_not_Verlet) then - call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) - endif - if (.not.Runge_not_Verlet) then - call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) - endif + !Time stepping schemes: + if (Runge_not_Verlet) then + call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) + endif + if (.not.Runge_not_Verlet) then + call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) + endif ! Saving all the iceberg variables. berg%axn=axn @@ -2059,12 +2061,14 @@ subroutine evolve_icebergs(bergs) enddo ! loop over all bergs enddo ; enddo + ! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) if (interactive_icebergs_on) then do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs - + + if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) !Updating old velocities (for use in iceberg interactions) @@ -2555,7 +2559,7 @@ subroutine update_verlet_position(bergs,berg) if (berg%lat>89.) on_tangential_plane=.true. lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1,berg%iceberg_num) dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel @@ -2866,22 +2870,27 @@ end subroutine adjust_index_and_ground !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine rotpos_to_tang(lon, lat, x, y) +subroutine rotpos_to_tang(lon, lat, x, y, iceberg_num_in) ! Arguments real, intent(in) :: lon, lat real, intent(out) :: x, y + integer, intent(in) , optional :: iceberg_num_in ! Local variables real :: r,colat,clon,slon - integer :: stderrunit + integer :: stderrunit, iceberg_num stderrunit = stderr() - + iceberg_num=000 + if (present(iceberg_num_in)) then + iceberg_num=iceberg_num_in + endif + if (lat>90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat, lon, iceberg_num call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) endif if (lat==90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat, lon call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index edefdce..b76e366 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -207,7 +207,9 @@ module ice_bergs_framework logical :: add_weight_to_ocean=.true. ! Add weight of bergs to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean - logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. + logical :: Static_icebergs=.False. !True= icebergs do no move logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -314,6 +316,8 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. +logical :: Static_icebergs=.False. !True= icebergs do no move logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -328,9 +332,9 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj, & +namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & - rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, & + rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -613,6 +617,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs + bergs%Static_icebergs=Static_icebergs bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon @@ -3260,6 +3266,7 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) y3=grd%lat(i ,j ) x4=grd%lon(i-1,j ) y4=grd%lat(i-1,j ) + if (present(explain)) then if(explain) then diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 150948a..216224e 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -700,6 +700,7 @@ subroutine read_restart_bergs(bergs,Time) type(iceberg) :: localberg ! NOT a pointer but an actual local variable real :: pos_is_good, pos_is_good_all_pe integer :: stderrunit +integer :: grdj, grdi real, allocatable, dimension(:) :: lon, & lat, & @@ -831,7 +832,12 @@ subroutine read_restart_bergs(bergs,Time) pos_is_good_all_pe=pos_is_good call mpp_sum(pos_is_good_all_pe) if (pos_is_good_all_pe .lt. 0.5) then - call error_mesg('diamonds, read_restart_bergs', 'One of the iceberg positions was not found', FATAL) + if (bergs%ignore_missing_restart_bergs) then + call error_mesg('diamonds, read_restart_bergs', 'Iceberg number', iceberg_num(k), 'positions was not found', WARNING) + else + call error_mesg('diamonds, read_restart_bergs', 'Iceberg number', iceberg_num(k), 'positions was not found', FATAL) + endif + endif if (really_debug) then write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& @@ -911,6 +917,7 @@ subroutine read_restart_bergs(bergs,Time) call mpp_sum( bergs%bergy_mass_start ) if (mpp_pe().eq.mpp_root_pe().and.verbose) write(*,'(a)') 'diamonds, read_restart_bergs: completed' + contains subroutine generate_bergs(bergs,Time) From 270838e3bfedffb904b181dcf7ba89b0af797412 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Apr 2016 15:24:04 -0400 Subject: [PATCH 100/361] 1) Added a flag to turn thermodynamics off 2) Changed the restart read routine so that the model ignores icebergs which are positioned in grid cells with zero area --- icebergs.F90 | 4 +++- icebergs_framework.F90 | 5 ++++- icebergs_io.F90 | 8 ++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c99b26d..7c1ce40 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1438,7 +1438,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Iceberg thermodynamics (melting) + rolling call mpp_clock_begin(bergs%clock_the) - call thermodynamics(bergs) + if (.not.bergs%Thermodynamics_off) then + call thermodynamics(bergs) + endif if (debug) call bergs_chksum(bergs, 'run bergs (thermo)') if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index b76e366..de5c08b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -210,6 +210,7 @@ module ice_bergs_framework logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move + logical :: Thermodynamics_off=.False. !True,, then icebergs do not decay logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -318,6 +319,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move +logical :: Thermodynamics_off=.False. !True,, then icebergs do not decay logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -335,7 +337,7 @@ subroutine ice_bergs_framework_init(bergs, & namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & - parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & + parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, Thermodynamics_off, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -619,6 +621,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%Runge_not_Verlet=Runge_not_Verlet bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs + bergs%Thermodynamics_off=Thermodynamics_off bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 216224e..2d34810 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -833,9 +833,9 @@ subroutine read_restart_bergs(bergs,Time) call mpp_sum(pos_is_good_all_pe) if (pos_is_good_all_pe .lt. 0.5) then if (bergs%ignore_missing_restart_bergs) then - call error_mesg('diamonds, read_restart_bergs', 'Iceberg number', iceberg_num(k), 'positions was not found', WARNING) + call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', WARNING) else - call error_mesg('diamonds, read_restart_bergs', 'Iceberg number', iceberg_num(k), 'positions was not found', FATAL) + call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', FATAL) endif endif @@ -873,7 +873,11 @@ subroutine read_restart_bergs(bergs,Time) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) + if (bergs%grd%area(localberg%ine,localberg%jne) .ne. 0) then call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + else + call error_mesg('diamonds, read_restart_bergs', 'Iceberg not added because it is grounded', WARNING) + endif if (really_debug) call print_berg(stderrunit, bergs%list(localberg%ine,localberg%jne)%first, 'read_restart_bergs, add_new_berg_to_list') elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) From a0fb9f09b88ad092aa1eaf40993bae0bdd836276 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 21 Apr 2016 16:48:38 -0400 Subject: [PATCH 101/361] 1) Iceberg spread mass to ocean routine has been edited to take into account the iceberg size. If the distance between an iceberg and the edge of a cell is greater than the iceberg length/2, then the iceberg does not share its mass with the neighbouring cell. This change allows icebergs which are initialized in a regular grid to interpolate their mass to a regular sea ice grid perfectly. 2) A piece of code has been added which initializes the iceberg halos on the edges of the domain correctly. Previously, the code only worked for a reentrant channel in the x-direction. The new code should work for non-reentrant boundary conditions and reentrant boundary conditions 3) The errors assosiated with an iceberg not being found in the restart file are changed to provide more information about which iceberg is not being found. --- icebergs.F90 | 67 +++++++++++++++++++++++++++--------------- icebergs_framework.F90 | 60 +++++++++++++++++++++++++++---------- icebergs_io.F90 | 12 ++++++-- 3 files changed, 98 insertions(+), 41 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7c1ce40..659a1f4 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1019,12 +1019,20 @@ subroutine thermodynamics(bergs) endif ! Store the new state of iceberg (with L>W) - this%mass=Mnew - this%mass_of_bits=nMbits - this%thickness=Tn - this%width=min(Wn,Ln) - this%length=max(Wn,Ln) - + if (.not.bergs%Thermodynamics_off) then + this%mass=Mnew + this%mass_of_bits=nMbits + this%thickness=Tn + this%width=min(Wn,Ln) + this%length=max(Wn,Ln) + else + Mnew=this%mass + Wn=this%width + Ln=this%length + Tn=this%thickness + nMbits=this%mass_of_bits + Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) + endif next=>this%next ! Did berg completely melt? @@ -1044,7 +1052,7 @@ subroutine thermodynamics(bergs) Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) endif - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width ) endif endif @@ -1056,26 +1064,41 @@ end subroutine thermodynamics ! ############################################################################## -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j - real, intent(in) :: x, y, Mberg, Mbits, scaling + real, intent(in) :: x, y, Mberg, Mbits, scaling, Area ! Local variables - real :: xL, xC, xR, yD, yC, yU, Mass + real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR real, parameter :: rho_seawater=1035. - + Mass=(Mberg+Mbits)*scaling ! This line attempts to "clip" the weight felt by the ocean. The concept of ! clipping is non-physical and this step should be replaced by grounding. if (grd%clipping_depth>0.) Mass=min(Mass,grd%clipping_depth*grd%area(i,j)*rho_seawater) + + !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. + + if (grd%area(i,j)>0) then + L=min( sqrt(Area / grd%area(i,j)),1.0) + else + L=1. + endif - xL=min(0.5, max(0., 0.5-x)) - xR=min(0.5, max(0., x-0.5)) + !xL=min(0.5, max(0., 0.5-x)) + !xR=min(0.5, max(0., x-0.5)) + !xC=max(0., 1.-(xL+xR)) + !yD=min(0.5, max(0., 0.5-y)) + !yU=min(0.5, max(0., y-0.5)) + !yC=max(0., 1.-(yD+yU)) + + xL=min(0.5, max(0., 0.5-(x/L))) + xR=min(0.5, max(0., (x/L)+(0.5-(1/L) ))) xC=max(0., 1.-(xL+xR)) - yD=min(0.5, max(0., 0.5-y)) - yU=min(0.5, max(0., y-0.5)) + yD=min(0.5, max(0., 0.5-(y/L))) + yU=min(0.5, max(0., (y/L)+(0.5-(1/L) ))) yC=max(0., 1.-(yD+yU)) yDxL=yD*xL*grd%msk(i-1,j-1) @@ -1438,9 +1461,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Iceberg thermodynamics (melting) + rolling call mpp_clock_begin(bergs%clock_the) - if (.not.bergs%Thermodynamics_off) then - call thermodynamics(bergs) - endif + call thermodynamics(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (thermo)') if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) @@ -2136,7 +2157,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) vvel3=vvel1+(dt_2*ayn) !Alon if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width ) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -2251,7 +2272,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo if (berg%lat>89.) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -2287,7 +2308,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -2342,7 +2363,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -2471,7 +2492,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index de5c08b..4f6faa3 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -503,12 +503,34 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_update_domains(grd%ocean_depth, grd%domain) call mpp_update_domains(grd%parity_x, grd%parity_y, grd%domain, gridtype=AGRID) ! If either parity_x/y is -ve, we need rotation of vectors - ! Sanitize lon and lat at the SW edges + ! Sanitize lon and lat in the southern halo do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied if (grd%lon(i,j).gt.900.) grd%lon(i,j)=grd%lon(i,j+1) if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) enddo; enddo + ! fix halos on edge of the domain + !1) South + do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied + if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i,j+1)-grd%lon(i,j+2) + if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) + enddo; enddo + !2) North + do j=grd%jec+1,grd%jed; do i=grd%isd,grd%ied + if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i,j-1)-grd%lon(i,j-2) + if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j-1)-grd%lat(i,j-2) + enddo; enddo + !3) West + do i=grd%isc-1,grd%isd,-1; do j=grd%jsd,grd%jed + if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i+1,j)-grd%lon(i+2,j) + if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i+1,j)-grd%lat(i+2,j) + enddo; enddo + !4) East + do i=grd%iec+1,grd%ied; do j=grd%jsd,grd%jed + if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i-1,j)-grd%lon(i-2,j) + if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i-1,j)-grd%lat(i-2,j) + enddo; enddo + if (.not. present(maskmap)) then ! Using a maskmap causes tickles this sanity check do j=grd%jsd,grd%jed; do i=grd%isd,grd%ied if (grd%lon(i,j).gt.900.) write(stderrunit,*) 'bad lon: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lon(i,j) @@ -538,6 +560,11 @@ subroutine ice_bergs_framework_init(bergs, & grd%lon(i,j)=modulo(grd%lon(i,j)-minl,360.)+minl enddo; enddo + + + + + ! lonc, latc used for searches do j=grd%jsd+1,grd%jed; do i=grd%isd+1,grd%ied grd%lonc(i,j)=0.25*( (grd%lon(i,j)+grd%lon(i-1,j-1)) & @@ -552,20 +579,20 @@ subroutine ice_bergs_framework_init(bergs, & ' [lon|lat][min|max]=', minval(grd%lon),maxval(grd%lon),minval(grd%lat),maxval(grd%lat) endif - !if (mpp_pe().eq.3) then - ! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) - ! enddo - ! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) - ! enddo - ! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) - ! enddo - !endif + if (mpp_pe().eq.15) then + write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) + enddo + endif !Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) @@ -3086,9 +3113,12 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) modulo(grd%lon(i ,j-1)-(x-180.),360.)+(x-180.), & modulo(grd%lon(i-1,j )-(x-180.),360.)+(x-180.), & modulo(grd%lon(i ,j )-(x-180.),360.)+(x-180.) ) + if (x.lt.xlo .or. x.gt.xhi) return ylo=min( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) yhi=max( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) + + if (y.lt.ylo .or. y.gt.yhi) return if (grd%lat(i,j).gt.89.999) then diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 2d34810..514e24d 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -833,7 +833,10 @@ subroutine read_restart_bergs(bergs,Time) call mpp_sum(pos_is_good_all_pe) if (pos_is_good_all_pe .lt. 0.5) then if (bergs%ignore_missing_restart_bergs) then - call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', WARNING) + if (mpp_pe().eq.mpp_root_pe()) then + print * , 'Iceberg not located: ', lon(k),lat(k), iceberg_num(k) + call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', WARNING) + endif else call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', FATAL) endif @@ -875,8 +878,11 @@ subroutine read_restart_bergs(bergs,Time) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) if (bergs%grd%area(localberg%ine,localberg%jne) .ne. 0) then call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) - else - call error_mesg('diamonds, read_restart_bergs', 'Iceberg not added because it is grounded', WARNING) + else + if (mpp_pe().eq.mpp_root_pe()) then + print * , 'Grounded iceberg: ', lat(k),lon(k), iceberg_num(k) + call error_mesg('diamonds, read_restart_bergs', 'Iceberg not added because it is grounded', WARNING) + endif endif if (really_debug) call print_berg(stderrunit, bergs%list(localberg%ine,localberg%jne)%first, 'read_restart_bergs, add_new_berg_to_list') elseif (multiPErestart .and. io_tile_id(1) .lt. 0) then From e4019842abf30151bc3bc3f97ecd626da84c7432 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 21 Apr 2016 17:08:08 -0400 Subject: [PATCH 102/361] Commenting out the grid printout. --- icebergs_framework.F90 | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 4f6faa3..93a9af1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -579,20 +579,20 @@ subroutine ice_bergs_framework_init(bergs, & ' [lon|lat][min|max]=', minval(grd%lon),maxval(grd%lon),minval(grd%lat),maxval(grd%lat) endif - if (mpp_pe().eq.15) then - write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) - enddo - endif + !if (mpp_pe().eq.15) then + ! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) + ! enddo + !endif !Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) From 418de89b71073221efdbf4d460271db577e0cf45 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 26 Apr 2016 18:24:27 -0400 Subject: [PATCH 103/361] Fixed a bug in the iceberg rolling scheme. The sign of the inequality was the wrong way, which was making the icebergs tip immediately. --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index c038011..548903d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -885,7 +885,7 @@ subroutine thermodynamics(bergs) ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 endif - if (Tn<(tip_parameter* Wn)) then !note that we use the Thickness instead of the Draft + if (Tn>(tip_parameter* Wn)) then !note that we use the Thickness instead of the Draft call swap_variables(Tn,Wn) endif endif From 76dfade7266e55e4456929973515e85373e5a62a Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 27 Apr 2016 12:01:24 -0400 Subject: [PATCH 104/361] Fixed bug in the Burton icebergs tipping scheme. Icebergs should be stable when Wn=Tn. The tipping criteria is Tn*tipping_parameter>Wn where tipping_paramter<1. --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 548903d..a861f71 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -885,7 +885,7 @@ subroutine thermodynamics(bergs) ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 endif - if (Tn>(tip_parameter* Wn)) then !note that we use the Thickness instead of the Draft + if ((tip_parameter*Tn)>Wn) then !note that we use the Thickness instead of the Draft call swap_variables(Tn,Wn) endif endif From 6471ed915807720d9ed120751f1181980bc68e9a Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 13 May 2016 09:45:09 -0400 Subject: [PATCH 105/361] Thermodynamics_off flag has been removed, since it was not really working anyway. Turning thermodynamic effects off can be achieved by setting calving to zero in the OCN in the datatable. --- icebergs.F90 | 11 +---------- icebergs_framework.F90 | 5 +---- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 659a1f4..10a2e82 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1019,21 +1019,12 @@ subroutine thermodynamics(bergs) endif ! Store the new state of iceberg (with L>W) - if (.not.bergs%Thermodynamics_off) then this%mass=Mnew this%mass_of_bits=nMbits this%thickness=Tn this%width=min(Wn,Ln) this%length=max(Wn,Ln) - else - Mnew=this%mass - Wn=this%width - Ln=this%length - Tn=this%thickness - nMbits=this%mass_of_bits - Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) - endif - next=>this%next + next=>this%next ! Did berg completely melt? if (Mnew<=0.) then ! Delete the berg diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 93a9af1..8193f2e 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -210,7 +210,6 @@ module ice_bergs_framework logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move - logical :: Thermodynamics_off=.False. !True,, then icebergs do not decay logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -319,7 +318,6 @@ subroutine ice_bergs_framework_init(bergs, & logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move -logical :: Thermodynamics_off=.False. !True,, then icebergs do not decay logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -337,7 +335,7 @@ subroutine ice_bergs_framework_init(bergs, & namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & - parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, Thermodynamics_off, & + parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -648,7 +646,6 @@ subroutine ice_bergs_framework_init(bergs, & bergs%Runge_not_Verlet=Runge_not_Verlet bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs - bergs%Thermodynamics_off=Thermodynamics_off bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon From 23390e2bc1cc853d6cbbd890cbf61104e3111bb1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 13 May 2016 12:11:13 -0400 Subject: [PATCH 106/361] Added a warning for icebergs being born on land --- icebergs.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/icebergs.F90 b/icebergs.F90 index d8326b9..7f52661 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1753,6 +1753,10 @@ subroutine calve_icebergs(bergs) write(stderrunit,*) 'diamonds, calve_icebergs: something went very wrong!',i,j,xi,yj call error_mesg('diamonds, calve_icebergs', 'berg xi,yj is not correct!', FATAL) endif + if (grd%msk(i,j)<0.5) then + write(stderrunit,*) 'diamonds, adjust: WARNING!!! Iceberg born in land cell',i,j,newberg%lon,newberg%lat + if (debug) call error_mesg('diamonds,calve_icebergs', 'Iceberg born in Land Cell!', FATAL) + endif newberg%ine=i newberg%jne=j newberg%xi=xi From 88050d2daa28536eac024a4bc45ef8b89b6b28b1 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 13 May 2016 12:56:40 -0400 Subject: [PATCH 107/361] Fixed comment in warning message - Warning message said it was issued from "adjust()" when it is actually issued from calve_icebergs(). - No answer changes. --- icebergs.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7f52661..75dd448 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1754,8 +1754,8 @@ subroutine calve_icebergs(bergs) call error_mesg('diamonds, calve_icebergs', 'berg xi,yj is not correct!', FATAL) endif if (grd%msk(i,j)<0.5) then - write(stderrunit,*) 'diamonds, adjust: WARNING!!! Iceberg born in land cell',i,j,newberg%lon,newberg%lat - if (debug) call error_mesg('diamonds,calve_icebergs', 'Iceberg born in Land Cell!', FATAL) + write(stderrunit,*) 'diamonds, calve_icebergs: WARNING!!! Iceberg born in land cell',i,j,newberg%lon,newberg%lat + if (debug) call error_mesg('diamonds, calve_icebergs', 'Iceberg born in Land Cell!', FATAL) endif newberg%ine=i newberg%jne=j From 10ca543baaf0d6ffa6f4b54ca13e86bdca983751 Mon Sep 17 00:00:00 2001 From: William Cooke Date: Fri, 27 May 2016 16:08:56 -0400 Subject: [PATCH 108/361] Fix for situation where no land points buffer the southern edge of the ocean. A situation arose where halo points had NaNs and were introduced through the surface stress fields. The workaround was to zero out the array before use. Proper fix might involve adding an extra gridpoint or two at the southern edge. This may be atmospheric resolution dependent. --- icebergs.F90 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/icebergs.F90 b/icebergs.F90 index 75dd448..cbbf95f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1199,6 +1199,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, Jv_off = (size(tauya,2) - (grd%jec - grd%jsc))/2 - grd%jsc + 1 allocate(uC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed), & vC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed)) + uC_tmp(:,:) = 0.0 + vC_tmp(:,:) = 0.0 ! If the iceberg model used symmetric memory, the starting value of these ! copies would need to be decremented by 1. do I=grd%isc,grd%iec ; do j=grd%jsc,grd%jec @@ -2615,6 +2617,12 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj if (.not. lret) then + write(0,*) 'i0, j0,=', i0,j0 + write(0,*) 'xi0, yj0,=', xi0,yj0 + write(0,*) 'grd%msk(i0, j0)=', grd%msk(i0,j0) + write(0,*) 'lon0, lat0,=', lon0,lat0 + write(0,*) 'i,j,lon, lat,grd%msk(i,j)=', i,j,lon,lat,grd%msk(i,j) + write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment' if (debug) error=.true. endif From ec650393bfb5bdea43cfce1410aace3d2de9301c Mon Sep 17 00:00:00 2001 From: Nicholas Hannah Date: Wed, 1 Jun 2016 11:30:24 +1000 Subject: [PATCH 109/361] Merge loops over identical ranges. #303 --- icebergs.F90 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 75dd448..dd31a52 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1201,10 +1201,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, vC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed)) ! If the iceberg model used symmetric memory, the starting value of these ! copies would need to be decremented by 1. - do I=grd%isc,grd%iec ; do j=grd%jsc,grd%jec - uC_tmp(I,j) = tauxa(I+Iu_off, j+ju_off) - enddo ; enddo - do i=grd%isc,grd%iec ; do J=grd%jsc,grd%jec + do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec + uC_tmp(i,j) = tauxa(i+Iu_off, j+ju_off) vC_tmp(i,J) = tauya(i+iv_off, J+Jv_off) enddo ; enddo From 47174d093c228698c2795cd9f9026ac87f08c1de Mon Sep 17 00:00:00 2001 From: Nicholas Hannah Date: Wed, 1 Jun 2016 15:59:22 +1000 Subject: [PATCH 110/361] Introduce missing value. This prevents valgrind errors on masked points. No answer changes. Closes https://github.com/NOAA-GFDL/MOM6/issues/303. --- icebergs.F90 | 3 +++ icebergs_framework.F90 | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index dd31a52..2ddf811 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -35,6 +35,7 @@ module ice_bergs use ice_bergs_framework, only: grd_chksum2,grd_chksum3 use ice_bergs_framework, only: fix_restart_dates, offset_berg_dates use ice_bergs_framework, only: orig_read ! Remove when backward compatibility no longer needed +use ice_bergs_framework, only: missing_value use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving @@ -1199,6 +1200,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, Jv_off = (size(tauya,2) - (grd%jec - grd%jsc))/2 - grd%jsc + 1 allocate(uC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed), & vC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed)) + uC_tmp(:,:) = missing_value + vC_tmp(:,:) = missing_value ! If the iceberg model used symmetric memory, the starting value of these ! copies would need to be decremented by 1. do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 4d255d5..a720096 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -18,6 +18,7 @@ module ice_bergs_framework integer, parameter :: buffer_width=28 !Changed from 20 to 28 by Alon integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes +real, parameter :: missing_value = -1.0e34 !Local Vars ! Global data (minimal for debugging) @@ -45,7 +46,7 @@ module ice_bergs_framework public nclasses,buffer_width,buffer_width_traj public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,old_bug_bilin,use_roundoff_fix public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget -public orig_read, force_all_pes_traj +public orig_read, force_all_pes_traj, missing_value !Public types From 16fb3f5bffe6c83bed3a732c9420b84945169515 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 2 Jun 2016 09:28:18 -0400 Subject: [PATCH 111/361] Replaced "missing_value" in stress halos with zero - When the wind stress is staggered the southern most edge of a global domain, or edge abutting a masked PE, might not be updated by mpp_update_domains(). A previous fix (47174d093c228) corrected the use of uninitialized data but set the stresses to hugely unphysical values in order to allow trapping. Since the values can be felt in cells next to these non-updated halos we are opting to set the stress to zero instead. --- icebergs.F90 | 5 ++--- icebergs_framework.F90 | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2ddf811..814debd 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -35,7 +35,6 @@ module ice_bergs use ice_bergs_framework, only: grd_chksum2,grd_chksum3 use ice_bergs_framework, only: fix_restart_dates, offset_berg_dates use ice_bergs_framework, only: orig_read ! Remove when backward compatibility no longer needed -use ice_bergs_framework, only: missing_value use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving @@ -1200,8 +1199,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, Jv_off = (size(tauya,2) - (grd%jec - grd%jsc))/2 - grd%jsc + 1 allocate(uC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed), & vC_tmp(grd%isd:grd%ied,grd%jsd:grd%jed)) - uC_tmp(:,:) = missing_value - vC_tmp(:,:) = missing_value + uC_tmp(:,:) = 0. ! This avoids uninitialized values that might remain in halo + vC_tmp(:,:) = 0. ! regions after the call to mpp_update_domains() below. ! If the iceberg model used symmetric memory, the starting value of these ! copies would need to be decremented by 1. do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index a720096..4d255d5 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -18,7 +18,6 @@ module ice_bergs_framework integer, parameter :: buffer_width=28 !Changed from 20 to 28 by Alon integer, parameter :: buffer_width_traj=31 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes -real, parameter :: missing_value = -1.0e34 !Local Vars ! Global data (minimal for debugging) @@ -46,7 +45,7 @@ module ice_bergs_framework public nclasses,buffer_width,buffer_width_traj public verbose, really_debug, debug, restart_input_dir,make_calving_reproduce,old_bug_bilin,use_roundoff_fix public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget -public orig_read, force_all_pes_traj, missing_value +public orig_read, force_all_pes_traj !Public types From 5ff50b2e4446f5755fb69b1b8991ade0e68c1289 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 22 Jun 2016 18:27:43 -0400 Subject: [PATCH 112/361] Added ability for icebergs to spread their mass as hexagons. It is not quite working yet, but is almost there. --- icebergs.F90 | 497 ++++++++++++++++++++++++++++++++++++++--- icebergs_framework.F90 | 5 +- 2 files changed, 465 insertions(+), 37 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 10a2e82..1e46be0 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1043,7 +1043,7 @@ subroutine thermodynamics(bergs) Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) endif - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width ) + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs ) endif endif @@ -1055,52 +1055,135 @@ end subroutine thermodynamics ! ############################################################################## -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: x, y, Mberg, Mbits, scaling, Area + logical, intent(in) :: hexagonal_icebergs ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR + real :: S, H, origin_x, origin_y, x0, y0, theta + real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex real, parameter :: rho_seawater=1035. + integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() Mass=(Mberg+Mbits)*scaling ! This line attempts to "clip" the weight felt by the ocean. The concept of ! clipping is non-physical and this step should be replaced by grounding. if (grd%clipping_depth>0.) Mass=min(Mass,grd%clipping_depth*grd%area(i,j)*rho_seawater) - !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. + !Initialize weights for each cell + yDxL=0. ; yDxC=0. ; yDxR=0. ; yCxL=0. ; yCxR=0. + yUxL=0. ; yUxC=0. ; yUxR=0. ; yCxC=1. + + if (.not. hexagonal_icebergs) then !Treat icebergs as rectangles of size L: + !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. + if (grd%area(i,j)>0) then + L=min( sqrt(Area / grd%area(i,j)),1.0) + else + L=1. + endif + + !Old version before icebergs were given size L + !xL=min(0.5, max(0., 0.5-x)) + !xR=min(0.5, max(0., x-0.5)) + !xC=max(0., 1.-(xL+xR)) + !yD=min(0.5, max(0., 0.5-y)) + !yU=min(0.5, max(0., y-0.5)) + !yC=max(0., 1.-(yD+yU)) + + xL=min(0.5, max(0., 0.5-(x/L))) + xR=min(0.5, max(0., (x/L)+(0.5-(1/L) ))) + xC=max(0., 1.-(xL+xR)) + yD=min(0.5, max(0., 0.5-(y/L))) + yU=min(0.5, max(0., (y/L)+(0.5-(1/L) ))) + yC=max(0., 1.-(yD+yU)) + + yDxL=yD*xL*grd%msk(i-1,j-1) + yDxC=yD*xC*grd%msk(i ,j-1) + yDxR=yD*xR*grd%msk(i+1,j-1) + yCxL=yC*xL*grd%msk(i-1,j ) + yCxR=yC*xR*grd%msk(i+1,j ) + yUxL=yU*xL*grd%msk(i-1,j+1) + yUxC=yU*xC*grd%msk(i ,j+1) + yUxR=yU*xR*grd%msk(i+1,j+1) + yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) - if (grd%area(i,j)>0) then - L=min( sqrt(Area / grd%area(i,j)),1.0) - else - L=1. - endif + + else !Spread mass as if elements area hexagonal - !xL=min(0.5, max(0., 0.5-x)) - !xR=min(0.5, max(0., x-0.5)) - !xC=max(0., 1.-(xL+xR)) - !yD=min(0.5, max(0., 0.5-y)) - !yU=min(0.5, max(0., y-0.5)) - !yC=max(0., 1.-(yD+yU)) - - xL=min(0.5, max(0., 0.5-(x/L))) - xR=min(0.5, max(0., (x/L)+(0.5-(1/L) ))) - xC=max(0., 1.-(xL+xR)) - yD=min(0.5, max(0., 0.5-(y/L))) - yU=min(0.5, max(0., (y/L)+(0.5-(1/L) ))) - yC=max(0., 1.-(yD+yU)) - - yDxL=yD*xL*grd%msk(i-1,j-1) - yDxC=yD*xC*grd%msk(i ,j-1) - yDxR=yD*xR*grd%msk(i+1,j-1) - yCxL=yC*xL*grd%msk(i-1,j ) - yCxR=yC*xR*grd%msk(i+1,j ) - yUxL=yU*xL*grd%msk(i-1,j+1) - yUxC=yU*xC*grd%msk(i ,j+1) - yUxR=yU*xR*grd%msk(i+1,j+1) - yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) + if (grd%area(i,j)>0) then + H = min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ; !Non dimensionalize element length by grid area. (This gives the non-dim Apothen of the hexagon) + else + H= (sqrt(3.)/2)*(0.49) !Larges allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) + endif + S=(2/sqrt(3.))*H !Side of the hexagon + + if (S>0.5) then + !The width of an iceberg should not be greater than half the gridcell, or else it can spread over 3 cells (i.e. S must be less than 0.5 nondimensionally) + !print 'Elements must be smaller than a whole gridcell', 'i.e.: S= ' , S , '>=0.5' + call error_mesg('diamonds, hexagonal spreading', 'Diameter of the iceberg is larger than a grid cell. Use smaller icebergs', WARNING) + endif + + !Subtracting the position of the nearest corner from x,y (The mass will then be spread over the 4 cells connected to that corner) + origin_x=1. ; origin_y=1. + if (x<0.5) origin_x=0. + if (y<0.5) origin_y=0. + + !Position of the hexagon center, relative to origin at the nearest vertex + x0=(x-origin_x) + y0=(y-origin_y) + + theta=0.0 + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + + if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <0) then + call error_mesg('diamonds, hexagonal spreading', 'Intersection with hexagons should not be negative!!!', WARNING) + endif + + Area_Q1=Area_Q1/Area_hex + Area_Q2=Area_Q2/Area_hex + Area_Q3=Area_Q3/Area_hex + Area_Q4=Area_Q4/Area_hex + + !Now, you decide which quadrant belongs to which mass on ocean cell. + if ((x.ge. 0.5) .and. (y.ge. 0.5)) then !Top right vertex + yUxR=Area_Q1 + yUxC=Area_Q2 + yCxC=Area_Q3 + yCxR=Area_Q4 + elseif ((x .lt. 0.5) .and. (y.ge. 0.5)) then !Top left vertex + yUxC=Area_Q1 + yUxL=Area_Q2 + yCxL=Area_Q3 + yCxC=Area_Q4 + elseif ((x.lt.0.5) .and. (y.lt. 0.5)) then !Bottom left vertex + yCxC=Area_Q1 + yCxL=Area_Q2 + yDxL=Area_Q3 + yDxC=Area_Q4 + elseif ((x.ge.0.5) .and. (y.lt. 0.5)) then!Bottom right vertex + yCxR=Area_Q1 + yCxC=Area_Q2 + yDxC=Area_Q3 + yDxR=Area_Q4 + endif + + + !Double check that all the mass is being used. + if (abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>0.001) then + !call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', WARNING) + write(stderrunit,*) 'diamonds, hexagonal spreading, dimensions',S, H, x0 , y0 + write(stderrunit,*) 'diamonds, hexagonal spreading, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1,Area_Q2 , Area_Q3,Area_Q4 + call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) + endif + + endif grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+yDxL*Mass grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+yDxC*Mass @@ -1114,8 +1197,350 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling end subroutine spread_mass_across_ocean_cells + + + + ! ############################################################################## +real function Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) + ! Arguments + real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy + Area_of_triangle = abs( 0.5*((Ax*(By-Cy))+(Bx*(Cy-Ay))+(Cx*(Ay-By))) ); +end function Area_of_triangle + + +logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,include_boundary) + !This function decides whether a point (qx,qy) is inside the triangle ABC. + !There is also the option to include the boundary of the triangle. + ! Arguments + real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy,include_boundary + real :: tol, invDenom,u,v + real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 + + tol=0.0000000001; + if (include_boundary==0.) tol=-tol; !Negative number excludes the boundary case. + + if ((Ax==qx .and. Ay==qy) .or. (Bx==qx .and. By==qy) .or. (Cx==qx .and. Cy==qy)) then !Exclude the pathelogical case + if (include_boundary==0.) then + point_in_triangle = .False. + else + point_in_triangle = .True. + endif + else + + !Compute vectors + v0x=Cx-Ax; + v1x=Bx-Ax; + v2x=qx-Ax; + v0y=Cy-Ay; + v1y=By-Ay; + v2y=qy-Ay; + + !Compute dot products + dot00 = (v0x*v0x)+(v0y*v0y); + dot01 = (v0x*v1x)+(v0y*v1y); + dot02 = (v0x*v2x)+(v0y*v2y); + dot11 = (v1x*v1x)+(v1y*v1y); + dot12 = (v1x*v2x)+(v1y*v2y); + + !Compute barycentric coordinates + invDenom= 1 / ((dot00 * dot11) - (dot01*dot01)); + u=((dot11*dot02)-(dot01*dot12))*invDenom; + v=((dot00*dot12)-(dot01*dot02))*invDenom; + + point_in_triangle = (( ((u+tol).ge.0.) .and. ((v+tol).ge.0)) .and. ((u+v).lt.(1+tol))) + endif +end function point_in_triangle + + +subroutine Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axis1,Area_positive, Area_negative) !You should change this name a little, so that it not similar the other routine. +!This function calculates the area of a triangle on opposited sides of an axis when the triangle is split with two points on one side, and one point on the other. +!In this fuction, A is the point on one side of the axis, and B,C are on the opposite sides + ! Arguments + real , intent(in) :: Ax,Ay,Bx,By,Cx,Cy + character , intent(in) :: axis1 + real, intent(out) :: Area_positive, Area_negative + real :: pABx, pABy, pACx, pACy, A0 + real :: A_half_triangle, A_triangle + + A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); + + call intercept_of_a_line(Ax,Ay,Bx,By,axis1,pABx, pABy); + call intercept_of_a_line(Ax,Ay,Cx,Cy,axis1,pACx, pACy); + + if (axis1=='x') A0=Ay; !Value used for if statements (deciding up/down vs left/right) + if (axis1=='y') A0=Ax; !Value used for if statements (deciding up/down vs left/right) + + A_half_triangle=Area_of_triangle(Ax,Ay,pABx,pABy,pACx,pACy); + if (A0>=0.) then + Area_positive= A_half_triangle; + Area_negative= A_triangle-A_half_triangle + else + Area_positive= A_triangle-A_half_triangle; + Area_negative= A_half_triangle; + endif + +end subroutine Area_of_triangle_across_axes + +subroutine intercept_of_a_line(Ax,Ay,Bx,By,axes1,x0,y0) +!This routine returns the position (x0,y0) at which a line AB intercepts the x or y axis +!The value No_intercept_val is returned when the line does not intercept the axis + !Arguments + real, intent(in) :: Ax,Ay,Bx,By + character, intent(in) ::axes1 + real, intent(out) :: x0,y0 + real :: No_intercept_val !Huge value used to make sure that the intercept is outside the triange in the parralel case. + + + No_intercept_val=100000000000.; !Huge value used to make sure that the intercept is outside the triange in the parralel case. + x0=No_intercept_val + y0=No_intercept_val + + if (axes1=='x') then !x intercept + if (Ay.ne.By) then + x0=Ax -(((Ax-Bx)/(Ay-By))*Ay) + y0=0. + endif + endif + + if (axes1=='y') then !y intercept + if (Ax.ne.Bx) then + x0=0. + y0=-(((Ay-By)/(Ax-Bx))*Ax)+Ay + endif + endif +end subroutine intercept_of_a_line + + +subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative) +!This routine gives you the area of a triangle on opposite sides of the axis specified. +!It also takes care of the special case where the triangle is totally on one side +!This routine calls Area_of_triangle_across_axes to calculate the areas when the triangles are split. + + !Arguments + real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy + character, intent(in) ::axes1 + real, intent(out) :: Area_positive, Area_negative + real :: A0,B0,C0 + real A_triangle + + if (axes1=='x') then !Use the y-coordinates for if statements to see which side of the line you are on + A0=Ay + B0=By + C0=Cy + endif + if (axes1=='y') then !Use the y-coordinates for if statements to see which side of the line you are on + A0=Ax + B0=Bx + C0=Cx + endif + + A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); + if ((B0*C0)>0.) then !B and C are on the same side (and non-zero) + if ((A0*B0).ge.0.) then !all three on the the same side (if it equals zero, then A0=0 and the otehrs are not) + if ((A0>0.) .or. ((A0==0.) .and. (B0>0.))) then + Area_positive= A_triangle; + Area_negative= 0.; + else + Area_positive= 0.; + Area_negative= A_triangle; + endif + else !A is on the opposite side to B and C + call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative); + endif + + elseif ((B0*C0)<0.) then !B and C are on the opposite sides + if ((A0*B0).ge. 0.) then !C is all alone + call Area_of_triangle_across_axes(Cx,Cy,Bx,By,Ax,Ay,axes1,Area_positive, Area_negative); + else !B is all alone + call Area_of_triangle_across_axes(Bx,By,Cx,Cy,Ax,Ay,axes1,Area_positive, Area_negative); + endif + + else !This is the case when either B or C is equal to zero (or both), A0 could be zero too. + if (((A0.eq.0.) .and. (B0.eq.0.)) .and. (C0.eq.0.)) then + Area_positive= 0.; + Area_negative= 0.; + elseif ((A0*B0<0.) .or. (A0*C0<0.)) then !A, B are on opposite sides, and C is zero. OR A, C are on opposite sides, and B is zero. + call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative); + elseif (((A0*B0>0.) .or. (A0*C0>0.)) .or. (((abs(A0)>0.) .and. (B0==0.)) .and. (C0==0.))) then + if (A0>0.) then + Area_positive= A_triangle; + Area_negative= 0.; + else + Area_positive= 0.; + Area_negative= A_triangle; + endif + + elseif (A0.eq. 0.) then !(one of B,C is zero too) + if ((B0>0.) .or. (C0>0.)) then + Area_positive= A_triangle; + Area_negative= 0.; + elseif ((B0<0.) .or. (C0<0.)) then + Area_positive= 0.; + Area_negative= A_triangle; + else + !print 'You should not get here1' + call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle dividing routine', FATAL) + endif + else + !print 'You should not get here2' + call error_mesg('diamonds, iceberg_run', 'Another logical error inside triangle dividing routine', FATAL) + endif + endif +end subroutine divding_triangle_across_axes + + +subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4) +!This routine takes a triangle, and finds the intersection with the four quadrants + !Arguments + real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy + real, intent(out) :: Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4 + real :: Area_Upper, Area_Lower, Area_Right, Area_Left + real :: px, py , qx , qy + real :: Area_key_quadrant + integer :: Key_quadrant + + Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); + + !Calculating area across axes + call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'x',Area_Upper ,Area_Lower); + call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'y',Area_Right ,Area_Left); + + !Decide if the origin is in the triangle. If so, then you have to divide the area 4 ways + !This is done by finding a quadrant where the intersection between the triangle and quadrant forms a new triangle + !(This occurs when on of the sides of the triangle intersects both the x and y axis) + if (point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.,0.)) then + !Find a line in the triangle that cuts both axes in/on the trianlge + call intercept_of_a_line(Ax,Ay,Bx,By,'x',px,py); !x_intercept + call intercept_of_a_line(Ax,Ay,Bx,By,'y',qx,qy); !y_intercept + !Note that the 1. here means that we include points on the boundary of the triange. + if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + call intercept_of_a_line(Ax,Ay,Cx,Cy,'x',px,py); !x_intercept + call intercept_of_a_line(Ax,Ay,Cx,Cy,'y',qx,qy); !y_intercept + if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + call intercept_of_a_line(Bx,By,Cx,Cy,'x',px,py); !x_intercept + call intercept_of_a_line(Bx,By,Cx,Cy,'y',qx,qy); !y_intercept + if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + !print 'Houston, we have a problem' + !You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. + call error_mesg('diamonds, iceberg_run', 'Something went wrong with Triangle_divide_into_four_quadrants', FATAL) + endif + endif + endif + + !Assigning quadrants. Key_quadrant is the quadrant with the baby triangle in it. + Area_key_quadrant=Area_of_triangle(px,py,qx,qy,0.,0.) + if ((px.ge. 0.) .and. (qy.ge. 0.)) then !First quadrant + Key_quadrant=1; + elseif ((px.lt.0.) .and. (qy.ge. 0.)) then !Second quadrant + Key_quadrant=2 + elseif ((px.lt. 0.) .and. (qy.lt. 0.)) then !Third quadrant + Key_quadrant=3; + else !#Forth quadrant + Key_quadrant=4 + endif + + else !At least one quadrant is empty, and this can be used to find the areas in the other quadrant. Assigning quadrants. Key_quadrant is the empty quadrant. + Area_key_quadrant=0; + if ( (.not. ((((Ax>0.) .and. (Ay>0.)) .or. ((Bx>0.) .and. (By> 0.))) .or. ((Cx>0.) .and. (Cy> 0.)))) .and. ((Area_Upper+Area_Right).le.Area_triangle) ) then + !No points land in this quadrant and triangle does not cross the quadrant + Key_quadrant=1; + elseif ( (.not. ((((Ax<0.) .and. (Ay>=0)) .or. ((Bx<0.) .and. (By>=0.))) .or. ((Cx<0.) .and. (Cy>=0.)))) .and. ((Area_Upper+Area_Left).le. Area_triangle) ) then + Key_quadrant=2 + elseif ( (.not. ((((Ax<0.) .and. (Ay<0.)) .or. ((Bx<0.) .and. (By< 0.))) .or. ((Cx<0.) .and. (Cy< 0.)))) .and. ((Area_Lower+Area_Left) .le.Area_triangle) ) then + Key_quadrant=3; + else + Key_quadrant=4 + endif + endif + + + !Assign values to quadrants + if (Key_quadrant .eq. 1) then + Area_Q1=Area_key_quadrant; + Area_Q2=Area_Upper-Area_Q1; + Area_Q4=Area_Right-Area_Q1; + Area_Q3=Area_Left-Area_Q2; + elseif (Key_quadrant .eq. 2) then + Area_Q2=Area_key_quadrant; + Area_Q1=Area_Upper-Area_Q2; + Area_Q4=Area_Right-Area_Q1; + Area_Q3=Area_Left-Area_Q2; + elseif (Key_quadrant==3) then + Area_Q3=Area_key_quadrant; + Area_Q2=Area_Left-Area_Q3; + Area_Q1=Area_Upper-Area_Q2; + Area_Q4=Area_Right-Area_Q1; + elseif (Key_quadrant==4) then + Area_Q4=Area_key_quadrant; + Area_Q1=Area_Right-Area_Q4; + Area_Q2=Area_Upper-Area_Q1; + Area_Q3=Area_Left-Area_Q2; + else + !print 'Help, I need somebody, help!' + call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle into four quadrants. Should not get here.', FATAL) + endif + + Area_Q1=max(Area_Q1,0.); + Area_Q2=max(Area_Q2,0.); + Area_Q3=max(Area_Q3,0.); + Area_Q4=max(Area_Q4,0.); + + +end subroutine Triangle_divided_into_four_quadrants + + +subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4) + !This subroutine divides a regular hexagon centered at x0,y0 with apothen H, and orientation theta into its intersection with the 4 quadrants + !Theta=0 assumes that the apothen points upwards. (also the rotation is not working yet) + !Script works by finding the corners of the 6 triangles, and then finding the intersection of each of these with each quadrant. + !Arguments + real, intent(in) :: x0,y0,H,theta + real, intent(out) :: Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4 + real :: C1x, C2x, C3x, C4x, C5x, C6x + real :: C1y, C2y, C3y, C4y, C5y, C6y + real :: T12_Area, T12_Q1, T12_Q2, T12_Q3, T12_Q4 + real :: T23_Area, T23_Q1, T23_Q2, T23_Q3, T23_Q4 + real :: T34_Area, T34_Q1, T34_Q2, T34_Q3, T34_Q4 + real :: T45_Area, T45_Q1, T45_Q2, T45_Q3, T45_Q4 + real :: T56_Area, T56_Q1, T56_Q2, T56_Q3, T56_Q4 + real :: T61_Area, T61_Q1, T61_Q2, T61_Q3, T61_Q4 + real :: S + + !Length of side of Hexagon + S=(2/sqrt(3.))*H + + !Finding positions of corners + C1x=S +x0 ; C1y=0.+y0; !Corner 1 (right) + C2x=H/sqrt(3.) +x0 ; C2y=H+y0; !Corner 2 (top right) + C3x=-H/sqrt(3.)+x0 ; C3y=H+y0; !Corner 3 (top left) + C4x=-S +x0 ; C4y=0.+y0; !Corner 4 (left) + C5x=-H/sqrt(3.) +x0; C5y=-H+y0; !Corner 5 (top left) + C6x=H/sqrt(3.) +x0 ; C6y=-H+y0; !Corner 3 (top left) + + !Area of Hexagon is the sum of the triangles + call Triangle_divided_into_four_quadrants(x0,y0,C1x,C1y,C2x,C2y,T12_Area,T12_Q1,T12_Q2,T12_Q3,T12_Q4); !Triangle 012 + call Triangle_divided_into_four_quadrants(x0,y0,C2x,C2y,C3x,C3y,T23_Area,T23_Q1,T23_Q2,T23_Q3,T23_Q4); !Triangle 023 + call Triangle_divided_into_four_quadrants(x0,y0,C3x,C3y,C4x,C4y,T34_Area,T34_Q1,T34_Q2,T34_Q3,T34_Q4); !Triangle 034 + call Triangle_divided_into_four_quadrants(x0,y0,C4x,C4y,C5x,C5y,T45_Area,T45_Q1,T45_Q2,T45_Q3,T45_Q4); !Triangle 045 + call Triangle_divided_into_four_quadrants(x0,y0,C5x,C5y,C6x,C6y,T56_Area,T56_Q1,T56_Q2,T56_Q3,T56_Q4); !Triangle 056 + call Triangle_divided_into_four_quadrants(x0,y0,C6x,C6y,C1x,C1y,T61_Area,T61_Q1,T61_Q2,T61_Q3,T61_Q4); !Triangle 061 + + !Summing up the triangles + Area_hex=T12_Area+T23_Area+T34_Area+T45_Area+T56_Area+T61_Area; + Area_Q1=T12_Q1+T23_Q1+T34_Q1+T45_Q1+T56_Q1+T61_Q1; + Area_Q2=T12_Q2+T23_Q2+T34_Q2+T45_Q2+T56_Q2+T61_Q2; + Area_Q3=T12_Q3+T23_Q3+T34_Q3+T45_Q3+T56_Q3+T61_Q3; + Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; + + +end subroutine Hexagon_into_quadrants_using_triangles + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) ! Arguments type(icebergs_gridded), pointer :: grd @@ -2148,7 +2573,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) vvel3=vvel1+(dt_2*ayn) !Alon if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width ) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs ) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -2263,7 +2688,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo if (berg%lat>89.) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -2299,7 +2724,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -2354,7 +2779,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -2483,7 +2908,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 8193f2e..980c8f9 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -208,6 +208,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... @@ -316,6 +317,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... @@ -335,7 +337,7 @@ subroutine ice_bergs_framework_init(bergs, & namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & - parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, & + parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj @@ -644,6 +646,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%hexagonal_icebergs=hexagonal_icebergs bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs bergs%only_interactive_forces=only_interactive_forces From c5d168e6737488e01fcbbdd30b881c22acfc798e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 24 Jun 2016 18:08:33 -0400 Subject: [PATCH 113/361] Spreading of mass treating icebergs as hexagonal elements is now working. This was done my fixing many bugs in the spreading scheme. One significant change is that we now apply thermodynamics to all the icebergs, including the halos. Before this change was made, the code did not reproduce across processors. Hexagonal elements can not rotate yet. --- icebergs.F90 | 246 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 187 insertions(+), 59 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 1e46be0..20e3e69 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -883,7 +883,8 @@ subroutine thermodynamics(bergs) ! For convenience grd=>bergs%grd - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + !do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') @@ -1068,6 +1069,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex real, parameter :: rho_seawater=1035. integer :: stderrunit + logical :: debug ! Get the stderr unit number stderrunit = stderr() @@ -1081,7 +1083,8 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yDxL=0. ; yDxC=0. ; yDxR=0. ; yCxL=0. ; yCxR=0. yUxL=0. ; yUxC=0. ; yUxR=0. ; yCxC=1. - if (.not. hexagonal_icebergs) then !Treat icebergs as rectangles of size L: + if (.not. hexagonal_icebergs) then !Treat icebergs as rectangles of size L: (this is the default) + !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. if (grd%area(i,j)>0) then L=min( sqrt(Area / grd%area(i,j)),1.0) @@ -1113,6 +1116,14 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yUxC=yU*xC*grd%msk(i ,j+1) yUxR=yU*xR*grd%msk(i+1,j+1) yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) + + !Temporary for debugging reasons. + if (mpp_pe()==mpp_root_pe()) then + write(stderrunit,*) 'diamonds, You are in the square!!!', grd%area(i,j),L + write(stderrunit,*) 'diamonds, x,y', x,y + write(stderrunit,*) 'diamonds, xL,xC,xR', xL,xC,xR + write(stderrunit,*) 'diamonds, yU,yC,yD', yU,yC,yD + endif else !Spread mass as if elements area hexagonal @@ -1142,8 +1153,9 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling theta=0.0 call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) - if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <0) then + if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-0.001) then call error_mesg('diamonds, hexagonal spreading', 'Intersection with hexagons should not be negative!!!', WARNING) + write(stderrunit,*) 'diamonds, yU,yC,yD', Area_Q1, Area_Q2, Area_Q3, Area_Q4 endif Area_Q1=Area_Q1/Area_hex @@ -1174,26 +1186,32 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yDxR=Area_Q4 endif + !Temporary for debugging reasons. + if (mpp_pe()==mpp_root_pe()) then + !write(stderrunit,*) 'diamonds, You are in the hexagonal domain now!!!' + endif !Double check that all the mass is being used. - if (abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>0.001) then + if ((abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>0.001) .and. (mpp_pe().eq.5)) then !call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', WARNING) - write(stderrunit,*) 'diamonds, hexagonal spreading, dimensions',S, H, x0 , y0 - write(stderrunit,*) 'diamonds, hexagonal spreading, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1,Area_Q2 , Area_Q3,Area_Q4 + write(stderrunit,*) 'diamonds, hexagonal, H,x0,y0', H, x0 , y0 + write(stderrunit,*) 'diamonds, hexagonal, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + debug=.True. + !call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4, debug) call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) endif endif - grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+yDxL*Mass - grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+yDxC*Mass - grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+yDxR*Mass - grd%mass_on_ocean(i,j,4)=grd%mass_on_ocean(i,j,4)+yCxL*Mass - grd%mass_on_ocean(i,j,5)=grd%mass_on_ocean(i,j,5)+yCxC*Mass - grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,6)+yCxR*Mass - grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,7)+yUxL*Mass - grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+yUxC*Mass - grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+yUxR*Mass + grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass) + grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass) + grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass) + grd%mass_on_ocean(i,j,4)=grd%mass_on_ocean(i,j,4)+(yCxL*Mass) + grd%mass_on_ocean(i,j,5)=grd%mass_on_ocean(i,j,5)+(yCxC*Mass) + grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,6)+(yCxR*Mass) + grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,7)+(yUxL*Mass) + grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass) + grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass) end subroutine spread_mass_across_ocean_cells @@ -1209,47 +1227,69 @@ real function Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) Area_of_triangle = abs( 0.5*((Ax*(By-Cy))+(Bx*(Cy-Ay))+(Cx*(Ay-By))) ); end function Area_of_triangle +real function roundoff(x,sig_fig) + ! Arguments + real, intent(in) :: x + integer, intent(in) :: sig_fig + !roundoff=round(x*(10**(sig_fig)) + roundoff=(FLOAT (INT(x * (10.**sig_fig) + 0.5)) / (10.**sig_fig)) +end function roundoff + +logical function point_in_interval(Ax,Ay,Bx,By,px,py) + ! Arguments + real, intent(in) :: Ax,Ay,Bx,By,px,py + point_in_interval=.False. + if ((px < max(Ax,Bx)) .and. (px > min(Ax,Bx))) then + if ((py < max(Ay,By)) .and. (py > min(Ay,By))) then + point_in_interval=.True. + endif + endif +end function point_in_interval + + +logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) + ! Arguments + real, intent(in) :: Ax,Ay,Bx,By,qx,qy + real :: tol, dxc,dyc,dxl,dyl,cross + tol=0.00000000000000; + dxc = qx - Ax; + dyc = qy - Ay; + dxl = Bx - Ax; + dyl = By - Ay; + cross = dxc * dyl - dyc * dxl; + if (abs(cross)<=tol) then + point_is_on_the_line=.True. + else + point_is_on_the_line=.False. + endif +end function point_is_on_the_line -logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,include_boundary) +logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy) !This function decides whether a point (qx,qy) is inside the triangle ABC. !There is also the option to include the boundary of the triangle. ! Arguments - real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy,include_boundary - real :: tol, invDenom,u,v + real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy + real :: l0,l1,l2,p0,p1,p2 real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 - tol=0.0000000001; - if (include_boundary==0.) tol=-tol; !Negative number excludes the boundary case. - + point_in_triangle = .False. if ((Ax==qx .and. Ay==qy) .or. (Bx==qx .and. By==qy) .or. (Cx==qx .and. Cy==qy)) then !Exclude the pathelogical case - if (include_boundary==0.) then + point_in_triangle = .False. + else + if (((point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) .or. (point_is_on_the_line(Ax,Ay,Cx,Cy,qx,qy))) .or. (point_is_on_the_line(Bx,By,Cx,Cy,qx,qy)))) then point_in_triangle = .False. else - point_in_triangle = .True. + !Compute point in triangle using Barycentric coordinates (the same as sum_sign_dot_prod routines) + l0=(qx-Ax)*(By-Ay)-(qy-Ay)*(Bx-Ax) + l1=(qx-Bx)*(Cy-By)-(qy-By)*(Cx-Bx) + l2=(qx-Cx)*(Ay-Cy)-(qy-Cy)*(Ax-Cx) + + p0=sign(1., l0); if (l0==0.) p0=0. + p1=sign(1., l1); if (l1==0.) p1=0. + p2=sign(1., l2); if (l2==0.) p2=0. + + if ( (abs(p0)+abs(p2))+(abs(p1)) == abs((p0+p2)+(p1)) ) point_in_triangle = .True. endif - else - - !Compute vectors - v0x=Cx-Ax; - v1x=Bx-Ax; - v2x=qx-Ax; - v0y=Cy-Ay; - v1y=By-Ay; - v2y=qy-Ay; - - !Compute dot products - dot00 = (v0x*v0x)+(v0y*v0y); - dot01 = (v0x*v1x)+(v0y*v1y); - dot02 = (v0x*v2x)+(v0y*v2y); - dot11 = (v1x*v1x)+(v1y*v1y); - dot12 = (v1x*v2x)+(v1y*v2y); - - !Compute barycentric coordinates - invDenom= 1 / ((dot00 * dot11) - (dot01*dot01)); - u=((dot11*dot02)-(dot01*dot12))*invDenom; - v=((dot00*dot12)-(dot01*dot02))*invDenom; - - point_in_triangle = (( ((u+tol).ge.0.) .and. ((v+tol).ge.0)) .and. ((u+v).lt.(1+tol))) endif end function point_in_triangle @@ -1398,8 +1438,23 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, real, intent(out) :: Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4 real :: Area_Upper, Area_Lower, Area_Right, Area_Left real :: px, py , qx , qy - real :: Area_key_quadrant + real :: Area_key_quadrant,Error integer :: Key_quadrant + integer ::sig_fig + integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() + + !Round of numbers before proceeding further. + !sig_fig=12; !Significan figures + !Ax=roundoff(Ax0,sig_fig) + !Ay=roundoff(Ay0,sig_fig) + !Bx=roundoff(Bx0,sig_fig) + !By=roundoff(By0,sig_fig) + !Cx=roundoff(Cx0,sig_fig) + !Cy=roundoff(Cy0,sig_fig) + Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); @@ -1410,20 +1465,23 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, !Decide if the origin is in the triangle. If so, then you have to divide the area 4 ways !This is done by finding a quadrant where the intersection between the triangle and quadrant forms a new triangle !(This occurs when on of the sides of the triangle intersects both the x and y axis) - if (point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.,0.)) then + if (point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)) then !Find a line in the triangle that cuts both axes in/on the trianlge call intercept_of_a_line(Ax,Ay,Bx,By,'x',px,py); !x_intercept call intercept_of_a_line(Ax,Ay,Bx,By,'y',qx,qy); !y_intercept !Note that the 1. here means that we include points on the boundary of the triange. - if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + if (.not.((point_in_interval(Ax,Ay,Bx,By,px,py)) .and. (point_in_interval(Ax,Ay,Bx,By,qx,qy)))) then call intercept_of_a_line(Ax,Ay,Cx,Cy,'x',px,py); !x_intercept call intercept_of_a_line(Ax,Ay,Cx,Cy,'y',qx,qy); !y_intercept - if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + if (.not.((point_in_interval(Ax,Ay,Cx,Cy,px,py)) .and. (point_in_interval(Ax,Ay,Cx,Cy,qx,qy)))) then call intercept_of_a_line(Bx,By,Cx,Cy,'x',px,py); !x_intercept call intercept_of_a_line(Bx,By,Cx,Cy,'y',qx,qy); !y_intercept - if (.not.(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,px,py,1.) .and. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy,1.))) then + if (.not.((point_in_interval(Bx,By,Cx,Cy,px,py)) .and. (point_in_interval(Bx,By,Cx,Cy,qx,qy)))) then !print 'Houston, we have a problem' !You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. + if (mpp_pe().eq.12) then + write(stderrunit,*) 'diamonds,corners', Ax,Ay,Bx,By,Cx,Cy + endif call error_mesg('diamonds, iceberg_run', 'Something went wrong with Triangle_divide_into_four_quadrants', FATAL) endif endif @@ -1461,22 +1519,26 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q1=Area_key_quadrant; Area_Q2=Area_Upper-Area_Q1; Area_Q4=Area_Right-Area_Q1; - Area_Q3=Area_Left-Area_Q2; + !Area_Q3=Area_Left-Area_Q2; !These lines have been changes so that the sum of the 4 quadrants exactly matches the triangle area. + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); elseif (Key_quadrant .eq. 2) then Area_Q2=Area_key_quadrant; Area_Q1=Area_Upper-Area_Q2; Area_Q4=Area_Right-Area_Q1; - Area_Q3=Area_Left-Area_Q2; + !Area_Q3=Area_Left-Area_Q2; + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); elseif (Key_quadrant==3) then Area_Q3=Area_key_quadrant; Area_Q2=Area_Left-Area_Q3; Area_Q1=Area_Upper-Area_Q2; - Area_Q4=Area_Right-Area_Q1; + !Area_Q4=Area_Right-Area_Q1; + Area_Q4=Area_triangle-(Area_Q1+Area_Q2+Area_Q3); elseif (Key_quadrant==4) then Area_Q4=Area_key_quadrant; Area_Q1=Area_Right-Area_Q4; Area_Q2=Area_Upper-Area_Q1; - Area_Q3=Area_Left-Area_Q2; + !Area_Q3=Area_Left-Area_Q2; + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); else !print 'Help, I need somebody, help!' call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle into four quadrants. Should not get here.', FATAL) @@ -1488,6 +1550,17 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q4=max(Area_Q4,0.); + Error=abs(Area_Q1+Area_Q2+Area_Q3+Area_Q4-Area_triangle) + if (Error>0.01) then + call error_mesg('diamonds, triangle spreading', 'Triangle not evaluated accurately!!', WARNING) + if (mpp_pe().eq.mpp_root_pe()) then + write(stderrunit,*) 'diamonds, Triangle corners:',Ax,Ay,Bx,By,Cx,Cy + write(stderrunit,*) 'diamonds, Triangle, Areas', Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + write(stderrunit,*) 'diamonds, Triangle, Areas', Error + endif + endif + + end subroutine Triangle_divided_into_four_quadrants @@ -1506,7 +1579,11 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q real :: T45_Area, T45_Q1, T45_Q2, T45_Q3, T45_Q4 real :: T56_Area, T56_Q1, T56_Q2, T56_Q3, T56_Q4 real :: T61_Area, T61_Q1, T61_Q2, T61_Q3, T61_Q4 - real :: S + real :: S, exact_hex_area, Error + integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() !Length of side of Hexagon S=(2/sqrt(3.))*H @@ -1532,8 +1609,53 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q Area_Q1=T12_Q1+T23_Q1+T34_Q1+T45_Q1+T56_Q1+T61_Q1; Area_Q2=T12_Q2+T23_Q2+T34_Q2+T45_Q2+T56_Q2+T61_Q2; Area_Q3=T12_Q3+T23_Q3+T34_Q3+T45_Q3+T56_Q3+T61_Q3; - Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; + Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; + + Area_Q1=max(Area_Q1,0.); + Area_Q2=max(Area_Q2,0.); + Area_Q3=max(Area_Q3,0.); + Area_Q4=max(Area_Q4,0.); + Error=Area_hex-(Area_Q1+Area_Q2+Area_Q3+Area_Q4) + if ((abs(Error)>0.01))then + if (mpp_pe().eq.mpp_root_pe()) then + call error_mesg('diamonds, hexagonal spreading', 'Hexagon error is large!!', WARNING) + write(stderrunit,*) 'diamonds, hex error, H,x0,y0, Error', H, x0 , y0, Error + write(stderrunit,*) 'diamonds, hex error, Areas',Area_hex, (Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + write(stderrunit,*) 'diamonds, Triangle1',C1x,C1y,C2x,C2y,T12_Area,T12_Q1,T12_Q2,T12_Q3,T12_Q4,(T12_Q1+T12_Q2+T12_Q3+T12_Q4-T12_Area) + write(stderrunit,*) 'diamonds, Triangle2',C2x,C2y,C3x,C3y,T23_Area,T23_Q1,T23_Q2,T23_Q3,T23_Q4,(T23_Q1+T23_Q2+T23_Q3+T23_Q4-T23_Area) + write(stderrunit,*) 'diamonds, Triangle3',C3x,C3y,C4x,C4y,T34_Area,T34_Q1,T34_Q2,T34_Q3,T34_Q4,(T34_Q1+T34_Q2+T34_Q3+T34_Q4-T34_Area) + write(stderrunit,*) 'diamonds, Triangle4',C4x,C4y,C5x,C5y,T45_Area,T45_Q1,T45_Q2,T45_Q3,T45_Q4,(T45_Q1+T45_Q2+T45_Q3+T45_Q4-T45_Area) + write(stderrunit,*) 'diamonds, Triangle5',C5x,C5y,C6x,C6y,T56_Area,T56_Q1,T56_Q2,T56_Q3,T56_Q4,(T56_Q1+T56_Q2+T56_Q3+T56_Q4-T56_Area) + write(stderrunit,*) 'diamonds, Triangle6',C6x,C6y,C1x,C1y,T61_Area,T61_Q1,T61_Q2,T61_Q3,T61_Q4,(T61_Q1+T61_Q2+T61_Q3+T61_Q4-T61_Area) + endif + endif + + exact_hex_area=((3.*sqrt(3.)/2)*(S*S)) + if (abs(Area_hex-exact_hex_area)>0.01) then + call error_mesg('diamonds, hexagonal spreading', 'Hexagon not evaluated accurately!!', WARNING) + if (mpp_pe().eq.mpp_root_pe()) then + write(stderrunit,*) 'diamonds, hex calculations, H,x0,y0', H, x0 , y0 + write(stderrunit,*) 'diamonds, hex calculations, Areas',Area_hex, (Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + endif + endif + + !Adjust Areas so that the error is zero by subtracting the error from the largest sector. + if (((Area_Q1>=Area_Q2) .and. (Area_Q1>=Area_Q3)) .and. (Area_Q1>=Area_Q4)) then + Area_Q1=Area_Q1+Error + elseif (((Area_Q2>=Area_Q1) .and. (Area_Q2>=Area_Q3)) .and. (Area_Q2>=Area_Q4)) then + Area_Q2=Area_Q2+Error + elseif (((Area_Q3>=Area_Q1) .and. (Area_Q3>=Area_Q2)) .and. (Area_Q3>=Area_Q4)) then + Area_Q3=Area_Q3+Error + elseif (((Area_Q4>=Area_Q1) .and. (Area_Q4>=Area_Q2)) .and. (Area_Q4>=Area_Q3)) then + Area_Q4=Area_Q4+Error + else + call error_mesg('diamonds, hexagonal spreading', 'Error in hexagon is larger than any quadrant!!', WARNING) + if (mpp_pe().eq.mpp_root_pe()) then + write(stderrunit,*) 'diamonds, hex quadrants, H,x0,y0', H, x0 , y0, Error + write(stderrunit,*) 'diamonds, hex quadrants, Areas',Area_hex, (Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + endif + endif end subroutine Hexagon_into_quadrants_using_triangles @@ -2201,6 +2323,11 @@ subroutine icebergs_incr_mass(bergs, mass, Time) type(icebergs_gridded), pointer :: grd real :: dmda logical :: lerr +integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() + if (.not. associated(bergs)) return @@ -2216,7 +2343,6 @@ subroutine icebergs_incr_mass(bergs, mass, Time) !mass(:,:)=mass(:,:)+( grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec) & ! + grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec) ) - if (debug) then grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass call grd_chksum2(grd, grd%tmp, 'mass in (incr)') @@ -2572,8 +2698,10 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) uvel3=uvel1+(dt_2*axn) !Alon vvel3=vvel1+(dt_2*ayn) !Alon + !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since + !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs ) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs ) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon From 695a0de8dbe65146eb7e223c9f720f91ff393b3d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 27 Jun 2016 15:09:43 -0400 Subject: [PATCH 114/361] A bug has been fixed, which prevented the model from reproducing across different layouts. The model was copying icebergs from the restart file onto two different processors. This was because when an iceberg is placed directly on the edge of a grid cell, which is positioned on the edge of a processor, then the iceberg was determined to be in both cells, and was thus placed on both processors. This has been fixed by editing the routine sum_sign_dot_prod4, so that it is asymtric, including points positioned on the south/west boundaries, and not including points on the north/east. Note: This has only been done for the sum_sign_dot_prod4, and not for the sum_sign_dot_prod5 routine, which is used for icebregs near the northpole. Two different tests have also been written to make sure that the correct amount of icebergs are read from the restart file. --- icebergs_framework.F90 | 10 ++++++---- icebergs_io.F90 | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 980c8f9..eb0cc78 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3186,10 +3186,12 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y, explai l2=(xx-xx2)*(y3-y2)-(y-y2)*(xx3-xx2) l3=(xx-xx3)*(y0-y3)-(y-y3)*(xx0-xx3) - p0=sign(1., l0); if (l0.eq.0.) p0=0. - p1=sign(1., l1); if (l1.eq.0.) p1=0. - p2=sign(1., l2); if (l2.eq.0.) p2=0. - p3=sign(1., l3); if (l3.eq.0.) p3=0. + !We use an asymerty between South and East line boundaries and North and East + !to avoid icebergs appearing to two cells (half values used for debugging + p0=sign(1., l0); if (l0.eq.0.) p0=-0.5 + p1=sign(1., l1); if (l1.eq.0.) p1=0.5 + p2=sign(1., l2); if (l2.eq.0.) p2=0.5 + p3=sign(1., l3); if (l3.eq.0.) p3=-0.5 if ( (abs(p0)+abs(p2))+(abs(p1)+abs(p3)) .eq. abs((p0+p2)+(p1+p3)) ) then sum_sign_dot_prod4=.true. diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 514e24d..8fd70ea 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -691,14 +691,15 @@ subroutine read_restart_bergs(bergs,Time) type(icebergs), pointer :: bergs type(time_type), intent(in) :: Time ! Local variables -integer :: k, siz(4), nbergs_in_file +integer :: k, siz(4), nbergs_in_file, nbergs_read logical :: lres, found_restart, found +logical :: explain logical :: multiPErestart ! Not needed with new restart read; currently kept for compatibility real :: lon0, lon1, lat0, lat1 character(len=33) :: filename, filename_base type(icebergs_gridded), pointer :: grd type(iceberg) :: localberg ! NOT a pointer but an actual local variable -real :: pos_is_good, pos_is_good_all_pe +real :: pos_is_good, pos_is_good_all_pe,eps integer :: stderrunit integer :: grdj, grdi @@ -831,8 +832,9 @@ subroutine read_restart_bergs(bergs,Time) endif pos_is_good_all_pe=pos_is_good call mpp_sum(pos_is_good_all_pe) + !Check to see if any iceberg in the restart file was not found if (pos_is_good_all_pe .lt. 0.5) then - if (bergs%ignore_missing_restart_bergs) then + if (bergs%ignore_missing_restart_bergs) then if (mpp_pe().eq.mpp_root_pe()) then print * , 'Iceberg not located: ', lon(k),lat(k), iceberg_num(k) call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', WARNING) @@ -842,6 +844,13 @@ subroutine read_restart_bergs(bergs,Time) endif endif + !Check to see if any iceberg was found more than once. + if (pos_is_good_all_pe .gt. 1.5) then + if (mpp_pe().eq.mpp_root_pe()) then + print * , 'Iceberg was found more than once: ', lon(k),lat(k), iceberg_num(k) + call error_mesg('diamonds, read_restart_bergs', 'Iceberg copied twice', FATAL) + endif + endif if (really_debug) then write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& & ' on PE ',mpp_pe() @@ -915,6 +924,25 @@ subroutine read_restart_bergs(bergs,Time) jne, & iceberg_num, & start_year ) + + !Checking the total number of icebergs read from the restart file. + nbergs_read=count_bergs(bergs) + call mpp_sum(nbergs_read) + if (mpp_pe().eq.mpp_root_pe()) then + write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of Icebergs in restart file=',nbergs_in_file,' Number of Icebergs read=', nbergs_read + if (nbergs_read .gt. nbergs_in_file) then + call error_mesg('diamonds, read_restart_bergs', 'More icebergs read than exist in restart file.', FATAL) + elseif (nbergs_read .lt. nbergs_in_file) then + if (bergs%ignore_missing_restart_bergs) then + call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found (ignore_missing flag is on)', WARNING) + else + call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found', FATAL) + endif + elseif (nbergs_read .eq. nbergs_in_file) then + write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of icebergs read (#',nbergs_read,') matches the number of icebergs in the file' + endif + endif + elseif(.not. found_restart .and. bergs%nbergs_start==0 .and. generate_test_icebergs) then call generate_bergs(bergs,Time) endif From 5394e98845160d863b880ea0cc7b260200514f65 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 27 Jun 2016 17:28:59 -0400 Subject: [PATCH 115/361] Added a diagnostic within the iceberg model called spread_mass. This shows how iceberg mass would be spread onto the ocean if the spread_mass_to_ocean flag was on, and the passive mode flag was off. This allows us to see what the weight on the ocean would have been even for simuation where the iceberg is not adding weight to ocean. This is useful for testing. --- icebergs.F90 | 57 ++++++++++++++++++++++++++++++++---------- icebergs_framework.F90 | 8 +++++- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 20e3e69..ff4be19 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1795,12 +1795,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality -real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass +real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger integer :: nbonds +logical :: within_iceberg_model integer :: stderrunit @@ -1824,6 +1825,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_src(:,:)=0. grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. + grd%spread_mass(:,:)=0. grd%mass(:,:)=0. if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. @@ -2013,6 +2015,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call write_trajectory(bergs%trajectories, bergs%save_short_traj) endif + !Update diagnostic of iceberg mass spread on ocean + if (grd%id_spread_mass>0) then + within_iceberg_model=.True. + call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model) + endif + ! Gridded diagnostics if (grd%id_uo>0) & lerr=send_data(grd%id_uo, grd%uo(grd%isc:grd%iec,grd%jsc:grd%jec), Time) @@ -2050,6 +2058,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_bergy_melt, grd%bergy_melt(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_bergy_mass>0) & lerr=send_data(grd%id_bergy_mass, grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_spread_mass>0) & + lerr=send_data(grd%id_spread_mass, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_mass>0) & lerr=send_data(grd%id_mass, grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_stored_ice>0) & @@ -2106,6 +2116,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%floating_mass_end=sum_mass(bergs) bergs%icebergs_mass_end=sum_mass(bergs,justbergs=.true.) bergs%bergy_mass_end=sum_mass(bergs,justbits=.true.) + bergs%spread_mass_end=sum_mass(bergs) !Not sure what this is bergs%floating_heat_end=sum_heat(bergs) grd%tmpc(:,:)=0.; call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r @@ -2118,6 +2129,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(bergs%floating_mass_end) call mpp_sum(bergs%icebergs_mass_end) call mpp_sum(bergs%bergy_mass_end) + call mpp_sum(bergs%spread_mass_end) call mpp_sum(bergs%floating_heat_end) call mpp_sum(bergs%returned_mass_on_ocean) call mpp_sum(bergs%nbergs_end) @@ -2144,6 +2156,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(grdd_berg_mass) grdd_bergy_mass=sum( grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum(grdd_bergy_mass) + grdd_spread_mass=sum( grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) + call mpp_sum(grdd_spread_mass) if (mpp_pe().eq.mpp_root_pe()) then 100 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a12,i8) 200 format("diamonds: ",a19,10(a18,"=",es14.7,x,a2,:,",")) @@ -2151,6 +2165,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call report_state('floating','kg','',bergs%floating_mass_start,'',bergs%floating_mass_end,'',bergs%nbergs_end) call report_state('icebergs','kg','',bergs%icebergs_mass_start,'',bergs%icebergs_mass_end,'') call report_state('bits','kg','',bergs%bergy_mass_start,'',bergs%bergy_mass_end,'') + call report_state('spread icebergs','kg','',bergs%spread_mass_start,'',bergs%spread_mass_end,'') call report_istate('berg #','',bergs%nbergs_start,'',bergs%nbergs_end,'') call report_ibudget('berg #','calved',bergs%nbergs_calved, & 'melted',bergs%nbergs_melted, & @@ -2172,6 +2187,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, 'net mass',bergs%stored_start+bergs%floating_mass_start, & bergs%stored_end+bergs%floating_mass_end) call report_consistant('iceberg mass','kg','gridded',grdd_berg_mass,'bergs',bergs%icebergs_mass_end) + call report_consistant('spread mass','kg','gridded',grdd_spread_mass,'bergs',bergs%spread_mass_end) call report_consistant('bits mass','kg','gridded',grdd_bergy_mass,'bits',bergs%bergy_mass_end) call report_consistant('wieght','kg','returned',bergs%returned_mass_on_ocean,'floating',bergs%floating_mass_end) call report_state('net heat','J','',bergs%stored_heat_start+bergs%floating_heat_start,'',& @@ -2207,6 +2223,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%floating_mass_start=bergs%floating_mass_end bergs%icebergs_mass_start=bergs%icebergs_mass_end bergs%bergy_mass_start=bergs%bergy_mass_end + bergs%spread_mass_start=bergs%spread_mass_end bergs%net_calving_used=0. bergs%net_calving_to_bergs=0. bergs%net_heat_to_bergs=0. @@ -2313,11 +2330,13 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, Time) +subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass type(time_type), intent(in), optional :: Time +logical, intent(in), optional :: within_iceberg_model +logical :: within_model ! Local variables integer :: i, j type(icebergs_gridded), pointer :: grd @@ -2327,14 +2346,19 @@ subroutine icebergs_incr_mass(bergs, mass, Time) ! Get the stderr unit number stderrunit = stderr() + + + within_model=.False. + if (present(within_iceberg_model)) then + within_model=within_iceberg_model + endif - - if (.not. associated(bergs)) return - - if (.not. bergs%add_weight_to_ocean) return - - call mpp_clock_begin(bergs%clock) - call mpp_clock_begin(bergs%clock_int) + if (.not.(within_model)) then + if (.not. associated(bergs)) return + if (.not. bergs%add_weight_to_ocean) return + call mpp_clock_begin(bergs%clock) + call mpp_clock_begin(bergs%clock_int) + endif ! For convenience grd=>bergs%grd @@ -2370,7 +2394,12 @@ subroutine icebergs_incr_mass(bergs, mass, Time) + ( (grd%mass_on_ocean(i-1,j ,6)+grd%mass_on_ocean(i+1,j ,4)) & + (grd%mass_on_ocean(i ,j-1,8)+grd%mass_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) - if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda + + if (.not.(within_model)) then + if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda + else + mass(i,j)=dmda + endif if (grd%id_mass_on_ocn>0) grd%tmp(i,j)=dmda enddo; enddo if (present(Time).and. (grd%id_mass_on_ocn>0)) & @@ -2382,9 +2411,10 @@ subroutine icebergs_incr_mass(bergs, mass, Time) call grd_chksum2(grd, grd%tmp, 'mass out (incr)') endif - call mpp_clock_end(bergs%clock_int) - call mpp_clock_end(bergs%clock) - + if (.not.(within_model)) then + call mpp_clock_end(bergs%clock_int) + call mpp_clock_end(bergs%clock) + endif end subroutine icebergs_incr_mass ! ############################################################################## @@ -3565,6 +3595,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%bergy_src) deallocate(bergs%grd%bergy_melt) deallocate(bergs%grd%bergy_mass) + deallocate(bergs%grd%spread_mass) deallocate(bergs%grd%virtual_area) deallocate(bergs%grd%mass) deallocate(bergs%grd%mass_on_ocean) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index eb0cc78..9d7736d 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -113,6 +113,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_src=>null() ! Mass flux from berg erosion into bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) + real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/s/m^2) real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) @@ -131,7 +132,7 @@ module ice_bergs_framework integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 - integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1 + integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_spread_mass=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -238,6 +239,7 @@ module ice_bergs_framework real :: floating_heat_start=0., floating_heat_end=0. real :: icebergs_mass_start=0., icebergs_mass_end=0. real :: bergy_mass_start=0., bergy_mass_end=0. + real :: spread_mass_start=0., spread_mass_end=0. real :: returned_mass_on_ocean=0. real :: net_melt=0., berg_melt=0., bergy_src=0., bergy_melt=0. integer :: nbergs_calved=0, nbergs_melted=0, nbergs_start=0, nbergs_end=0 @@ -451,6 +453,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%bergy_src(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_src(:,:)=0. allocate( grd%bergy_melt(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_melt(:,:)=0. allocate( grd%bergy_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_mass(:,:)=0. + allocate( grd%spread_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_mass(:,:)=0. allocate( grd%virtual_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%virtual_area(:,:)=0. allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. @@ -696,6 +699,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Melt rate of bergy bits', 'kg/(m^2*s)') grd%id_bergy_mass=register_diag_field('icebergs', 'bergy_mass', axes, Time, & 'Bergy bit density field', 'kg/(m^2)') + grd%id_spread_mass=register_diag_field('icebergs', 'spread_mass', axes, Time, & + 'Iceberg mass after spreading', 'kg/(m^2)') grd%id_virtual_area=register_diag_field('icebergs', 'virtual_area', axes, Time, & 'Virtual coverage by icebergs', 'm^2') grd%id_mass=register_diag_field('icebergs', 'mass', axes, Time, & @@ -3595,6 +3600,7 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%bergy_src, 'bergy_src') call grd_chksum2(grd, grd%bergy_melt, 'bergy_melt') call grd_chksum2(grd, grd%bergy_mass, 'bergy_mass') + call grd_chksum2(grd, grd%bergy_mass, 'spread_mass') call grd_chksum2(grd, grd%virtual_area, 'varea') call grd_chksum2(grd, grd%floating_melt, 'floating_melt') call grd_chksum2(grd, grd%berg_melt, 'berg_melt') From 91a90281d4c23d6dfb3e3a1903cb64e2e6cc9284 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 27 Jun 2016 18:28:53 -0400 Subject: [PATCH 116/361] A warning has been added when Runge Kutta algorithm is used with interactive icebergs. This is because it is unclear whether the model is stable when interactive forces are used the Runge Kutta with interactions using the old iceberg positions and velocities (since iceberg interact with the positions and velocities of other icebergs at the begining of a time step.) A warning has been added when iceberg bonds are used without interactive force. --- icebergs_framework.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 9d7736d..09e99a9 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -613,11 +613,13 @@ subroutine ice_bergs_framework_init(bergs, & iceberg_halo=halo endif -if (Runge_not_Verlet) then - interactive_icebergs_on=.false. ! Iceberg interactions only with Verlet +if (interactive_icebergs_on) then + !Runge_not_Verlet=.false. ! Iceberg interactions only with Verlet + call error_mesg('diamonds, framework', 'It is unlcear whther interactive icebergs work with Runge Kutta stepping.', WARNING) endif if (.not.interactive_icebergs_on) then - !iceberg_bonds_on=.false. ! This line needs to included later, but is omitted for testing + !iceberg_bonds_on=.false. + call error_mesg('diamonds, framework', 'Interactive icebergs off requires iceberg bonds off (turning bonds off).', WARNING) endif if (.not. iceberg_bonds_on) then max_bonds=0 From a9bf6fd44550d51d7d2902e984686d1599630c2c Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 28 Jun 2016 10:14:55 -0400 Subject: [PATCH 117/361] The WARNINGs using Runge Kutta with interactive icebergs, and bonds without interactions have now been implemented correctly (with appropriate if statements) --- icebergs_framework.F90 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 09e99a9..ac9b068 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -614,12 +614,16 @@ subroutine ice_bergs_framework_init(bergs, & endif if (interactive_icebergs_on) then - !Runge_not_Verlet=.false. ! Iceberg interactions only with Verlet - call error_mesg('diamonds, framework', 'It is unlcear whther interactive icebergs work with Runge Kutta stepping.', WARNING) + if (Runge_not_Verlet.eq..true.) then + !Runge_not_Verlet=.false. ! Iceberg interactions only with Verlet + call error_mesg('diamonds, framework', 'It is unlcear whther interactive icebergs work with Runge Kutta stepping.', WARNING) + endif endif if (.not.interactive_icebergs_on) then - !iceberg_bonds_on=.false. - call error_mesg('diamonds, framework', 'Interactive icebergs off requires iceberg bonds off (turning bonds off).', WARNING) + if (iceberg_bonds_on.eq..true.) then + !iceberg_bonds_on=.false. + call error_mesg('diamonds, framework', 'Interactive icebergs off requires iceberg bonds off (turning bonds off).', WARNING) + endif endif if (.not. iceberg_bonds_on) then max_bonds=0 From 21578ddbf282f416698174d60ddd4511dc07de1e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 28 Jun 2016 10:55:45 -0400 Subject: [PATCH 118/361] Removing some text output which was there for debuggin reasons --- icebergs.F90 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index ff4be19..26489cf 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1117,15 +1117,6 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yUxR=yU*xR*grd%msk(i+1,j+1) yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) - !Temporary for debugging reasons. - if (mpp_pe()==mpp_root_pe()) then - write(stderrunit,*) 'diamonds, You are in the square!!!', grd%area(i,j),L - write(stderrunit,*) 'diamonds, x,y', x,y - write(stderrunit,*) 'diamonds, xL,xC,xR', xL,xC,xR - write(stderrunit,*) 'diamonds, yU,yC,yD', yU,yC,yD - endif - - else !Spread mass as if elements area hexagonal if (grd%area(i,j)>0) then From 19773277fe11f771e0f6e258dfe8e28c9a93c366 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 28 Jun 2016 11:43:37 -0400 Subject: [PATCH 119/361] Two new flags have been added: 1)set_melt_rates_to_zero - this sets all melt to zero for testing purposes. The thermodynamic routine is still run. (Default=false) 2)allow_bergs_to_roll - this flag allows you to turn rolling off (Default = true) --- icebergs.F90 | 17 +++++++++++++---- icebergs_framework.F90 | 9 ++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 26489cf..160f24c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -916,6 +916,13 @@ subroutine thermodynamics(bergs) *perday ! convert to m/s Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion *perday ! convert to m/s + + if (bergs%set_melt_rates_to_zero) then + Mv=0.0 + Mb=0.0 + Me=0.0 + endif + if (bergs%use_operator_splitting) then ! Operator split update of volume/mass @@ -1009,14 +1016,16 @@ subroutine thermodynamics(bergs) endif ! Rolling - Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) - if ( Dn>0. ) then - if ( max(Wn,Ln)0. ) then + if ( max(Wn,Ln)W) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ac9b068..ed21d50 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -209,7 +209,9 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: set_melt_rates_to_zero=.False. !Sets all melt rates to zero, for testing purposes (thermodynamics routine is still run) logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) + logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... @@ -319,6 +321,8 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: set_melt_rates_to_zero=.False. !Sets all melt rates to zero, for testing purposes (thermodynamics routine is still run) +logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move @@ -341,7 +345,8 @@ subroutine ice_bergs_framework_init(bergs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & - old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj + old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & + allow_bergs_to_roll,set_melt_rates_to_zero ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -655,6 +660,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%set_melt_rates_to_zero=set_melt_rates_to_zero + bergs%allow_bergs_to_roll=allow_bergs_to_roll bergs%hexagonal_icebergs=hexagonal_icebergs bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs From 379d4e8cfbf5c1f926e6d71dd325eed827020628 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 28 Jun 2016 14:37:07 -0400 Subject: [PATCH 120/361] A runtime parameter called Omega_icebergs, which allows you to change the rotation rate. --- icebergs.F90 | 2 +- icebergs_framework.F90 | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 160f24c..c1d5b8d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -475,7 +475,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) - f_cori=(2.*omega)*sin(pi_180*lat) + f_cori=(2.*bergs%Omega_icebergs)*sin(pi_180*lat) ! f_cori=0. M=berg%mass diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ed21d50..dfc68d9 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -201,6 +201,7 @@ module ice_bergs_framework real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0 Date: Wed, 29 Jun 2016 16:12:27 -0400 Subject: [PATCH 121/361] A bug has been fixed where NaN values were being copied into the halos of the gridded fields for simulations using non-periodic domains (also happened sometimes with periodic domains). This has been fixed by setting the gridded values equal to zero in the cases where the mask is equal to zero (ie: in the masked region) --- icebergs.F90 | 34 ++++++++++++++++++++++++++-------- icebergs_framework.F90 | 28 ++++++++++++++-------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c1d5b8d..66da55f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1676,6 +1676,10 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, #endif real :: hxm, hxp real, parameter :: ssh_coast=0.00 +integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() cos_rot=bilin(grd, grd%cos, i, j, xi, yj) ! If true, uses the inverted bilin function sin_rot=bilin(grd, grd%sin, i, j, xi, yj) @@ -1691,7 +1695,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst=grd%sst(i,j) ! A-grid cn=grd%cn(i,j) ! A-grid hi=grd%hi(i,j) ! A-grid - + ! Estimate SSH gradient in X direction #ifdef USE_OLD_SSH_GRADIENT dxp=0.5*(grd%dx(i+1,j)+grd%dx(i+1,j-1)) @@ -1928,8 +1932,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Interpolate wind stresses from C-grid velocity-points. ! This masking is needed for now to prevent icebergs from running up on to land. mask = min(grd%msk(i,j), grd%msk(i+1,j), grd%msk(i,j+1), grd%msk(i+1,j+1)) - grd%ua(I,J) = mask * 0.5*(uC_tmp(I,j)+uC_tmp(I,j+1)) - grd%va(I,J) = mask * 0.5*(vC_tmp(i,J)+vC_tmp(i+1,J)) + grd%ua(I,J) = mask * 0.5*(uC_tmp(I,j)+uC_tmp(I,j+1)) + grd%va(I,J) = mask * 0.5*(vC_tmp(i,J)+vC_tmp(i+1,J)) enddo ; enddo deallocate(uC_tmp, vC_tmp) else @@ -1954,6 +1958,18 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%hi(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=hi(:,:) call mpp_update_domains(grd%hi, grd%domain) + !Make sure that gridded values agree with mask (to get ride of NaN values) + do i=grd%isd,grd%ied ; do j=grd%jsc-1,grd%jed + !Initializing all gridded values to zero + if (grd%msk(i,j).lt. 0.5) then + grd%ua(i,j) = 0.0 ; grd%va(i,j) = 0.0 + grd%uo(i,j) = 0.0 ; grd%vo(i,j) = 0.0 + grd%ui(i,j) = 0.0 ; grd%vi(i,j) = 0.0 + grd%sst(i,j) = 0.0; grd%cn(i,j) = 0.0 + grd%hi(i,j) = 0.0 + endif + enddo; enddo + if (debug) call bergs_chksum(bergs, 'run bergs (top)') if (debug) call checksum_gridded(bergs%grd, 'top of s/r run') @@ -3144,6 +3160,10 @@ subroutine update_verlet_position(bergs,berg) real :: dx, dt, dt_2 integer :: i, j logical :: on_tangential_plane, error_flag, bounced +integer :: stderrunit + + ! Get the stderr unit number + stderrunit = stderr() ! For convenience grd=>bergs%grd @@ -3361,7 +3381,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (grd%msk(i-1,j)>0.) then if (i>grd%isd+1) i=i-1 else - !write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from west',lon,lat,xi,yj,uvel,vvel,mpp_pe() + write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from west',lon,lat,xi,yj,uvel,vvel,mpp_pe() bounced=.true. endif endif @@ -3380,7 +3400,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (grd%msk(i,j-1)>0.) then if (j>grd%jsd+1) j=j-1 else - !write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from south',lon,lat,xi,yj,uvel,vvel,mpp_pe() + write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from south',lon,lat,xi,yj,uvel,vvel,mpp_pe() bounced=.true. endif endif @@ -3389,7 +3409,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (grd%msk(i,j+1)>0.) then if (j2) then ! stop 'diamonds, adjust: Moved too far in i!' @@ -3460,7 +3479,6 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment' if (debug) error=.true. endif - end subroutine adjust_index_and_ground !end subroutine evolve_icebergs diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index dfc68d9..8fbdd2c 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -589,20 +589,20 @@ subroutine ice_bergs_framework_init(bergs, & ' [lon|lat][min|max]=', minval(grd%lon),maxval(grd%lon),minval(grd%lat),maxval(grd%lat) endif - !if (mpp_pe().eq.15) then - ! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) - ! enddo - ! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) - ! enddo - ! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) - ! do j=grd%jed,grd%jsd,-1 - ! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) - ! enddo - !endif +! if (mpp_pe().eq.3) then +! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) +! do j=grd%jed,grd%jsd,-1 +! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) +! enddo +! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) +! do j=grd%jed,grd%jsd,-1 +! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) +! enddo +! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) +! do j=grd%jed,grd%jsd,-1 +! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) +! enddo +! endif !Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) From e8ef485ec72c780c66156eb7ada4d855b12c49d1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 1 Jul 2016 09:46:05 -0400 Subject: [PATCH 122/361] A piece of code has been added to the routine which handels spreading mass to ocean. The new code reassigns mass which should be spread onto land points (masked points). The unused mass is assigned to the other grid around the iceberg in proportion to the percent of the iceberg which is in that grid cell. This piece of code completes the hexagonal spreading, and allows the hexagonal spreading to interact with boundaries. For the square spreading, the code should not make any difference, because all of the mass is already distributed (with the center grid cell taking all the mass which would have otherwise been put onto a masked cell. At some point we may want to change the way this works (and make it work more like the hexagonal case). However, for now, we leave it as it was, so that the answers should not change. --- icebergs.F90 | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 66da55f..96298a8 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1076,6 +1076,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR real :: S, H, origin_x, origin_y, x0, y0, theta real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex + real :: fraction_used real, parameter :: rho_seawater=1035. integer :: stderrunit logical :: debug @@ -1202,16 +1203,22 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling endif endif - - grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass) - grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass) - grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass) - grd%mass_on_ocean(i,j,4)=grd%mass_on_ocean(i,j,4)+(yCxL*Mass) - grd%mass_on_ocean(i,j,5)=grd%mass_on_ocean(i,j,5)+(yCxC*Mass) - grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,6)+(yCxR*Mass) - grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,7)+(yUxL*Mass) - grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass) - grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass) + + !Scale each cell by (1/fraction_used) in order to redisribute ice mass which landed up on the land, back into the ocean + !Note that for the square elements, the mass has already been reassigned, so fraction_used shoule be equal to 1 aready + fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& + +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) + + + grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass/fraction_used) + grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass/fraction_used) + grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass/fraction_used) + grd%mass_on_ocean(i,j,4)=grd%mass_on_ocean(i,j,4)+(yCxL*Mass/fraction_used) + grd%mass_on_ocean(i,j,5)=grd%mass_on_ocean(i,j,5)+(yCxC*Mass/fraction_used) + grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,6)+(yCxR*Mass/fraction_used) + grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,7)+(yUxL*Mass/fraction_used) + grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass/fraction_used) + grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass/fraction_used) end subroutine spread_mass_across_ocean_cells @@ -1504,7 +1511,7 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, if ( (.not. ((((Ax>0.) .and. (Ay>0.)) .or. ((Bx>0.) .and. (By> 0.))) .or. ((Cx>0.) .and. (Cy> 0.)))) .and. ((Area_Upper+Area_Right).le.Area_triangle) ) then !No points land in this quadrant and triangle does not cross the quadrant Key_quadrant=1; - elseif ( (.not. ((((Ax<0.) .and. (Ay>=0)) .or. ((Bx<0.) .and. (By>=0.))) .or. ((Cx<0.) .and. (Cy>=0.)))) .and. ((Area_Upper+Area_Left).le. Area_triangle) ) then + elseif ( (.not. ((((Ax<0.) .and. (Ay>0)) .or. ((Bx<0.) .and. (By>0.))) .or. ((Cx<0.) .and. (Cy>0.)))) .and. ((Area_Upper+Area_Left).le. Area_triangle) ) then Key_quadrant=2 elseif ( (.not. ((((Ax<0.) .and. (Ay<0.)) .or. ((Bx<0.) .and. (By< 0.))) .or. ((Cx<0.) .and. (Cy< 0.)))) .and. ((Area_Lower+Area_Left) .le.Area_triangle) ) then Key_quadrant=3; @@ -1553,10 +1560,15 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Error=abs(Area_Q1+Area_Q2+Area_Q3+Area_Q4-Area_triangle) if (Error>0.01) then call error_mesg('diamonds, triangle spreading', 'Triangle not evaluated accurately!!', WARNING) - if (mpp_pe().eq.mpp_root_pe()) then + !if (mpp_pe().eq.mpp_root_pe()) then + if (mpp_pe().eq. 0) then write(stderrunit,*) 'diamonds, Triangle corners:',Ax,Ay,Bx,By,Cx,Cy write(stderrunit,*) 'diamonds, Triangle, Areas', Area_Q1, Area_Q2 , Area_Q3, Area_Q4 write(stderrunit,*) 'diamonds, Triangle, Areas', Error + write(stderrunit,*) 'diamonds, point in triangle',(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)),Key_quadrant + write(stderrunit,*) 'diamonds, halves',Area_Upper,Area_Lower,Area_Right,Area_Left + + endif endif From 7c666e97b25c09072e00dd4bc75cc2d49b66e018 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 1 Jul 2016 13:33:47 -0400 Subject: [PATCH 123/361] An iceberg property called static_berg has been added to icebergs (and to restart files). If static iceberg =1, then the iceberg does not move. An if statement has been added to evolve_icebergs routine to stop the static icebergs from moving. The static_berg variable is useful for running ice shelf simulations. The static_berg can later be used to simulate iceberg grounding (by letting a partially grounded iceberg have static_berg between 0 and 1. --- icebergs.F90 | 111 +++++++++++++++++++++-------------------- icebergs_framework.F90 | 45 ++++++++++------- icebergs_io.F90 | 18 ++++++- 3 files changed, 98 insertions(+), 76 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 96298a8..474c50b 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2575,6 +2575,7 @@ subroutine calve_icebergs(bergs) newberg%mass_scaling=bergs%mass_scaling(k) newberg%mass_of_bits=0. newberg%halo_berg=0. + newberg%static_berg=0. newberg%heat_density=grd%stored_heat(i,j)/grd%stored_ice(i,j,k) ! This is in J/kg call add_new_berg_to_list(bergs%list(i,j)%first, newberg) calved_to_berg=bergs%initial_mass(k)*bergs%mass_scaling(k) ! Units of kg @@ -2633,53 +2634,54 @@ subroutine evolve_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs + if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve - !Checking it everything is ok: - if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - call print_berg(stderrunit, berg, 'evolve_iceberg, berg is not in proper starting cell') - write(stderrunit,'(a,i3,2(i4,3f8.2))') 'evolve_iceberg: pe,lon/lat(i,j)=', mpp_pe(), & - berg%ine,berg%lon,grd%lon(berg%ine-1,berg%jne-1),grd%lon(berg%ine,berg%jne), & - berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) - endif - if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') - - !Time stepping schemes: - if (Runge_not_Verlet) then - call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) - endif - if (.not.Runge_not_Verlet) then - call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) - endif - - ! Saving all the iceberg variables. - berg%axn=axn - berg%ayn=ayn - berg%bxn=bxn - berg%byn=byn - berg%uvel=uveln - berg%vvel=vveln - - if (Runge_not_Verlet) then - berg%lon=lonn ; berg%lat=latn - berg%ine=i ; berg%jne=j - berg%xi=xi ; berg%yj=yj - else - if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) - endif - - !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) - !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') - if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') + !Checking it everything is ok: + if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + call print_berg(stderrunit, berg, 'evolve_iceberg, berg is not in proper starting cell') + write(stderrunit,'(a,i3,2(i4,3f8.2))') 'evolve_iceberg: pe,lon/lat(i,j)=', mpp_pe(), & + berg%ine,berg%lon,grd%lon(berg%ine-1,berg%jne-1),grd%lon(berg%ine,berg%jne), & + berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) + endif + if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') + + !Time stepping schemes: + if (Runge_not_Verlet) then + call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) + endif + if (.not.Runge_not_Verlet) then + call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) + endif + + ! Saving all the iceberg variables. + berg%axn=axn + berg%ayn=ayn + berg%bxn=bxn + berg%byn=byn + berg%uvel=uveln + berg%vvel=vveln + + if (Runge_not_Verlet) then + berg%lon=lonn ; berg%lat=latn + berg%ine=i ; berg%jne=j + berg%xi=xi ; berg%yj=yj + else + if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) + endif + !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) + !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') + if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') + endif berg=>berg%next enddo ! loop over all bergs enddo ; enddo @@ -2690,16 +2692,15 @@ subroutine evolve_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs - - - if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) - - !Updating old velocities (for use in iceberg interactions) - berg%uvel_old=berg%uvel - berg%vvel_old=berg%vvel - berg%lon_old=berg%lon ! lon_old, lat_old are not really needed for Verlet. But are needed for RK - berg%lat_old=berg%lat - + if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve + if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) + + !Updating old velocities (for use in iceberg interactions) + berg%uvel_old=berg%uvel + berg%vvel_old=berg%vvel + berg%lon_old=berg%lon ! lon_old, lat_old are not really needed for Verlet. But are needed for RK + berg%lat_old=berg%lat + endif berg=>berg%next enddo ! loop over all bergs enddo ; enddo diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 8fbdd2c..b3d7caa 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -15,8 +15,8 @@ module ice_bergs_framework implicit none ; private -integer :: buffer_width=26 !Changed from 20 to 28 by Alon -integer :: buffer_width_traj=29 !Changed from 23 by Alon +integer :: buffer_width=27 !Changed from 20 to 28 by Alon +integer :: buffer_width_traj=30 !Changed from 23 by Alon !integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon !integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes @@ -142,7 +142,7 @@ module ice_bergs_framework real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg + real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg, static_berg real :: mass_of_bits, heat_density integer :: year, iceberg_num type(xyt), pointer :: next=>null() @@ -156,6 +156,7 @@ module ice_bergs_framework real :: start_lon, start_lat, start_day, start_mass, mass_scaling real :: mass_of_bits, heat_density real :: halo_berg ! Equal to zero for bergs on computational domain, and =1 for bergs on the halo + real :: static_berg ! Equal to 1 for icebergs which are static (not allowed to move). Might be extended to grounding later. integer :: start_year integer :: iceberg_num integer :: ine, jne ! nearest index in NE direction (for convenience) @@ -1493,9 +1494,10 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) buff%data(24,n)=berg%byn !Alon buff%data(25,n)=float(berg%iceberg_num) buff%data(26,n)=berg%halo_berg + buff%data(27,n)=berg%static_berg if (max_bonds .gt. 0) then - counter=26 !how many data points being passed so far (must match above) + counter=27 !how many data points being passed so far (must match above) current_bond=>berg%first_bond do k = 1,max_bonds if (associated(current_bond)) then @@ -1637,6 +1639,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%byn=buff%data(24,n) !Alon localberg%iceberg_num=nint(buff%data(25,n)) localberg%halo_berg=buff%data(26,n) + localberg%static_berg=buff%data(27,n) !These quantities no longer need to be passed between processors localberg%uvel_old=localberg%uvel @@ -1838,6 +1841,7 @@ subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) buff%data(27,n)=traj%bxn !Alon buff%data(28,n)=traj%byn !Alon buff%data(29,n)=traj%halo_berg !Alon + buff%data(30,n)=traj%static_berg !Alon endif end subroutine pack_traj_into_buffer2 @@ -1884,6 +1888,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n, save_short_traj) traj%bxn=buff%data(27,n) !Alon traj%byn=buff%data(28,n) !Alon traj%halo_berg=buff%data(29,n) !Alon + traj%static_berg=buff%data(30,n) !Alon endif call append_posn(first, traj) @@ -2695,6 +2700,7 @@ subroutine record_posn(bergs) posn%lon_old=this%lon_old posn%lat_old=this%lat_old posn%halo_berg=this%halo_berg + posn%static_berg=this%static_berg call push_posn(this%trajectory, posn) @@ -3905,23 +3911,24 @@ integer function berg_chksum(berg ) rtmp(26)=berg%ssh_y rtmp(27)=berg%cn rtmp(28)=berg%hi - rtmp(29)=berg%axn !Added by Alon - rtmp(30)=berg%ayn !Added by Alon - rtmp(31)=berg%bxn !Added by Alon - rtmp(32)=berg%byn !Added by Alon - rtmp(33)=berg%uvel_old !Added by Alon - rtmp(34)=berg%vvel_old !Added by Alon - rtmp(35)=berg%lat_old !Added by Alon - rtmp(36)=berg%lon_old !Added by Alon - itmp(37)=berg%halo_berg !Changed from 31 to 40 by Alon - itmp(1:37)=transfer(rtmp,i8) !Changed from 28 to 37 by Alon - itmp(38)=berg%start_year !Changed from 29 to 38 by Alon - itmp(39)=berg%ine !Changed from 30 to 39 by Alon - itmp(40)=berg%jne !Changed from 31 to 40 by Alon - itmp(41)=berg%iceberg_num !added by Alon + rtmp(29)=berg%axn + rtmp(30)=berg%ayn + rtmp(31)=berg%bxn + rtmp(32)=berg%byn + rtmp(33)=berg%uvel_old + rtmp(34)=berg%vvel_old + rtmp(35)=berg%lat_old + rtmp(36)=berg%lon_old + itmp(37)=berg%halo_berg + itmp(38)=berg%static_berg + itmp(1:38)=transfer(rtmp,i8) + itmp(39)=berg%start_year + itmp(40)=berg%ine + itmp(41)=berg%jne + itmp(42)=berg%iceberg_num ichk1=0; ichk2=0; ichk3=0 - do i=1,37+4 !Changd from 28 to 37, 3 to 4 by Alon + do i=1,38+4 ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 8fd70ea..c6c686b 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -131,6 +131,7 @@ subroutine write_restart(bergs) mass_scaling, & mass_of_bits, & halo_berg, & + static_berg, & heat_density integer, allocatable, dimension(:) :: ine, & @@ -184,6 +185,7 @@ subroutine write_restart(bergs) allocate(mass_of_bits(nbergs)) allocate(heat_density(nbergs)) allocate(halo_berg(nbergs)) + allocate(static_berg(nbergs)) allocate(ine(nbergs)) allocate(jne(nbergs)) @@ -235,6 +237,8 @@ subroutine write_restart(bergs) longname='heat density',units='J/kg') id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & longname='halo_berg',units='dimensionless') + id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & + longname='static_berg',units='dimensionless') ! Write variables @@ -255,6 +259,7 @@ subroutine write_restart(bergs) start_year(i) = this%start_year; start_day(i) = this%start_day start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling halo_berg(i) = this%halo_berg + static_berg(i) = this%static_berg iceberg_num(i) = this%iceberg_num; mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density this=>this%next @@ -284,7 +289,7 @@ subroutine write_restart(bergs) start_mass, & mass_scaling, & mass_of_bits, & - halo_berg, & + static_berg, & heat_density ) deallocate( & @@ -406,7 +411,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, iceberg_numid, start_dayid, start_massid -integer :: scaling_id, mass_of_bits_id, heat_density_id, halo_bergid +integer :: scaling_id, mass_of_bits_id, heat_density_id, halo_bergid, static_bergid logical :: lres, found_restart, multiPErestart real :: lon0, lon1, lat0, lat1 character(len=33) :: filename, filename_base @@ -481,6 +486,7 @@ subroutine read_restart_bergs_orig(bergs,Time) start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') halo_bergid=inq_var(ncid, 'halo_berg') + static_bergid=inq_var(ncid, 'static_berg') mass_of_bits_id=inq_var(ncid, 'mass_of_bits',unsafe=.true.) heat_density_id=inq_var(ncid, 'heat_density',unsafe=.true.) ineid=inq_var(ncid, 'ine',unsafe=.true.) @@ -536,6 +542,7 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) localberg%halo_berg=get_double(ncid, halo_bergid, k) + localberg%static_berg=get_double(ncid, static_bergid, k) if (mass_of_bits_id>0) then ! Allow reading of older restart with no bergy bits localberg%mass_of_bits=get_double(ncid, mass_of_bits_id, k) else @@ -627,6 +634,7 @@ subroutine generate_bergs(bergs,Time) localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. localberg%halo_berg=0. + localberg%static_berg=0. localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. @@ -722,6 +730,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & halo_berg, & + static_berg, & heat_density integer, allocatable, dimension(:) :: ine, & jne, & @@ -768,6 +777,7 @@ subroutine read_restart_bergs(bergs,Time) allocate(mass_scaling(nbergs_in_file)) allocate(mass_of_bits(nbergs_in_file)) allocate(halo_berg(nbergs_in_file)) + allocate(static_berg(nbergs_in_file)) allocate(heat_density(nbergs_in_file)) allocate(ine(nbergs_in_file)) @@ -794,6 +804,7 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) call read_unlimited_axis(filename,'halo_berg',halo_berg,domain=grd%domain) + call read_unlimited_axis(filename,'static_berg',static_berg,domain=grd%domain) call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) @@ -880,6 +891,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%mass_scaling=mass_scaling(k) localberg%mass_of_bits=mass_of_bits(k) localberg%halo_berg=halo_berg(k) + localberg%static_berg=static_berg(k) localberg%heat_density=heat_density(k) localberg%first_bond=>null() if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) @@ -918,6 +930,7 @@ subroutine read_restart_bergs(bergs,Time) mass_scaling, & mass_of_bits, & halo_berg, & + static_berg, & heat_density ) deallocate( & ine, & @@ -997,6 +1010,7 @@ subroutine generate_bergs(bergs,Time) localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. localberg%halo_berg=0. + localberg%static_berg=0. localberg%heat_density=0. localberg%uvel=1. localberg%vvel=0. From b4ad6a5bc8b13f54edb68a7a041ffe7124708002 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 5 Jul 2016 15:16:51 -0400 Subject: [PATCH 124/361] The routine initialize bonds, which initializes the bonds automatically when the manual flag is turned on, has been edited. The edits mean that the distance between the two icebergs is calculated correctly. However, this distance is not used. The routine should be removed at some point. It was created for development. A few more lines have been adde in order to allow icebergs to have an orientation which is achieve through the positions of their bonds. However, this is not quite working yet --- icebergs.F90 | 74 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 474c50b..447b007 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -144,6 +144,7 @@ subroutine initialize_iceberg_bonds(bergs) type(icebergs_gridded), pointer :: grd real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg +real :: dlon,dlat real :: r_dist_x, r_dist_y, r_dist integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner @@ -157,7 +158,7 @@ subroutine initialize_iceberg_bonds(bergs) do while (associated(berg)) ! loop over all bergs lon1=berg%lon; lat1=berg%lat - call rotpos_to_tang(lon1,lat1,x1,y1) + !call rotpos_to_tang(lon1,lat1,x1,y1) !Is this correct? Shouldn't it only be on tangent plane? do grdj_inner = grd%jsc,grd%jec ; do grdi_inner = grd%isc,grd%iec !This line uses n^2 steps ! do grdj_inner = berg%jne-1,berg%jne+1 ; do grdi_inner = berg%ine-1,berg%ine+1 !Only looping through adjacent cells. @@ -166,9 +167,15 @@ subroutine initialize_iceberg_bonds(bergs) if (berg%iceberg_num .ne. other_berg%iceberg_num) then lon2=other_berg%lon; lat2=other_berg%lat - call rotpos_to_tang(lon2,lat2,x2,y2) - r_dist_x=x1-x2 ; r_dist_y=y1-y2 - r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + !call rotpos_to_tang(lon2,lat2,x2,y2) !Is this correct? Shouldn't it only be on tangent plane? + !r_dist_x=x1-x2 ; r_dist_y=y1-y2 + !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + + dlon=lon1-lon2 + dlat=lat1-lat2 + r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) + r_dist_y=dlat*(pi/180)*Rearth + r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond call form_a_bond(berg, other_berg%iceberg_num, other_berg%ine, other_berg%jne, other_berg) @@ -879,6 +886,7 @@ subroutine thermodynamics(bergs) type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. integer :: grdi, grdj +real :: orientation ! For convenience grd=>bergs%grd @@ -1053,6 +1061,15 @@ subroutine thermodynamics(bergs) Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) endif + + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then + orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation) + print *, 'orientation: ', orientation, this%iceberg_num + + endif + + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs ) endif endif @@ -1063,6 +1080,55 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics +!MPP1 +real function find_orientation_using_iceberg_bonds(berg,initial_orientation) + ! Arguments + type(iceberg) :: berg + real, intent(in) :: initial_orientation + type(iceberg), pointer :: other_berg + type(bond), pointer :: current_bond + real :: angle, lat1,lat2,lon1,lon2,dlat,dlon + real :: r_dist_x, r_dist_y + real :: theta, bond_count, Average_angle + + bond_count=0. + Average_angle=0. + current_bond=>berg%first_bond + lat1=berg%lat + lon1=berg%lon + do while (associated(current_bond)) ! loop over all bonds + other_berg=>current_bond%other_berg + if (.not. associated(current_bond)) then + call error_mesg('diamonds,calculating orientation', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) + else + lat2=other_berg%lat + lon2=other_berg%lon + + dlat=lat2-lat1 + dlon=lon2-lon1 + + r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) + r_dist_y=dlat*(pi/180)*Rearth + if (r_dist_y .eq. 0.) then + angle=pi/2. + else + angle=atan(r_dist_x/r_dist_y) + angle= ((pi/2) - (initial_orientation*(pi/180))) - angle + angle=modulo(angle-(2*pi) ,pi/6.) + endif + bond_count=bond_count+1. + Average_angle=Average_angle+angle + + endif + current_bond=>current_bond%next_bond + enddo + Average_angle =Average_angle/bond_count + find_orientation_using_iceberg_bonds=modulo(angle-(2*pi) ,pi/6.) + +end function find_orientation_using_iceberg_bonds + + + ! ############################################################################## subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs) From 4f879b0ad2e297e9ff3598753d7a293a43626651 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 5 Jul 2016 20:00:37 -0400 Subject: [PATCH 125/361] Code has been added to allow for non periodic domains, for periodic domains which are not of length 360, and also for grids which are not lat lon grids. The periodicity of the domain (in the x-direction) is in imput variable. For non-periodic domains, this should be set to a very large number. A flag has been added which signals whether the grid_is_latlon. The various metric terms have been adjusted according to this flag. Period domains in the y-direction have not yet been implemented. The code has not yet been tested, but it does compile. --- icebergs.F90 | 184 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 118 insertions(+), 66 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 447b007..129bb31 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -145,6 +145,7 @@ subroutine initialize_iceberg_bonds(bergs) real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg real :: dlon,dlat +real :: dx_dlon,dy_dlat, lat_ref real :: r_dist_x, r_dist_y, r_dist integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner @@ -173,8 +174,10 @@ subroutine initialize_iceberg_bonds(bergs) dlon=lon1-lon2 dlat=lat1-lat2 - r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) - r_dist_y=dlat*(pi/180)*Rearth + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,bergs%grid_is_latlon,dx_dlon,dy_dlat) + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond @@ -191,6 +194,39 @@ subroutine initialize_iceberg_bonds(bergs) end subroutine initialize_iceberg_bonds +subroutine convert_from_grid_to_meters(lat_ref,grid_is_latlon ,dx_dlon,dy_dlat) + ! Arguments + real, intent(in) :: lat_ref + logical, intent(in) :: grid_is_latlon + real, intent(out) :: dx_dlon,dy_dlat + + if (grid_is_latlon) then + dx_dlon=(pi/180.)*Rearth*cos((lat_ref)*(pi/180.)) + dy_dlat=(pi/180.)*Rearth + + else + dx_dlon=1. + dy_dlat=1. + + endif +end subroutine convert_from_grid_to_meters + +subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) + ! Arguments + real, intent(in) :: lat_ref + logical, intent(in) :: grid_is_latlon + real, intent(out) :: dlon_dx,dlat_dy + + if (grid_is_latlon) then + dlon_dx=(180./pi)/(Rearth*cos((lat_ref)*(pi/180.))) + dlat_dy=(180./pi)/Rearth + + else + dlon_dx=1. + dlat_dy=1. + + endif +end subroutine convert_from_meters_to_grid ! ############################################################################## subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 @@ -255,6 +291,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i real :: P_11, P_12, P_21, P_22 real :: M1, M2, M_min real :: u2, v2 + real :: lat_ref, dx_dlon, dy_dlat logical :: critical_interaction_damping_on real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef real, intent(inout) :: IA_x, IA_y @@ -305,10 +342,12 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i !Approximation for small distances. Should be fine. !r_dist_x=x1-x2 ; r_dist_y=y1-y2 !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) - r_dist_y=dlat*(pi/180)*Rearth - r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,bergs%grid_is_latlon,dx_dlon,dy_dlat) + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat + r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) !if (berg%iceberg_num .eq. 1) then !print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist @@ -895,7 +934,7 @@ subroutine thermodynamics(bergs) do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly this=>bergs%list(grdi,grdj)%first do while(associated(this)) - if (debug) call check_position(grd, this, 'thermodynamics (top)') + if (debug) call check_position(grd, this, 'thermodynamics (top)',bergs%Lx,bergs%grid_is_latlon) call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & @@ -1064,7 +1103,7 @@ subroutine thermodynamics(bergs) orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then - orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation) + orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grid_is_latlon) print *, 'orientation: ', orientation, this%iceberg_num endif @@ -1081,14 +1120,16 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics !MPP1 -real function find_orientation_using_iceberg_bonds(berg,initial_orientation) +real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid_is_latlon) ! Arguments type(iceberg) :: berg real, intent(in) :: initial_orientation + logical, intent(in) :: grid_is_latlon type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond real :: angle, lat1,lat2,lon1,lon2,dlat,dlon - real :: r_dist_x, r_dist_y + real :: r_dist_x, r_dist_y + real :: lat_ref, dx_dlon, dy_dlat real :: theta, bond_count, Average_angle bond_count=0. @@ -1107,8 +1148,11 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation) dlat=lat2-lat1 dlon=lon2-lon1 - r_dist_x=dlon*(pi/180)*Rearth*cos(0.5*(lat1+lat2)*(pi/180)) - r_dist_y=dlat*(pi/180)*Rearth + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,grid_is_latlon,dx_dlon,dy_dlat) + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat + if (r_dist_y .eq. 0.) then angle=pi/2. else @@ -2609,7 +2653,7 @@ subroutine calve_icebergs(bergs) newberg%lon=0.25*((grd%lon(i,j)+grd%lon(i-1,j-1))+(grd%lon(i-1,j)+grd%lon(i,j-1))) newberg%lat=0.25*((grd%lat(i,j)+grd%lat(i-1,j-1))+(grd%lat(i-1,j)+grd%lat(i,j-1))) !write(stderr(),*) 'diamonds, calve_icebergs: creating new iceberg at ',newberg%lon,newberg%lat - lret=pos_within_cell(grd, newberg%lon, newberg%lat, i, j, xi, yj) + lret=pos_within_cell(grd, newberg%lon, newberg%lat, i, j, xi, yj,bergs%Lx,bergs%grid_is_latlon) if (.not.lret) then write(stderrunit,*) 'diamonds, calve_icebergs: something went very wrong!',i,j,xi,yj call error_mesg('diamonds, calve_icebergs', 'berg is not in the correct cell!', FATAL) @@ -2703,7 +2747,7 @@ subroutine evolve_icebergs(bergs) if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve !Checking it everything is ok: - if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then + if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne,bergs%Lx,bergs%grid_is_latlon) ) then write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) @@ -2718,7 +2762,7 @@ subroutine evolve_icebergs(bergs) berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) endif - if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') + if (debug) call check_position(grd, berg, 'evolve_iceberg (top)',bergs%Lx,bergs%grid_is_latlon) !Time stepping schemes: if (Runge_not_Verlet) then @@ -2746,7 +2790,7 @@ subroutine evolve_icebergs(bergs) !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') - if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') + if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)',bergs%Lx,bergs%grid_is_latlon) endif berg=>berg%next enddo ! loop over all bergs @@ -2833,7 +2877,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !Solving for the new velocity on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. if (on_tangential_plane) then call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) @@ -2849,7 +2893,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! error_flag=.false. if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -2868,13 +2912,13 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) & dt*ay1 write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj) + error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon ,explain=.true.) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 @@ -2938,7 +2982,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo yj=berg%yj bounced=.false. on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) @@ -2951,8 +2995,10 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo ! A1 = A(X1) lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - dydl=r180_pi/Rearth + + call convert_from_meters_to_grid(lat1,bergs%grid_is_latlon ,dxdl1,dydl) + !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + !dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) u1=uvel1*dxdl1; v1=vvel1*dydl @@ -2974,13 +3020,13 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3002,15 +3048,16 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, bergs%Lx,bergs%grid_is_latlon,explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) endif - dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) + call convert_from_meters_to_grid(lat2,bergs%grid_is_latlon ,dxdl2,dydl) + !dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 @@ -3029,13 +3076,13 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3057,18 +3104,19 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, bergs%Lx,bergs%grid_is_latlon,explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) endif - dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) + call convert_from_meters_to_grid(lat3,bergs%grid_is_latlon ,dxdl3,dydl) + !dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) @@ -3086,11 +3134,11 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) i4=i; j4=j ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3112,21 +3160,22 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,bergs%Lx,bergs%grid_is_latlon, explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) endif - dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) + call convert_from_meters_to_grid(lat4,bergs%grid_is_latlon ,dxdl4,dydl) + !dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) @@ -3159,12 +3208,12 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3193,21 +3242,21 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' - error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) + error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj,bergs%Lx,bergs%grid_is_latlon) call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon, explain=.true.) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 @@ -3252,12 +3301,13 @@ subroutine update_verlet_position(bergs,berg) on_tangential_plane=.false. - if (berg%lat>89.) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1,berg%iceberg_num) - dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - dydl=r180_pi/Rearth + !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + !dydl=r180_pi/Rearth + call convert_from_meters_to_grid(lat1,bergs%grid_is_latlon ,dxdl1,dydl) uvel1=berg%uvel; vvel1=berg%vvel ! Loading past acceleartions - Alon @@ -3280,7 +3330,8 @@ subroutine update_verlet_position(bergs,berg) else lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon endif - dxdln=r180_pi/(Rearth*cos(latn*pi_180)) + !dxdln=r180_pi/(Rearth*cos(latn*pi_180)) + call convert_from_meters_to_grid(latn,bergs%grid_is_latlon ,dxdln,dydl) ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon @@ -3289,7 +3340,7 @@ subroutine update_verlet_position(bergs,berg) ! Adjusting mass... !MP3 i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) !Alon:"unclear which velocity to use here?" !if (bounced) then ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag @@ -3350,10 +3401,11 @@ end subroutine rotvec_from_tang ! ############################################################################## -subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error) +subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error, Lx,grid_is_latlon) ! Arguments type(icebergs_gridded), pointer :: grd -real, intent(inout) :: lon, lat, uvel, vvel, xi, yj +real, intent(inout) :: lon, lat, uvel, vvel, xi, yj, Lx +logical, intent(in) :: grid_is_latlon integer, intent(inout) :: i,j logical, intent(out) :: bounced, error ! Local variables @@ -3370,12 +3422,12 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun error=.false. lon0=lon; lat0=lat ! original position i0=i; j0=j ! original i,j - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) ! print *, 'Alon:', lon, lat, i, j, xi, yj, lret xi0=xi; yj0=yj ! original xi,yj if (debug) then !Sanity check lret, xi and yj - lret=is_point_in_cell(grd, lon, lat, i, j) + lret=is_point_in_cell(grd, lon, lat, i, j, Lx, grid_is_latlon) if (xi<0. .or. xi>1. .or. yj<0. .or. yj>1.) then if (lret) then write(stderrunit,*) 'diamonds, adjust: WARNING!!! lret=T but |xi,yj|>1',mpp_pe() @@ -3385,9 +3437,9 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: yi=',yj,' lat=',lat write(stderrunit,*) 'diamonds, adjust: y3 y2=',grd%lat(i-1,j),grd%lat(i,j) write(stderrunit,*) 'diamonds, adjust: y0 y1=',grd%lat(i-1,j-1),grd%lat(i,j-1) - lret=is_point_in_cell(grd, lon, lat, i, j, explain=.true.) + lret=is_point_in_cell(grd, lon, lat, i, j, Lx,grid_is_latlon,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn is_point_in_cell=',lret - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx,grid_is_latlon,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' error=.true.; return @@ -3401,15 +3453,15 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: yi=',yj,' lat=',lat write(stderrunit,*) 'diamonds, adjust: y3 y2=',grd%lat(i-1,j),grd%lat(i,j) write(stderrunit,*) 'diamonds, adjust: y0 y1=',grd%lat(i-1,j-1),grd%lat(i,j-1) - lret=is_point_in_cell(grd, lon, lat, i, j, explain=.true.) + lret=is_point_in_cell(grd, lon, lat, i, j, Lx, grid_is_latlon, explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn is_point_in_cell=',lret - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx, grid_is_latlon,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' error=.true.; return endif endif - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) endif ! debug if (lret) return ! Berg was already in cell @@ -3439,7 +3491,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun jnm=jnm+1 endif endif - lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj,Lx,grid_is_latlon) ! Update xi and yj enddo if (abs(inm-i0)>1) then write(stderrunit,*) 'pe=',mpp_pe(),'diamonds, adjust: inm,i0,inm-i0=',inm,i0,inm-i0 @@ -3452,7 +3504,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun ! Adjust i,j based on xi,yj while bouncing off of masked land cells icount=0 - lret=pos_within_cell(grd, lon, lat, i0, j0, xi, yj) + lret=pos_within_cell(grd, lon, lat, i0, j0, xi, yj,Lx,grid_is_latlon) do while ( .not.lret.and. icount<4 ) icount=icount+1 if (xi.lt.0.) then @@ -3504,7 +3556,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (debug) then if (grd%msk(i,j)==0.) stop 'diamonds, adjust: Berg is in land! This should not happen...' endif - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) ! Update xi and yj enddo !if (debug) then ! if (abs(i-i0)>2) then @@ -3527,7 +3579,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: i,j=',i,j write(stderrunit,*) 'diamonds, adjust: inm,jnm=',inm,jnm write(stderrunit,*) 'diamonds, adjust: icount=',icount - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx,grid_is_latlon,explain=.true.) write(stderrunit,*) 'diamonds, adjust: lret=',lret endif if (abs(i-i0)+abs(j-j0)==0) then @@ -3552,7 +3604,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (yj<0.) yj=posn_eps lon=bilin(grd, grd%lon, i, j, xi, yj) lat=bilin(grd, grd%lat, i, j, xi, yj) - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) ! Update xi and yj if (.not. lret) then write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment' From 6e9e32877a5a4ae8dd0f2892cd9af84af5fbbc5f Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 6 Jul 2016 10:35:30 -0400 Subject: [PATCH 126/361] The length of the domain, Lx, and the flag grid_is_latlon have been included in the gridded_icebergs type, which means that these variables do not have to be passed around as explicitly. This neatens the code. A flag has been added to allow the code to run on an f-plane. The reference latitude for the f_plane is an input parameter, lat_ref. The option to change omega has been removed. No rotation can be achieved by setting the lat_ref to zero and using the f-plane (this is the default for when grid_is_latlon is off) The model has been set to default to an f-plane when grid_is_latlon is off. The periodicity in the x-direction is set by Lx. When grid_is_latlon is set to False, and Lx=360 (default), then Lx is set to a very large number which makes the model not periodic. --- icebergs.F90 | 121 +++++++++++----------- icebergs_framework.F90 | 224 ++++++++++++++++++++++++----------------- icebergs_io.F90 | 2 +- 3 files changed, 193 insertions(+), 154 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 129bb31..1db6a3f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -175,7 +175,7 @@ subroutine initialize_iceberg_bonds(bergs) dlon=lon1-lon2 dlat=lat1-lat2 lat_ref=0.5*(lat1+lat2) - call convert_from_grid_to_meters(lat_ref,bergs%grid_is_latlon,dx_dlon,dy_dlat) + call convert_from_grid_to_meters(lat_ref,grd%grid_is_latlon,dx_dlon,dy_dlat) r_dist_x=dlon*dx_dlon r_dist_y=dlat*dy_dlat r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) @@ -343,7 +343,7 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i !r_dist_x=x1-x2 ; r_dist_y=y1-y2 !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) lat_ref=0.5*(lat1+lat2) - call convert_from_grid_to_meters(lat_ref,bergs%grid_is_latlon,dx_dlon,dy_dlat) + call convert_from_grid_to_meters(lat_ref,bergs%grd%grid_is_latlon,dx_dlon,dy_dlat) r_dist_x=dlon*dx_dlon r_dist_y=dlat*dy_dlat @@ -521,7 +521,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) - f_cori=(2.*bergs%Omega_icebergs)*sin(pi_180*lat) + if ((grd%grid_is_latlon) .and. (.not. bergs%use_f_plane)) then + f_cori=(2.*omega)*sin(pi_180*lat) + else + f_cori=(2.*omega)*sin(pi_180*bergs%lat_ref) + endif ! f_cori=0. M=berg%mass @@ -934,7 +938,7 @@ subroutine thermodynamics(bergs) do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly this=>bergs%list(grdi,grdj)%first do while(associated(this)) - if (debug) call check_position(grd, this, 'thermodynamics (top)',bergs%Lx,bergs%grid_is_latlon) + if (debug) call check_position(grd, this, 'thermodynamics (top)') call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & @@ -1103,7 +1107,7 @@ subroutine thermodynamics(bergs) orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then - orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grid_is_latlon) + orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grd%grid_is_latlon) print *, 'orientation: ', orientation, this%iceberg_num endif @@ -2653,7 +2657,7 @@ subroutine calve_icebergs(bergs) newberg%lon=0.25*((grd%lon(i,j)+grd%lon(i-1,j-1))+(grd%lon(i-1,j)+grd%lon(i,j-1))) newberg%lat=0.25*((grd%lat(i,j)+grd%lat(i-1,j-1))+(grd%lat(i-1,j)+grd%lat(i,j-1))) !write(stderr(),*) 'diamonds, calve_icebergs: creating new iceberg at ',newberg%lon,newberg%lat - lret=pos_within_cell(grd, newberg%lon, newberg%lat, i, j, xi, yj,bergs%Lx,bergs%grid_is_latlon) + lret=pos_within_cell(grd, newberg%lon, newberg%lat, i, j, xi, yj) if (.not.lret) then write(stderrunit,*) 'diamonds, calve_icebergs: something went very wrong!',i,j,xi,yj call error_mesg('diamonds, calve_icebergs', 'berg is not in the correct cell!', FATAL) @@ -2747,7 +2751,7 @@ subroutine evolve_icebergs(bergs) if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve !Checking it everything is ok: - if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne,bergs%Lx,bergs%grid_is_latlon) ) then + if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) @@ -2762,7 +2766,7 @@ subroutine evolve_icebergs(bergs) berg%jne,berg%lat,grd%lat(berg%ine-1,berg%jne-1),grd%lat(berg%ine,berg%jne) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is in wrong starting cell!',FATAL) endif - if (debug) call check_position(grd, berg, 'evolve_iceberg (top)',bergs%Lx,bergs%grid_is_latlon) + if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') !Time stepping schemes: if (Runge_not_Verlet) then @@ -2790,7 +2794,7 @@ subroutine evolve_icebergs(bergs) !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) !if (debug) call print_berg(stderr(), berg, 'evolve_iceberg, final posn.') - if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)',bergs%Lx,bergs%grid_is_latlon) + if (debug) call check_position(grd, berg, 'evolve_iceberg (bot)') endif berg=>berg%next enddo ! loop over all bergs @@ -2877,7 +2881,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !Solving for the new velocity on_tangential_plane=.false. - if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. if (on_tangential_plane) then call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) @@ -2893,7 +2897,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! error_flag=.false. if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -2912,13 +2916,13 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) & dt*ay1 write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj) call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon ,explain=.true.) + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,explain=.true.) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 @@ -2982,7 +2986,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo yj=berg%yj bounced=.false. on_tangential_plane=.false. - if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) @@ -2996,7 +3000,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - call convert_from_meters_to_grid(lat1,bergs%grid_is_latlon ,dxdl1,dydl) + call convert_from_meters_to_grid(lat1,bergs%grd%grid_is_latlon ,dxdl1,dydl) !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) !dydl=r180_pi/Rearth uvel1=berg%uvel; vvel1=berg%vvel @@ -3020,13 +3024,13 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) + call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3048,15 +3052,15 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, bergs%Lx,bergs%grid_is_latlon,explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) endif - call convert_from_meters_to_grid(lat2,bergs%grid_is_latlon ,dxdl2,dydl) + call convert_from_meters_to_grid(lat2,bergs%grd%grid_is_latlon ,dxdl2,dydl) !dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) u2=uvel2*dxdl2; v2=vvel2*dydl call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3076,13 +3080,13 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) + call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3104,18 +3108,18 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, bergs%Lx,bergs%grid_is_latlon,explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) endif - call convert_from_meters_to_grid(lat3,bergs%grid_is_latlon ,dxdl3,dydl) + call convert_from_meters_to_grid(lat3,bergs%grd%grid_is_latlon ,dxdl3,dydl) !dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) u3=uvel3*dxdl3; v3=vvel3*dydl call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3134,11 +3138,11 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) + call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag) i4=i; j4=j ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. + if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3160,21 +3164,21 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,bergs%Lx,bergs%grid_is_latlon, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) endif - call convert_from_meters_to_grid(lat4,bergs%grid_is_latlon ,dxdl4,dydl) + call convert_from_meters_to_grid(lat4,bergs%grd%grid_is_latlon ,dxdl4,dydl) !dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) u4=uvel4*dxdl4; v4=vvel4*dydl call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3208,12 +3212,12 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon)) error_flag=.true. + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. endif if (error_flag) then call print_fld(grd, grd%msk, 'msk') @@ -3242,21 +3246,21 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,*) 'Acceleration terms for position 4' - error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj,bergs%Lx,bergs%grid_is_latlon) + error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,bergs%Lx,bergs%grid_is_latlon, explain=.true.) + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) do j=grd%jed,grd%jsd,-1 @@ -3301,13 +3305,13 @@ subroutine update_verlet_position(bergs,berg) on_tangential_plane=.false. - if ((berg%lat>89.) .and. (bergs%grid_is_latlon)) on_tangential_plane=.true. + if ((berg%lat>89.) .and. (grd%grid_is_latlon)) on_tangential_plane=.true. lon1=berg%lon; lat1=berg%lat if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1,berg%iceberg_num) !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) !dydl=r180_pi/Rearth - call convert_from_meters_to_grid(lat1,bergs%grid_is_latlon ,dxdl1,dydl) + call convert_from_meters_to_grid(lat1,grd%grid_is_latlon ,dxdl1,dydl) uvel1=berg%uvel; vvel1=berg%vvel ! Loading past acceleartions - Alon @@ -3331,7 +3335,7 @@ subroutine update_verlet_position(bergs,berg) lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon endif !dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - call convert_from_meters_to_grid(latn,bergs%grid_is_latlon ,dxdln,dydl) + call convert_from_meters_to_grid(latn,grd%grid_is_latlon ,dxdln,dydl) ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon @@ -3340,7 +3344,7 @@ subroutine update_verlet_position(bergs,berg) ! Adjusting mass... !MP3 i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag,bergs%Lx,bergs%grid_is_latlon) !Alon:"unclear which velocity to use here?" + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" !if (bounced) then ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag @@ -3401,11 +3405,10 @@ end subroutine rotvec_from_tang ! ############################################################################## -subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error, Lx,grid_is_latlon) +subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error) ! Arguments type(icebergs_gridded), pointer :: grd -real, intent(inout) :: lon, lat, uvel, vvel, xi, yj, Lx -logical, intent(in) :: grid_is_latlon +real, intent(inout) :: lon, lat, uvel, vvel, xi, yj integer, intent(inout) :: i,j logical, intent(out) :: bounced, error ! Local variables @@ -3422,12 +3425,12 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun error=.false. lon0=lon; lat0=lat ! original position i0=i; j0=j ! original i,j - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! print *, 'Alon:', lon, lat, i, j, xi, yj, lret xi0=xi; yj0=yj ! original xi,yj if (debug) then !Sanity check lret, xi and yj - lret=is_point_in_cell(grd, lon, lat, i, j, Lx, grid_is_latlon) + lret=is_point_in_cell(grd, lon, lat, i, j) if (xi<0. .or. xi>1. .or. yj<0. .or. yj>1.) then if (lret) then write(stderrunit,*) 'diamonds, adjust: WARNING!!! lret=T but |xi,yj|>1',mpp_pe() @@ -3437,9 +3440,9 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: yi=',yj,' lat=',lat write(stderrunit,*) 'diamonds, adjust: y3 y2=',grd%lat(i-1,j),grd%lat(i,j) write(stderrunit,*) 'diamonds, adjust: y0 y1=',grd%lat(i-1,j-1),grd%lat(i,j-1) - lret=is_point_in_cell(grd, lon, lat, i, j, Lx,grid_is_latlon,explain=.true.) + lret=is_point_in_cell(grd, lon, lat, i, j,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn is_point_in_cell=',lret - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx,grid_is_latlon,explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' error=.true.; return @@ -3453,15 +3456,15 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: yi=',yj,' lat=',lat write(stderrunit,*) 'diamonds, adjust: y3 y2=',grd%lat(i-1,j),grd%lat(i,j) write(stderrunit,*) 'diamonds, adjust: y0 y1=',grd%lat(i-1,j-1),grd%lat(i,j-1) - lret=is_point_in_cell(grd, lon, lat, i, j, Lx, grid_is_latlon, explain=.true.) + lret=is_point_in_cell(grd, lon, lat, i, j, explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn is_point_in_cell=',lret - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx, grid_is_latlon,explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' error=.true.; return endif endif - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) endif ! debug if (lret) return ! Berg was already in cell @@ -3491,7 +3494,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun jnm=jnm+1 endif endif - lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj,Lx,grid_is_latlon) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj) ! Update xi and yj enddo if (abs(inm-i0)>1) then write(stderrunit,*) 'pe=',mpp_pe(),'diamonds, adjust: inm,i0,inm-i0=',inm,i0,inm-i0 @@ -3504,7 +3507,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun ! Adjust i,j based on xi,yj while bouncing off of masked land cells icount=0 - lret=pos_within_cell(grd, lon, lat, i0, j0, xi, yj,Lx,grid_is_latlon) + lret=pos_within_cell(grd, lon, lat, i0, j0, xi, yj) do while ( .not.lret.and. icount<4 ) icount=icount+1 if (xi.lt.0.) then @@ -3556,7 +3559,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (debug) then if (grd%msk(i,j)==0.) stop 'diamonds, adjust: Berg is in land! This should not happen...' endif - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj enddo !if (debug) then ! if (abs(i-i0)>2) then @@ -3579,7 +3582,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun write(stderrunit,*) 'diamonds, adjust: i,j=',i,j write(stderrunit,*) 'diamonds, adjust: inm,jnm=',inm,jnm write(stderrunit,*) 'diamonds, adjust: icount=',icount - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, Lx,grid_is_latlon,explain=.true.) + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) write(stderrunit,*) 'diamonds, adjust: lret=',lret endif if (abs(i-i0)+abs(j-j0)==0) then @@ -3604,7 +3607,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (yj<0.) yj=posn_eps lon=bilin(grd, grd%lon, i, j, xi, yj) lat=bilin(grd, grd%lat, i, j, xi, yj) - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,Lx,grid_is_latlon) ! Update xi and yj + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj if (.not. lret) then write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment' diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index b3d7caa..d886856 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -81,7 +81,9 @@ module ice_bergs_framework integer :: isc, iec, jsc, jec ! Indices of computational domain integer :: isd, ied, jsd, jed ! Indices of data domain integer :: isg, ieg, jsg, jeg ! Indices of global domain - integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE identifiers + integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE idenLx ! Length of domain, for periodic boundary condition (Ly to be adde later if needed) + logical :: grid_is_latlon !Flag to say whether the coordinate is in lat lon degrees, or meters + real :: Lx !Length of the domain in x direction real, dimension(:,:), pointer :: lon=>null() ! Longitude of cell corners real, dimension(:,:), pointer :: lat=>null() ! Latitude of cell corners real, dimension(:,:), pointer :: lonc=>null() ! Longitude of cell centers @@ -202,7 +204,8 @@ module ice_bergs_framework real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0 null() enddo ; enddo + big_number=1.0E30 !write(stderrunit,*) 'diamonds: allocating grid' - allocate( grd%lon(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lon(:,:)=999. - allocate( grd%lat(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lat(:,:)=999. - allocate( grd%lonc(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lon(:,:)=999. - allocate( grd%latc(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lat(:,:)=999. + allocate( grd%lon(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lon(:,:)=big_number + allocate( grd%lat(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lat(:,:)=big_number + allocate( grd%lonc(grd%isd:grd%ied, grd%jsd:grd%jed) );grd%lon(:,:)=big_number + allocate( grd%latc(grd%isd:grd%ied, grd%jsd:grd%jed) );grd%lat(:,:)=big_number allocate( grd%dx(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%dx(:,:)=0. allocate( grd%dy(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%dy(:,:)=0. allocate( grd%area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%area(:,:)=0. @@ -516,59 +527,59 @@ subroutine ice_bergs_framework_init(bergs, & ! Sanitize lon and lat in the southern halo do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied - if (grd%lon(i,j).gt.900.) grd%lon(i,j)=grd%lon(i,j+1) - if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) + if (grd%lon(i,j).ge.big_number) grd%lon(i,j)=grd%lon(i,j+1) + if (grd%lat(i,j).ge.big_number) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) enddo; enddo ! fix halos on edge of the domain !1) South do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied - if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i,j+1)-grd%lon(i,j+2) - if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) + if (grd%lon(i,j).ge.big_number) grd%lon(i,j)=2.*grd%lon(i,j+1)-grd%lon(i,j+2) + if (grd%lat(i,j).ge.big_number) grd%lat(i,j)=2.*grd%lat(i,j+1)-grd%lat(i,j+2) enddo; enddo !2) North do j=grd%jec+1,grd%jed; do i=grd%isd,grd%ied - if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i,j-1)-grd%lon(i,j-2) - if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i,j-1)-grd%lat(i,j-2) + if (grd%lon(i,j).ge.big_number) grd%lon(i,j)=2.*grd%lon(i,j-1)-grd%lon(i,j-2) + if (grd%lat(i,j).ge.big_number) grd%lat(i,j)=2.*grd%lat(i,j-1)-grd%lat(i,j-2) enddo; enddo !3) West do i=grd%isc-1,grd%isd,-1; do j=grd%jsd,grd%jed - if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i+1,j)-grd%lon(i+2,j) - if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i+1,j)-grd%lat(i+2,j) + if (grd%lon(i,j).ge.big_number) grd%lon(i,j)=2.*grd%lon(i+1,j)-grd%lon(i+2,j) + if (grd%lat(i,j).ge.big_number) grd%lat(i,j)=2.*grd%lat(i+1,j)-grd%lat(i+2,j) enddo; enddo !4) East do i=grd%iec+1,grd%ied; do j=grd%jsd,grd%jed - if (grd%lon(i,j).gt.900.) grd%lon(i,j)=2.*grd%lon(i-1,j)-grd%lon(i-2,j) - if (grd%lat(i,j).gt.900.) grd%lat(i,j)=2.*grd%lat(i-1,j)-grd%lat(i-2,j) + if (grd%lon(i,j).ge.big_number) grd%lon(i,j)=2.*grd%lon(i-1,j)-grd%lon(i-2,j) + if (grd%lat(i,j).ge.big_number) grd%lat(i,j)=2.*grd%lat(i-1,j)-grd%lat(i-2,j) enddo; enddo if (.not. present(maskmap)) then ! Using a maskmap causes tickles this sanity check do j=grd%jsd,grd%jed; do i=grd%isd,grd%ied - if (grd%lon(i,j).gt.900.) write(stderrunit,*) 'bad lon: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lon(i,j) - if (grd%lat(i,j).gt.900.) write(stderrunit,*) 'bad lat: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lat(i,j) + if (grd%lon(i,j).ge.big_number) write(stderrunit,*) 'bad lon: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lon(i,j) + if (grd%lat(i,j).ge.big_number) write(stderrunit,*) 'bad lat: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lat(i,j) enddo; enddo endif !The fix to reproduce across PE layout change, from AJA j=grd%jsc; do i=grd%isc+1,grd%ied - minl=grd%lon(i-1,j)-180. - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,360.)+minl))>180.) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,360.)+minl + minl=grd%lon(i-1,j)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl enddo j=grd%jsc; do i=grd%isc-1,grd%isd,-1 - minl=grd%lon(i+1,j)-180. - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,360.)+minl))>180.) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,360.)+minl + minl=grd%lon(i+1,j)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl enddo do j=grd%jsc+1,grd%jed; do i=grd%isd,grd%ied - minl=grd%lon(i,j-1)-180. - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,360.)+minl))>180.) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,360.)+minl + minl=grd%lon(i,j-1)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl enddo; enddo do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied - minl=grd%lon(i,j+1)-180. - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,360.)+minl))>180.) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,360.)+minl + minl=grd%lon(i,j+1)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl enddo; enddo @@ -640,6 +651,10 @@ subroutine ice_bergs_framework_init(bergs, & endif if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj +if ((.not. grid_is_latlon) .and. (Lx.eq.360.)) then + call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) + Lx=1E31 +endif ! Parameters bergs%dt=dt @@ -648,6 +663,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%save_short_traj=save_short_traj bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo + bergs%grd%Lx=Lx + bergs%grd%grid_is_latlon=grid_is_latlon bergs%max_bonds=max_bonds bergs%grd%iceberg_halo=iceberg_halo bergs%rho_bergs=rho_bergs @@ -663,7 +680,10 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet - bergs%Omega_icebergs=Omega_icebergs + bergs%use_f_plane=use_f_plane + bergs%rotate_icebergs_for_mass_spreading=rotate_icebergs_for_mass_spreading + bergs%lat_ref=lat_ref + bergs%initial_orientation=initial_orientation bergs%set_melt_rates_to_zero=set_melt_rates_to_zero bergs%allow_bergs_to_roll=allow_bergs_to_roll bergs%hexagonal_icebergs=hexagonal_icebergs @@ -2827,17 +2847,19 @@ logical function find_cell_by_search(grd, x, y, i, j) integer :: is,ie,js,je,di,dj,io,jo,icnt real :: d0,d1,d2,d3,d4,d5,d6,d7,d8,dmin logical :: explain=.false. - +real :: Lx + 911 continue + Lx=grd%Lx find_cell_by_search=.false. is=grd%isc; ie=grd%iec; js=grd%jsc; je=grd%jec ! Start at nearest corner - d1=dcost(x,y,grd%lonc(is+1,js+1),grd%latc(is+1,js+1)) - d2=dcost(x,y,grd%lonc(ie-1,js+1),grd%latc(ie-1,js+1)) - d3=dcost(x,y,grd%lonc(ie-1,je-1),grd%latc(ie-1,je-1)) - d4=dcost(x,y,grd%lonc(is+1,je-1),grd%latc(is+1,je-1)) + d1=dcost(x,y,grd%lonc(is+1,js+1),grd%latc(is+1,js+1),Lx) + d2=dcost(x,y,grd%lonc(ie-1,js+1),grd%latc(ie-1,js+1),Lx) + d3=dcost(x,y,grd%lonc(ie-1,je-1),grd%latc(ie-1,je-1),Lx) + d4=dcost(x,y,grd%lonc(is+1,je-1),grd%latc(is+1,je-1),Lx) dmin=min(d1,d2,d3,d4) if (d1==dmin) then; i=is+1; j=js+1 elseif (d2==dmin) then; i=ie-1; j=js+1 @@ -2861,15 +2883,15 @@ logical function find_cell_by_search(grd, x, y, i, j) do icnt=1, 1*(ie-is+je-js) io=i; jo=j - d0=dcost(x,y,grd%lonc(io,jo),grd%latc(io,jo)) - d1=dcost(x,y,grd%lonc(io,jo+1),grd%latc(io,jo+1)) - d2=dcost(x,y,grd%lonc(io-1,jo+1),grd%latc(io-1,jo+1)) - d3=dcost(x,y,grd%lonc(io-1,jo),grd%latc(io-1,jo)) - d4=dcost(x,y,grd%lonc(io-1,jo-1),grd%latc(io-1,jo-1)) - d5=dcost(x,y,grd%lonc(io,jo-1),grd%latc(io,jo-1)) - d6=dcost(x,y,grd%lonc(io+1,jo-1),grd%latc(io+1,jo-1)) - d7=dcost(x,y,grd%lonc(io+1,jo),grd%latc(io+1,jo)) - d8=dcost(x,y,grd%lonc(io+1,jo+1),grd%latc(io+1,jo+1)) + d0=dcost(x,y,grd%lonc(io,jo),grd%latc(io,jo),Lx) + d1=dcost(x,y,grd%lonc(io,jo+1),grd%latc(io,jo+1),Lx) + d2=dcost(x,y,grd%lonc(io-1,jo+1),grd%latc(io-1,jo+1),Lx) + d3=dcost(x,y,grd%lonc(io-1,jo),grd%latc(io-1,jo),Lx) + d4=dcost(x,y,grd%lonc(io-1,jo-1),grd%latc(io-1,jo-1),Lx) + d5=dcost(x,y,grd%lonc(io,jo-1),grd%latc(io,jo-1),Lx) + d6=dcost(x,y,grd%lonc(io+1,jo-1),grd%latc(io+1,jo-1),Lx) + d7=dcost(x,y,grd%lonc(io+1,jo),grd%latc(io+1,jo),Lx) + d8=dcost(x,y,grd%lonc(io+1,jo+1),grd%latc(io+1,jo+1),Lx) ! dmin=min(d0,d1,d3,d5,d7) dmin=min(d0,d1,d2,d3,d4,d5,d6,d7,d8) @@ -2950,13 +2972,13 @@ logical function find_cell_by_search(grd, x, y, i, j) ! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - real function dcost(x1, y1, x2, y2) + real function dcost(x1, y1, x2, y2,Lx) ! Arguments - real, intent(in) :: x1, x2, y1, y2 + real, intent(in) :: x1, x2, y1, y2,Lx ! Local variables real :: x1m - x1m=modulo(x1-(x2-180.),360.)+(x2-180.) + x1m=modulo(x1-(x2-(Lx/2.)),Lx)+(x2-(Lx/2.)) ! dcost=(x2-x1)**2+(y2-y1)**2 dcost=(x2-x1m)**2+(y2-y1)**2 end function dcost @@ -2972,6 +2994,9 @@ logical function find_better_min(grd, x, y, w, oi, oj) ! Local variables integer :: i,j,xs,xe,ys,ye real :: dmin, dcst + real :: Lx + + Lx=grd%Lx xs=max(grd%isc, oi-w) xe=min(grd%iec, oi+w) @@ -2979,9 +3004,9 @@ logical function find_better_min(grd, x, y, w, oi, oj) ye=min(grd%jec, oj+w) find_better_min=.false. - dmin=dcost(x,y,grd%lonc(oi,oj),grd%latc(oi,oj)) + dmin=dcost(x,y,grd%lonc(oi,oj),grd%latc(oi,oj),Lx) do j=ys,ye; do i=xs,xe - dcst=dcost(x,y,grd%lonc(i,j),grd%latc(i,j)) + dcst=dcost(x,y,grd%lonc(i,j),grd%latc(i,j),Lx) if (dcst0.5.or.abs(yj-0.5)>0.5) then ! Scale internal coordinates to be consistent with is_point_in_cell() @@ -3380,7 +3414,7 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) endif if (present(explain)) then - if(explain) write(stderrunit,'(a,2f12.6)') 'pos_within_cell: xi,yj=',xi,yj + if(explain) write(stderrunit,'(a,2f12.6)') 'pos_within_cell: xi,yj=',xi,yj endif !if (.not. is_point_in_cell(grd, x, y, i, j) ) then @@ -3389,7 +3423,7 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) !endif if (xi.ge.0. .and. xi.le.1. .and. yj.ge.0. .and. yj.le.1.) then - pos_within_cell=is_point_in_cell(grd, x, y, i, j, explain=explain) + pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=explain) if (.not. pos_within_cell .and. verbose) then if (debug) call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is in cell BUT is_point_in_cell disagrees!', WARNING) endif @@ -3398,18 +3432,20 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) contains - subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, explain) + subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) ! Arguments - real, intent(in) :: x1, x2, x3, x4, y1, y2, y3, y4, x, y + real, intent(in) :: x1, x2, x3, x4, y1, y2, y3, y4, x, y, Lx real, intent(out) :: xi, yj logical, intent(in), optional :: explain ! Local variables real :: alpha, beta, gamma, delta, epsilon, kappa, a, b, c, d, dx, dy, yy1, yy2 logical :: expl=.false. integer :: stderrunit + real :: Lx_2 ! Get the stderr unit number stderrunit=stderr() + Lx_2=Lx/2. expl=.false. if (present(explain)) then @@ -3425,7 +3461,7 @@ subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, explain) if (expl) write(stderrunit,'(a,1p6e12.4)') 'calc_xiyj: coeffs delta,epsilon,kappa',alpha,beta,gamma,delta,epsilon,kappa a=(kappa*beta-gamma*epsilon) - dx=modulo(x-(x1-180.),360.)+(x1-180.)-x1 + dx=modulo(x-(x1-Lx_2),Lx)+(x1-Lx_2)-x1 dy=y-y1 b=(delta*beta-alpha*epsilon)-(kappa*dx-gamma*dy) c=(alpha*dy-delta*dx) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index c6c686b..5157350 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -894,7 +894,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%static_berg=static_berg(k) localberg%heat_density=heat_density(k) localberg%first_bond=>null() - if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) + if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne,explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) if (bergs%grd%area(localberg%ine,localberg%jne) .ne. 0) then From 634913c1d025070223d47d6a412c67e6dca223de Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 6 Jul 2016 16:02:43 -0400 Subject: [PATCH 127/361] Finite domains have been tested a bit more, and appear to be working (there were a few bugs) --- icebergs.F90 | 15 +++++---------- icebergs_framework.F90 | 13 ++++++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 1db6a3f..52f855c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1161,7 +1161,7 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid angle=pi/2. else angle=atan(r_dist_x/r_dist_y) - angle= ((pi/2) - (initial_orientation*(pi/180))) - angle + angle= ((pi/2) - (initial_orientation*(pi/180.))) - angle angle=modulo(angle-(2*pi) ,pi/6.) endif bond_count=bond_count+1. @@ -1323,7 +1323,6 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) - grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass/fraction_used) grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass/fraction_used) grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass/fraction_used) @@ -1541,11 +1540,9 @@ subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, A Area_positive= 0.; Area_negative= A_triangle; else - !print 'You should not get here1' call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle dividing routine', FATAL) endif else - !print 'You should not get here2' call error_mesg('diamonds, iceberg_run', 'Another logical error inside triangle dividing routine', FATAL) endif endif @@ -1598,7 +1595,6 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, call intercept_of_a_line(Bx,By,Cx,Cy,'x',px,py); !x_intercept call intercept_of_a_line(Bx,By,Cx,Cy,'y',qx,qy); !y_intercept if (.not.((point_in_interval(Bx,By,Cx,Cy,px,py)) .and. (point_in_interval(Bx,By,Cx,Cy,qx,qy)))) then - !print 'Houston, we have a problem' !You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. if (mpp_pe().eq.12) then write(stderrunit,*) 'diamonds,corners', Ax,Ay,Bx,By,Cx,Cy @@ -1661,7 +1657,6 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, !Area_Q3=Area_Left-Area_Q2; Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); else - !print 'Help, I need somebody, help!' call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle into four quadrants. Should not get here.', FATAL) endif @@ -1957,6 +1952,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_mass(:,:)=0. grd%spread_mass(:,:)=0. grd%mass(:,:)=0. + if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. @@ -2748,6 +2744,7 @@ subroutine evolve_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs + if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve !Checking it everything is ok: @@ -3287,7 +3284,7 @@ subroutine update_verlet_position(bergs,berg) real :: lon1, lat1, dxdl1, dydl real :: uvel1, vvel1, uvel2, vvel2 real :: axn, ayn, bxn, byn -real :: xdot2, ydot2, dxdln +real :: xdot2, ydot2 real :: u2, v2, x1, y1, xn, yn real :: dx, dt, dt_2 integer :: i, j @@ -3322,7 +3319,7 @@ subroutine update_verlet_position(bergs,berg) uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon - dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) + !dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) u2=uvel2*dxdl1; v2=vvel2*dydl @@ -3334,8 +3331,6 @@ subroutine update_verlet_position(bergs,berg) else lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon endif - !dxdln=r180_pi/(Rearth*cos(latn*pi_180)) - call convert_from_meters_to_grid(latn,grd%grid_is_latlon ,dxdln,dydl) ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) uvel3=uvel1+(dt_2*axn) !Alon diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d886856..3f4ec26 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -560,6 +560,14 @@ subroutine ice_bergs_framework_init(bergs, & enddo; enddo endif + if (Lx.gt.1E15 ) then + call error_mesg('diamonds, framework', 'Model does not enjoy the domain being larger than 1E15. Not sure why. Probably to do with floating point precision.', WARNING) + endif + if ((.not. grid_is_latlon) .and. (Lx.eq.360.)) then + call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) + Lx=1E14 + endif + !The fix to reproduce across PE layout change, from AJA j=grd%jsc; do i=grd%isc+1,grd%ied minl=grd%lon(i-1,j)-(Lx/2.) @@ -651,11 +659,6 @@ subroutine ice_bergs_framework_init(bergs, & endif if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj -if ((.not. grid_is_latlon) .and. (Lx.eq.360.)) then - call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) - Lx=1E31 -endif - ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs From 8d45d45eb4629f5b485d69cea544fab1a244ab5f Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 6 Jul 2016 18:43:26 -0400 Subject: [PATCH 128/361] A bug has been fixed by setting all NaN's in ua,va,uo,vo,ui,ui,sst,hi and cn to zero. I believe that NaN's can enter these variables if the iceberg grid does not match the atmospheric grid (for example). We need to think further on how to properly handle undefined quanties. Setting them to zero stops the model from crashing. --- icebergs.F90 | 58 ++++++++++++++++++++++++++++++++++++------ icebergs_framework.F90 | 6 +++-- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 52f855c..86c3de5 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1798,6 +1798,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, real :: hxm, hxp real, parameter :: ssh_coast=0.00 integer :: stderrunit +integer :: ii, jj ! Get the stderr unit number stderrunit = stderr() @@ -1811,6 +1812,29 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, vi=bilin(grd, grd%vi, i, j, xi, yj) ua=bilin(grd, grd%ua, i, j, xi, yj) va=bilin(grd, grd%va, i, j, xi, yj) + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if (ua.ne.ua) then + if (mpp_pe().eq.9) then + write(stderrunit,'(a3,32i7)') 'ua',(ii,ii=grd%isd,grd%ied) + do jj=grd%jed,grd%jsd,-1 + write(stderrunit,'(i3,32f7.1)') jj,(grd%ua(ii,jj),ii=grd%isd,grd%ied) + enddo + ! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) + ! enddo + ! endif + call error_mesg('diamonds, interp fields', 'ua is NaNs', FATAL) + endif + endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + ! These fields are cell centered (A-grid) and would ! best be interpolated using PLM. For now we use PCM! sst=grd%sst(i,j) ! A-grid @@ -1865,6 +1889,14 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, call rotate(ua, va, cos_rot, sin_rot) call rotate(ssh_x, ssh_y, cos_rot, sin_rot) + if (((((uo.ne.uo) .or. (vo.ne.vo)) .or. ((ui.ne.ui) .or. (vi.ne.vi))) .or. (((ua.ne.ua) .or. (va.ne.va)) .or. ((ssh_x.ne.ssh_x) .or. (ssh_y.ne.ssh_y)))) .or. \ + (((sst.ne. sst) .or. (cn.ne.cn)) .or. (hi.ne. hi))) then + write(stderrunit,*) 'diamonds, Error in interpolate: uo,vo,ui,vi',uo, vo, ui, vi + write(stderrunit,*) 'diamonds, Error in interpolate: ua,va,ssh_x,ssh_y', ua, va, ssh_x, ssh_y + write(stderrunit,*) 'diamonds, Error in interpolate: sst,cn,hi', sst, cn, hi, mpp_pe() + call error_mesg('diamonds, interp fields', 'field interpaolations has NaNs', FATAL) + + endif contains real function ddx_ssh(grd,i,j) @@ -2081,7 +2113,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_update_domains(grd%hi, grd%domain) !Make sure that gridded values agree with mask (to get ride of NaN values) - do i=grd%isd,grd%ied ; do j=grd%jsc-1,grd%jed + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed !Initializing all gridded values to zero if (grd%msk(i,j).lt. 0.5) then grd%ua(i,j) = 0.0 ; grd%va(i,j) = 0.0 @@ -2090,6 +2122,15 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%sst(i,j) = 0.0; grd%cn(i,j) = 0.0 grd%hi(i,j) = 0.0 endif + if (grd%ua(i,j) .ne. grd%ua(i,j)) grd%ua(i,j)=0. + if (grd%va(i,j) .ne. grd%va(i,j)) grd%va(i,j)=0. + if (grd%uo(i,j) .ne. grd%uo(i,j)) grd%uo(i,j)=0. + if (grd%vo(i,j) .ne. grd%vo(i,j)) grd%vo(i,j)=0. + if (grd%ui(i,j) .ne. grd%ui(i,j)) grd%ui(i,j)=0. + if (grd%vi(i,j) .ne. grd%vi(i,j)) grd%vi(i,j)=0. + if (grd%sst(i,j) .ne. grd%sst(i,j)) grd%sst(i,j)=0. + if (grd%cn(i,j) .ne. grd%cn(i,j)) grd%cn(i,j)=0. + if (grd%hi(i,j) .ne. grd%hi(i,j)) grd%hi(i,j)=0. enddo; enddo if (debug) call bergs_chksum(bergs, 'run bergs (top)') @@ -3021,7 +3062,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) @@ -3077,7 +3118,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) @@ -3135,7 +3176,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 endif i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i4=i; j4=j ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) if (.not.error_flag) then @@ -3209,7 +3250,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag) + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) @@ -3339,7 +3380,7 @@ subroutine update_verlet_position(bergs,berg) ! Adjusting mass... !MP3 i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag) !Alon:"unclear which velocity to use here?" + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) !Alon:"unclear which velocity to use here?" !if (bounced) then ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag @@ -3400,11 +3441,12 @@ end subroutine rotvec_from_tang ! ############################################################################## -subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error) +subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error, iceberg_num) ! Arguments type(icebergs_gridded), pointer :: grd real, intent(inout) :: lon, lat, uvel, vvel, xi, yj integer, intent(inout) :: i,j +integer, intent(in) :: iceberg_num logical, intent(out) :: bounced, error ! Local variables logical lret, lpos @@ -3605,7 +3647,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj if (.not. lret) then - write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment' + write(stderrunit,*) 'diamonds, adjust: Should not get here! Berg is not in cell after adjustment', iceberg_num, mpp_pe() if (debug) error=.true. endif end subroutine adjust_index_and_ground diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3f4ec26..82b9aa4 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -560,11 +560,13 @@ subroutine ice_bergs_framework_init(bergs, & enddo; enddo endif - if (Lx.gt.1E15 ) then + if ((Lx.gt.1E15 ) .and. (mpp_pe().eq.mpp_root_pe())) then call error_mesg('diamonds, framework', 'Model does not enjoy the domain being larger than 1E15. Not sure why. Probably to do with floating point precision.', WARNING) endif if ((.not. grid_is_latlon) .and. (Lx.eq.360.)) then - call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) + if (mpp_pe().eq.mpp_root_pe()) then + call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) + endif Lx=1E14 endif From c4b68edf3961cf8a3b9c370451979ed24297dc57 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 7 Jul 2016 17:52:18 -0400 Subject: [PATCH 129/361] 1) Fixed a bug in the calculation of hexagon areas (the case where the point lies on the x-axis) 2) Added some new diagnostic output for loading bonds from a restart file. 3) Changed some code in the adjust_indext rountine which excludes the north and east boundary of the cell. I am not 100% sure that this is correct, but it does seem right. The code runs after these changes. This might change the answers in certain setups 4)Still working on rotating the hexagons. The finding the orientation part is almost done. --- icebergs.F90 | 75 +++++++++++++++++++++++++++++------------ icebergs_framework.F90 | 76 ++++++++++++++++++++++++++++++------------ icebergs_io.F90 | 11 +++++- 3 files changed, 117 insertions(+), 45 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 86c3de5..f85dd8f 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -747,16 +747,23 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a byn= ay-(ayn/2) !Alon ! Limit speed of bergs based on a CFL criteria - if (bergs%speed_limit>0.) then + if ((bergs%speed_limit>0.) .or. (bergs%speed_limit .eq.-1.)) then speed=sqrt(uveln*uveln+vveln*vveln) ! Speed of berg if (speed>0.) then loc_dx=min(0.5*(grd%dx(i,j)+grd%dx(i,j-1)),0.5*(grd%dy(i,j)+grd%dy(i-1,j))) ! min(dx,dy) - !new_speed=min(loc_dx/dt*bergs%speed_limit,speed) ! Restrict speed to dx/dt x factor + !new_speed=min(loc_dx/dt*bergs%speed_limit,speed) ! Restrict speed to dx/dt x factor new_speed=loc_dx/dt*bergs%speed_limit ! Speed limit as a factor of dx / dt if (new_speed0.) then + uveln=uveln*(new_speed/speed) ! Scale velocity to reduce speed + vveln=vveln*(new_speed/speed) ! without changing the direction + bergs%nspeeding_tickets=bergs%nspeeding_tickets+1 + else + call error_mesg('diamonds, Speeding icebergs', 'Faster than the CFL!', WARNING) + write(stderrunit,*) 'diamonds, Speeding berg1! =',mpp_pe(), berg%iceberg_num + write(stderrunit,*) 'diamonds, Speeding berg2, speed =',speed, loc_dx/dt + write(stderrunit,*) 'diamonds, Speeding berg3, lat, lon =',lat,xi,yj + endif endif endif endif @@ -1105,10 +1112,13 @@ subroutine thermodynamics(bergs) if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 + !call show_all_bonds(bergs) + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grd%grid_is_latlon) - print *, 'orientation: ', orientation, this%iceberg_num + print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num endif @@ -1141,6 +1151,7 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid current_bond=>berg%first_bond lat1=berg%lat lon1=berg%lon + print *, 'Looking for orientation: ' do while (associated(current_bond)) ! loop over all bonds other_berg=>current_bond%other_berg if (.not. associated(current_bond)) then @@ -1160,10 +1171,12 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid if (r_dist_y .eq. 0.) then angle=pi/2. else - angle=atan(r_dist_x/r_dist_y) + angle=atan(r_dist_y/r_dist_x) angle= ((pi/2) - (initial_orientation*(pi/180.))) - angle - angle=modulo(angle-(2*pi) ,pi/6.) + print *, 'angle: ', angle, initial_orientation + angle=modulo(angle ,pi/6.) endif + print *, 'angle2: ', angle bond_count=bond_count+1. Average_angle=Average_angle+angle @@ -1171,7 +1184,8 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid current_bond=>current_bond%next_bond enddo Average_angle =Average_angle/bond_count - find_orientation_using_iceberg_bonds=modulo(angle-(2*pi) ,pi/6.) + find_orientation_using_iceberg_bonds=modulo(angle ,pi/3.) + print *, 'Finished looking: ' end function find_orientation_using_iceberg_bonds @@ -1359,8 +1373,8 @@ logical function point_in_interval(Ax,Ay,Bx,By,px,py) ! Arguments real, intent(in) :: Ax,Ay,Bx,By,px,py point_in_interval=.False. - if ((px < max(Ax,Bx)) .and. (px > min(Ax,Bx))) then - if ((py < max(Ay,By)) .and. (py > min(Ay,By))) then + if ((px <= max(Ax,Bx)) .and. (px >= min(Ax,Bx))) then + if ((py <= max(Ay,By)) .and. (py >= min(Ay,By))) then point_in_interval=.True. endif endif @@ -1596,9 +1610,9 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, call intercept_of_a_line(Bx,By,Cx,Cy,'y',qx,qy); !y_intercept if (.not.((point_in_interval(Bx,By,Cx,Cy,px,py)) .and. (point_in_interval(Bx,By,Cx,Cy,qx,qy)))) then !You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. - if (mpp_pe().eq.12) then + !if (mpp_pe().eq.12) then write(stderrunit,*) 'diamonds,corners', Ax,Ay,Bx,By,Cx,Cy - endif + !endif call error_mesg('diamonds, iceberg_run', 'Something went wrong with Triangle_divide_into_four_quadrants', FATAL) endif endif @@ -2948,6 +2962,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: iceberg_num=',berg%iceberg_num write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& & dt*ax1 write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& @@ -3465,6 +3480,9 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! print *, 'Alon:', lon, lat, i, j, xi, yj, lret xi0=xi; yj0=yj ! original xi,yj + + + !Removing this while debuggin if (debug) then !Sanity check lret, xi and yj lret=is_point_in_cell(grd, lon, lat, i, j) @@ -3503,6 +3521,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun endif lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) endif ! debug + if (lret) return ! Berg was already in cell ! Find inm, jnm (as if adjusting i,j) based on xi,yj @@ -3518,6 +3537,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun inm=inm-1 endif elseif (xi.gt.1.) then +! elseif (xi.ge.1.) then !Alon: maybe it should be .ge. if (inm0.) then if (i>grd%isd+1) i=i-1 else - write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from west',lon,lat,xi,yj,uvel,vvel,mpp_pe() + !write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from west',lon,lat,xi,yj,uvel,vvel,mpp_pe() bounced=.true. endif endif - elseif (xi.gt.1.) then + elseif (xi.ge.1.) then !Alon!!!! +! elseif (xi.gt.1.) then if (i0.) then if (i0.) then if (j>grd%jsd+1) j=j-1 else - write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from south',lon,lat,xi,yj,uvel,vvel,mpp_pe() + !write(stderr(),'(a,6f8.3,i)') 'diamonds, adjust: bouncing berg from south',lon,lat,xi,yj,uvel,vvel,mpp_pe() bounced=.true. endif endif - elseif (yj.gt.1.) then + elseif (yj.ge.1.) then !Alon. +! elseif (yj.gt.1.) then if (j0.) then if (j1.) xi=1.-posn_eps + if (xi>=1.) xi=1.-posn_eps !Alon. +! if (xi>1.) xi=1.-posn_eps ! if (xi<0.) xi=posn_eps - if (yj>1.) yj=1.-posn_eps + if (yj>=1.) yj=1.-posn_eps !Alon. +! if (yj>1.) yj=1.-posn_eps if (yj<0.) yj=posn_eps lon=bilin(grd, grd%lon, i, j, xi, yj) lat=bilin(grd, grd%lat, i, j, xi, yj) @@ -3634,14 +3659,20 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun yj=(yj-0.5)*(1.-posn_eps)+0.5 endif call error_mesg('diamonds, adjust', 'Berg did not move or bounce during iterations AND was not in cell. Adjusting!', WARNING) + write(stderrunit,*) 'diamonds, adjust: The adjusting iceberg is: ', iceberg_num, mpp_pe() + write(stderrunit,*) 'diamonds, adjust: The adjusting lon,lat,u,v: ', lon, lat, uvel, vvel + write(stderrunit,*) 'diamonds, adjust: The adjusting xi,ji: ', xi, yj + lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj,explain=.true.) else call error_mesg('diamonds, adjust', 'Berg iterated many times without bouncing!', WARNING) endif endif - if (xi>1.) xi=1.-posn_eps +! if (xi>1.) xi=1.-posn_eps !Alon + if (xi>=1.) xi=1.-posn_eps if (xi<0.) xi=posn_eps if (yj>1.) yj=1.-posn_eps - if (yj<0.) yj=posn_eps +! if (yj>1.) yj=1.-posn_eps + if (yj<=0.) yj=posn_eps !Alon lon=bilin(grd, grd%lon, i, j, xi, yj) lat=bilin(grd, grd%lat, i, j, xi, yj) lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 82b9aa4..736e472 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -448,7 +448,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%list(i,j)%first => null() enddo ; enddo - big_number=1.0E30 + big_number=1.0E15 !write(stderrunit,*) 'diamonds: allocating grid' allocate( grd%lon(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lon(:,:)=big_number allocate( grd%lat(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%lat(:,:)=big_number @@ -501,6 +501,24 @@ subroutine ice_bergs_framework_init(bergs, & grd%lon(is:ie,js:je)=ice_lon(:,:) grd%lat(is:ie,js:je)=ice_lat(:,:) grd%area(is:ie,js:je)=ice_area(:,:) !sis2 has *(4.*pi*radius*radius) + + !!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!! + !if (mpp_pe().eq.5) then + ! write(stderrunit,'(a3,32i7)') 'LB',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Ice lon',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(ice_lon(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'LA',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) + ! enddo + !endif + !!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!! + !For SIS not to change answers if(present(fractional_area)) then if(fractional_area) grd%area(is:ie,js:je)=ice_area(:,:) *(4.*pi*radius*radius) @@ -555,8 +573,8 @@ subroutine ice_bergs_framework_init(bergs, & if (.not. present(maskmap)) then ! Using a maskmap causes tickles this sanity check do j=grd%jsd,grd%jed; do i=grd%isd,grd%ied - if (grd%lon(i,j).ge.big_number) write(stderrunit,*) 'bad lon: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lon(i,j) - if (grd%lat(i,j).ge.big_number) write(stderrunit,*) 'bad lat: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lat(i,j) + !if (grd%lon(i,j).ge.big_number) write(stderrunit,*) 'bad lon: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lon(i,j) + !if (grd%lat(i,j).ge.big_number) write(stderrunit,*) 'bad lat: ',mpp_pe(),i-grd%isc+1,j-grd%jsc+1,grd%lat(i,j) enddo; enddo endif @@ -611,20 +629,32 @@ subroutine ice_bergs_framework_init(bergs, & ' [lon|lat][min|max]=', minval(grd%lon),maxval(grd%lon),minval(grd%lat),maxval(grd%lat) endif -! if (mpp_pe().eq.3) then -! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) -! do j=grd%jed,grd%jsd,-1 -! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) -! enddo -! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) -! do j=grd%jed,grd%jsd,-1 -! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) -! enddo -! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) -! do j=grd%jed,grd%jsd,-1 -! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) -! enddo -! endif + !if (mpp_pe().eq.5) then + ! write(stderrunit,'(a3,32i7)') 'Lon',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lon(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Lat',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%lat(i,j),i=grd%isd,grd%ied) + ! enddo + ! write(stderrunit,'(a3,32i7)') 'Msk',(i,i=grd%isd,grd%ied) + ! do j=grd%jed,grd%jsd,-1 + ! write(stderrunit,'(i3,32f7.1)') j,(grd%msk(i,j),i=grd%isd,grd%ied) + ! enddo + !endif + +! Final check for NaN's in the latlon grid: + do j=grd%jsd+1,grd%jed; do i=grd%isd+1,grd%ied + if (grd%lat(i,j) .ne. grd%lat(i,j)) then + write(stderrunit,*) 'Lat not defined properly', mpp_pe(),i,j,grd%lat(i,j) + call error_mesg('diamonds,grid defining', 'Latitude contains NaNs', FATAL) + endif + if (grd%lon(i,j) .ne. grd%lon(i,j)) then + write(stderrunit,*) 'Lon not defined properly', mpp_pe(),i,j,grd%lon(i,j) + call error_mesg('diamonds, grid defining', 'Longatudes contains NaNs', FATAL) + endif + enddo; enddo !Added by Alon - If a freq distribution is input, we have to convert the freq distribution to a mass flux distribution) @@ -3238,7 +3268,7 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp Lx_2=Lx/2. sum_sign_dot_prod4=.false. - xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2of x0 + xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2 of x0 xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2of xx xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2of xx xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2of xx @@ -3249,8 +3279,10 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp l2=(xx-xx2)*(y3-y2)-(y-y2)*(xx3-xx2) l3=(xx-xx3)*(y0-y3)-(y-y3)*(xx0-xx3) - !We use an asymerty between South and East line boundaries and North and East - !to avoid icebergs appearing to two cells (half values used for debugging + !We use an assymerty between South and East line boundaries and North and East + !to avoid icebergs appearing to two cells (half values used for debugging) + !This is intended to make the South and East boundaries be part of the + !cell, while the North and West are not part of the cell. p0=sign(1., l0); if (l0.eq.0.) p0=-0.5 p1=sign(1., l1); if (l1.eq.0.) p1=0.5 p2=sign(1., l2); if (l2.eq.0.) p2=0.5 @@ -3920,8 +3952,8 @@ integer function berg_chksum(berg ) ! Arguments type(iceberg), pointer :: berg ! Local variables -real :: rtmp(37) !Changed from 28 to 34 by Alon -integer :: itmp(37+4), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon +real :: rtmp(38) !Changed from 28 to 34 by Alon +integer :: itmp(38+4), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon integer :: i rtmp(:)=0. diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 5157350..b134249 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1114,15 +1114,20 @@ subroutine read_restart_bonds(bergs,Time) ! Zero out nbergs_in_file nbonds_in_file = 0 + all_pe_number_perfect_bonds=0 filename_base=trim(restart_input_dir)//'bonds_iceberg.res.nc' found_restart = find_restart_file(filename_base, filename, multiPErestart, io_tile_id(1)) - call error_mesg('read_restart_bonds_bergs_new', 'Using new icebergs bond restart read', NOTE) + call error_mesg('read_restart_bonds_bergs_new', 'Using icebergs bond restart read', NOTE) filename = filename_base call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) nbonds_in_file = siz(1) + + if (mpp_pe() .eq. mpp_root_pe()) then + write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds in file', nbonds_in_file + endif if (nbonds_in_file .gt. 0) then @@ -1279,6 +1284,10 @@ subroutine read_restart_bonds(bergs,Time) other_berg_ine, & other_berg_jne ) endif + + if (mpp_pe() .eq. mpp_root_pe()) then + write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds created', all_pe_number_perfect_bonds + endif end subroutine read_restart_bonds From 9ba6aeec55f1975d93f196381dc402e01024c617 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Jul 2016 11:10:22 -0400 Subject: [PATCH 130/361] A bug has been fixed in the code which calculates the orientation of an icebergs by the average position of the icebergs it is bonded to. This is now working. Code has been added which allows icebergs to distribute their mass as hexigons which are oriented according to the angle calculated above. This code has not yet been tested. --- icebergs.F90 | 82 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index f85dd8f..521fa30 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1112,18 +1112,14 @@ subroutine thermodynamics(bergs) if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 - !call show_all_bonds(bergs) - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then - orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grd%grid_is_latlon) - print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num - + orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grd%grid_is_latlon) + !print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num + else + orientation=0.0 endif - - - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs ) + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs,orientation) endif endif @@ -1133,7 +1129,7 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics -!MPP1 + real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid_is_latlon) ! Arguments type(iceberg) :: berg @@ -1167,44 +1163,43 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid call convert_from_grid_to_meters(lat_ref,grid_is_latlon,dx_dlon,dy_dlat) r_dist_x=dlon*dx_dlon r_dist_y=dlat*dy_dlat + !print *, 'r_dist_x,r_dist_y: ', r_dist_x,r_dist_y - if (r_dist_y .eq. 0.) then + if (r_dist_x .eq. 0.) then angle=pi/2. else angle=atan(r_dist_y/r_dist_x) - angle= ((pi/2) - (initial_orientation*(pi/180.))) - angle - print *, 'angle: ', angle, initial_orientation - angle=modulo(angle ,pi/6.) + angle= ((pi/2.) - (initial_orientation*(pi/180.))) - angle + !print *, 'angle: ', angle*(180/pi), initial_orientation + angle=modulo(angle ,pi/3.) endif - print *, 'angle2: ', angle + !print *, 'angle2: ', angle*(180/pi) bond_count=bond_count+1. Average_angle=Average_angle+angle - endif current_bond=>current_bond%next_bond enddo Average_angle =Average_angle/bond_count + !print *, 'Average angle', Average_angle*(180/pi), bond_count find_orientation_using_iceberg_bonds=modulo(angle ,pi/3.) - print *, 'Finished looking: ' + !print *, 'Finished looking: ' end function find_orientation_using_iceberg_bonds - - -! ############################################################################## - -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs,theta_in) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: x, y, Mberg, Mbits, scaling, Area logical, intent(in) :: hexagonal_icebergs + real, optional, intent(in) :: theta_in ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR - real :: S, H, origin_x, origin_y, x0, y0, theta + real :: S, H, origin_x, origin_y, x0, y0 real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex real :: fraction_used + real :: theta real, parameter :: rho_seawater=1035. integer :: stderrunit logical :: debug @@ -1212,6 +1207,12 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling ! Get the stderr unit number stderrunit = stderr() + theta=0.0 + !This is here because the findinding orientaion scheme is not coded when spread mass to ocean is called directly from the time stepping scheme. + if (present(theta_in)) then + theta=theta_in + endif + Mass=(Mberg+Mbits)*scaling ! This line attempts to "clip" the weight felt by the ocean. The concept of ! clipping is non-physical and this step should be replaced by grounding. @@ -1279,7 +1280,6 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling x0=(x-origin_x) y0=(y-origin_y) - theta=0.0 call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-0.001) then @@ -1698,6 +1698,20 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, end subroutine Triangle_divided_into_four_quadrants +subroutine rotate_and_translate(px,py,theta,x0,y0) + !This function takes a point px,py, and rotates it clockwise around the origin by theta degrees, and then translates by (x0,y0) + ! Arguments + real, intent(in) :: x0,y0,theta + real, intent(inout) :: px,py + + !Rotation + px = ( cos(theta*pi/180)*px) + (sin(theta*pi/180)*py) + py = (-sin(theta*pi/180)*px) + (cos(theta*pi/180)*py) + + !Translation + px= px + x0 + py= py + y0 +end subroutine rotate_and_translate subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4) !This subroutine divides a regular hexagon centered at x0,y0 with apothen H, and orientation theta into its intersection with the 4 quadrants @@ -1724,12 +1738,20 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q S=(2/sqrt(3.))*H !Finding positions of corners - C1x=S +x0 ; C1y=0.+y0; !Corner 1 (right) - C2x=H/sqrt(3.) +x0 ; C2y=H+y0; !Corner 2 (top right) - C3x=-H/sqrt(3.)+x0 ; C3y=H+y0; !Corner 3 (top left) - C4x=-S +x0 ; C4y=0.+y0; !Corner 4 (left) - C5x=-H/sqrt(3.) +x0; C5y=-H+y0; !Corner 5 (top left) - C6x=H/sqrt(3.) +x0 ; C6y=-H+y0; !Corner 3 (top left) + C1x=S ; C1y=0. !Corner 1 (right) + C2x=H/sqrt(3.) ; C2y=H; !Corner 2 (top right) + C3x=-H/sqrt(3.) ; C3y=H; !Corner 3 (top left) + C4x=-S ; C4y=0.; !Corner 4 (left) + C5x=-H/sqrt(3.) ; C5y=-H; !Corner 5 (bottom left) + C6x=H/sqrt(3.) ; C6y=-H; !Corner 6 (bottom right) + + !Finding positions of corners + call rotate_and_translate(C1x,C1y,theta,x0,y0) + call rotate_and_translate(C2x,C2y,theta,x0,y0) + call rotate_and_translate(C3x,C3y,theta,x0,y0) + call rotate_and_translate(C4x,C4y,theta,x0,y0) + call rotate_and_translate(C5x,C5y,theta,x0,y0) + call rotate_and_translate(C6x,C6y,theta,x0,y0) !Area of Hexagon is the sum of the triangles call Triangle_divided_into_four_quadrants(x0,y0,C1x,C1y,C2x,C2y,T12_Area,T12_Q1,T12_Q2,T12_Q3,T12_Q4); !Triangle 012 From 54017536e56e533fa0688fe603521e1fead299bb Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Jul 2016 11:14:18 -0400 Subject: [PATCH 131/361] A print statement has been removed. --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 521fa30..0192950 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1147,7 +1147,7 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid current_bond=>berg%first_bond lat1=berg%lat lon1=berg%lon - print *, 'Looking for orientation: ' + !print *, 'Looking for orientation: ' do while (associated(current_bond)) ! loop over all bonds other_berg=>current_bond%other_berg if (.not. associated(current_bond)) then From 90e9f2c506f30ac3ca99a053e26ab0ce63685b2e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Jul 2016 13:36:10 -0400 Subject: [PATCH 132/361] Fixed a bug to do with iceberg bonds being moved betweeen proceesors. The numbering for packing and unpacking icebergs must be the same. This bug was introuduced when the Static_berg property was added. With this correction, the bonds can move accross processors --- icebergs_framework.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 736e472..1086178 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1688,13 +1688,14 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ localberg%mass_of_bits=buff%data(17,n) localberg%heat_density=buff%data(18,n) - localberg%axn=buff%data(21,n) !Alon - localberg%ayn=buff%data(22,n) !Alon - localberg%bxn=buff%data(23,n) !Alon - localberg%byn=buff%data(24,n) !Alon + localberg%axn=buff%data(21,n) + localberg%ayn=buff%data(22,n) + localberg%bxn=buff%data(23,n) + localberg%byn=buff%data(24,n) localberg%iceberg_num=nint(buff%data(25,n)) localberg%halo_berg=buff%data(26,n) localberg%static_berg=buff%data(27,n) + counter=27 !how many data points being passed so far (must match largest number directly above) !These quantities no longer need to be passed between processors localberg%uvel_old=localberg%uvel @@ -1743,7 +1744,6 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ this%first_bond=>null() if (max_bonds .gt. 0) then - counter=26 !how many data points being passed so far (must match above) do k = 1,max_bonds other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) From 1432626bbdf18f96e68238bb51b005175d265d25 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 19 Jul 2016 15:46:49 -0400 Subject: [PATCH 133/361] Code has been added which allows the radius for interactions between icebergs to depend on the iceberg packing. In particular, when the icebergs are packed as hexagons, and the bergs%hexagonal_icebergs flag is true, then the radius is calculated appropriately. With this change, icebergs which are perfectly packed and bonded together, do not move (in a test with no forcing) --- icebergs.F90 | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 0192950..db19f90 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -272,9 +272,9 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i enddo endif -!print *,'IA_x=',IA_x,'IA_y',IA_y, berg%iceberg_num -!print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 -!print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y + !print *,'IA_x=',IA_x,'IA_y',IA_y, berg%iceberg_num + !print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 + !print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y contains @@ -317,11 +317,9 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i T1=berg%thickness M1=berg%mass A1=L1*W1 - R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) lon1=berg%lon_old; lat1=berg%lat_old !call rotpos_to_tang(lon1,lat1,x1,y1) - !From Berg 1 L2=other_berg%length W2=other_berg%width @@ -330,7 +328,6 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i u2=other_berg%uvel_old !Old values are used to make it order invariant v2=other_berg%vvel_old !Old values are used to make it order invariant A2=L2*W2 - R2=sqrt(A2/pi) ! Interaction radius of the other iceberg lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant !call rotpos_to_tang(lon2,lat2,x2,y2) @@ -348,14 +345,25 @@ subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_i r_dist_x=dlon*dx_dlon r_dist_y=dlat*dy_dlat r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) - - !if (berg%iceberg_num .eq. 1) then - !print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist - !print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon, r_dist - !print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded - !print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg - !endif - !print *, 'outside the loop',R1, R2,r_dist, bonded + + if (bergs%hexagonal_icebergs) then + R1=sqrt(A1/(2.*sqrt(3.))) + R2=sqrt(A2/(2.*sqrt(3.))) + else !square packing + R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) + R2=sqrt(A2/pi) ! Interaction radius of the other iceberg + endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!!MP1 + ! if (berg%iceberg_num .eq. 1) then + ! print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon + ! print *, 'Comparing latitudes: ', lat1, lat2, r_dist_y, dlat + ! print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded + ! print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg + ! endif + ! print *, 'outside the loop',R1, R2,r_dist, bonded + !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!! + + !call overlap_area(R1,R2,r_dist,A_o,trapped) !T_min=min(T1,T2) !A_min = min((pi*R1**R1),(pi*R2*R2)) @@ -1261,7 +1269,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling if (grd%area(i,j)>0) then H = min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ; !Non dimensionalize element length by grid area. (This gives the non-dim Apothen of the hexagon) else - H= (sqrt(3.)/2)*(0.49) !Larges allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) + H= (sqrt(3.)/2)*(0.49) !Largest allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) endif S=(2/sqrt(3.))*H !Side of the hexagon From 813a1c5c4aaca21e4917c128d3203a78634e5baa Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 20 Jul 2016 15:55:55 -0400 Subject: [PATCH 134/361] 1) Removed icebergs_halos width, so that the iceberg_halos and the gridded halos are the same. This makes the code easier to understand. And avoids errors assosiated with having non-matching halos. I can not think of any reason why we would need the iceberg halos to be different from the gridded halos. If this is needed, it can be added at a later time. 2) The second derivative of the sea surface height (used to estimate ssh_x, ssh_y) were giving NaN's close to the boundary because of masked points (when using a non-periodic domain). This has been resolved by setting ddh_x to zero when it is NaN. This works for now. At a later stage we can consider what gradients should be used at these boundaries. 3) The model can not run with iceberg bond when the halo width <2. An Warning has been added when the halo width is less than 2 and iceberg interactions are being used. The halo widths are now automatically set to 2 in this situation. 4) An error was occuring with the finding orientation code. This resulted from the fact that icebergs on the edge of the halo are not always assosiated with their bonded icebergs (since they they might not be on the halo). This means that we can not find the orientation of these icebergs using the average positions of their bonds. Luckily, we do not need the orientation of these icebergs, since if the halo has width greater than 2, these icebergs on the edge of the halos do not spread their mass onto the computational domain. (Recall that the iceberg orientation is used in the spread_mass_to_ocean calculation). This is a reason why the halos need to be >= 2 when bonds are used. This issue has been resolved using an if statement to get around this case. 5) A couple of other things have been cleaned up (this is bad git practice) --- icebergs.F90 | 112 +++++++++++++++++++++++------------------ icebergs_framework.F90 | 18 +++---- icebergs_io.F90 | 36 +++++++++---- 3 files changed, 97 insertions(+), 69 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index db19f90..2cff5b3 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -263,8 +263,8 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds other_berg=>current_bond%other_berg - if (.not. associated(current_bond)) then - call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) + if (.not. associated(other_berg)) then + call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated berg!' ,FATAL) else call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) endif @@ -951,6 +951,7 @@ subroutine thermodynamics(bergs) !do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly + !do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') @@ -962,8 +963,8 @@ subroutine thermodynamics(bergs) IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration M=this%mass T=this%thickness ! total thickness - ! D=(bergs%rho_bergs/rho_seawater)*T ! draught (keel depth) - ! F=T-D ! freeboard + !D=(bergs%rho_bergs/rho_seawater)*T ! draught (keel depth) + !F=T-D ! freeboard W=this%width L=this%length i=this%ine @@ -988,7 +989,6 @@ subroutine thermodynamics(bergs) Mb=0.0 Me=0.0 endif - if (bergs%use_operator_splitting) then ! Operator split update of volume/mass @@ -1095,12 +1095,12 @@ subroutine thermodynamics(bergs) endif ! Store the new state of iceberg (with L>W) - this%mass=Mnew - this%mass_of_bits=nMbits - this%thickness=Tn - this%width=min(Wn,Ln) - this%length=max(Wn,Ln) - next=>this%next + this%mass=Mnew + this%mass_of_bits=nMbits + this%thickness=Tn + this%width=min(Wn,Ln) + this%length=max(Wn,Ln) + next=>this%next ! Did berg completely melt? if (Mnew<=0.) then ! Delete the berg @@ -1122,10 +1122,11 @@ subroutine thermodynamics(bergs) orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then - orientation=find_orientation_using_iceberg_bonds(this,bergs%initial_orientation,bergs%grd%grid_is_latlon) + !Don't check orientation of the edges of halo, since they can contain unassosiated bonds (this is why halo width must be larger >= 2 to use bonds) + if ( ((this%ine .gt. grd%isd) .and. (this%ine .lt. grd%ied)) .and. ((this%jne .ge. grd%jsd) .and. (this%jne .le. grd%jed) ) ) then + orientation=find_orientation_using_iceberg_bonds(grd,this,bergs%initial_orientation) + endif !print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num - else - orientation=0.0 endif call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs,orientation) endif @@ -1138,18 +1139,20 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics -real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid_is_latlon) +real function find_orientation_using_iceberg_bonds(grd,berg,initial_orientation) ! Arguments - type(iceberg) :: berg + type(iceberg), pointer :: berg real, intent(in) :: initial_orientation - logical, intent(in) :: grid_is_latlon + type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond real :: angle, lat1,lat2,lon1,lon2,dlat,dlon real :: r_dist_x, r_dist_y real :: lat_ref, dx_dlon, dy_dlat real :: theta, bond_count, Average_angle + logical :: grid_is_latlon + grid_is_latlon=grd%grid_is_latlon bond_count=0. Average_angle=0. current_bond=>berg%first_bond @@ -1157,39 +1160,50 @@ real function find_orientation_using_iceberg_bonds(berg,initial_orientation,grid lon1=berg%lon !print *, 'Looking for orientation: ' do while (associated(current_bond)) ! loop over all bonds - other_berg=>current_bond%other_berg - if (.not. associated(current_bond)) then - call error_mesg('diamonds,calculating orientation', 'Trying to do Bond interactions with unassosiated bond!' ,FATAL) - else - lat2=other_berg%lat - lon2=other_berg%lon - - dlat=lat2-lat1 - dlon=lon2-lon1 - - lat_ref=0.5*(lat1+lat2) - call convert_from_grid_to_meters(lat_ref,grid_is_latlon,dx_dlon,dy_dlat) - r_dist_x=dlon*dx_dlon - r_dist_y=dlat*dy_dlat - !print *, 'r_dist_x,r_dist_y: ', r_dist_x,r_dist_y + other_berg=>current_bond%other_berg + if (.not. associated(other_berg)) then !good place for debugging + !One valid option: current iceberg is on the edge of halo, with other berg on the next pe (not influencing mass spreading) + !print *, 'Iceberg bond details:',berg%iceberg_num, current_bond%other_berg_num,berg%halo_berg, mpp_pe() + !print *, 'Iceberg bond details2:',berg%ine, berg%jne, current_bond%other_berg_ine, current_bond%other_berg_jne + !print *, 'Iceberg isd,ied,jsd,jed:',grd%isd, grd%ied, grd%jsd, grd%jed + !print *, 'Iceberg isc,iec,jsc,jec:',grd%isc, grd%iec, grd%jsc, grd%jec + !call error_mesg('diamonds,calculating orientation', 'Looking at bond interactions of unassosiated berg!' ,FATAL) + !endif + else + lat2=other_berg%lat + lon2=other_berg%lon - if (r_dist_x .eq. 0.) then - angle=pi/2. - else - angle=atan(r_dist_y/r_dist_x) - angle= ((pi/2.) - (initial_orientation*(pi/180.))) - angle - !print *, 'angle: ', angle*(180/pi), initial_orientation - angle=modulo(angle ,pi/3.) - endif - !print *, 'angle2: ', angle*(180/pi) - bond_count=bond_count+1. - Average_angle=Average_angle+angle + dlat=lat2-lat1 + dlon=lon2-lon1 + + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,grid_is_latlon,dx_dlon,dy_dlat) + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat + !print *, 'r_dist_x,r_dist_y: ', r_dist_x,r_dist_y + + if (r_dist_x .eq. 0.) then + angle=pi/2. + else + angle=atan(r_dist_y/r_dist_x) + angle= ((pi/2.) - (initial_orientation*(pi/180.))) - angle + !print *, 'angle: ', angle*(180/pi), initial_orientation + angle=modulo(angle ,pi/3.) endif - current_bond=>current_bond%next_bond - enddo + !print *, 'angle2: ', angle*(180/pi) + bond_count=bond_count+1. + Average_angle=Average_angle+angle + endif + current_bond=>current_bond%next_bond + enddo !End loop over bonds + if (bond_count.gt.0) then Average_angle =Average_angle/bond_count + else + Average_angle =0. + endif !print *, 'Average angle', Average_angle*(180/pi), bond_count - find_orientation_using_iceberg_bonds=modulo(angle ,pi/3.) + find_orientation_using_iceberg_bonds=modulo(Average_angle ,pi/3.) + !find_orientation_using_iceberg_bonds=modulo(angle ,pi/3.) !print *, 'Finished looking: ' end function find_orientation_using_iceberg_bonds @@ -1857,7 +1871,6 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, ua=bilin(grd, grd%ua, i, j, xi, yj) va=bilin(grd, grd%va, i, j, xi, yj) - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (ua.ne.ua) then if (mpp_pe().eq.9) then write(stderrunit,'(a3,32i7)') 'ua',(ii,ii=grd%isd,grd%ied) @@ -1876,8 +1889,6 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, call error_mesg('diamonds, interp fields', 'ua is NaNs', FATAL) endif endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! These fields are cell centered (A-grid) and would ! best be interpolated using PLM. For now we use PCM! @@ -1952,6 +1963,8 @@ real function ddx_ssh(grd,i,j) dxp=0.5*(grd%dx(i+1,j)+grd%dx(i+1,j-1)) dx0=0.5*(grd%dx(i,j)+grd%dx(i,j-1)) ddx_ssh=2.*(grd%ssh(i+1,j)-grd%ssh(i,j))/(dx0+dxp)*grd%msk(i+1,j)*grd%msk(i,j) + + if (ddx_ssh .ne. ddx_ssh) ddx_ssh=0. !This makes the model not crash for finite domains. end function ddx_ssh real function ddy_ssh(grd,i,j) @@ -1963,6 +1976,7 @@ real function ddy_ssh(grd,i,j) dyp=0.5*(grd%dy(i,j+1)+grd%dy(i-1,j+1)) dy0=0.5*(grd%dy(i,j)+grd%dy(i-1,j)) ddy_ssh=2.*(grd%ssh(i,j+1)-grd%ssh(i,j))/(dy0+dyp)*grd%msk(i,j+1)*grd%msk(i,j) + if (ddy_ssh .ne. ddy_ssh) ddy_ssh=0. !This makes the model not crash for finite domains. end function ddy_ssh subroutine rotate(u, v, cos_rot, sin_rot) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 1086178..97501cd 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -77,7 +77,6 @@ module ice_bergs_framework type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain integer :: halo ! Nominal halo width - integer :: iceberg_halo ! halo width used by icebergs (must be lt halo) integer :: isc, iec, jsc, jec ! Indices of computational domain integer :: isd, ied, jsd, jed ! Indices of data domain integer :: isg, ieg, jsg, jeg ! Indices of global domain @@ -308,7 +307,6 @@ subroutine ice_bergs_framework_init(bergs, & ! Namelist parameters (and defaults) integer :: halo=4 ! Width of halo region -integer :: iceberg_halo=2 ! Width of halo region for icebergs (must be lt halo) integer :: traj_sample_hrs=24 ! Period between sampling of position for trajectory storage integer :: traj_write_hrs=480 ! Period between writing sampled trajectories to disk integer :: verbose_hrs=24 ! Period between verbose messages @@ -353,7 +351,7 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) -namelist /icebergs_nml/ verbose, budget, halo, iceberg_halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & +namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & @@ -668,8 +666,9 @@ subroutine ice_bergs_framework_init(bergs, & enddo endif -if (iceberg_halo .gt. halo) then - iceberg_halo=halo +if ((halo .lt. 2) .and. (interactive_icebergs_on .or. iceberg_bonds_on) ) then + halo=2 + call error_mesg('diamonds, framework', 'Setting iceberg halos =2, since halos must be >= 2 for interactions', WARNING) endif if (interactive_icebergs_on) then @@ -701,7 +700,6 @@ subroutine ice_bergs_framework_init(bergs, & bergs%grd%Lx=Lx bergs%grd%grid_is_latlon=grid_is_latlon bergs%max_bonds=max_bonds - bergs%grd%iceberg_halo=iceberg_halo bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef bergs%bond_coef=bond_coef @@ -954,8 +952,8 @@ subroutine update_halo_icebergs(bergs) logical :: halo_debugging force_app =.true. -halo_width=bergs%grd%iceberg_halo ! Must be less than current halo value used for updating weight. -halo_debugging=bergs%halo_debugging ! Must be less than current halo value used for updating weight. +halo_width=bergs%grd%halo +halo_debugging=bergs%halo_debugging ! Get the stderr unit number stderrunit = stderr() @@ -964,7 +962,7 @@ subroutine update_halo_icebergs(bergs) grd=>bergs%grd -!For debugging +!For debugging, MP1 if (halo_debugging) then do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first @@ -3126,7 +3124,7 @@ end subroutine find_individual_iceberg ! ############################################################################## -logical function find_cell(grd, x, y, oi, oj) !MP1 +logical function find_cell(grd, x, y, oi, oj) ! Arguments type(icebergs_gridded), intent(in) :: grd real, intent(in) :: x, y diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b134249..84d4ff7 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1093,8 +1093,10 @@ subroutine read_restart_bonds(bergs,Time) integer :: number_second_bonds_matched !How many second bond bergs found on pe integer :: number_perfect_bonds ! How many complete bonds formed integer :: number_partial_bonds ! How many either complete/partial bonds formed. +integer :: number_perfect_bonds_with_first_on_pe ! How many bonds with first bond on the compuational domain integer :: all_pe_number_perfect_bonds, all_pe_number_partial_bonds integer :: all_pe_number_first_bonds_matched, all_pe_number_second_bonds_matched +integer :: all_pe_number_perfect_bonds_with_first_on_pe integer :: ine, jne logical :: search_data_domain real :: berg_found, berg_found_all_pe @@ -1150,6 +1152,7 @@ subroutine read_restart_bonds(bergs,Time) number_second_bonds_matched=0 number_perfect_bonds=0 number_partial_bonds=0 + number_perfect_bonds_with_first_on_pe=0 do k=1, nbonds_in_file @@ -1164,13 +1167,9 @@ subroutine read_restart_bonds(bergs,Time) if (berg_found_all_pe .gt. 0.5) then first_berg_ine(k)=ine first_berg_jne(k)=jne - !endif else - call error_mesg('read_restart_bonds_bergs_new', 'First iceberg in bond not found on any pe', FATAL) - endif - if (berg_found_all_pe .lt. 0.5) then - print * , 'First bond berg not located: ', first_berg_num(k),berg_found, mpp_pe(),ine, jne - call error_mesg('read_restart_bonds_bergs_new', 'First bond iceberg not located', FATAL) + print * , 'First bond berg not located: ', first_berg_num(k),berg_found, mpp_pe(),ine, jne + call error_mesg('read_restart_bonds_bergs_new', 'First iceberg in bond not found on any pe', FATAL) endif !else @@ -1199,7 +1198,7 @@ subroutine read_restart_bonds(bergs,Time) if ( (first_berg_ine(k)>=grd%isd) .and. (first_berg_ine(k)<=grd%ied) .and. & (first_berg_jne(k)>=grd%jsd) .and. (first_berg_jne(k)<=grd%jed) ) then number_first_bonds_matched=number_first_bonds_matched+1 - + ! Search for the first berg, which the bond belongs to first_berg_found=.false. first_berg=>null() @@ -1208,14 +1207,13 @@ subroutine read_restart_bonds(bergs,Time) if (this%iceberg_num == first_berg_num(k)) then first_berg_found=.true. first_berg=>this - if (first_berg%halo_berg.gt.0.5) print *, 'bonding halo berg:', first_berg_num(k), first_berg_ine(k),first_berg_jne(k) ,grd%isc, grd%iec, mpp_pe() + !if (first_berg%halo_berg.gt.0.5) print *, 'bonding halo berg:', first_berg_num(k), first_berg_ine(k),first_berg_jne(k) ,grd%isc, grd%iec, mpp_pe() this=>null() else this=>this%next endif enddo -!Note, this is a bug since there are no bergs in the halos up to here, are there? ! Decide whether the second iceberg is on the processeor (data domain) second_berg_found=.false. @@ -1244,6 +1242,13 @@ subroutine read_restart_bonds(bergs,Time) if (second_berg_found) then call form_a_bond(first_berg, other_berg_num(k), other_berg_ine(k), other_berg_jne(k), second_berg) number_perfect_bonds=number_perfect_bonds+1 + + !Counting number of bonds where the first bond is in the computational domain + if ( (first_berg_ine(k)>=grd%isc) .and. (first_berg_ine(k)<=grd%iec) .and. & + (first_berg_jne(k)>=grd%jsc) .and. (first_berg_jne(k)<=grd%jec) ) then + number_perfect_bonds_with_first_on_pe=number_perfect_bonds_with_first_on_pe+1 + endif + else !print *, 'Forming a bond of the second type', mpp_pe(), first_berg_num(k), other_berg_num(k) !call form_a_bond(first_berg, other_berg_num(k),other_berg_ine(k),other_berg_jne(k)) @@ -1257,11 +1262,13 @@ subroutine read_restart_bonds(bergs,Time) !Analyse how many bonds were created and take appropriate action all_pe_number_perfect_bonds=number_perfect_bonds + all_pe_number_perfect_bonds_with_first_on_pe=number_perfect_bonds_with_first_on_pe all_pe_number_partial_bonds=number_partial_bonds all_pe_number_first_bonds_matched=number_first_bonds_matched all_pe_number_second_bonds_matched=number_second_bonds_matched call mpp_sum(all_pe_number_perfect_bonds) call mpp_sum(all_pe_number_partial_bonds) + call mpp_sum(all_pe_number_perfect_bonds_with_first_on_pe) if (all_pe_number_partial_bonds .lt. nbonds_in_file) then write(stderrunit,*) 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file @@ -1276,6 +1283,14 @@ subroutine read_restart_bonds(bergs,Time) call error_mesg('read_restart_bonds_bergs_new', 'Not enough perfect bonds formed', NOTE) endif + if (all_pe_number_perfect_bonds_with_first_on_pe .ne. nbonds_in_file) then + call mpp_sum(all_pe_number_first_bonds_matched) + call mpp_sum(all_pe_number_second_bonds_matched) + write(stderrunit,*) 'diamonds, bond read restart : ','Warning, # bonds with first bond on computational domain, does not match file', all_pe_number_first_bonds_matched , nbonds_in_file + write(stderrunit,*) 'diamonds, bond read restart : ','Computational bond, first second:', all_pe_number_second_bonds_matched , nbonds_in_file + call error_mesg('read_restart_bonds_bergs_new', 'Computational perfect bonds do not match those in file', NOTE) + endif + deallocate( & first_berg_num, & other_berg_num, & @@ -1286,7 +1301,8 @@ subroutine read_restart_bonds(bergs,Time) endif if (mpp_pe() .eq. mpp_root_pe()) then - write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds created', all_pe_number_perfect_bonds + write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds (including halos)', all_pe_number_perfect_bonds + write(stderrunit,*) 'diamonds, bond read restart : ','Number of true bonds created', all_pe_number_perfect_bonds_with_first_on_pe endif end subroutine read_restart_bonds From afd006cd75ec5df01c60acea907001be64ea4c14 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 28 Jul 2016 12:57:46 -0400 Subject: [PATCH 135/361] Added namelist flag read_old_restart - This allows icebergs to read a restart with out the iceberg_number identifier entry in the restart file. --- icebergs_framework.F90 | 8 ++++++-- icebergs_io.F90 | 20 +++++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ec503ca..d40dcc5 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -189,6 +189,7 @@ module ice_bergs_framework logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon + logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovation real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -287,7 +288,8 @@ subroutine ice_bergs_framework_init(bergs, & logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests -logical :: input_freq_distribution=.false. ! Alon: flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) +logical :: input_freq_distribution=.false. ! Flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) +logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovations real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) @@ -297,7 +299,8 @@ subroutine ice_bergs_framework_init(bergs, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & - old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj + old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & + read_old_restarts ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -556,6 +559,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean + bergs%read_old_restarts=read_old_restarts allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) allocate( bergs%distribution(nclasses) ); bergs%distribution(:)=distribution(:) allocate( bergs%mass_scaling(nclasses) ); bergs%mass_scaling(:)=mass_scaling(:) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 1c77753..81fbfa7 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -341,13 +341,15 @@ subroutine read_restart_bergs_orig(bergs,Time) character(len=33) :: filename, filename_base type(icebergs_gridded), pointer :: grd type(iceberg) :: localberg ! NOT a pointer but an actual local variable -integer :: stderrunit +integer :: stderrunit, iNg, jNg, i, j ! Get the stderr unit number stderrunit=stderr() ! For convenience grd=>bergs%grd + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction, used with read_old_restarts=.true. + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction, used with read_old_restarts=.true. ! Find a restart file multiPErestart=.false. @@ -409,7 +411,11 @@ subroutine read_restart_bergs_orig(bergs,Time) start_lonid=inq_var(ncid, 'start_lon') start_latid=inq_var(ncid, 'start_lat') start_yearid=inq_var(ncid, 'start_year') - iceberg_numid=inq_var(ncid, 'icberg_num') + if (bergs%read_old_restarts) then + iceberg_numid=-1 + else + iceberg_numid=inq_var(ncid, 'icberg_num') + endif start_dayid=inq_var(ncid, 'start_day') start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') @@ -467,7 +473,15 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_lon=get_double(ncid, start_lonid, k) localberg%start_lat=get_double(ncid, start_latid, k) localberg%start_year=get_int(ncid, start_yearid, k) - localberg%iceberg_num=get_int(ncid, iceberg_numid, k) + if (bergs%read_old_restarts) then + ! This emulates the iceberg counter used at calving sites but uses the restart position instead + i = localberg%ine + j = localberg%jne + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 + else + localberg%iceberg_num=get_int(ncid, iceberg_numid, k) + endif localberg%start_day=get_double(ncid, start_dayid, k) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) From 516c4168ea88acd8f330dfeaa8e75d85914a2f75 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 28 Jul 2016 13:49:44 -0400 Subject: [PATCH 136/361] Initialize *_old data when not using Verlet algorithm - The checksums included uvle_old, vvel_old, lon_old and lat_old even when not using the Verlet algorithm that uses this data. - Regression tests across restarts were passing even though the checksums appeared to differ across restarts. This was due to uninitialized values in this *_old iceberg attributes. - Restarts and checksums now reproduce across restarts. --- icebergs.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/icebergs.F90 b/icebergs.F90 index 8d21f4f..9196916 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1779,6 +1779,10 @@ subroutine calve_icebergs(bergs) newberg%mass_scaling=bergs%mass_scaling(k) newberg%mass_of_bits=0. newberg%heat_density=grd%stored_heat(i,j)/grd%stored_ice(i,j,k) ! This is in J/kg + newberg%lon_old=newberg%lon + newberg%lat_old=newberg%lat + newberg%uvel_old=newberg%uvel + newberg%vvel_old=newberg%vvel call add_new_berg_to_list(bergs%first, newberg) calved_to_berg=bergs%initial_mass(k)*bergs%mass_scaling(k) ! Units of kg ! Heat content From 0f2ac729140ab4a6e619a13be0a0596009123f0c Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 28 Jul 2016 15:13:32 -0400 Subject: [PATCH 137/361] Fixed read_old_restarts for new i/o method - In commit afd006cd75e we forgot to update the new FMS i/o version of read_restarts. --- icebergs_framework.F90 | 1 + icebergs_io.F90 | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d40dcc5..e793967 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -569,6 +569,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%initial_width(:)=sqrt(initial_mass(:)/(LoW_ratio*rho_bergs*initial_thickness(:))) bergs%initial_length(:)=LoW_ratio*bergs%initial_width(:) + if (bergs%read_old_restarts) call error_mesg('diamonds, ice_bergs_framework_init', 'Setting "read_old_restarts=.true." can lead to non-reproducing checksums in restarts!', WARNING) ! Diagnostics id_class = diag_axis_init('mass_class', initial_mass, 'kg','Z', 'iceberg mass') diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 81fbfa7..e2633c4 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -646,7 +646,7 @@ subroutine read_restart_bergs(bergs,Time) character(len=33) :: filename, filename_base type(icebergs_gridded), pointer :: grd type(iceberg) :: localberg ! NOT a pointer but an actual local variable -integer :: stderrunit +integer :: stderrunit, iNg, jNg, i, j real, allocatable, dimension(:) :: lon, & lat, & @@ -684,6 +684,8 @@ subroutine read_restart_bergs(bergs,Time) ! For convenience grd=>bergs%grd + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction, used with read_old_restarts=.true. + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction, used with read_old_restarts=.true. ! Zero out nbergs_in_file nbergs_in_file = 0 @@ -756,7 +758,11 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) - call read_unlimited_axis(filename,'iceberg_num',iceberg_num,domain=grd%domain) + if (bergs%read_old_restarts) then + iceberg_num(:)=-1 + else + call read_unlimited_axis(filename,'iceberg_num',iceberg_num,domain=grd%domain) + endif endif ! Find approx outer bounds for tile @@ -806,7 +812,15 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_lon=start_lon(k) localberg%start_lat=start_lat(k) localberg%start_year=start_year(k) - localberg%iceberg_num=iceberg_num(k) + if (bergs%read_old_restarts) then + ! This emulates the iceberg counter used at calving sites but uses the restart position instead + i = localberg%ine + j = localberg%jne + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 + else + localberg%iceberg_num=iceberg_num(k) + endif localberg%start_day=start_day(k) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) From 40aab7a801f2c9c8381991e35cb60ad3074a76d0 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 28 Jul 2016 15:31:14 -0400 Subject: [PATCH 138/361] Code added which sets sea surface slope gradients to 0 if they equal NaN. This is needed when using finite domains (since they code which calculates gradients was written for periodic domain). This is not a perfect solution, but stops the model from crashing A line of code has been added which stops the model from doing many checksums when the time step is small. --- icebergs.F90 | 10 ++++++---- icebergs_framework.F90 | 10 +++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2cff5b3..3258306 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1944,6 +1944,10 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, call rotate(ua, va, cos_rot, sin_rot) call rotate(ssh_x, ssh_y, cos_rot, sin_rot) + !There are some issues with the boundaries ssh gradient calculation in a finite domain. This is a temporary fix + if (ssh_x.ne.ssh_x) ssh_x=0. + if (ssh_y.ne.ssh_y) ssh_y=0. + if (((((uo.ne.uo) .or. (vo.ne.vo)) .or. ((ui.ne.ui) .or. (vi.ne.vi))) .or. (((ua.ne.ua) .or. (va.ne.va)) .or. ((ssh_x.ne.ssh_x) .or. (ssh_y.ne.ssh_y)))) .or. \ (((sst.ne. sst) .or. (cn.ne.cn)) .or. (hi.ne. hi))) then write(stderrunit,*) 'diamonds, Error in interpolate: uo,vo,ui,vi',uo, vo, ui, vi @@ -1963,8 +1967,6 @@ real function ddx_ssh(grd,i,j) dxp=0.5*(grd%dx(i+1,j)+grd%dx(i+1,j-1)) dx0=0.5*(grd%dx(i,j)+grd%dx(i,j-1)) ddx_ssh=2.*(grd%ssh(i+1,j)-grd%ssh(i,j))/(dx0+dxp)*grd%msk(i+1,j)*grd%msk(i,j) - - if (ddx_ssh .ne. ddx_ssh) ddx_ssh=0. !This makes the model not crash for finite domains. end function ddx_ssh real function ddy_ssh(grd,i,j) @@ -1976,7 +1978,6 @@ real function ddy_ssh(grd,i,j) dyp=0.5*(grd%dy(i,j+1)+grd%dy(i-1,j+1)) dy0=0.5*(grd%dy(i,j)+grd%dy(i-1,j)) ddy_ssh=2.*(grd%ssh(i,j+1)-grd%ssh(i,j))/(dy0+dyp)*grd%msk(i,j+1)*grd%msk(i,j) - if (ddy_ssh .ne. ddy_ssh) ddy_ssh=0. !This makes the model not crash for finite domains. end function ddy_ssh subroutine rotate(u, v, cos_rot, sin_rot) @@ -2065,7 +2066,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, end if lbudget=.false. if (bergs%verbose_hrs>0) then - if (mod(24*iday+ihr,bergs%verbose_hrs).eq.0) lbudget=budget + !if (mod(24*iday+ihr,bergs%verbose_hrs).eq.0) lbudget=budget + if (mod(24*iday+ihr+(imin/60.),float(bergs%verbose_hrs)).eq.0) lbudget=budget !Added minutes, so that it does not repeat when smaller time steps are used.:q end if if (mpp_pe()==mpp_root_pe().and.lverbose) write(*,'(a,3i5,a,3i5,a,i5,f8.3)') & 'diamonds: y,m,d=',iyr, imon, iday,' h,m,s=', ihr, imin, isec, & diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 97501cd..e7c1e9b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2647,8 +2647,10 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) call mpp_sum(number_of_bonds_all_pe) bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's - if (number_of_bonds .gt. 0) then - write(stderrunit,*) "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() + if (debug) then + if (number_of_bonds .gt. 0) then + write(stderrunit,*) "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() + endif endif if (quality_check) then @@ -2667,7 +2669,9 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) endif endif if ((num_unmatched_bonds_all_pe == 0) .and. (num_unassosiated_bond_pairs_all_pe == 0)) then - if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds: All iceberg bonds are connected and working well.' + if (mpp_pe().eq.mpp_root_pe()) then + write(stderrunit,*) "Total number of bonds is: ", number_of_bonds_all_PE, "All iceberg bonds are connected and working well" + endif check_bond_quality=.true. else if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds: Warning, Broken Bonds! ' From 0b045915f79927268a8c0005b262e480cd85e4d1 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 29 Jul 2016 11:58:45 -0400 Subject: [PATCH 139/361] Added run-time parameter use_old_spreading - use_old_spreading=.true. recovers the original implementation of spreading which essentially treats the icebergs as one cell wide. --- icebergs.F90 | 51 +++++++++++++++++++++++++----------------- icebergs_framework.F90 | 5 ++++- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 19a8fab..88673c6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1128,7 +1128,8 @@ subroutine thermodynamics(bergs) endif !print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num endif - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs,orientation) + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, & + this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation) endif endif @@ -1208,12 +1209,13 @@ real function find_orientation_using_iceberg_bonds(grd,berg,initial_orientation) end function find_orientation_using_iceberg_bonds -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs,theta_in) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading, hexagonal_icebergs, theta_in) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: x, y, Mberg, Mbits, scaling, Area logical, intent(in) :: hexagonal_icebergs + logical, intent(in) :: use_old_spreading real, optional, intent(in) :: theta_in ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L @@ -1253,20 +1255,22 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling L=1. endif - !Old version before icebergs were given size L - !xL=min(0.5, max(0., 0.5-x)) - !xR=min(0.5, max(0., x-0.5)) - !xC=max(0., 1.-(xL+xR)) - !yD=min(0.5, max(0., 0.5-y)) - !yU=min(0.5, max(0., y-0.5)) - !yC=max(0., 1.-(yD+yU)) - - xL=min(0.5, max(0., 0.5-(x/L))) - xR=min(0.5, max(0., (x/L)+(0.5-(1/L) ))) - xC=max(0., 1.-(xL+xR)) - yD=min(0.5, max(0., 0.5-(y/L))) - yU=min(0.5, max(0., (y/L)+(0.5-(1/L) ))) - yC=max(0., 1.-(yD+yU)) + if (use_old_spreading) then + !Old version before icebergs were given size L + xL=min(0.5, max(0., 0.5-x)) + xR=min(0.5, max(0., x-0.5)) + xC=max(0., 1.-(xL+xR)) + yD=min(0.5, max(0., 0.5-y)) + yU=min(0.5, max(0., y-0.5)) + yC=max(0., 1.-(yD+yU)) + else + xL=min(0.5, max(0., 0.5-(x/L))) + xR=min(0.5, max(0., (x/L)+(0.5-(1/L) ))) + xC=max(0., 1.-(xL+xR)) + yD=min(0.5, max(0., 0.5-(y/L))) + yU=min(0.5, max(0., (y/L)+(0.5-(1/L) ))) + yC=max(0., 1.-(yD+yU)) + endif yDxL=yD*xL*grd%msk(i-1,j-1) yDxC=yD*xC*grd%msk(i ,j-1) @@ -2989,7 +2993,8 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs ) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, & + bergs%use_old_spreading, bergs%hexagonal_icebergs) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3105,7 +3110,8 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & + bergs%use_old_spreading, bergs%hexagonal_icebergs) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -3143,7 +3149,8 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & + bergs%use_old_spreading, bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -3199,7 +3206,8 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & + bergs%use_old_spreading, bergs%hexagonal_icebergs) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -3330,7 +3338,8 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & + bergs%use_old_spreading, bergs%hexagonal_icebergs) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index bfdc391..2b08563 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -229,6 +229,7 @@ module ice_bergs_framework logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon + logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -348,6 +349,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests logical :: input_freq_distribution=.false. ! Alon: flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) +logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) @@ -358,7 +360,7 @@ subroutine ice_bergs_framework_init(bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & - allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane + allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane, use_old_spreading ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -732,6 +734,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean + bergs%use_old_spreading=use_old_spreading allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) allocate( bergs%distribution(nclasses) ); bergs%distribution(:)=distribution(:) allocate( bergs%mass_scaling(nclasses) ); bergs%mass_scaling(:)=mass_scaling(:) From 04b480198bc1ecfa2a5fc8fae1574ceaf594c2cb Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 1 Aug 2016 17:46:25 -0400 Subject: [PATCH 140/361] 1) Static icebergs which have hexagonal packing now do not conserve mass at side boundaries. Excess mass which is in masked cells is discarded. This is only true for static icebergs. Dynamic icebergs still retain this excess mass. 2) A few unit tests have been added to test the hexagon code. These are not comprehensive, but are a start 3) A flag has been added to see if the grid is a regular cartesian grid. If it is a regular cartesian grid, then a more effitient method is used to find the position of an iceberg in a cell. 4) The tolorance values for the errors made while calculating the hexagonal mass spreading have been changed to 1.e-10, so that the code has to be more precise. --- icebergs.F90 | 188 +++++++++++++++++++++++++++++++++++------ icebergs_framework.F90 | 19 ++++- icebergs_io.F90 | 1 + 3 files changed, 178 insertions(+), 30 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3258306..3696982 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -102,6 +102,8 @@ subroutine icebergs_init(bergs, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & cos_rot, sin_rot, ocean_depth=ocean_depth, maskmap=maskmap, fractional_area=fractional_area) + call unit_testing() + call mpp_clock_begin(bergs%clock_ior) call ice_bergs_io_init(bergs,io_layout) call read_restart_calving(bergs) !This is moved to before restart_bergs (by Alon) so that generate icebergs can have the correct counter @@ -134,6 +136,124 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init +! ############################################################################## +subroutine unit_testing() +! Arguments + +call hexagon_test() + +end subroutine unit_testing + + +subroutine hexagon_test() +! Arguments +real :: x0,y0 !Position of icebergs +real :: H,theta,S !Apothen of iceberg and angle. +real :: Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 ! Areas of icebergs +real :: tol +logical :: fail_unit_test +integer :: stderrunit + + ! Get the stderr unit number. + stderrunit = stderr() + + fail_unit_test=.False. + + tol=1.e-10 + theta=0.0 + H=1. + S=2.*H/sqrt(3.) + + !Test 1: center at origin: Areas should be equal + x0=0. ; y0=0. + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (abs(Area_hex - ((3.*sqrt(3.)/2.)*(S*S)))>tol) then + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon at origin has the wrong area!', WARNING) + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + fail_unit_test=.True. + endif + if (((abs((Area_hex/4)-Area_Q1 )>tol) .or. (abs((Area_hex/4)-Area_Q2 )>tol)) .or. ((abs((Area_hex/4)-Area_Q3 )>tol) .or. (abs((Area_hex/4)-Area_Q4 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon at origin divides into unqual parts!', WARNING) + fail_unit_test=.True. + endif + + ! Test 2: Hexagon split into two quadrants + !Test 2a: center on x>0 axis + x0=S ; y0=0. + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((Area_hex/2)-Area_Q1 )>tol) .or. (abs(0-Area_Q2 )>tol)) .or. ((abs(0-Area_Q3 )>tol) .or. (abs((Area_hex/2)-Area_Q4 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split btw 1 and 4!', WARNING) + fail_unit_test=.True. + endif + !Test 2b: center on x<0 axis + x0=-S ; y0=0. + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((Area_hex/2)-Area_Q2 )>tol) .or. (abs(0-Area_Q1 )>tol)) .or. ((abs(0-Area_Q4 )>tol) .or. (abs((Area_hex/2)-Area_Q3 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split btw 2 and 3!', WARNING) + fail_unit_test=.True. + endif + !Test 2c: center on y>0 axis + x0=0. ; y0=H + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((Area_hex/2)-Area_Q1 )>tol) .or. (abs(0-Area_Q3 )>tol)) .or. ((abs(0-Area_Q4 )>tol) .or. (abs((Area_hex/2)-Area_Q2 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split btw 1 and 2!', WARNING) + fail_unit_test=.True. + endif + !Test 3d: center on y<0 axis + x0=0. ; y0=-H + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((Area_hex/2)-Area_Q3 )>tol) .or. (abs(0-Area_Q1 )>tol)) .or. ((abs(0-Area_Q2 )>tol) .or. (abs((Area_hex/2)-Area_Q4 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split btw 3 and 4!', WARNING) + fail_unit_test=.True. + endif + + ! Test 3: Two corners of hex on the axis + !Test 3a: center on x>0 axis + x0=S/2. ; y0=0. + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((2.5*Area_hex/6.)-Area_Q1 )>tol) .or. (abs((0.5*Area_hex/6.)-Area_Q2 )>tol)) .or. ((abs((0.5*Area_hex/6.)-Area_Q3 )>tol) .or. (abs((2.5*Area_hex/6.)-Area_Q4 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split two coners of hex (x>0)!', WARNING) + fail_unit_test=.True. + endif + !Test 3b: center on x<0 axis + x0=-S/2. ; y0=0. + call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + if (((abs((2.5*Area_hex/6.)-Area_Q2 )>tol) .or. (abs((0.5*Area_hex/6.)-Area_Q1 )>tol)) .or. ((abs((0.5*Area_hex/6.)-Area_Q4 )>tol) .or. (abs((2.5*Area_hex/6.)-Area_Q3 )>tol))) then + if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split two coners of hex (x<0)!', WARNING) + fail_unit_test=.True. + endif + !Test 3c: center on y>0 axis + !x0=0. ; y0=H/2. + !call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + !if (((abs((2.5*Area_hex/6.)-Area_Q1 )>tol) .or. (abs((0.5*Area_hex/6.)-Area_Q3 )>tol)) .or. ((abs((0.5*Area_hex/6.)-Area_Q4 )>tol) .or. (abs((2.5*Area_hex/6.)-Area_Q2 )>tol))) then + !if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + !if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon errors =', (abs((2.5*Area_hex/6.)-Area_Q1 )), (abs((0.5*Area_hex/6.)-Area_Q3 )),& + ! call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split two coners of hex (y>0)!', WARNING) + ! fail_unit_test=.True. + !endif + !!Test 3d: center on y<0 axis + !x0=0. ; y0=-H/2. + !call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + !if (((abs((2.5*Area_hex/6.)-Area_Q3 )>tol) .or. (abs((0.5*Area_hex/6.)-Area_Q2 )>tol)) .or. ((abs((0.5*Area_hex/6.)-Area_Q1 )>tol) .or. (abs((2.5*Area_hex/6.)-Area_Q4 )>tol))) then + !if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon areas =', Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 + !if (mpp_pe() .eq. mpp_root_pe()) write(stderrunit,*) 'diamonds, hexagon errots =', (abs((2.5*Area_hex/6.)-Area_Q3 )), (abs((0.5*Area_hex/6.)-Area_Q2 )),& + ! call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split two coners of hex (y<0)!', WARNING) + ! fail_unit_test=.True. + !endif + + + if (fail_unit_test) call error_mesg('diamonds, hexagon unit testing:', 'Hexagon unit testing does not pass!', FATAL) + + +end subroutine hexagon_test + ! ############################################################################## subroutine initialize_iceberg_bonds(bergs) @@ -944,10 +1064,13 @@ subroutine thermodynamics(bergs) type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. integer :: grdi, grdj -real :: orientation +real :: orientation, static_berg ! For convenience grd=>bergs%grd + + !Initializing static_berg + static_berg=0. !do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly @@ -1128,7 +1251,8 @@ subroutine thermodynamics(bergs) endif !print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num endif - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs,orientation) + if (bergs%hexagonal_icebergs) static_berg=this%static_berg !Change this to use_old_restart=false when this is merged in + call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, this%length*this%width, bergs%hexagonal_icebergs,orientation,static_berg) endif endif @@ -1208,13 +1332,14 @@ real function find_orientation_using_iceberg_bonds(grd,berg,initial_orientation) end function find_orientation_using_iceberg_bonds -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs,theta_in) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, hexagonal_icebergs,theta_in,static_berg) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: x, y, Mberg, Mbits, scaling, Area logical, intent(in) :: hexagonal_icebergs real, optional, intent(in) :: theta_in + real, optional, intent(in) :: static_berg ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR @@ -1222,6 +1347,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex real :: fraction_used real :: theta + real :: tol real, parameter :: rho_seawater=1035. integer :: stderrunit logical :: debug @@ -1230,6 +1356,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling stderrunit = stderr() theta=0.0 + tol=1.e-10 !This is here because the findinding orientaion scheme is not coded when spread mass to ocean is called directly from the time stepping scheme. if (present(theta_in)) then theta=theta_in @@ -1304,7 +1431,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) - if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-0.001) then + if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-tol) then call error_mesg('diamonds, hexagonal spreading', 'Intersection with hexagons should not be negative!!!', WARNING) write(stderrunit,*) 'diamonds, yU,yC,yD', Area_Q1, Area_Q2, Area_Q3, Area_Q4 endif @@ -1343,7 +1470,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling endif !Double check that all the mass is being used. - if ((abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>0.001) .and. (mpp_pe().eq.5)) then + if ((abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>tol) .and. (mpp_pe().eq. mpp_root_pe())) then !call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', WARNING) write(stderrunit,*) 'diamonds, hexagonal, H,x0,y0', H, x0 , y0 write(stderrunit,*) 'diamonds, hexagonal, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 @@ -1359,6 +1486,11 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) + if ((hexagonal_icebergs) .and. (static_berg .eq. 1)) then + !Change this to use_old_restart=false when this is merged in + fraction_used=1. !Static icebergs do not share their mass with the boundary (this to initialize icebergs in regular arrangements against boundaries) + endif + grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass/fraction_used) grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass/fraction_used) grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass/fraction_used) @@ -1369,6 +1501,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass/fraction_used) grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass/fraction_used) + end subroutine spread_mass_across_ocean_cells @@ -1407,7 +1540,7 @@ logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) ! Arguments real, intent(in) :: Ax,Ay,Bx,By,qx,qy real :: tol, dxc,dyc,dxl,dyl,cross - tol=0.00000000000000; + tol=1.e-12; dxc = qx - Ax; dyc = qy - Ay; dxl = Bx - Ax; @@ -1593,22 +1726,14 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, real :: Area_Upper, Area_Lower, Area_Right, Area_Left real :: px, py , qx , qy real :: Area_key_quadrant,Error + real :: tol integer :: Key_quadrant integer ::sig_fig integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() - - !Round of numbers before proceeding further. - !sig_fig=12; !Significan figures - !Ax=roundoff(Ax0,sig_fig) - !Ay=roundoff(Ay0,sig_fig) - !Bx=roundoff(Bx0,sig_fig) - !By=roundoff(By0,sig_fig) - !Cx=roundoff(Cx0,sig_fig) - !Cy=roundoff(Cy0,sig_fig) - + tol=1.e-10 Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); @@ -1703,7 +1828,7 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Error=abs(Area_Q1+Area_Q2+Area_Q3+Area_Q4-Area_triangle) - if (Error>0.01) then + if (Error>tol) then call error_mesg('diamonds, triangle spreading', 'Triangle not evaluated accurately!!', WARNING) !if (mpp_pe().eq.mpp_root_pe()) then if (mpp_pe().eq. 0) then @@ -1751,10 +1876,12 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q real :: T56_Area, T56_Q1, T56_Q2, T56_Q3, T56_Q4 real :: T61_Area, T61_Q1, T61_Q2, T61_Q3, T61_Q4 real :: S, exact_hex_area, Error + real :: tol integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() + tol=1.e-10 !Length of side of Hexagon S=(2/sqrt(3.))*H @@ -1796,7 +1923,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q Area_Q4=max(Area_Q4,0.); Error=Area_hex-(Area_Q1+Area_Q2+Area_Q3+Area_Q4) - if ((abs(Error)>0.01))then + if ((abs(Error)>tol))then if (mpp_pe().eq.mpp_root_pe()) then call error_mesg('diamonds, hexagonal spreading', 'Hexagon error is large!!', WARNING) write(stderrunit,*) 'diamonds, hex error, H,x0,y0, Error', H, x0 , y0, Error @@ -1811,7 +1938,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q endif exact_hex_area=((3.*sqrt(3.)/2)*(S*S)) - if (abs(Area_hex-exact_hex_area)>0.01) then + if (abs(Area_hex-exact_hex_area)>tol) then call error_mesg('diamonds, hexagonal spreading', 'Hexagon not evaluated accurately!!', WARNING) if (mpp_pe().eq.mpp_root_pe()) then write(stderrunit,*) 'diamonds, hex calculations, H,x0,y0', H, x0 , y0 @@ -1839,9 +1966,6 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q end subroutine Hexagon_into_quadrants_using_triangles - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) ! Arguments type(icebergs_gridded), pointer :: grd @@ -2648,6 +2772,7 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') call grd_chksum2(grd, grd%tmp, 'mass out (incr)') + endif if (.not.(within_model)) then @@ -2936,6 +3061,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) real :: xdot3, ydot3 real :: xdotn, ydotn real :: dt, dt_2, dt_6, dydl +real :: static_berg logical :: bounced, on_tangential_plane, error_flag integer :: i, j integer :: stderrunit @@ -2958,6 +3084,10 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) dt=bergs%dt dt_2=0.5*dt + static_berg=0. !Initializing + if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in + + lonn = berg%lon ; latn = berg%lat axn = berg%axn ; ayn = berg%ayn bxn= berg%bxn ; byn = berg%byn @@ -2972,7 +3102,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs ) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling, berg%length*berg%width ,bergs%hexagonal_icebergs,static_berg ) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3053,6 +3183,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n real :: xn, xdotn, xddotn, yn, ydotn, yddotn, xddotnn, yddotnn real :: dt, dt_2, dt_6, dydl +real :: static_berg integer :: i1,j1,i2,j2,i3,j3,i4,j4 integer :: stderrunit logical :: bounced, on_tangential_plane, error_flag @@ -3078,6 +3209,9 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo dt=bergs%dt dt_2=0.5*dt dt_6=dt/6. + + static_berg=0. !Initializing + if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in i=berg%ine j=berg%jne @@ -3088,7 +3222,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs,static_berg) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -3126,7 +3260,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling, berg%length*berg%width , bergs%hexagonal_icebergs,static_berg) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -3182,7 +3316,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs,static_berg) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -3313,7 +3447,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs) + call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, bergs%hexagonal_icebergs,static_berg) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e7c1e9b..1aacc10 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -82,6 +82,7 @@ module ice_bergs_framework integer :: isg, ieg, jsg, jeg ! Indices of global domain integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE idenLx ! Length of domain, for periodic boundary condition (Ly to be adde later if needed) logical :: grid_is_latlon !Flag to say whether the coordinate is in lat lon degrees, or meters + logical :: grid_is_regular !Flag to say whether point in cell can be found assuming regular cartesian grid real :: Lx !Length of the domain in x direction real, dimension(:,:), pointer :: lon=>null() ! Longitude of cell corners real, dimension(:,:), pointer :: lat=>null() ! Latitude of cell corners @@ -331,6 +332,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation logical :: grid_is_latlon=.True. !True means that the grid is specified in lat lon, and uses to radius of the earth to convert to distance +logical :: grid_is_regular !Flag to say whether point in cell can be found assuming regular cartesian grid logical :: rotate_icebergs_for_mass_spreading=.True. !Flag allows icebergs to rotate for spreading their mass (in hexagonal spreading mode) logical :: set_melt_rates_to_zero=.False. !Sets all melt rates to zero, for testing purposes (thermodynamics routine is still run) logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met @@ -357,7 +359,7 @@ subroutine ice_bergs_framework_init(bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & - allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane + allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_regular,grid_is_latlon,Lx,use_f_plane ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -699,6 +701,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%grd%halo=halo bergs%grd%Lx=Lx bergs%grd%grid_is_latlon=grid_is_latlon + bergs%grd%grid_is_regular=grid_is_regular bergs%max_bonds=max_bonds bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef @@ -3382,7 +3385,7 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) ! Local variables real :: x1,y1,x2,y2,x3,y3,x4,y4,xx,yy,fac integer :: stderrunit -real :: Lx +real :: Lx, dx,dy ! Get the stderr unit number stderrunit=stderr() @@ -3412,7 +3415,16 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) endif endif - if ((max(y1,y2,y3,y4)<89.999).or. (.not. grd%grid_is_latlon) ) then + !This part only works for a regular cartesian grid. For more complex grids, we + !should use calc_xiyj + if ((.not. grd%grid_is_latlon) .and. (grd%grid_is_regular)) then + dx=(grd%lon(i ,j )-grd%lon(i-1 ,j )) + dy=(grd%lat(i ,j )-grd%lat(i ,j-1 )) + x1=grd%lon(i ,j )-(dx/2) + y1=grd%lat(i ,j )-(dy/2) + xi=((x-x1)/dx)+0.5 + yj=((y-y1)/dy)+0.5 + elseif ((max(y1,y2,y3,y4)<89.999) .or.(.not. grd%grid_is_latlon)) then call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, Lx, explain=explain) else if (debug) write(stderrunit,*) 'diamonds, pos_within_cell: working in tangential plane!' @@ -3490,6 +3502,7 @@ subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) if (present(explain)) then if(explain) expl=.true. endif + alpha=x2-x1 delta=y2-y1 beta=x4-x1 diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 84d4ff7..2d014f6 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -896,6 +896,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%first_bond=>null() if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne,explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) + !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) if (bergs%grd%area(localberg%ine,localberg%jne) .ne. 0) then call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) From cc0138ecb5ef22468b0e03b7a800bc65f6053877 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 2 Aug 2016 12:03:36 -0400 Subject: [PATCH 141/361] Not sure what has been changed here --- .icebergs.F90.swo | Bin 20480 -> 0 bytes icebergs_framework.F90 | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 .icebergs.F90.swo diff --git a/.icebergs.F90.swo b/.icebergs.F90.swo deleted file mode 100644 index ddfd693b44f034bd69bd80bd09917230ed1d2d10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeHPS&Sq{5iN6H28-(hfynX7Y3M3>D_aOubiSvv5w2iq>!Hdl7>gt}Eowb1vP__2; zR7Ye)Mn*C_GSjpzuK9 zfx-iY2mVhyAp6g>UWKtd%#5dH{$4fr_n+o-hoPUG<3Gaup77r_$Nz_sKV#^RFda<# z`McrYY4|Ui>MCUrhS{x#3SfOA7@#20Sx%)V=e2|KneH}o{QcFtN=g8GuV3pA9yVA7~o@guDcDm6?i^y z0(bz=nx6tb3A_q80^Ez|+xGw)z~g}r;{ohe;40wVc(z{$zKAh@0r(*BTHxitS>QBq z3OE6fUz)%kA2$jm_rt`p4v5h6+ZJPPm&e>i)kG-}VY9J(q|A;TV*?Q zb`-NjaE3aH1r`e)*sKo&djb}cVJ*+`yUlvFUT-Y31y(wh$(PwlQs73S-S%BygpzFu zITRwqUsPl;9(tsD394D?MA_Oy`vBUHlImMTEPa;;{~^W0f5Ys^6+FC*(Zh#k^nPl& zHu>=3hu~>0dr@*3llh?8s2+OIe!i^QPRs|s95;_vk3jKF>KB)YV?-BsT@i?wezH=p zmfXI)YXrpI$U%?{IpVF^s4pL`LeomWA4j7q^F)|HKa1KdN#iz0AW^KU#_aj59<^9$ zyHo4kerQkK+=tp~14>U$m4P@X&Q6>-v0H$WdD^z4NA)OkYTB_#x(~`4EQRLL#`V=3 zX6@06Xr1gosJ`zsj?|ldzlJ~LtX32vd&mUd>cm1MOhzo`p3f=m^wX`tcWHI2HR<@F z8#_IoB=(e+@PTkJ6v<<`i-0e4ZIQ)tzv48^{YqryZaaN3B_TJXTnouTBK3rV-N^c} zKfqL5R+?IDjn zljPN^ql>QK(xx~F?Xf^;@UiVisTpfx>lL9VYCpZ98(=MCP*H%frX5GA-A}6R!!yXv zft_7BTVqPYvD=-o#ZNFFG!1^J1u#3#(3f5Fd%vELn6{z>8G-Ko!PxNxj70Fz_r&Bl zk_c$e84ADCl^B2Ob%eArElv!#c!+Zc;lE#3S&Ey?6B~`EnQNMpY_^rQ+akUKeI|Oc zkWiUIrvjwc4rVmuSi(*(LQ>RuK+*XKext0S`q-;!EIL?85LXS_z6hWtBO)7PGlYRF zvWjIaa;`K=zbAIhK*b2gckMb#vH|^rLt1k>-QZm>d{U$KNupD zqL5~0E28CNvyIJj7f#vi{N_dav$}Hrg3T_ip1*J*y5F=Ow5)$U;` zqr45|5jaZn5Vx#v2kw`CyI#^!P6ET$F3rnRZ642IGF08C$eXN|@IK6SxZic7@u9a)+J3+L?1BXlL z40w?48d+Gsp+jLu_hJ=;Hl8c#?iuz1M;QP@fXu6ys$Y16Vph)B-uIEXdZL2?pITqT zV|wJJL2hGa(ewY;@m&9VfS&)&vA6Y4L;D@ki%;Q!!UKf|3J(+>C_GSjpzuK9fx-iY z2MP}q9wS6jtfTf=QpMep4^eTMe`Tq_xnh)T)|8C$FzyaU~IPZTe&@P6QK;AOy_z_q})P%H2T;5EPz;C|Ez`~;x-flmN$2U6fR z-~_M$Tm}39wFBP)J_CFlpxT0W0&fKF0$vJG9r_w@9dIw|3cdvlfoB0QIPy;pLNjBkJ8Gz2ca~LiUpA{UPDK?hh~LK%BP2@d?Z0mK zZ`(#zNgTc5Exfi%j9if4$t!ccvH6B8;$@J6i0JjryA3sa4FcU`)SR@+!Z2gEoe^6uX9i+XZ(yk*{jFUWOJN6L11F|T-mtt-c>9?6NSHBQG9 zco}t1oVC{0nM;T8vCp9q{}8HPgwA{!L{Xo@n6YW7)fX{ye5|O`$kEi1Zk&&GK5Fuj zxRLR3laHyY3i@?<6v38T!UrsONj zid{j$3+ZMIjhj5^cXZTMg;Jq!68=n5rq$({Za>GS+fpQ#u zf#Xiqjy$h)D<##AtjfA`G7yUyTJhX=&1Rr9^ID8boEL zX|Q5K;}aSTn$Y~oz~MpidQK6|)KWUDNYiE&X_`?qGf}&lR^QDw5NCDLAVA#5y83SB zfjFy+>;uv0(%~<87V(JM)9uXRHlrE?I)q&c1O$*)*foLkAE{#B%prjM`EAmmeNZ;if*}xEK%0hKNDO2V_hS&MM*|4d= z^fYb&SP67bAVc%zr3soVm1>UwjigC!J0RDJ`ePiyqJ)h$7}U&G4X6(l(%9(1Ba5`R zgFC9?PL(K?(_k%H=}Rj3gC7}vYG*3y#!EG@gUY2!*H`51i~Oma*d!?`Dx^(RjXB1pi5;dx>9Y3svzbkDA7~Sw;=}p03om< AAOHXW diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 1aacc10..4bf28e5 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -332,7 +332,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation logical :: grid_is_latlon=.True. !True means that the grid is specified in lat lon, and uses to radius of the earth to convert to distance -logical :: grid_is_regular !Flag to say whether point in cell can be found assuming regular cartesian grid +logical :: grid_is_regular=.True. !Flag to say whether point in cell can be found assuming regular cartesian grid logical :: rotate_icebergs_for_mass_spreading=.True. !Flag allows icebergs to rotate for spreading their mass (in hexagonal spreading mode) logical :: set_melt_rates_to_zero=.False. !Sets all melt rates to zero, for testing purposes (thermodynamics routine is still run) logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met From 203baad4e1aaa107eb4ec46a094b7b28a5f7e4f0 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 2 Aug 2016 13:59:13 -0400 Subject: [PATCH 142/361] Iceberg bond restart file will only be written when iceberg_bonds_on flag is true --- icebergs_io.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 84d4ff7..9dac66b 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -307,7 +307,6 @@ subroutine write_restart(bergs) if (bergs%iceberg_bonds_on) then check_bond_quality=.true. call count_bonds(bergs, nbonds,check_bond_quality) - endif allocate(first_berg_num(nbonds)) allocate(other_berg_num(nbonds)) @@ -369,7 +368,7 @@ subroutine write_restart(bergs) call nullify_domain() - + endif !############################################################################################# ! Write stored ice From af0f7a48011373438fd1839596aea4ac2eedc446 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 2 Aug 2016 15:49:59 -0400 Subject: [PATCH 143/361] Option to find the orientation of an iceberg from its bonds has been added inside the Verlet Scheme. The orientaion code has not yet been properly tested. The code has been refactored slightly so that the orientation scheme can be called more easily. --- icebergs.F90 | 142 +++++++++++++++++++---------------------- icebergs_framework.F90 | 5 +- 2 files changed, 70 insertions(+), 77 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5eaf16d..1c84f67 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1065,16 +1065,19 @@ subroutine thermodynamics(bergs) real, parameter :: perday=1./86400. integer :: grdi, grdj real :: orientation, static_berg +integer :: extra_cell ! For convenience grd=>bergs%grd !Initializing static_berg static_berg=0. + extra_cell=0 + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) extra_cell=1 - !do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec - !do grdj = grd%jsd+2,grd%jed-1 ; do grdi = grd%isd+2,grd%ied-1 ! Thermodynamics of halos now calculated, so that spread mass to ocean works correctly - do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly + ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly + ! Thermodynamics of first second halo row is calculated if orientation is being found using bonds + do grdj = grd%jsc-1-extra_cell,grd%jec+1+extra_cell ; do grdi = grd%isc-1-extra_cell,grd%iec+1+extra_cell this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') @@ -1244,13 +1247,7 @@ subroutine thermodynamics(bergs) endif orientation=bergs%initial_orientation - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) then - !Don't check orientation of the edges of halo, since they can contain unassosiated bonds (this is why halo width must be larger >= 2 to use bonds) - if ( ((this%ine .gt. grd%isd) .and. (this%ine .lt. grd%ied)) .and. ((this%jne .ge. grd%jsd) .and. (this%jne .le. grd%jed) ) ) then - orientation=find_orientation_using_iceberg_bonds(grd,this,bergs%initial_orientation) - endif - !print *, 'orientation: ', (180/pi)*orientation, this%iceberg_num - endif + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,this,orientation) if (bergs%hexagonal_icebergs) static_berg=this%static_berg !Change this to use_old_restart=false when this is merged in call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, & this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg) @@ -1264,10 +1261,10 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics -real function find_orientation_using_iceberg_bonds(grd,berg,initial_orientation) +subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) ! Arguments type(iceberg), pointer :: berg - real, intent(in) :: initial_orientation + real, intent(inout) :: orientation type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond @@ -1275,72 +1272,67 @@ real function find_orientation_using_iceberg_bonds(grd,berg,initial_orientation) real :: r_dist_x, r_dist_y real :: lat_ref, dx_dlon, dy_dlat real :: theta, bond_count, Average_angle - logical :: grid_is_latlon - grid_is_latlon=grd%grid_is_latlon bond_count=0. Average_angle=0. - current_bond=>berg%first_bond - lat1=berg%lat - lon1=berg%lon - !print *, 'Looking for orientation: ' - do while (associated(current_bond)) ! loop over all bonds - other_berg=>current_bond%other_berg - if (.not. associated(other_berg)) then !good place for debugging - !One valid option: current iceberg is on the edge of halo, with other berg on the next pe (not influencing mass spreading) - !print *, 'Iceberg bond details:',berg%iceberg_num, current_bond%other_berg_num,berg%halo_berg, mpp_pe() - !print *, 'Iceberg bond details2:',berg%ine, berg%jne, current_bond%other_berg_ine, current_bond%other_berg_jne - !print *, 'Iceberg isd,ied,jsd,jed:',grd%isd, grd%ied, grd%jsd, grd%jed - !print *, 'Iceberg isc,iec,jsc,jec:',grd%isc, grd%iec, grd%jsc, grd%jec - !call error_mesg('diamonds,calculating orientation', 'Looking at bond interactions of unassosiated berg!' ,FATAL) - !endif - else - lat2=other_berg%lat - lon2=other_berg%lon - - dlat=lat2-lat1 - dlon=lon2-lon1 - - lat_ref=0.5*(lat1+lat2) - call convert_from_grid_to_meters(lat_ref,grid_is_latlon,dx_dlon,dy_dlat) - r_dist_x=dlon*dx_dlon - r_dist_y=dlat*dy_dlat - !print *, 'r_dist_x,r_dist_y: ', r_dist_x,r_dist_y - - if (r_dist_x .eq. 0.) then - angle=pi/2. + !Don't check orientation of the edges of halo, since they can contain unassosiated bonds (this is why halo width must be larger >= 2 to use bonds) + if ( ((berg%ine .gt. grd%isd) .and. (berg%ine .lt. grd%ied)) .and. ((berg%jne .ge. grd%jsd) .and. (berg%jne .le. grd%jed) ) ) then + current_bond=>berg%first_bond + lat1=berg%lat + lon1=berg%lon + do while (associated(current_bond)) ! loop over all bonds + other_berg=>current_bond%other_berg + if (.not. associated(other_berg)) then !good place for debugging + !One valid option: current iceberg is on the edge of halo, with other berg on the next pe (not influencing mass spreading) + !print *, 'Iceberg bond details:',berg%iceberg_num, current_bond%other_berg_num,berg%halo_berg, mpp_pe() + !print *, 'Iceberg bond details2:',berg%ine, berg%jne, current_bond%other_berg_ine, current_bond%other_berg_jne + !print *, 'Iceberg isd,ied,jsd,jed:',grd%isd, grd%ied, grd%jsd, grd%jed + !print *, 'Iceberg isc,iec,jsc,jec:',grd%isc, grd%iec, grd%jsc, grd%jec + !call error_mesg('diamonds,calculating orientation', 'Looking at bond interactions of unassosiated berg!' ,FATAL) + !endif else - angle=atan(r_dist_y/r_dist_x) - angle= ((pi/2.) - (initial_orientation*(pi/180.))) - angle - !print *, 'angle: ', angle*(180/pi), initial_orientation - angle=modulo(angle ,pi/3.) + lat2=other_berg%lat + lon2=other_berg%lon + + dlat=lat2-lat1 + dlon=lon2-lon1 + + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,grd%grid_is_latlon,dx_dlon,dy_dlat) + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat + + if (r_dist_x .eq. 0.) then + angle=pi/2. + else + angle=atan(r_dist_y/r_dist_x) + angle= ((pi/2.) - (orientation*(pi/180.))) - angle + !print *, 'angle: ', angle*(180/pi), initial_orientation + angle=modulo(angle ,pi/3.) + endif + bond_count=bond_count+1. + Average_angle=Average_angle+angle endif - !print *, 'angle2: ', angle*(180/pi) - bond_count=bond_count+1. - Average_angle=Average_angle+angle + current_bond=>current_bond%next_bond + enddo !End loop over bonds + if (bond_count.gt.0) then + Average_angle =Average_angle/bond_count + else + Average_angle =0. endif - current_bond=>current_bond%next_bond - enddo !End loop over bonds - if (bond_count.gt.0) then - Average_angle =Average_angle/bond_count - else - Average_angle =0. + orientation=modulo(Average_angle ,pi/3.) endif - !print *, 'Average angle', Average_angle*(180/pi), bond_count - find_orientation_using_iceberg_bonds=modulo(Average_angle ,pi/3.) - !find_orientation_using_iceberg_bonds=modulo(angle ,pi/3.) - !print *, 'Finished looking: ' -end function find_orientation_using_iceberg_bonds +end subroutine find_orientation_using_iceberg_bonds -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading,hexagonal_icebergs,theta_in,static_berg) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading,hexagonal_icebergs,theta,static_berg) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: x, y, Mberg, Mbits, scaling, Area logical, intent(in) :: hexagonal_icebergs logical, intent(in) :: use_old_spreading - real, optional, intent(in) :: theta_in + real, intent(in) :: theta real, optional, intent(in) :: static_berg ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L @@ -1348,7 +1340,6 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: S, H, origin_x, origin_y, x0, y0 real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex real :: fraction_used - real :: theta real :: tol real, parameter :: rho_seawater=1035. integer :: stderrunit @@ -1357,12 +1348,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling ! Get the stderr unit number stderrunit = stderr() - theta=0.0 tol=1.e-10 - !This is here because the findinding orientaion scheme is not coded when spread mass to ocean is called directly from the time stepping scheme. - if (present(theta_in)) then - theta=theta_in - endif Mass=(Mberg+Mbits)*scaling ! This line attempts to "clip" the weight felt by the ocean. The concept of @@ -3082,7 +3068,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) real :: xdot3, ydot3 real :: xdotn, ydotn real :: dt, dt_2, dt_6, dydl -real :: static_berg +real :: static_berg, orientation logical :: bounced, on_tangential_plane, error_flag integer :: i, j integer :: stderrunit @@ -3106,6 +3092,8 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) dt_2=0.5*dt static_berg=0. !Initializing + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in @@ -3124,7 +3112,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3205,7 +3193,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n real :: xn, xdotn, xddotn, yn, ydotn, yddotn, xddotnn, yddotnn real :: dt, dt_2, dt_6, dydl -real :: static_berg +real :: static_berg,orientation integer :: i1,j1,i2,j2,i3,j3,i4,j4 integer :: stderrunit logical :: bounced, on_tangential_plane, error_flag @@ -3233,6 +3221,8 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo dt_6=dt/6. static_berg=0. !Initializing + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) !Not sure if this works with Runge Kutta if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in i=berg%ine @@ -3245,7 +3235,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -3284,7 +3274,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -3341,7 +3331,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -3473,7 +3463,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index ae749f7..d221651 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -671,7 +671,10 @@ subroutine ice_bergs_framework_init(bergs, & enddo endif -if ((halo .lt. 2) .and. (interactive_icebergs_on .or. iceberg_bonds_on) ) then +if ((halo .lt. 3) .and. (rotate_icebergs_for_mass_spreading .and. iceberg_bonds_on) ) then + halo=3 + call error_mesg('diamonds, framework', 'Setting iceberg halos =3, since halos must be >= 3 for rotating icebergs for mass spreading', WARNING) +elseif ((halo .lt. 2) .and. (interactive_icebergs_on .or. iceberg_bonds_on) ) then halo=2 call error_mesg('diamonds, framework', 'Setting iceberg halos =2, since halos must be >= 2 for interactions', WARNING) endif From 5377f0c376c6854b5b037f4fd9721aa54930be8f Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 3 Aug 2016 16:14:39 -0400 Subject: [PATCH 144/361] Fixed a bug in the routing which rotates the hexagons by a prescibed angle. --- icebergs.F90 | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 1c84f67..8a97485 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1065,19 +1065,15 @@ subroutine thermodynamics(bergs) real, parameter :: perday=1./86400. integer :: grdi, grdj real :: orientation, static_berg -integer :: extra_cell ! For convenience grd=>bergs%grd !Initializing static_berg static_berg=0. - extra_cell=0 - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) extra_cell=1 ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly - ! Thermodynamics of first second halo row is calculated if orientation is being found using bonds - do grdj = grd%jsc-1-extra_cell,grd%jec+1+extra_cell ; do grdi = grd%isc-1-extra_cell,grd%iec+1+extra_cell + do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') @@ -1253,7 +1249,6 @@ subroutine thermodynamics(bergs) this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg) endif endif - this=>next enddo enddo ; enddo @@ -1840,14 +1835,15 @@ subroutine rotate_and_translate(px,py,theta,x0,y0) ! Arguments real, intent(in) :: x0,y0,theta real, intent(inout) :: px,py + real :: px_temp,py_temp !Rotation - px = ( cos(theta*pi/180)*px) + (sin(theta*pi/180)*py) - py = (-sin(theta*pi/180)*px) + (cos(theta*pi/180)*py) + px_temp = ( cos(theta*pi/180)*px) + (sin(theta*pi/180)*py) + py_temp = (-sin(theta*pi/180)*px) + (cos(theta*pi/180)*py) !Translation - px= px + x0 - py= py + y0 + px= px_temp + x0 + py= py_temp + y0 end subroutine rotate_and_translate subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4) From cfa98aa42bf84ee196bf0678fa4dbbfde593654f Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 5 Aug 2016 16:43:35 -0400 Subject: [PATCH 145/361] 1) Added an option to override the iceberg velocitiy and set accelerations to zero. This is useful for testing the ocean model with fixed iceberg velocities 2) Added a gridded diagnostic of the average (mass weighted) iceberg velocity in a grid cell. This does not account for icebergs being mass spreading across grid cells. 3) Fixed a random bug which incorrectly set the sea ice velocity incorrecly. 3) Added an if statement that sets the sea ice drag force to zero when the sea ice thinckness is equal to one. --- icebergs.F90 | 57 +++++++++++++++++++++++++++++++++++++++--- icebergs_framework.F90 | 26 +++++++++++++++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 8a97485..7fd3140 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -649,6 +649,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !Temporary for messing around + !ssh_x=0. + !ssh_y=0. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ((grd%grid_is_latlon) .and. (.not. bergs%use_f_plane)) then f_cori=(2.*omega)*sin(pi_180*lat) else @@ -695,7 +702,11 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Weighted drag coefficients c_ocn=rho_seawater/M*(0.5*Cd_wv*W*(D_hi)+Cd_wh*W*L) c_atm=rho_air /M*(0.5*Cd_av*W*F +Cd_ah*W*L) - c_ice=rho_ice /M*(0.5*Cd_iv*W*hi ) + if (abs(hi).eq.0.) then + c_ice=0. + else + c_ice=rho_ice /M*(0.5*Cd_iv*W*hi ) + endif if (abs(ui)+abs(vi).eq.0.) c_ice=0. !Turning drag off for testing - Alon @@ -997,6 +1008,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a call print_berg(stderrunit,berg,'diamonds, accel, large accel') endif + !Used for testing the ocean response to fixed iceberg motion. + if (bergs%override_iceberg_velocities) then + ax = 0.0; ay = 0.0; + axn = 0.0; ayn = 0.0; + bxn = 0.0; byn = 0.0; + endif + contains subroutine dump_locfld(grd,i0,j0,A,lbl) @@ -1232,8 +1250,13 @@ subroutine thermodynamics(bergs) else ! Diagnose mass distribution on grid if (grd%id_virtual_area>0)& & grd%virtual_area(i,j)=grd%virtual_area(i,j)+(Wn*Ln+Abits)*this%mass_scaling ! m^2 - if (grd%id_mass>0 .or. bergs%add_weight_to_ocean)& + if ((grd%id_mass>0 .or. bergs%add_weight_to_ocean) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 + !Finding the average iceberg velocity in a grid cell (mass weighted) + if (grd%id_u_iceberg>0 )& + & grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%uvel) ! kg/m2 + if (grd%id_v_iceberg>0 )& + & grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%vvel) ! kg/m2 if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then @@ -1252,6 +1275,16 @@ subroutine thermodynamics(bergs) this=>next enddo enddo ; enddo + + !Scaling the gridded iceberg velocity by the iceberg mass + if ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0)) then + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + if ((grd%id_u_iceberg>0 ).and. (grd%mass(i,j)>0.)) & + & grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) + if ((grd%id_v_iceberg>0 ).and. (grd%mass(i,j)>0.)) & + & grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) + enddo; enddo + endif end subroutine thermodynamics @@ -2123,6 +2156,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, type(icebergs_gridded), pointer :: grd logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass +real :: grdd_u_iceberg, grdd_v_iceberg integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp @@ -2154,6 +2188,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. grd%spread_mass(:,:)=0. + grd%u_iceberg(:,:)=0. + grd%v_iceberg(:,:)=0. grd%mass(:,:)=0. if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. @@ -2226,7 +2262,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%uo(I,J) = mask * 0.5*(uo(Iu,ju)+uo(Iu,ju+1)) grd%ui(I,J) = mask * 0.5*(ui(Iu,ju)+ui(Iu,ju+1)) grd%vo(I,J) = mask * 0.5*(vo(iv,Jv)+vo(iv+1,Jv)) - grd%vi(I,J) = mask * 0.5*(vi(iv,Jv)+vo(iv+1,Jv)) + grd%vi(I,J) = mask * 0.5*(vi(iv,Jv)+vi(iv+1,Jv)) !There was a bug here. enddo ; enddo else call error_mesg('diamonds, iceberg_run', 'Unrecognized value of stagger!', FATAL) @@ -2411,6 +2447,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_bergy_mass, grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_spread_mass>0) & lerr=send_data(grd%id_spread_mass, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_u_iceberg>0) & + lerr=send_data(grd%id_u_iceberg, grd%u_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_v_iceberg>0) & + lerr=send_data(grd%id_v_iceberg, grd%v_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_mass>0) & lerr=send_data(grd%id_mass, grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_stored_ice>0) & @@ -2483,6 +2523,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%icebergs_mass_end=sum_mass(bergs,justbergs=.true.) bergs%bergy_mass_end=sum_mass(bergs,justbits=.true.) bergs%spread_mass_end=sum_mass(bergs) !Not sure what this is + bergs%u_iceberg_end=sum_mass(bergs) !Not sure what this is + bergs%v_iceberg_end=sum_mass(bergs) !Not sure what this is bergs%floating_heat_end=sum_heat(bergs) grd%tmpc(:,:)=0.; call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r @@ -2496,6 +2538,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(bergs%icebergs_mass_end) call mpp_sum(bergs%bergy_mass_end) call mpp_sum(bergs%spread_mass_end) + call mpp_sum(bergs%u_iceberg_end) + call mpp_sum(bergs%v_iceberg_end) call mpp_sum(bergs%floating_heat_end) call mpp_sum(bergs%returned_mass_on_ocean) call mpp_sum(bergs%nbergs_end) @@ -2973,7 +3017,6 @@ subroutine evolve_icebergs(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs - if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve !Checking it everything is ok: @@ -3002,6 +3045,12 @@ subroutine evolve_icebergs(bergs) call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) endif + !Used for testing the ocean response to fixed iceberg motion. + if (bergs%override_iceberg_velocities) then + uveln = bergs%u_override + vveln = bergs%v_override + endif + ! Saving all the iceberg variables. berg%axn=axn berg%ayn=ayn diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d221651..0edb2f8 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -116,6 +116,8 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/s/m^2) + real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) + real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) @@ -135,7 +137,7 @@ module ice_bergs_framework integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_spread_mass=-1 - integer :: id_count=-1, id_chksum=-1 + integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -206,6 +208,8 @@ module ice_bergs_framework real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0 Date: Tue, 9 Aug 2016 11:32:21 -0400 Subject: [PATCH 146/361] 1) Fixed a bug affecting the adjust_index_and_ground routine (the actuall fix is in the prod_sum_sign_dot_prod5,4 routines). The probelm was related to do with periodic boundary conditions. When non-periodic boundary conditions are being used, we let the domain size be periodic at length Lx where Lx is large. One unintended consiquence of this is that taking the modulo using Lx, rounds off the numbers. The result of this was that points which area in a grid cell where being found to be not in a grid cell (therefore the adjust_index_and_ground could not find the correct cell for points near the boundaries). This is resolved by only applying the modulo when Lx<10**14. Note that there are other places in the code where modulo Lx is used. This might cause rounding errors. Most of these seem to be rounding of the grid values rather than the iceberg location, which should not be a problem (hopefully). 2) A bug in is point_is_on_the_line routine has been fixed. Tolerence has been set to zero, so that only points which are directly on the line will be judged to be on the line. Before this was set to zero, points which were near the line where getting the wrong result, which was causing errors in the point_is_on_the_line() routine. 3) A unit test for point_in_triangle has been added. --- icebergs.F90 | 73 +++++++++++++++++++++++++++++++++++----- icebergs_framework.F90 | 76 ++++++++++++++++++++++++++++++++---------- 2 files changed, 122 insertions(+), 27 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7fd3140..5bb3c79 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -141,9 +141,29 @@ subroutine unit_testing() ! Arguments call hexagon_test() +call point_in_triangle_test() end subroutine unit_testing +subroutine point_in_triangle_test() +! Arguments +real :: Ax,Ay,Bx,By,Cx,Cy !Position of icebergs +logical :: fail_unit_test +integer :: stderrunit + + ! Get the stderr unit number. + stderrunit = stderr() + Ax= -2.695732526092343E-012 + Ay=0.204344508198090 + Bx=-2.695750202346321E-012 + By= -8.433062639672301E-002 + Cx=0.249999999997304 + Cy=6.000694090068343E-002 + + fail_unit_test=(.not. point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)) + if (fail_unit_test) call error_mesg('diamonds, hexagon unit testing:', 'Point in triangle test does not pass!', FATAL) + +end subroutine point_in_triangle_test subroutine hexagon_test() ! Arguments @@ -1558,7 +1578,8 @@ logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) ! Arguments real, intent(in) :: Ax,Ay,Bx,By,qx,qy real :: tol, dxc,dyc,dxl,dyl,cross - tol=1.e-12; + !tol=1.e-12; + tol=0.0; dxc = qx - Ax; dyc = qy - Ay; dxl = Bx - Ax; @@ -1791,8 +1812,11 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Key_quadrant=2 elseif ((px.lt. 0.) .and. (qy.lt. 0.)) then !Third quadrant Key_quadrant=3; - else !#Forth quadrant + elseif ((px.ge. 0.) .and. (qy.lt. 0.)) then !Forth quadrant Key_quadrant=4 + else ! + call error_mesg('diamonds, iceberg_run', 'None of the quadrants are Key', WARNING) + write(stderrunit,*) 'diamonds, Triangle, px,qy', px,qy endif else !At least one quadrant is empty, and this can be used to find the areas in the other quadrant. Assigning quadrants. Key_quadrant is the empty quadrant. @@ -1849,14 +1873,14 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, if (Error>tol) then call error_mesg('diamonds, triangle spreading', 'Triangle not evaluated accurately!!', WARNING) !if (mpp_pe().eq.mpp_root_pe()) then - if (mpp_pe().eq. 0) then + if (mpp_pe().eq. 20) then write(stderrunit,*) 'diamonds, Triangle corners:',Ax,Ay,Bx,By,Cx,Cy + write(stderrunit,*) 'diamonds, Triangle, Full Area', Area_Q1+ Area_Q2+ Area_Q3+ Area_Q4 write(stderrunit,*) 'diamonds, Triangle, Areas', Area_Q1, Area_Q2 , Area_Q3, Area_Q4 write(stderrunit,*) 'diamonds, Triangle, Areas', Error - write(stderrunit,*) 'diamonds, point in triangle',(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)),Key_quadrant + write(stderrunit,*) 'diamonds, Key quadrant',Key_quadrant,Area_key_quadrant + write(stderrunit,*) 'diamonds, point in triangle',(point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)) write(stderrunit,*) 'diamonds, halves',Area_Upper,Area_Lower,Area_Right,Area_Left - - endif endif @@ -2187,7 +2211,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_src(:,:)=0. grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. - grd%spread_mass(:,:)=0. + !grd%spread_mass(:,:)=0. !Don't zero this out yet, because we can first use this an add it onto the SSH grd%u_iceberg(:,:)=0. grd%v_iceberg(:,:)=0. grd%mass(:,:)=0. @@ -2309,8 +2333,18 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !grd%ua(grd%isc:grd%iec,grd%jsc:grd%jec)=sign(sqrt(abs(tauxa(:,:))/0.01),tauxa(:,:)) ! Note rough conversion from stress to speed !grd%va(grd%isc:grd%iec,grd%jsc:grd%jec)=sign(sqrt(abs(tauya(:,:))/0.01),tauya(:,:)) ! Note rough conversion from stress to speed call mpp_update_domains(grd%ua, grd%va, grd%domain, gridtype=BGRID_NE) + ! Copy sea surface height and temperature(resides on A grid) grd%ssh(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=ssh(:,:) + if (bergs%add_iceberg_thickness_to_SSH) then + !We might need to make sure spread_mass is defined on halos (or this might be done automatically. I need to look into this) + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed + if (grd%area(i,j)>0) then + grd%ssh(i,j) = ((grd%spread_mass(i,j)/grd%area(i,j))*(bergs%rho_bergs/rho_seawater)) !Is this an appropriate sea water density to use? Should be freezing point. + endif + enddo ;enddo + endif + call mpp_update_domains(grd%ssh, grd%domain) grd%sst(grd%isc:grd%iec,grd%jsc:grd%jec)=sst(:,:)-273.15 ! Note convert from Kelvin to Celsius call mpp_update_domains(grd%sst, grd%domain) @@ -2404,7 +2438,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !Update diagnostic of iceberg mass spread on ocean if (grd%id_spread_mass>0) then - within_iceberg_model=.True. + grd%spread_mass(:,:)=0. + within_iceberg_model=.True. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model) endif @@ -3863,6 +3898,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (grd%msk(i,j)==0.) stop 'diamonds, adjust: Berg is in land! This should not happen...' endif lret=pos_within_cell(grd, lon, lat, i, j, xi, yj) ! Update xi and yj + enddo !if (debug) then ! if (abs(i-i0)>2) then @@ -3874,8 +3910,8 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun !endif if (.not.bounced.and.lret.and.grd%msk(i,j)>0.) return ! Landed in ocean without bouncing so all is well + if (.not.bounced.and..not.lret) then ! This implies the berg traveled many cells without getting far enough - ! OR that it did not move at all (round-off problem) if (debug) then write(stderrunit,*) 'diamonds, adjust: lon0, lat0=',lon0,lat0 write(stderrunit,*) 'diamonds, adjust: xi0, yj0=',xi0,yj0 @@ -3888,6 +3924,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) write(stderrunit,*) 'diamonds, adjust: lret=',lret endif + if (abs(i-i0)+abs(j-j0)==0) then if (use_roundoff_fix) then ! This is a special case due to round off where is_point_in_cell() @@ -3906,6 +3943,24 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj,explain=.true.) else call error_mesg('diamonds, adjust', 'Berg iterated many times without bouncing!', WARNING) + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 + if (iceberg_num .eq. 29217) then + write(stderrunit,*) 'iceberg_num',iceberg_num, mpp_pe(), bounced + write(stderrunit,*) ' lon, lat',lon, lat + write(stderrunit,*) ' i,j',i,j + write(stderrunit,*) ' xi,yj',xi,yj + write(stderrunit,*) 'diamonds, adjust: lon0, lat0=',lon0,lat0 + write(stderrunit,*) 'diamonds, adjust: xi0, yj0=',xi0,yj0 + write(stderrunit,*) 'diamonds, adjust: i0,j0=',i0,j0 + write(stderrunit,*) 'diamonds, adjust: lon, lat=',lon,lat + write(stderrunit,*) 'diamonds, adjust: xi,yj=',xi,yj + write(stderrunit,*) 'diamonds, adjust: i,j=',i,j + write(stderrunit,*) 'diamonds, adjust: inm,jnm=',inm,jnm + write(stderrunit,*) 'diamonds, adjust: icount=',icount + lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) + write(stderrunit,*) 'diamonds, adjust: lret=',lret + endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 endif endif ! if (xi>1.) xi=1.-posn_eps !Alon diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 0edb2f8..1f6f305 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -219,6 +219,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: add_iceberg_thickness_to_SSH=.False. !Adds the iceberg contribution to SSH. logical :: override_iceberg_velocities=.False. !Allows you to set a fixed iceberg velocity for all non-static icebergs. logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation logical :: rotate_icebergs_for_mass_spreading=.True. !Flag allows icebergs to rotate for spreading their mass (in hexagonal spreading mode) @@ -341,6 +342,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: add_iceberg_thickness_to_SSH=.False. !Adds the iceberg contribution to SSH. logical :: override_iceberg_velocities=.False. !Allows you to set a fixed iceberg velocity for all non-static icebergs. logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation logical :: grid_is_latlon=.True. !True means that the grid is specified in lat lon, and uses to radius of the earth to convert to distance @@ -373,7 +375,7 @@ subroutine ice_bergs_framework_init(bergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & - grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override + grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -735,6 +737,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%add_iceberg_thickness_to_SSH=add_iceberg_thickness_to_SSH bergs%override_iceberg_velocities=override_iceberg_velocities bergs%use_f_plane=use_f_plane bergs%rotate_icebergs_for_mass_spreading=rotate_icebergs_for_mass_spreading @@ -3314,11 +3317,19 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp Lx_2=Lx/2. sum_sign_dot_prod4=.false. - xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2 of x0 - xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2of xx - xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2of xx - xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2of xx - xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2of xx + if (Lx .ge. 1E14 ) then + xx=x + xx0=x0 + xx1=x1 + xx2=x2 + xx3=x3 + else + xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2 of x0 + xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2of xx + xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2of xx + xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2of xx + xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2of xx + endif l0=(xx-xx0)*(y1-y0)-(y-y0)*(xx1-xx0) l1=(xx-xx1)*(y2-y1)-(y-y1)*(xx2-xx1) @@ -3374,12 +3385,21 @@ logical function sum_sign_dot_prod5(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x, y Lx_2=Lx/2. sum_sign_dot_prod5=.false. - xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2of x0 - xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2of xx - xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2of xx - xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2of xx - xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2of xx - xx4=modulo(x4-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x4 to within Lx_2of xx + if (Lx .ge. 1E14 ) then + xx=x + xx0=x0 + xx1=x1 + xx2=x2 + xx3=x3 + xx4=x4 + else + xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2of x0 + xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2 of xx + xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2 of xx + xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2 of xx + xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2 of xx + xx4=modulo(x4-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x4 to within Lx_2 of xx + endif l0=(xx-xx0)*(y1-y0)-(y-y0)*(xx1-xx0) l1=(xx-xx1)*(y2-y1)-(y-y1)*(xx2-xx1) @@ -3430,6 +3450,15 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) ! Get the stderr unit number stderrunit=stderr() + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if (present(explain)) then + if(explain) then + write(stderrunit,'(a,2f12.6)') 'pos_within_cell: x ',x + print *,'x',x + write(stderrunit,'(a,2f12.6)') 'pos_within_cell: y ',y + endif + endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Lx=grd%Lx pos_within_cell=.false.; xi=-999.; yj=-999. if (i-1 Date: Wed, 10 Aug 2016 14:41:34 -0400 Subject: [PATCH 147/361] No real changes, just a little bit of cleaning up. --- icebergs.F90 | 29 +----------------------- icebergs_framework.F90 | 51 +++++++++++++++--------------------------- 2 files changed, 19 insertions(+), 61 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5bb3c79..9106be9 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -128,8 +128,8 @@ subroutine icebergs_init(bergs, & endif call update_halo_icebergs(bergs) call connect_all_bonds(bergs) - check_bond_quality=.True. nbonds=0 + check_bond_quality=.True. call count_bonds(bergs, nbonds,check_bond_quality) endif @@ -669,13 +669,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !Temporary for messing around - !ssh_x=0. - !ssh_y=0. - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if ((grd%grid_is_latlon) .and. (.not. bergs%use_f_plane)) then f_cori=(2.*omega)*sin(pi_180*lat) else @@ -1308,7 +1301,6 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics - subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) ! Arguments type(iceberg), pointer :: berg @@ -2409,7 +2401,6 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) - ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) if (bergs%iceberg_bonds_on) call bond_address_update(bergs) @@ -3943,24 +3934,6 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, inm, jnm, xi, yj,explain=.true.) else call error_mesg('diamonds, adjust', 'Berg iterated many times without bouncing!', WARNING) - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 - if (iceberg_num .eq. 29217) then - write(stderrunit,*) 'iceberg_num',iceberg_num, mpp_pe(), bounced - write(stderrunit,*) ' lon, lat',lon, lat - write(stderrunit,*) ' i,j',i,j - write(stderrunit,*) ' xi,yj',xi,yj - write(stderrunit,*) 'diamonds, adjust: lon0, lat0=',lon0,lat0 - write(stderrunit,*) 'diamonds, adjust: xi0, yj0=',xi0,yj0 - write(stderrunit,*) 'diamonds, adjust: i0,j0=',i0,j0 - write(stderrunit,*) 'diamonds, adjust: lon, lat=',lon,lat - write(stderrunit,*) 'diamonds, adjust: xi,yj=',xi,yj - write(stderrunit,*) 'diamonds, adjust: i,j=',i,j - write(stderrunit,*) 'diamonds, adjust: inm,jnm=',inm,jnm - write(stderrunit,*) 'diamonds, adjust: icount=',icount - lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) - write(stderrunit,*) 'diamonds, adjust: lret=',lret - endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 endif endif ! if (xi>1.) xi=1.-posn_eps !Alon diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 1f6f305..49ba07a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -713,6 +713,7 @@ subroutine ice_bergs_framework_init(bergs, & endif if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj + ! Parameters bergs%dt=dt bergs%traj_sample_hrs=traj_sample_hrs @@ -1002,7 +1003,7 @@ subroutine update_halo_icebergs(bergs) do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) - write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj this=>this%next enddo enddo; enddo @@ -1256,6 +1257,7 @@ subroutine update_halo_icebergs(bergs) this=>this%next enddo enddo; enddo + call show_all_bonds(bergs) endif end subroutine update_halo_icebergs @@ -2494,13 +2496,16 @@ subroutine show_all_bonds(bergs) current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds print *, 'Show Bond1 :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine, current_bond%other_berg_jne, mpp_pe() + !print *, 'Current:', berg%iceberg_num, berg%ine, berg%jne,berg%halo_berg, mpp_pe() if (associated(current_bond%other_berg)) then if (current_bond%other_berg%iceberg_num .ne. current_bond%other_berg_num) then - print *, 'Bond matching', berg%iceberg_num,current_bond%other_berg%iceberg_num, current_bond%other_berg_num, mpp_pe() + print *, 'Bond matching', berg%iceberg_num,current_bond%other_berg%iceberg_num, current_bond%other_berg_num,\ + berg%halo_berg,current_bond%other_berg%halo_berg ,mpp_pe() call error_mesg('diamonds, show all bonds:', 'The bonds are not matching properly!', FATAL) endif else - print *, 'This bond has an non-assosiated other berg :', berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine, current_bond%other_berg_jne, mpp_pe() + print *, 'This bond has an non-assosiated other berg :', berg%iceberg_num, current_bond%other_berg_num,& + current_bond%other_berg_ine, current_bond%other_berg_jne, berg%halo_berg, mpp_pe() endif current_bond=>current_bond%next_bond enddo @@ -2541,7 +2546,7 @@ subroutine connect_all_bonds(bergs) if ( (i.gt. grd%isd-1) .and. (i .lt. grd%ied+1) .and. (j .gt. grd%jsd-1) .and. (j .lt. grd%jed+1)) then other_berg=>bergs%list(i,j)%first do while (associated(other_berg)) ! loop over all other bergs - if (other_berg%iceberg_num == current_bond%other_berg_num) then + if (other_berg%iceberg_num .eq. current_bond%other_berg_num) then current_bond%other_berg=>other_berg other_berg=>null() bond_matched=.true. @@ -2559,7 +2564,7 @@ subroutine connect_all_bonds(bergs) .and. ((grdi_inner .ne. i) .or. (grdj_inner .ne. j)) ) then other_berg=>bergs%list(grdi_inner,grdj_inner)%first do while (associated(other_berg)) ! loop over all other bergs - if (other_berg%iceberg_num == current_bond%other_berg_num) then + if (other_berg%iceberg_num .eq. current_bond%other_berg_num) then current_bond%other_berg=>other_berg other_berg=>null() bond_matched=.true. @@ -2632,12 +2637,13 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs + current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds number_of_bonds=number_of_bonds+1 ! ##### Beginning Quality Check on Bonds ###### -! print *, 'Quality check', mpp_pe(), berg%iceberg_num + ! print *, 'Quality check', mpp_pe(), berg%iceberg_num if (quality_check) then num_unmatched_bonds=0 num_unassosiated_bond_pairs=0 @@ -2645,10 +2651,9 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) other_berg=>current_bond%other_berg if (associated(other_berg)) then other_berg_bond=>other_berg%first_bond - do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list if (associated(other_berg_bond%other_berg)) then - if (other_berg_bond%other_berg%iceberg_num==berg%iceberg_num) then + if (other_berg_bond%other_berg%iceberg_num .eq.berg%iceberg_num) then bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found endif endif @@ -2671,12 +2676,11 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) endif endif ! ##### Ending Quality Check on Bonds ###### - current_bond=>current_bond%next_bond - enddo !End of loop over current bonds - berg=>berg%next - enddo ! End of loop over all bergs - enddo; enddo !End of loop over all grid cells + enddo !End of loop over current bonds + berg=>berg%next + enddo ! End of loop over all bergs + enddo; enddo !End of loop over all grid cells number_of_bonds_all_pe=number_of_bonds call mpp_sum(number_of_bonds_all_pe) @@ -2703,7 +2707,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) write(*,'(2a)') 'diamonds, Bonds parnters not located!!!! PE=', mpp_pe() endif endif - if ((num_unmatched_bonds_all_pe == 0) .and. (num_unassosiated_bond_pairs_all_pe == 0)) then + if ((num_unmatched_bonds_all_pe .eq. 0) .and. (num_unassosiated_bond_pairs_all_pe .eq. 0)) then if (mpp_pe().eq.mpp_root_pe()) then write(stderrunit,*) "Total number of bonds is: ", number_of_bonds_all_PE, "All iceberg bonds are connected and working well" endif @@ -3450,15 +3454,6 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) ! Get the stderr unit number stderrunit=stderr() - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (present(explain)) then - if(explain) then - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: x ',x - print *,'x',x - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: y ',y - endif - endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Lx=grd%Lx pos_within_cell=.false.; xi=-999.; yj=-999. if (i-1 Date: Fri, 12 Aug 2016 11:34:30 -0400 Subject: [PATCH 148/361] A routine which implements the two equation melting model and three equation melting model have been added. These schemes have not yet been added to the thermodynamics routine, and have also not been properly tested. A unit test of these two schemes has been added. --- icebergs.F90 | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 346 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9106be9..e9a98c7 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -77,6 +77,7 @@ subroutine icebergs_init(bergs, & cos_rot, sin_rot, ocean_depth, maskmap, fractional_area) ! Arguments type(icebergs), pointer :: bergs +type(icebergs_gridded), pointer :: grd => null() integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) integer, intent(in) :: dom_x_flags, dom_y_flags real, intent(in) :: dt @@ -102,7 +103,7 @@ subroutine icebergs_init(bergs, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & cos_rot, sin_rot, ocean_depth=ocean_depth, maskmap=maskmap, fractional_area=fractional_area) - call unit_testing() + call unit_testing(bergs) call mpp_clock_begin(bergs%clock_ior) call ice_bergs_io_init(bergs,io_layout) @@ -137,14 +138,34 @@ end subroutine icebergs_init ! ############################################################################## -subroutine unit_testing() +subroutine unit_testing(bergs) ! Arguments +type(icebergs), pointer :: bergs call hexagon_test() call point_in_triangle_test() +call basal_melt_test(bergs) end subroutine unit_testing +subroutine basal_melt_test(bergs) + ! Arguments + type(icebergs), pointer :: bergs + real :: dvo,lat,salt,temp, basal_melt, thickness + logical :: Use_three_equation_model + + if (mpp_pe() .eq. mpp_root_pe() ) print *, 'Begining Basal Melting Unit Test' + dvo=0.2 ;lat=0.0 ; salt=35.0 ; temp=2.0 ;thickness=100. + Use_three_equation_model=.False. + call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) + if (mpp_pe() .eq. mpp_root_pe()) print *, 'Two equation model basal_melt =',basal_melt + + Use_three_equation_model=.True. + call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) + if (mpp_pe() .eq. mpp_root_pe()) print *, 'Three equation model basal_melt =',basal_melt + +end subroutine basal_melt_test + subroutine point_in_triangle_test() ! Arguments real :: Ax,Ay,Bx,By,Cx,Cy !Position of icebergs @@ -1301,6 +1322,329 @@ subroutine thermodynamics(bergs) end subroutine thermodynamics + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) + ! Arguments + type(icebergs), pointer :: bergs + ! Local variables + real , intent(out) :: basal_melt !Melt rate underneath the icebergs + real , intent(in) :: dvo !Speed of iceberg relative to ocean mixed layer + real , intent(in) :: salt !Salinity of mixed layer + real , intent(in) :: temp !Temperature of mixed layer + real , intent(in) :: lat !Latitude (for boundary layer calculation) + real , intent(in) :: thickness !Ice thickness - needed to work out the pressure below the ice + logical , intent(in) :: Use_three_equation_model !True uses the 3 equation model, False uses the 2 equation model. + + ! Local variables + real :: utide, ustar_bg, ustar, f_cori, absf,tfreeze + real :: Hml !Mixed layer depth + + !These could also be useful output variables if needed. + real :: t_flux, exch_vel_t, exch_vel_s,tflux_shelf,lprec + + real :: Rhoml ! Ocean mixed layer density in kg m-3. + real :: p_int ! The pressure at the ice-ocean interface, in Pa. + + real, parameter :: VK = 0.40 ! Von Karman's constant - dimensionless + real :: ZETA_N = 0.052 ! The fraction of the boundary layer over which the + ! viscosity is linearly increasing. (Was 1/8. Why?) + real, parameter :: RC = 0.20 ! critical flux Richardson number. + real :: I_ZETA_N ! The inverse of ZETA_N. + real :: I_LF ! Inverse of Latent Heat of fusion (J kg-1) + real :: I_VK ! The inverse of VK. + real :: PR, SC ! The Prandtl number and Schmidt number, nondim. +! + ! 3 equation formulation variables + real :: Sbdry ! Salinities in the ocean at the interface with the + real :: Sbdry_it ! the ice shelf, in PSU. + real :: dS_it ! The interface salinity change during an iteration, in PSU. + real :: hBL_neut ! The neutral boundary layer thickness, in m. + real :: hBL_neut_h_molec ! The ratio of the neutral boundary layer thickness + ! to the molecular boundary layer thickness, ND. + real :: wT_flux ! The vertical fluxes of heat and buoyancy just inside the + real :: wB_flux ! ocean, in C m s-1 and m2 s-3, ###CURRENTLY POSITIVE UPWARD. + real :: dB_dS ! The derivative of buoyancy with salinity, in m s-2 PSU-1. + real :: dB_dT ! The derivative of buoyancy with temperature, in m s-2 C-1. + real :: I_n_star, n_star_term + real :: dIns_dwB ! The partial derivative of I_n_star with wB_flux, in ???. + real :: dT_ustar, dS_ustar + real :: ustar_h + real :: Gam_turb + real :: Gam_mol_t, Gam_mol_s + real :: RhoCp + real :: I_RhoLF + real :: Rho0 + real :: ln_neut + real :: mass_exch + real :: Sb_min, Sb_max + real :: dS_min, dS_max + real :: density_ice +! + ! Variables used in iterating for wB_flux. + real :: wB_flux_new, DwB, dDwB_dwB_in + real :: I_Gam_T, I_Gam_S + real :: dG_dwB, iDens + logical :: Sb_min_set, Sb_max_set + + real, parameter :: c2_3 = 2.0/3.0 + integer :: it1, it3 + + !Parameters copied ice shelf module defaults (could be entered in the namelist later) + real, parameter :: dR0_dT = -0.038357 ! Partial derivative of the mixed layer density with temperature, in units of kg m-3 K-1. + real, parameter :: dR0_dS = 0.805876 ! Partial derivative of the mixed layer density with salinity, in units of kg m-3 psu-1. + real, parameter :: RHO_T0_S0 = 999.910681 ! Density of water with T=0, S=0 for linear EOS + real, parameter :: Salin_Ice =0.0 !Salinity of ice + real, parameter :: Temp_Ice = -15.0 !Salinity of ice + real, parameter :: kd_molec_salt= 8.02e-10 !The molecular diffusivity of salt in sea water at the freezing point + real, parameter :: kd_molec_temp= 1.41e-7 !The molecular diffusivity of heat in sea water at the freezing point + real, parameter :: kv_molec= 1.95e-6 !The molecular molecular kinimatic viscosity of sea water at the freezing point + real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) + real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) + real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) + real, parameter :: cdrag = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) + real, parameter :: gamma_t = 0.0 ! Exchange velcoity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independ of u_star. + ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. + real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + density_ice = bergs%rho_bergs + Rho0=rho_seawater !Note that the ice shelf code has a default of Rho0=1035 + utide=0. ! Tidal speeds, set to zero for now. + ustar_bg=0.001 !Background u_star under iceshelf. This should be linked to a value felt by the ocean boundary layer + Hml =10. !Mixed layer depth. This is an approximate value. It looks like the code is not sensitive to it (since it enters in log(Hml) + p_int= p_atm+(gravity*thickness*density_ice) ! The pressure at the ice-ocean interface, in Pa. + + ! Find the ocean mixed layer density in kg m-3. + call calculate_density(temp, salt, p_int, Rhoml, Rho_T0_S0, dR0_dT, dR0_dS) + + ! This routine finds the melt at the base of the icebergs using the 2 equation + ! model or 3 equation model. This code is adapted from the ice shelf code. Once + ! the iceberg model is inside the ocean model, we should use the same code. + + I_ZETA_N = 1.0 / ZETA_N + I_RhoLF = 1.0/(Rho0*LF) + I_LF = 1.0 / LF + SC = kv_molec/kd_molec_salt + PR = kv_molec/kd_molec_temp + I_VK = 1.0/VK + RhoCp = Rho0 * Cp_ml + + !first calculate molecular component + Gam_mol_t = 12.5 * (PR**c2_3) - 6 + Gam_mol_s = 12.5 * (SC**c2_3) - 6 + + iDens = 1.0/Rho0 + + !Preparing the mixed layer properties for use in both 2 and 3 equation version + ustar = cdrag*(dvo + utide) + ustar_h = MAX(ustar_bg, ustar) + + ! Estimate the neutral ocean boundary layer thickness as the minimum of the + ! reported ocean mixed layer thickness and the neutral Ekman depth. + !(Note that in Dan's code, f is spread over adjacent grid cells) + if ((bergs%grd%grid_is_latlon) .and. (.not. bergs%use_f_plane)) then + f_cori=(2.*omega)*sin(pi_180*lat) + else + f_cori=(2.*omega)*sin(pi_180*bergs%lat_ref) + endif + absf = abs(f_cori) !Absolute value of the Coriolis parameter + if ((absf*Hml <= VK*ustar_h) .or. (absf.eq.0.)) then + hBL_neut = Hml + else + hBL_neut = (VK*ustar_h) / absf + endif + hBL_neut_h_molec = ZETA_N * ((hBL_neut * ustar_h) / (5.0 * Kv_molec)) + ln_neut = 0.0 ; if (hBL_neut_h_molec > 1.0) ln_neut = log(hBL_neut_h_molec) + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if (.not. Use_three_equation_model) then + ! In the 2-equation form, the mixed layer turbulent exchange velocity + ! is specified and large enough that the ocean salinity at the interface + ! is about the same as the boundary layer salinity. + ! Alon: I have adapted the code so that the turbulent exchange velocoty is not constant, but rather proportional to the frictional velocity. + ! This should give you the same answers as the 3 equation model when salinity gradients in the mixed layer are zero (I think/hope) + + call calculate_TFreeze(salt, p_int, tfreeze) + + Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + + exch_vel_t= ustar_h * I_Gam_T + if (gamma_t>0.0) exch_vel_t = gamma_t !Option to set the exchange to a constant, independent of the frictional velocity (as was previously coded) + wT_flux = exch_vel_t *(temp - tfreeze) + + t_flux = RhoCp * wT_flux + tflux_shelf = 0.0 + lprec = I_LF * t_flux + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + else ! Use 3 equation model + ! 3 equation model solves for the melt rates iteratively. This is not working right now, because we don't have access to the mixed layer + ! temperature and salinty gradients + + + ! Guess sss as the iteration starting point for the boundary salinity. + Sbdry = salt ; Sb_max_set = .false. ; Sb_min_set = .false. + + ! Determine the mixed layer buoyancy flux, wB_flux. + dB_dS = (gravity / Rhoml) * dR0_dS + dB_dT = (gravity / Rhoml) * dR0_dT + + do it1 = 1,20 + ! Determine the potential temperature at the ice-ocean interface. + call calculate_TFreeze(Sbdry, p_int, tfreeze) + + dT_ustar = (temp - tfreeze) * ustar_h + dS_ustar = (salt - Sbdry) * ustar_h + + ! First, determine the buoyancy flux assuming no effects of stability + ! on the turbulence. Following H & J '99, this limit also applies + ! when the buoyancy flux is destabilizing. + + Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + wT_flux = dT_ustar * I_Gam_T + wB_flux = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux + + if (wB_flux > 0.0) then + ! The buoyancy flux is stabilizing and will reduce the tubulent + ! fluxes, and iteration is required. + n_star_term = (ZETA_N/RC) * (hBL_neut * VK) / ustar_h**3 + do it3 = 1,30 + ! n_star <= 1.0 is the ratio of working boundary layer thickness + ! to the neutral thickness. + ! hBL = n_star*hBL_neut ; hSub = 1/8*n_star*hBL + I_n_star = sqrt(1.0 + n_star_term * wB_flux) + dIns_dwB = 0.5 * n_star_term / I_n_star + if (hBL_neut_h_molec > I_n_star**2) then + Gam_turb = I_VK * ((ln_neut - 2.0*log(I_n_star)) + & + (0.5*I_ZETA_N*I_n_star - 1.0)) + dG_dwB = I_VK * ( -2.0 / I_n_star + (0.5 * I_ZETA_N)) * dIns_dwB + else + ! The layer dominated by molecular viscosity is smaller than + ! the assumed boundary layer. This should be rare! + Gam_turb = I_VK * (0.5 * I_ZETA_N*I_n_star - 1.0) + dG_dwB = I_VK * (0.5 * I_ZETA_N) * dIns_dwB + endif + + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + wT_flux = dT_ustar * I_Gam_T + wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux + + ! Find the root where dwB = 0.0 + DwB = wB_flux_new - wB_flux + if (abs(wB_flux_new - wB_flux) < & + 1e-4*(abs(wB_flux_new) + abs(wB_flux))) exit + + dDwB_dwB_in = -dG_dwB * (dB_dS * (dS_ustar * I_Gam_S**2) + & + dB_dT * (dT_ustar * I_Gam_T**2)) - 1.0 + ! This is Newton's method without any bounds. ( ### SHOULD BOUNDS BE NEEDED?) + wB_flux_new = wB_flux - DwB / dDwB_dwB_in + enddo !it3 + endif + + t_flux = RhoCp * wT_flux + exch_vel_t = ustar_h * I_Gam_T + exch_vel_s = ustar_h * I_Gam_S + + if (t_flux <= 0.0) then ! Freezing occurs, so zero ice heat flux. + lprec = I_LF * t_flux + tflux_shelf = 0.0 + else + !no conduction/perfect insulator + tflux_shelf = 0.0 + lprec = I_LF * t_flux + ! With melting, from H&J 1999, eqs (31) & (26)... + ! Q_ice ~= cp_ice * (Temp_Ice-T_freeze) * lprec + ! RhoLF*lprec = Q_ice + t_flux + ! lprec = (t_flux) / (LF + cp_ice * (T_freeze-Temp_Ice)) + ! lprec = t_flux / (LF + Cp_ice * (tfreeze - Temp_Ice)) + ! tflux_shelf = t_flux - LF*lprec + !other options: dTi/dz linear through shelf + ! dTi_dz = (Temp_Ice - tfreeze)/draft + ! tflux_shelf = - Rho_Ice * Cp_ice * KTI * dTi_dz + endif + + mass_exch = exch_vel_s * Rho0 + Sbdry_it = (salt * mass_exch + Salin_Ice * lprec) / (mass_exch + lprec) + dS_it = Sbdry_it - Sbdry + if (abs(dS_it) < 1e-4*(0.5*(salt + Sbdry + 1.e-10))) exit + + if (dS_it < 0.0) then ! Sbdry is now the upper bound. + if (Sb_max_set .and. (Sbdry > Sb_max)) & + call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (max).' ,FATAL) + Sb_max = Sbdry ; dS_max = dS_it ; Sb_max_set = .true. + else ! Sbdry is now the lower bound. + if (Sb_min_set .and. (Sbdry < Sb_min)) & + call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (min).' ,FATAL) + Sb_min = Sbdry ; dS_min = dS_it ; Sb_min_set = .true. + endif + if (Sb_min_set .and. Sb_max_set) then + ! Use the false position method for the next iteration. + Sbdry = Sb_min + (Sb_max-Sb_min) * (dS_min / (dS_min - dS_max)) + else + Sbdry = Sbdry_it + endif + Sbdry = Sbdry_it + enddo !it1 + endif +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! melt in m/s (melts of ice melted per second) + basal_melt = lprec /density_ice + +contains + + subroutine calculate_TFreeze(S, pres, T_Fr) + !Arguments + real, intent(in) :: S, pres + real, intent(out) :: T_Fr + real, parameter :: dTFr_dp = -7.53E-08 !DTFREEZE_DP in MOM_input + real, parameter :: dTFr_dS = -0.0573 !DTFREEZE_DS in MOM_input + real, parameter :: TFr_S0_P0 =0.0832 !TFREEZE_S0_P0 in MOM_input + ! This subroutine computes the freezing point potential temparature + ! (in deg C) from salinity (in psu), and pressure (in Pa) using a simple + ! linear expression, with coefficients passed in as arguments. + ! Copied from subroutine calculate_TFreeze_linear_scalar (in MOM/equation_of_state) + ! + ! Arguments: S - salinity in PSU. + ! (in) pres - pressure in Pa. + ! (out) T_Fr - Freezing point potential temperature in deg C. + ! (in) TFr_S0_P0 - The freezing point at S=0, p=0, in deg C. + ! (in) dTFr_dS - The derivatives of freezing point with salinity, in + ! deg C PSU-1. + ! (in) dTFr_dp - The derivatives of freezing point with pressure, in + ! deg C Pa-1. + T_Fr = (TFr_S0_P0 + dTFr_dS*S) + dTFr_dp*pres + end subroutine calculate_TFreeze + + subroutine calculate_density(T, S, pressure, rho, Rho_T0_S0, dRho_dT, dRho_dS) + !Arguments + real, intent(in) :: T, S, pressure + real, intent(out) :: rho + real, intent(in) :: Rho_T0_S0, dRho_dT, dRho_dS + ! * This subroutine computes the density of sea water with a trivial * + ! * linear equation of state (in kg/m^3) from salinity (sal in psu), * + ! * potential temperature (T in deg C), and pressure in Pa. * + ! Copied from subroutine calculate_density_scalar_linear (in MOM/equation_of_state) + ! * * + ! * Arguments: T - potential temperature relative to the surface in C. * + ! * (in) S - salinity in PSU. * + ! * (in) pressure - pressure in Pa. * + ! * (out) rho - in situ density in kg m-3. * + ! * (in) start - the starting point in the arrays. * + ! * (in) npts - the number of values to calculate. * + ! * (in) Rho_T0_S0 - The density at T=0, S=0, in kg m-3. * + ! * (in) dRho_dT - The derivatives of density with temperature * + ! * (in) dRho_dS - and salinity, in kg m-3 C-1 and kg m-3 psu-1. * + rho = Rho_T0_S0 + dRho_dT*T + dRho_dS*S + end subroutine calculate_density + +end subroutine find_basal_melt +! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) ! Arguments type(iceberg), pointer :: berg From 5e3153f91199edcd3b61e43aae547fe1537570c1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 17 Aug 2016 09:49:19 -0400 Subject: [PATCH 149/361] 1) Added an option to melt the icebergs without the icebergs changing mass. In this mode, the melt rates are calculated, the freshwater is fluxed into the ocean, but the icebergs do not decay. The flag for this mode is Iceberg_melt_without_decay=.true. 2) Added an option to melt the icebergs using the 2 or 3 equation model (instead of the usual parametrizations for iceberg melt). The flag for this option is melt_icebergs_as_ice_shelf=.true. In this mode, buoyant convection and wave erosion are set to zero. Later we should include a way to melt some icebergs as ice shelves and others as icebergs, perhaps using iceberg bonds. 3) Added an option to find the freshwater flux into the ocean using the difference in spread_mass. This allows melt water fluxes for icebergs to be spread across grid cells, and allows for smoother melt fields. The flag for this option is find_melt_using_spread_mass=.true. Note that the three equation melt model is not working quite yet. --- icebergs.F90 | 60 +++++++++++++++++++++++++++++++++++------- icebergs_framework.F90 | 15 ++++++++++- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index e9a98c7..7fb47d3 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1117,6 +1117,7 @@ subroutine thermodynamics(bergs) real, parameter :: perday=1./86400. integer :: grdi, grdj real :: orientation, static_berg +real :: SSS !Temporarily here ! For convenience grd=>bergs%grd @@ -1129,7 +1130,6 @@ subroutine thermodynamics(bergs) this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') - call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & this%cn, this%hi) @@ -1158,6 +1158,16 @@ subroutine thermodynamics(bergs) Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion *perday ! convert to m/s + !For icebergs acting as ice shelves + if (bergs%melt_icebergs_as_ice_shelf) then + Mv=0.0 + Mb=0.0 + Me=0.0 + SSS=33. !Temporarily here. + call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb) + Mb=max(Mb,0.) + endif + if (bergs%set_melt_rates_to_zero) then Mv=0.0 Mb=0.0 @@ -1267,13 +1277,29 @@ subroutine thermodynamics(bergs) end if endif endif - - ! Store the new state of iceberg (with L>W) - this%mass=Mnew - this%mass_of_bits=nMbits - this%thickness=Tn - this%width=min(Wn,Ln) - this%length=max(Wn,Ln) + + + !This option allows iceberg melt fluxes to enter the ocean without the icebergs changing shape + if (bergs%Iceberg_melt_without_decay) then + Mnew=this%mass + nMbits=this%mass_of_bits + Tn=this%thickness + Wn=this%width + Ln=this%length + if (bergs%bergy_bit_erosion_fraction>0.) then + Mbits=this%mass_of_bits ! mass of bergy bits (kg) + nMbits=Mbits + Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + endif + else + ! Store the new state of iceberg (with L>W) + this%mass=Mnew + this%mass_of_bits=nMbits + this%thickness=Tn + this%width=min(Wn,Ln) + this%length=max(Wn,Ln) + endif next=>this%next ! Did berg completely melt? @@ -2771,11 +2797,25 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call write_trajectory(bergs%trajectories, bergs%save_short_traj) endif - !Update diagnostic of iceberg mass spread on ocean - if (grd%id_spread_mass>0) then + !Update diagnostic of iceberg mass spread on ocean,MP1 + if ( (grd%id_spread_mass>0) .or. (bergs%find_melt_using_spread_mass) ) then + if ((bergs%find_melt_using_spread_mass) ) then + grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) !Temporarily using the variable calving for storing old mass (not sure better way) + endif grd%spread_mass(:,:)=0. within_iceberg_model=.True. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model) + if (bergs%find_melt_using_spread_mass) then + do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec + if (grd%area(i,j)>0.0) then + grd%floating_melt(i,j)=max((grd%floating_melt(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) + !grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. + grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*0.0 !Not 100% sure this is correct. + else + grd%floating_melt(i,j)=0.0 + endif + enddo ;enddo + endif endif ! Gridded diagnostics diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 49ba07a..3525c47 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -219,6 +219,10 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. + logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. + logical :: melt_icebergs_as_ice_shelf=.False. !Uses iceshelf type thermodynamics + logical :: Iceberg_melt_without_decay=.False. !Allows icebergs meltwater fluxes to enter the ocean, without the iceberg decaying or changing shape. logical :: add_iceberg_thickness_to_SSH=.False. !Adds the iceberg contribution to SSH. logical :: override_iceberg_velocities=.False. !Allows you to set a fixed iceberg velocity for all non-static icebergs. logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation @@ -342,6 +346,10 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. +logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. +logical :: melt_icebergs_as_ice_shelf=.False. !Uses iceshelf type thermodynamics +logical :: Iceberg_melt_without_decay=.False. !Allows icebergs meltwater fluxes to enter the ocean, without the iceberg decaying or changing shape. logical :: add_iceberg_thickness_to_SSH=.False. !Adds the iceberg contribution to SSH. logical :: override_iceberg_velocities=.False. !Allows you to set a fixed iceberg velocity for all non-static icebergs. logical :: use_f_plane=.False. !Flag to use a f-plane for the rotation @@ -375,7 +383,8 @@ subroutine ice_bergs_framework_init(bergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & - grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH + grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & + Use_three_equation_model,find_melt_using_spread_mass ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -738,6 +747,10 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%find_melt_using_spread_mass=find_melt_using_spread_mass + bergs%Use_three_equation_model=Use_three_equation_model + bergs%melt_icebergs_as_ice_shelf=melt_icebergs_as_ice_shelf + bergs%Iceberg_melt_without_decay=Iceberg_melt_without_decay bergs%add_iceberg_thickness_to_SSH=add_iceberg_thickness_to_SSH bergs%override_iceberg_velocities=override_iceberg_velocities bergs%use_f_plane=use_f_plane From b2b19086f021f2f2989f4d9f00aebca328f4d632 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 17 Aug 2016 10:11:43 -0400 Subject: [PATCH 150/361] Added an optional argument to included sea surface salinity in the icebergs_run call. --- icebergs.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 522d0cd..fe06c5c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1109,13 +1109,14 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger) + stagger, stress_stagger,sss) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time real, dimension(:,:), intent(inout) :: calving, calving_hflx real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger +real, dimension(:,:), optional, intent(in) :: sss ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd From 6923967c48e13e1cbbe6dd074be7535d7458f41e Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 17 Aug 2016 10:59:27 -0400 Subject: [PATCH 151/361] Added an optional argument to included sea surface salinity in the icebergs_run call. --- icebergs.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7fb47d3..6125f27 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2530,13 +2530,14 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger) + stagger, stress_stagger,sss) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time real, dimension(:,:), intent(inout) :: calving, calving_hflx real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger +real, dimension(:,:), optional, intent(in) :: sss ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd From 4106264e6074d08b94a6cbeb7b9d6a6c99d8432c Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 17 Aug 2016 13:15:57 -0400 Subject: [PATCH 152/361] Added sea surface salinity to the iceberg code. The sss is added to icebergs_run as an optional argument. It is used in the thermodynamics when using the three equation model. The sss is set to -1 when no salinity is provided by the sea ice model. --- icebergs.F90 | 44 +++++++++++++++++++++++++++++++----------- icebergs_framework.F90 | 21 +++++++++++++++----- icebergs_io.F90 | 7 ++++++- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 6125f27..b157542 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -638,7 +638,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a logical, optional :: debug_flag ! Local variables type(icebergs_gridded), pointer :: grd -real :: uo, vo, ui, vi, ua, va, uwave, vwave, ssh_x, ssh_y, sst, cn, hi +real :: uo, vo, ui, vi, ua, va, uwave, vwave, ssh_x, ssh_y, sst, sss, cn, hi real :: f_cori, T, D, W, L, M, F real :: drag_ocn, drag_atm, drag_ice, wave_rad real :: c_ocn, c_atm, c_ice @@ -688,7 +688,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a grd=>bergs%grd ! Interpolate gridded fields to berg - Note: It should be possible to move this to evolve, so that it only needs to be called once. !!!! - call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) + call interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi) if ((grd%grid_is_latlon) .and. (.not. bergs%use_f_plane)) then f_cori=(2.*omega)*sin(pi_180*lat) @@ -1029,6 +1029,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a call dump_locfld(grd,i,j,grd%msk,'MSK') call dump_locfld(grd,i,j,grd%ssh,'SSH') call dump_locfld(grd,i,j,grd%sst,'SST') + call dump_locfld(grd,i,j,grd%sss,'SSS') call dump_locvel(grd,i,j,grd%uo,'Uo') call dump_locvel(grd,i,j,grd%vo,'Vo') call dump_locvel(grd,i,j,grd%ua,'Ua') @@ -1132,8 +1133,9 @@ subroutine thermodynamics(bergs) if (debug) call check_position(grd, this, 'thermodynamics (top)') call interp_flds(grd, this%ine, this%jne, this%xi, this%yj, this%uo, this%vo, & this%ui, this%vi, this%ua, this%va, this%ssh_x, this%ssh_y, this%sst, & - this%cn, this%hi) + this%sss,this%cn, this%hi) SST=this%sst + SSS=this%sss IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration M=this%mass T=this%thickness ! total thickness @@ -1163,7 +1165,7 @@ subroutine thermodynamics(bergs) Mv=0.0 Mb=0.0 Me=0.0 - SSS=33. !Temporarily here. + if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb) Mb=max(Mb,0.) endif @@ -2371,12 +2373,12 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q end subroutine Hexagon_into_quadrants_using_triangles -subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi) +subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j real, intent(in) :: xi, yj -real, intent(out) :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi +real, intent(out) :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi ! Local variables real :: cos_rot, sin_rot #ifdef USE_OLD_SSH_GRADIENT @@ -2422,6 +2424,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, ! These fields are cell centered (A-grid) and would ! best be interpolated using PLM. For now we use PCM! sst=grd%sst(i,j) ! A-grid + sss=grd%sss(i,j) ! A-grid cn=grd%cn(i,j) ! A-grid hi=grd%hi(i,j) ! A-grid @@ -2479,10 +2482,10 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, if (((((uo.ne.uo) .or. (vo.ne.vo)) .or. ((ui.ne.ui) .or. (vi.ne.vi))) .or. & (((ua.ne.ua) .or. (va.ne.va)) .or. ((ssh_x.ne.ssh_x) .or. (ssh_y.ne.ssh_y)))) .or. & - (((sst.ne. sst) .or. (cn.ne.cn)) .or. (hi.ne. hi))) then + (((sst.ne. sst) .or. (sss.ne. sss) .or. (cn.ne.cn)) .or. (hi.ne. hi))) then write(stderrunit,*) 'diamonds, Error in interpolate: uo,vo,ui,vi',uo, vo, ui, vi write(stderrunit,*) 'diamonds, Error in interpolate: ua,va,ssh_x,ssh_y', ua, va, ssh_x, ssh_y - write(stderrunit,*) 'diamonds, Error in interpolate: sst,cn,hi', sst, cn, hi, mpp_pe() + write(stderrunit,*) 'diamonds, Error in interpolate: sst,cn,hi', sst, sss, cn, hi, mpp_pe() call error_mesg('diamonds, interp fields', 'field interpaolations has NaNs', FATAL) endif @@ -2530,7 +2533,7 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger,sss) + stagger, stress_stagger, sss) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time @@ -2716,6 +2719,16 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_update_domains(grd%cn, grd%domain) grd%hi(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=hi(:,:) call mpp_update_domains(grd%hi, grd%domain) + + !Adding gridded salinity. + if (present(sss)) then + grd%sss(grd%isc:grd%iec,grd%jsc:grd%jec)=sss(:,:) + else + grd%sss(grd%isc:grd%iec,grd%jsc:grd%jec)=-1.0 + if ((bergs%use_mixed_layer_salinity_for_thermo) .and. (bergs%melt_icebergs_as_ice_shelf)) then + call error_mesg('diamonds, icebergs_run', 'Can not use salinity for thermo. Ocean ML salinity not present!', FATAL) + endif + endif !Make sure that gridded values agree with mask (to get ride of NaN values) do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed @@ -2724,8 +2737,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%ua(i,j) = 0.0 ; grd%va(i,j) = 0.0 grd%uo(i,j) = 0.0 ; grd%vo(i,j) = 0.0 grd%ui(i,j) = 0.0 ; grd%vi(i,j) = 0.0 - grd%sst(i,j) = 0.0; grd%cn(i,j) = 0.0 - grd%hi(i,j) = 0.0 + grd%sst(i,j)= 0.0; grd%sss(i,j)= 0.0 + grd%cn(i,j) = 0.0 ; grd%hi(i,j) = 0.0 endif if (grd%ua(i,j) .ne. grd%ua(i,j)) grd%ua(i,j)=0. if (grd%va(i,j) .ne. grd%va(i,j)) grd%va(i,j)=0. @@ -2734,6 +2747,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (grd%ui(i,j) .ne. grd%ui(i,j)) grd%ui(i,j)=0. if (grd%vi(i,j) .ne. grd%vi(i,j)) grd%vi(i,j)=0. if (grd%sst(i,j) .ne. grd%sst(i,j)) grd%sst(i,j)=0. + if (grd%sss(i,j) .ne. grd%sss(i,j)) grd%sss(i,j)=0. if (grd%cn(i,j) .ne. grd%cn(i,j)) grd%cn(i,j)=0. if (grd%hi(i,j) .ne. grd%hi(i,j)) grd%hi(i,j)=0. enddo; enddo @@ -2834,6 +2848,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_va, grd%va(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_sst>0) & lerr=send_data(grd%id_sst, grd%sst(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_sss>0) & + lerr=send_data(grd%id_sss, grd%sss(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_cn>0) & lerr=send_data(grd%id_cn, grd%cn(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_hi>0) & @@ -3597,6 +3613,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) call print_fld(grd, grd%msk, 'msk') call print_fld(grd, grd%ssh, 'ssh') call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed @@ -3739,6 +3756,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call print_fld(grd, grd%msk, 'msk') call print_fld(grd, grd%ssh, 'ssh') call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed @@ -3796,6 +3814,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call print_fld(grd, grd%msk, 'msk') call print_fld(grd, grd%ssh, 'ssh') call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed @@ -3852,6 +3871,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call print_fld(grd, grd%msk, 'msk') call print_fld(grd, grd%ssh, 'ssh') call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed @@ -3928,6 +3948,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call print_fld(grd, grd%msk, 'msk') call print_fld(grd, grd%ssh, 'ssh') call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') call print_fld(grd, grd%hi, 'hi') write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed @@ -4485,6 +4506,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%va) deallocate(bergs%grd%ssh) deallocate(bergs%grd%sst) + deallocate(bergs%grd%sss) deallocate(bergs%grd%cn) deallocate(bergs%grd%hi) deallocate(bergs%grd%domain) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3525c47..3d158c7 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -16,7 +16,7 @@ module ice_bergs_framework implicit none ; private integer :: buffer_width=27 !Changed from 20 to 28 by Alon -integer :: buffer_width_traj=30 !Changed from 23 by Alon +integer :: buffer_width_traj=31 !Changed from 23 by Alon !integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon !integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes @@ -103,6 +103,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: va=>null() ! Atmosphere meridional flow (m/s) real, dimension(:,:), pointer :: ssh=>null() ! Sea surface height (m) real, dimension(:,:), pointer :: sst=>null() ! Sea surface temperature (oC) + real, dimension(:,:), pointer :: sss=>null() ! Sea surface salinity (psu) real, dimension(:,:), pointer :: cn=>null() ! Sea-ice concentration (0 to 1) real, dimension(:,:), pointer :: hi=>null() ! Sea-ice thickness (m) real, dimension(:,:), pointer :: calving=>null() ! Calving mass rate [frozen runoff] (kg/s) (into stored ice) @@ -137,7 +138,7 @@ module ice_bergs_framework integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_spread_mass=-1 - integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1 + integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -147,7 +148,7 @@ module ice_bergs_framework real :: lon, lat, day real :: mass, thickness, width, length, uvel, vvel real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi, halo_berg, static_berg + real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi, halo_berg, static_berg real :: mass_of_bits, heat_density integer :: year, iceberg_num type(xyt), pointer :: next=>null() @@ -167,7 +168,7 @@ module ice_bergs_framework integer :: ine, jne ! nearest index in NE direction (for convenience) real :: xi, yj ! Non-dimensional coords within current cell (0..1) ! Environment variables (as seen by the iceberg) - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, cn, hi + real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi type(xyt), pointer :: trajectory=>null() type(bond), pointer :: first_bond=>null() !First element of bond list. end type iceberg @@ -219,6 +220,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. logical :: melt_icebergs_as_ice_shelf=.False. !Uses iceshelf type thermodynamics @@ -346,6 +348,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. logical :: melt_icebergs_as_ice_shelf=.False. !Uses iceshelf type thermodynamics @@ -384,7 +387,7 @@ subroutine ice_bergs_framework_init(bergs, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & - Use_three_equation_model,find_melt_using_spread_mass + Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -513,6 +516,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%va(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%va(:,:)=0. allocate( grd%ssh(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%ssh(:,:)=0. allocate( grd%sst(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%sst(:,:)=0. + allocate( grd%sss(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%sss(:,:)=0. allocate( grd%cn(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%cn(:,:)=0. allocate( grd%hi(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%hi(:,:)=0. allocate( grd%tmp(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%tmp(:,:)=0. @@ -747,6 +751,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%use_mixed_layer_salinity_for_thermo=use_mixed_layer_salinity_for_thermo bergs%find_melt_using_spread_mass=find_melt_using_spread_mass bergs%Use_three_equation_model=Use_three_equation_model bergs%melt_icebergs_as_ice_shelf=melt_icebergs_as_ice_shelf @@ -846,6 +851,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Atmos meridional component of velocity', 'm s^-1') grd%id_sst=register_diag_field('icebergs', 'sst', axes, Time, & 'Sea surface temperature', 'degrees_C') + grd%id_sss=register_diag_field('icebergs', 'sss', axes, Time, & + 'Sea surface salinity', 'psu') grd%id_cn=register_diag_field('icebergs', 'cn', axes, Time, & 'Sea ice concentration', '(fraction)') grd%id_hi=register_diag_field('icebergs', 'hi', axes, Time, & @@ -1945,6 +1952,7 @@ subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) buff%data(28,n)=traj%byn !Alon buff%data(29,n)=traj%halo_berg !Alon buff%data(30,n)=traj%static_berg !Alon + buff%data(31,n)=traj%sss endif end subroutine pack_traj_into_buffer2 @@ -1992,6 +2000,7 @@ subroutine unpack_traj_from_buffer2(first, buff, n, save_short_traj) traj%byn=buff%data(28,n) !Alon traj%halo_berg=buff%data(29,n) !Alon traj%static_berg=buff%data(30,n) !Alon + traj%sss=buff%data(31,n) endif call append_posn(first, traj) @@ -2810,6 +2819,7 @@ subroutine record_posn(bergs) posn%ssh_x=this%ssh_x posn%ssh_y=this%ssh_y posn%sst=this%sst + posn%sss=this%sss posn%cn=this%cn posn%hi=this%hi posn%axn=this%axn @@ -3773,6 +3783,7 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%vi, 'vi') call grd_chksum2(grd, grd%ssh, 'ssh') call grd_chksum2(grd, grd%sst, 'sst') + call grd_chksum2(grd, grd%sss, 'sss') call grd_chksum2(grd, grd%hi, 'hi') call grd_chksum2(grd, grd%cn, 'cn') call grd_chksum2(grd, grd%calving, 'calving') diff --git a/icebergs_io.F90 b/icebergs_io.F90 index d01c767..ec8017d 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1396,7 +1396,7 @@ subroutine write_trajectory(trajectory, save_short_traj) ! Local variables integer :: iret, ncid, i_dim, i integer :: lonid, latid, yearid, dayid, uvelid, vvelid, iceberg_numid -integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid +integer :: uoid, void, uiid, viid, uaid, vaid, sshxid, sshyid, sstid, sssid integer :: cnid, hiid integer :: mid, did, wid, lid, mbid, hdid character(len=37) :: filename @@ -1534,6 +1534,7 @@ subroutine write_trajectory(trajectory, save_short_traj) sshxid = inq_varid(ncid, 'ssh_x') sshyid = inq_varid(ncid, 'ssh_y') sstid = inq_varid(ncid, 'sst') + sssid = inq_varid(ncid, 'sss') cnid = inq_varid(ncid, 'cn') hiid = inq_varid(ncid, 'hi') endif @@ -1566,6 +1567,7 @@ subroutine write_trajectory(trajectory, save_short_traj) sshxid = def_var(ncid, 'ssh_x', NF_DOUBLE, i_dim) sshyid = def_var(ncid, 'ssh_y', NF_DOUBLE, i_dim) sstid = def_var(ncid, 'sst', NF_DOUBLE, i_dim) + sssid = def_var(ncid, 'sss', NF_DOUBLE, i_dim) cnid = def_var(ncid, 'cn', NF_DOUBLE, i_dim) hiid = def_var(ncid, 'hi', NF_DOUBLE, i_dim) endif @@ -1619,6 +1621,8 @@ subroutine write_trajectory(trajectory, save_short_traj) call put_att(ncid, sshyid, 'units', 'non-dim') call put_att(ncid, sstid, 'long_name', 'sea surface temperature') call put_att(ncid, sstid, 'units', 'degrees_C') + call put_att(ncid, sssid, 'long_name', 'sea surface salinity') + call put_att(ncid, sssid, 'units', 'psu') call put_att(ncid, cnid, 'long_name', 'sea ice concentration') call put_att(ncid, cnid, 'units', 'none') call put_att(ncid, hiid, 'long_name', 'sea ice thickness') @@ -1661,6 +1665,7 @@ subroutine write_trajectory(trajectory, save_short_traj) call put_double(ncid, sshxid, i, this%ssh_x) call put_double(ncid, sshyid, i, this%ssh_y) call put_double(ncid, sstid, i, this%sst) + call put_double(ncid, sssid, i, this%sss) call put_double(ncid, cnid, i, this%cn) call put_double(ncid, hiid, i, this%hi) endif From a0d4913459afc2eea3c7305714e5f75f74d28791 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 23 Aug 2016 17:11:19 -0400 Subject: [PATCH 153/361] When using the 3 equation iceberg model, when the iteration does not converge, the two equation model is used instead. This gives an error when run in debug mode. --- icebergs.F90 | 81 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index b157542..3b25127 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -152,16 +152,17 @@ subroutine basal_melt_test(bergs) ! Arguments type(icebergs), pointer :: bergs real :: dvo,lat,salt,temp, basal_melt, thickness + integer :: iceberg_num logical :: Use_three_equation_model if (mpp_pe() .eq. mpp_root_pe() ) print *, 'Begining Basal Melting Unit Test' - dvo=0.2 ;lat=0.0 ; salt=35.0 ; temp=2.0 ;thickness=100. + dvo=0.2 ;lat=0.0 ; salt=35.0 ; temp=2.0 ;thickness=100.; iceberg_num=0 Use_three_equation_model=.False. - call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) + call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt,iceberg_num) if (mpp_pe() .eq. mpp_root_pe()) print *, 'Two equation model basal_melt =',basal_melt Use_three_equation_model=.True. - call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) + call find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt,iceberg_num) if (mpp_pe() .eq. mpp_root_pe()) print *, 'Three equation model basal_melt =',basal_melt end subroutine basal_melt_test @@ -1166,7 +1167,7 @@ subroutine thermodynamics(bergs) Mb=0.0 Me=0.0 if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 - call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb) + call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb,this%iceberg_num) Mb=max(Mb,0.) endif @@ -1352,7 +1353,7 @@ end subroutine thermodynamics !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt) +subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt,iceberg_num) ! Arguments type(icebergs), pointer :: bergs ! Local variables @@ -1361,6 +1362,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic real , intent(in) :: salt !Salinity of mixed layer real , intent(in) :: temp !Temperature of mixed layer real , intent(in) :: lat !Latitude (for boundary layer calculation) + integer , intent(in) :: iceberg_num !Iceberg number, used for debugging (error messages) real , intent(in) :: thickness !Ice thickness - needed to work out the pressure below the ice logical , intent(in) :: Use_three_equation_model !True uses the 3 equation model, False uses the 2 equation model. @@ -1414,6 +1416,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic real :: I_Gam_T, I_Gam_S real :: dG_dwB, iDens logical :: Sb_min_set, Sb_max_set + logical :: out_of_bounds real, parameter :: c2_3 = 2.0/3.0 integer :: it1, it3 @@ -1486,33 +1489,14 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic ln_neut = 0.0 ; if (hBL_neut_h_molec > 1.0) ln_neut = log(hBL_neut_h_molec) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - if (.not. Use_three_equation_model) then - ! In the 2-equation form, the mixed layer turbulent exchange velocity - ! is specified and large enough that the ocean salinity at the interface - ! is about the same as the boundary layer salinity. - ! Alon: I have adapted the code so that the turbulent exchange velocoty is not constant, but rather proportional to the frictional velocity. - ! This should give you the same answers as the 3 equation model when salinity gradients in the mixed layer are zero (I think/hope) - - call calculate_TFreeze(salt, p_int, tfreeze) - - Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) - I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) - - exch_vel_t= ustar_h * I_Gam_T - if (gamma_t>0.0) exch_vel_t = gamma_t !Option to set the exchange to a constant, independent of the frictional velocity (as was previously coded) - wT_flux = exch_vel_t *(temp - tfreeze) - - t_flux = RhoCp * wT_flux - tflux_shelf = 0.0 - lprec = I_LF * t_flux - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - else ! Use 3 equation model + if (Use_three_equation_model) then ! Use 3 equation model ! 3 equation model solves for the melt rates iteratively. This is not working right now, because we don't have access to the mixed layer ! temperature and salinty gradients ! Guess sss as the iteration starting point for the boundary salinity. Sbdry = salt ; Sb_max_set = .false. ; Sb_min_set = .false. + out_of_bounds=.false. ! Determine the mixed layer buoyancy flux, wB_flux. dB_dS = (gravity / Rhoml) * dR0_dS @@ -1601,12 +1585,24 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic if (abs(dS_it) < 1e-4*(0.5*(salt + Sbdry + 1.e-10))) exit if (dS_it < 0.0) then ! Sbdry is now the upper bound. - if (Sb_max_set .and. (Sbdry > Sb_max)) & - call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (max).' ,FATAL) + if (Sb_max_set .and. (Sbdry > Sb_max)) then + if (debug) then + call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (max).' ,WARNING) + print *, 'Sbdry error: iceberg_num,dvo,temp,salt,lat,thickness :',iceberg_num,dvo,temp,salt,lat,thickness + endif + out_of_bounds=.true. + exit + endif Sb_max = Sbdry ; dS_max = dS_it ; Sb_max_set = .true. else ! Sbdry is now the lower bound. - if (Sb_min_set .and. (Sbdry < Sb_min)) & - call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (min).' ,FATAL) + if (Sb_min_set .and. (Sbdry < Sb_min)) then + if (debug) then + call error_mesg('diamonds,Find basal melt', 'shelf_calc_flux: Irregular iteration for Sbdry (min).' ,WARNING) + print *, 'Sbdry error: iceberg_num,dvo,temp,salt,lat,thickness :',iceberg_num,dvo,temp,salt,lat,thickness + endif + out_of_bounds=.true. + exit + endif Sb_min = Sbdry ; dS_min = dS_it ; Sb_min_set = .true. endif if (Sb_min_set .and. Sb_max_set) then @@ -1618,7 +1614,30 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic Sbdry = Sbdry_it enddo !it1 endif -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ((.not. Use_three_equation_model) .or. (out_of_bounds)) then + ! In the 2-equation form, the mixed layer turbulent exchange velocity + ! is specified and large enough that the ocean salinity at the interface + ! is about the same as the boundary layer salinity. + ! Alon: I have adapted the code so that the turbulent exchange velocoty is not constant, but rather proportional to the frictional velocity. + ! This should give you the same answers as the 3 equation model when salinity gradients in the mixed layer are zero (I think/hope) + ! Use 2-equation model when 3 equation version fails. + + call calculate_TFreeze(salt, p_int, tfreeze) + + Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + + exch_vel_t= ustar_h * I_Gam_T + if (gamma_t>0.0) exch_vel_t = gamma_t !Option to set the exchange to a constant, independent of the frictional velocity (as was previously coded) + wT_flux = exch_vel_t *(temp - tfreeze) + + t_flux = RhoCp * wT_flux + tflux_shelf = 0.0 + lprec = I_LF * t_flux + endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! melt in m/s (melts of ice melted per second) basal_melt = lprec /density_ice From 30ab56fd15a1a82e8eaab885170f9a6fa218ce77 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Aug 2016 10:57:46 -0400 Subject: [PATCH 154/361] A option has been added which allows the incoming calving field to be smoothed over a time scale tau_calving. This is done so that the calving will be uncoupled from the seasonal cylce. The smoothing is achieved by keeping track of a running mean calving and calving heat flux. These running means are time stepped with a Newton cooling type relaxation over a time scale tau_calving. When tau_calving is set to zero, the instantious calving field is used, and it should revert back to the original scheme. This is the default option and should not change the answers. --- icebergs.F90 | 39 +++++++++++++++++++++++++++++++++++++++ icebergs_framework.F90 | 19 +++++++++++++++++-- icebergs_io.F90 | 25 +++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 522d0cd..3fe3971 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1177,10 +1177,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, 'diamonds: y,m,d=',iyr, imon, iday,' h,m,s=', ihr, imin, isec, & ' yr,yrdy=', bergs%current_year, bergs%current_yearday + ! Adapt calving flux from coupler for use here !call sanitize_field(grd%calving,1.e20) tmpsum=sum( calving(:,:)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%net_calving_received=bergs%net_calving_received+tmpsum*bergs%dt + + call get_running_mean_calving(bergs,calving,calving_hflx) grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)=calving(:,:) ! Units of kg/m2/s grd%calving(:,:)=grd%calving(:,:)*grd%msk(:,:)*grd%area(:,:) ! Convert to kg/s tmpsum=sum( grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) @@ -1368,6 +1371,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_mass, grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_stored_ice>0) & lerr=send_data(grd%id_stored_ice, grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) + if (grd%id_mean_calving>0) & + lerr=send_data(grd%id_mean_calving, grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_mean_calving_hflx>0) & + lerr=send_data(grd%id_mean_calving_hflx, grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_real_calving>0) & lerr=send_data(grd%id_real_calving, grd%real_calving(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) if (grd%id_ssh>0) & @@ -1412,6 +1419,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%net_outgoing_calving_heat=bergs%net_outgoing_calving_heat+tmpsum*bergs%dt ! Units of J if (lbudget) then bergs%stored_end=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) + bergs%mean_calving_end=sum( grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%mean_calving_hflx_end=sum( grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%stored_heat_end=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%floating_mass_end=sum_mass(bergs%first) bergs%icebergs_mass_end=sum_mass(bergs%first,justbergs=.true.) @@ -1613,6 +1622,35 @@ subroutine report_ibudget(budgetstr,instr,inval,outstr,outval,delstr,startval,en 200 format("diamonds: ",a19,10(a18,"=",i14,x,:,",")) end subroutine report_ibudget + subroutine get_running_mean_calving(bergs,calving,calving_hflx) + ! Arguments + type(icebergs), pointer :: bergs + real, dimension(:,:), intent(inout) :: calving, calving_hflx + ! Local variables + real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) + real :: tau !Relaxation timescale in seconds + !This subroutine takes in the new calving and calving_hflx, and uses them to time step a mean_calving value + !The time stepping uses a time scale tau. When tau is equal to zero, the + !running mean is exactly equal to the new calving value. + !In the first iteration (or if the running mean is not yet set), then alpha is set to zero (this is done using the 999. trick) + + !Applying "Newton cooling" with timescale tau, to smooth out the calving field. + tau=bergs%tau_calving/(365.*24*60*60) !Converting time scale from years to seconds + alpha=tau/(tau+bergs%dt) + if ((maxval(bergs%grd%mean_calving).eq.999.0) .or. (maxval(bergs%grd%mean_calving_hflx).eq.999.0)) alpha=0.0 !Special case for first time step. + bergs%grd%mean_calving=calving + alpha*(bergs%grd%mean_calving-calving) + bergs%grd%mean_calving_hflx=calving + alpha*(bergs%grd%mean_calving_hflx-calving) + + !Removing negative values + bergs%grd%mean_calving=max(bergs%grd%mean_calving,0.) + bergs%grd%mean_calving_hflx=max(bergs%grd%mean_calving_hflx,0.) + + !Setting calving used by the iceberg model equal to the running mean + calving=bergs%grd%mean_calving + calving_hflx=bergs%grd%mean_calving_hflx + + end subroutine get_running_mean_calving + end subroutine icebergs_run ! ############################################################################## @@ -2792,6 +2830,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%tmp) deallocate(bergs%grd%tmpc) deallocate(bergs%grd%stored_ice) + deallocate(bergs%grd%mean_calving) deallocate(bergs%grd%real_calving) deallocate(bergs%grd%uo) deallocate(bergs%grd%vo) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d6e6763..3940961 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -111,6 +111,8 @@ module ice_bergs_framework real, dimension(:,:), pointer :: tmp=>null() ! Temporary work space real, dimension(:,:), pointer :: tmpc=>null() ! Temporary work space real, dimension(:,:,:), pointer :: stored_ice=>null() ! Accumulated ice mass flux at calving locations (kg) + real, dimension(:,:), pointer :: mean_calving=>null() !Running mean for ice calving + real, dimension(:,:), pointer :: mean_calving_hflx=>null() !Running mean for ice calving real, dimension(:,:), pointer :: stored_heat=>null() ! Heat content of stored ice (J) real, dimension(:,:,:), pointer :: real_calving=>null() ! Calving rate into iceberg class at calving locations (kg/s) real, dimension(:,:), pointer :: iceberg_heat_content=>null() ! Distributed heat content of bergs (J/m^2) @@ -123,7 +125,7 @@ module ice_bergs_framework integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 - integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1 + integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_mean_calving=-1, id_mean_calving_hflx=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -192,6 +194,7 @@ module ice_bergs_framework logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovation real :: speed_limit=0. ! CFL speed limit for a berg [m/s] + real :: tau_calving=0. ! Time scale for smoothing out calving field (years) real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities) real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -205,6 +208,8 @@ module ice_bergs_framework real :: net_incoming_calving_heat=0., net_outgoing_calving_heat=0. real :: net_incoming_calving_heat_used=0., net_heat_to_bergs=0. real :: stored_start=0., stored_end=0. + real :: mean_calving_start=0., mean_calving_end=0. + real :: mean_calving_hflx_start=0., mean_calving_hflx_end=0. real :: stored_heat_start=0., stored_heat_end=0., net_heat_to_ocean=0. real :: net_calving_used=0., net_calving_to_bergs=0. real :: floating_mass_start=0., floating_mass_end=0. @@ -284,6 +289,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean real :: speed_limit=0. ! CFL speed limit for a berg +real :: tau_calving=0. ! Time scale for smoothing out calving field (years) real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon @@ -304,7 +310,7 @@ subroutine ice_bergs_framework_init(bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, tip_parameter, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & - read_old_restarts + read_old_restarts,tau_calving ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -415,6 +421,8 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. allocate( grd%stored_ice(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%stored_ice(:,:,:)=0. + allocate( grd%mean_calving(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mean_calving(:,:)=999. + allocate( grd%mean_calving_hflx(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mean_calving_hflx(:,:)=999. allocate( grd%real_calving(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%real_calving(:,:,:)=0. allocate( grd%uo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%uo(:,:)=0. allocate( grd%vo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%vo(:,:)=0. @@ -557,6 +565,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%passive_mode=passive_mode bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit + bergs%tau_calving=tau_calving bergs%tip_parameter=tip_parameter bergs%Runge_not_Verlet=Runge_not_Verlet !Alon bergs%use_updated_rolling_scheme=use_updated_rolling_scheme !Alon @@ -615,6 +624,10 @@ subroutine ice_bergs_framework_init(bergs, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & 'Calving into iceberg class', 'kg/s') + grd%id_mean_calving=register_diag_field('icebergs', 'mean_calving', axes, Time, & + 'Running mean of calving', 'kg/s') + grd%id_mean_calving_hflx=register_diag_field('icebergs', 'mean_calving_hflx', axes, Time, & + 'Running mean of calving heat flux', 'J/s') grd%id_uo=register_diag_field('icebergs', 'uo', axes, Time, & 'Ocean zonal component of velocity', 'm s^-1') grd%id_vo=register_diag_field('icebergs', 'vo', axes, Time, & @@ -2593,6 +2606,8 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%mass, 'mass') call grd_chksum3(grd, grd%mass_on_ocean, 'mass_on_ocean') call grd_chksum3(grd, grd%stored_ice, 'stored_ice') + call grd_chksum2(grd, grd%mean_calving, 'mean_calving') + call grd_chksum2(grd, grd%mean_calving_hflx, 'mean_calving_hflx') call grd_chksum2(grd, grd%stored_heat, 'stored_heat') call grd_chksum2(grd, grd%melt_buoy, 'melt_b') call grd_chksum2(grd, grd%melt_eros, 'melt_e') diff --git a/icebergs_io.F90 b/icebergs_io.F90 index e2633c4..eea6035 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -306,6 +306,9 @@ subroutine write_restart(bergs) call write_data(filename, 'stored_heat', bergs%grd%stored_heat, bergs%grd%domain) !call grd_chksum2(bergs%grd, bergs%grd%iceberg_counter_grd, 'write iceberg_counter_grd') call write_data(filename, 'iceberg_counter_grd', bergs%grd%iceberg_counter_grd, bergs%grd%domain) + call grd_chksum2(bergs%grd, bergs%grd%stored_ice, 'write calving mean') + call write_data(filename, 'mean_calving', bergs%grd%mean_calving, bergs%grd%domain) + call write_data(filename, 'mean_calving_hflx', bergs%grd%mean_calving_hflx, bergs%grd%domain) contains function last_berg(berg) @@ -1006,6 +1009,24 @@ subroutine read_restart_calving(bergs) 'diamonds, read_restart_calving: stored_heat WAS NOT FOUND in the file. Setting to 0.' grd%stored_heat(:,:)=0. endif + if (field_exist(filename, 'mean_calving')) then + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: reading mean_calving from restart file.' + call read_data(filename, 'mean_calving', grd%mean_calving, grd%domain) + else + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: mean_calving WAS NOT FOUND in the file. Setting to 0.' + grd%mean_calving(:,:)=999. + endif + if (field_exist(filename, 'mean_calving_hflx')) then + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: reading mean_calving_hflx from restart file.' + call read_data(filename, 'mean_calving_hflx', grd%mean_calving_hflx, grd%domain) + else + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: mean_calving_hflx WAS NOT FOUND in the file. Setting to 0.' + grd%mean_calving_hflx(:,:)=999. + endif if (field_exist(filename, 'iceberg_counter_grd')) then if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: reading iceberg_counter_grd from restart file.' @@ -1045,9 +1066,13 @@ subroutine read_restart_calving(bergs) endif call grd_chksum3(bergs%grd, bergs%grd%stored_ice, 'read_restart_calving, stored_ice') + call grd_chksum2(bergs%grd, bergs%grd%mean_calving, 'read_restart_calving, mean_calving') + call grd_chksum2(bergs%grd, bergs%grd%mean_calving_hflx, 'read_restart_calving, mean_calving_hflx') call grd_chksum2(bergs%grd, bergs%grd%stored_heat, 'read_restart_calving, stored_heat') bergs%stored_start=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) + bergs%mean_calving_start=sum( grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%mean_calving_hflx_start=sum( grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum( bergs%stored_start ) bergs%stored_heat_start=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum( bergs%stored_heat_start ) From 7e257bb0f9574bc60ed579fd9be5a6cfb429b90d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 24 Aug 2016 11:06:16 -0400 Subject: [PATCH 155/361] Deallocate mean_calving_hflx has been added --- icebergs.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/icebergs.F90 b/icebergs.F90 index 3fe3971..6c2a597 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2831,6 +2831,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%tmpc) deallocate(bergs%grd%stored_ice) deallocate(bergs%grd%mean_calving) + deallocate(bergs%grd%mean_calving_hflx) deallocate(bergs%grd%real_calving) deallocate(bergs%grd%uo) deallocate(bergs%grd%vo) From 83ec1c894a59c3a37f72da1b8db393f57bb9a340 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 24 Aug 2016 13:17:02 -0400 Subject: [PATCH 156/361] Renamed grd%mean_calving to grd%rmean_calving - The field grd%mean_calving(:,:) stores the running-mean so we change the name to include "rmean". - Fixed bug where rmean_calving_hflx was using calving instead of calving_hlf. - Added explicit array syntax; a(:)=b(:) is preferred to a=b. - Added a logical flag to catch need to initialize the running mean fields. - Avoid doing any computation when weight alpha==0. - Switch to a sign preserving form of the running mean expression. --- icebergs.F90 | 78 +++++++++++++++++++++++++++--------------- icebergs_framework.F90 | 24 +++++++------ icebergs_io.F90 | 35 ++++++++++--------- 3 files changed, 81 insertions(+), 56 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 6c2a597..49c280e 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1178,21 +1178,29 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ' yr,yrdy=', bergs%current_year, bergs%current_yearday - ! Adapt calving flux from coupler for use here !call sanitize_field(grd%calving,1.e20) tmpsum=sum( calving(:,:)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%net_calving_received=bergs%net_calving_received+tmpsum*bergs%dt + + ! Adapt calving heat flux from coupler + grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=calving_hflx(:,:) & ! Units of W/m2 + *grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec) - call get_running_mean_calving(bergs,calving,calving_hflx) - grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)=calving(:,:) ! Units of kg/m2/s + ! Adapt calving flux from coupler for use here + grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)=calving(:,:) & ! Units of kg/m2/s + *grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec) + + ! Running means of calving and calving_hflx + call get_running_mean_calving(bergs, grd%calving, grd%calving_hflx) + calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ! Copy back from grd%calving if using running-mean + calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) + grd%calving(:,:)=grd%calving(:,:)*grd%msk(:,:)*grd%area(:,:) ! Convert to kg/s tmpsum=sum( grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%net_incoming_calving=bergs%net_incoming_calving+tmpsum*bergs%dt if (grd%id_calving>0) & lerr=send_data(grd%id_calving, grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec), Time) - ! Adapt calving heat flux from coupler - grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=calving_hflx(:,:) ! Units of W/m2 grd%calving_hflx(:,:)=grd%calving_hflx(:,:)*grd%msk(:,:) ! Mask (just in case) if (grd%id_calving_hflx_in>0) & lerr=send_data(grd%id_calving_hflx_in, grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec), Time) @@ -1371,10 +1379,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_mass, grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_stored_ice>0) & lerr=send_data(grd%id_stored_ice, grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) - if (grd%id_mean_calving>0) & - lerr=send_data(grd%id_mean_calving, grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec), Time) - if (grd%id_mean_calving_hflx>0) & - lerr=send_data(grd%id_mean_calving_hflx, grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_rmean_calving>0) & + lerr=send_data(grd%id_rmean_calving, grd%rmean_calving(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_rmean_calving_hflx>0) & + lerr=send_data(grd%id_rmean_calving_hflx, grd%rmean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_real_calving>0) & lerr=send_data(grd%id_real_calving, grd%real_calving(grd%isc:grd%iec,grd%jsc:grd%jec,:), Time) if (grd%id_ssh>0) & @@ -1419,8 +1427,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%net_outgoing_calving_heat=bergs%net_outgoing_calving_heat+tmpsum*bergs%dt ! Units of J if (lbudget) then bergs%stored_end=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) - bergs%mean_calving_end=sum( grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) - bergs%mean_calving_hflx_end=sum( grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%rmean_calving_end=sum( grd%rmean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%rmean_calving_hflx_end=sum( grd%rmean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%stored_heat_end=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%floating_mass_end=sum_mass(bergs%first) bergs%icebergs_mass_end=sum_mass(bergs%first,justbergs=.true.) @@ -1627,28 +1635,42 @@ subroutine get_running_mean_calving(bergs,calving,calving_hflx) type(icebergs), pointer :: bergs real, dimension(:,:), intent(inout) :: calving, calving_hflx ! Local variables - real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) - real :: tau !Relaxation timescale in seconds - !This subroutine takes in the new calving and calving_hflx, and uses them to time step a mean_calving value + real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) + real :: tau !Relaxation timescale in seconds + real :: beta ! = 1-alpha (0<=beta<1) + !This subroutine takes in the new calving and calving_hflx, and uses them to time step a running-mean_calving value !The time stepping uses a time scale tau. When tau is equal to zero, the - !running mean is exactly equal to the new calving value. - !In the first iteration (or if the running mean is not yet set), then alpha is set to zero (this is done using the 999. trick) + !running mean is exactly equal to the new calving value. + + ! For the first time-step, initialize the running mean with the current data + if (.not. bergs%grd%rmean_calving_initialized) then + bergs%grd%rmean_calving(:,:)=calving(:,:) + bergs%grd%rmean_calving_initialized=.true. + endif + if (.not. bergs%grd%rmean_calving_hflx_initialized) then + bergs%grd%rmean_calving_hflx(:,:)=calving_hflx(:,:) + bergs%grd%rmean_calving_hflx_initialized=.true. + endif !Applying "Newton cooling" with timescale tau, to smooth out the calving field. tau=bergs%tau_calving/(365.*24*60*60) !Converting time scale from years to seconds alpha=tau/(tau+bergs%dt) - if ((maxval(bergs%grd%mean_calving).eq.999.0) .or. (maxval(bergs%grd%mean_calving_hflx).eq.999.0)) alpha=0.0 !Special case for first time step. - bergs%grd%mean_calving=calving + alpha*(bergs%grd%mean_calving-calving) - bergs%grd%mean_calving_hflx=calving + alpha*(bergs%grd%mean_calving_hflx-calving) - - !Removing negative values - bergs%grd%mean_calving=max(bergs%grd%mean_calving,0.) - bergs%grd%mean_calving_hflx=max(bergs%grd%mean_calving_hflx,0.) + if (alpha==0.) return ! Avoids unnecessary copying of arrays + if (alpha>0.5) then ! beta is small + beta=bergs%dt/(tau+bergs%dt) + alpha=1.-beta + else ! alpha is small + beta=1.-alpha + endif + + ! For non-negative alpha and beta, these expressions for the running means are sign preserving + bergs%grd%rmean_calving(:,:)=beta*calving(:,:) + alpha*bergs%grd%rmean_calving(:,:) + bergs%grd%rmean_calving_hflx(:,:)=beta*calving_hflx(:,:) + alpha*bergs%grd%rmean_calving_hflx(:,:) !Setting calving used by the iceberg model equal to the running mean - calving=bergs%grd%mean_calving - calving_hflx=bergs%grd%mean_calving_hflx - + calving(:,:)=bergs%grd%rmean_calving(:,:) + calving_hflx(:,:)=bergs%grd%rmean_calving_hflx(:,:) + end subroutine get_running_mean_calving end subroutine icebergs_run @@ -2830,8 +2852,8 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%tmp) deallocate(bergs%grd%tmpc) deallocate(bergs%grd%stored_ice) - deallocate(bergs%grd%mean_calving) - deallocate(bergs%grd%mean_calving_hflx) + deallocate(bergs%grd%rmean_calving) + deallocate(bergs%grd%rmean_calving_hflx) deallocate(bergs%grd%real_calving) deallocate(bergs%grd%uo) deallocate(bergs%grd%vo) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3940961..3d51418 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -111,21 +111,23 @@ module ice_bergs_framework real, dimension(:,:), pointer :: tmp=>null() ! Temporary work space real, dimension(:,:), pointer :: tmpc=>null() ! Temporary work space real, dimension(:,:,:), pointer :: stored_ice=>null() ! Accumulated ice mass flux at calving locations (kg) - real, dimension(:,:), pointer :: mean_calving=>null() !Running mean for ice calving - real, dimension(:,:), pointer :: mean_calving_hflx=>null() !Running mean for ice calving + real, dimension(:,:), pointer :: rmean_calving=>null() ! Running mean for ice calving + real, dimension(:,:), pointer :: rmean_calving_hflx=>null() ! Running mean for ice calving real, dimension(:,:), pointer :: stored_heat=>null() ! Heat content of stored ice (J) real, dimension(:,:,:), pointer :: real_calving=>null() ! Calving rate into iceberg class at calving locations (kg/s) real, dimension(:,:), pointer :: iceberg_heat_content=>null() ! Distributed heat content of bergs (J/m^2) real, dimension(:,:), pointer :: parity_x=>null() ! X component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) real, dimension(:,:), pointer :: parity_y=>null() ! Y component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) integer, dimension(:,:), pointer :: iceberg_counter_grd=>null() ! Counts icebergs created for naming purposes + logical :: rmean_calving_initialized = .false. ! True if rmean_calving(:,:) has been filled with meaningful data + logical :: rmean_calving_hflx_initialized = .false. ! True if rmean_calving_hflx(:,:) has been filled with meaningful data ! Diagnostics handles integer :: id_uo=-1, id_vo=-1, id_calving=-1, id_stored_ice=-1, id_accum=-1, id_unused=-1, id_floating_melt=-1 integer :: id_melt_buoy=-1, id_melt_eros=-1, id_melt_conv=-1, id_virtual_area=-1, id_real_calving=-1 integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 - integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_mean_calving=-1, id_mean_calving_hflx=-1 + integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_rmean_calving=-1, id_rmean_calving_hflx=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -208,8 +210,8 @@ module ice_bergs_framework real :: net_incoming_calving_heat=0., net_outgoing_calving_heat=0. real :: net_incoming_calving_heat_used=0., net_heat_to_bergs=0. real :: stored_start=0., stored_end=0. - real :: mean_calving_start=0., mean_calving_end=0. - real :: mean_calving_hflx_start=0., mean_calving_hflx_end=0. + real :: rmean_calving_start=0., rmean_calving_end=0. + real :: rmean_calving_hflx_start=0., rmean_calving_hflx_end=0. real :: stored_heat_start=0., stored_heat_end=0., net_heat_to_ocean=0. real :: net_calving_used=0., net_calving_to_bergs=0. real :: floating_mass_start=0., floating_mass_end=0. @@ -421,8 +423,8 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. allocate( grd%stored_ice(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%stored_ice(:,:,:)=0. - allocate( grd%mean_calving(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mean_calving(:,:)=999. - allocate( grd%mean_calving_hflx(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mean_calving_hflx(:,:)=999. + allocate( grd%rmean_calving(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%rmean_calving(:,:)=0. + allocate( grd%rmean_calving_hflx(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%rmean_calving_hflx(:,:)=0. allocate( grd%real_calving(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%real_calving(:,:,:)=0. allocate( grd%uo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%uo(:,:)=0. allocate( grd%vo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%vo(:,:)=0. @@ -624,9 +626,9 @@ subroutine ice_bergs_framework_init(bergs, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & 'Calving into iceberg class', 'kg/s') - grd%id_mean_calving=register_diag_field('icebergs', 'mean_calving', axes, Time, & + grd%id_rmean_calving=register_diag_field('icebergs', 'running_mean_calving', axes, Time, & 'Running mean of calving', 'kg/s') - grd%id_mean_calving_hflx=register_diag_field('icebergs', 'mean_calving_hflx', axes, Time, & + grd%id_rmean_calving_hflx=register_diag_field('icebergs', 'running_mean_calving_hflx', axes, Time, & 'Running mean of calving heat flux', 'J/s') grd%id_uo=register_diag_field('icebergs', 'uo', axes, Time, & 'Ocean zonal component of velocity', 'm s^-1') @@ -2606,8 +2608,8 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%mass, 'mass') call grd_chksum3(grd, grd%mass_on_ocean, 'mass_on_ocean') call grd_chksum3(grd, grd%stored_ice, 'stored_ice') - call grd_chksum2(grd, grd%mean_calving, 'mean_calving') - call grd_chksum2(grd, grd%mean_calving_hflx, 'mean_calving_hflx') + call grd_chksum2(grd, grd%rmean_calving, 'rmean_calving') + call grd_chksum2(grd, grd%rmean_calving_hflx, 'rmean_calving_hflx') call grd_chksum2(grd, grd%stored_heat, 'stored_heat') call grd_chksum2(grd, grd%melt_buoy, 'melt_b') call grd_chksum2(grd, grd%melt_eros, 'melt_e') diff --git a/icebergs_io.F90 b/icebergs_io.F90 index eea6035..bc0bc76 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -306,9 +306,10 @@ subroutine write_restart(bergs) call write_data(filename, 'stored_heat', bergs%grd%stored_heat, bergs%grd%domain) !call grd_chksum2(bergs%grd, bergs%grd%iceberg_counter_grd, 'write iceberg_counter_grd') call write_data(filename, 'iceberg_counter_grd', bergs%grd%iceberg_counter_grd, bergs%grd%domain) - call grd_chksum2(bergs%grd, bergs%grd%stored_ice, 'write calving mean') - call write_data(filename, 'mean_calving', bergs%grd%mean_calving, bergs%grd%domain) - call write_data(filename, 'mean_calving_hflx', bergs%grd%mean_calving_hflx, bergs%grd%domain) + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving, 'write mean calving') + call write_data(filename, 'rmean_calving', bergs%grd%rmean_calving, bergs%grd%domain) + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving_hflx, 'write mean calving_hflx') + call write_data(filename, 'rmean_calving_hflx', bergs%grd%rmean_calving_hflx, bergs%grd%domain) contains function last_berg(berg) @@ -1009,23 +1010,23 @@ subroutine read_restart_calving(bergs) 'diamonds, read_restart_calving: stored_heat WAS NOT FOUND in the file. Setting to 0.' grd%stored_heat(:,:)=0. endif - if (field_exist(filename, 'mean_calving')) then + if (field_exist(filename, 'rmean_calving')) then if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & - 'diamonds, read_restart_calving: reading mean_calving from restart file.' - call read_data(filename, 'mean_calving', grd%mean_calving, grd%domain) + 'diamonds, read_restart_calving: reading rmean_calving from restart file.' + call read_data(filename, 'rmean_calving', grd%rmean_calving, grd%domain) + grd%rmean_calving_initialized=.true. else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & - 'diamonds, read_restart_calving: mean_calving WAS NOT FOUND in the file. Setting to 0.' - grd%mean_calving(:,:)=999. + 'diamonds, read_restart_calving: rmean_calving WAS NOT FOUND in the file. Setting to 0.' endif - if (field_exist(filename, 'mean_calving_hflx')) then + if (field_exist(filename, 'rmean_calving_hflx')) then if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & - 'diamonds, read_restart_calving: reading mean_calving_hflx from restart file.' - call read_data(filename, 'mean_calving_hflx', grd%mean_calving_hflx, grd%domain) + 'diamonds, read_restart_calving: reading rmean_calving_hflx from restart file.' + call read_data(filename, 'rmean_calving_hflx', grd%rmean_calving_hflx, grd%domain) + grd%rmean_calving_hflx_initialized=.true. else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & - 'diamonds, read_restart_calving: mean_calving_hflx WAS NOT FOUND in the file. Setting to 0.' - grd%mean_calving_hflx(:,:)=999. + 'diamonds, read_restart_calving: rmean_calving_hflx WAS NOT FOUND in the file. Setting to 0.' endif if (field_exist(filename, 'iceberg_counter_grd')) then if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & @@ -1066,13 +1067,13 @@ subroutine read_restart_calving(bergs) endif call grd_chksum3(bergs%grd, bergs%grd%stored_ice, 'read_restart_calving, stored_ice') - call grd_chksum2(bergs%grd, bergs%grd%mean_calving, 'read_restart_calving, mean_calving') - call grd_chksum2(bergs%grd, bergs%grd%mean_calving_hflx, 'read_restart_calving, mean_calving_hflx') call grd_chksum2(bergs%grd, bergs%grd%stored_heat, 'read_restart_calving, stored_heat') + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving, 'read_restart_calving, rmean_calving') + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving_hflx, 'read_restart_calving, rmean_calving_hflx') bergs%stored_start=sum( grd%stored_ice(grd%isc:grd%iec,grd%jsc:grd%jec,:) ) - bergs%mean_calving_start=sum( grd%mean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) - bergs%mean_calving_hflx_start=sum( grd%mean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%rmean_calving_start=sum( grd%rmean_calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) + bergs%rmean_calving_hflx_start=sum( grd%rmean_calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum( bergs%stored_start ) bergs%stored_heat_start=sum( grd%stored_heat(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum( bergs%stored_heat_start ) From a28e4abbcc5ca7b7f4aae69f719858e24baba9a5 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 24 Aug 2016 15:43:04 -0400 Subject: [PATCH 157/361] Wrapped running-mean of calving in logical if-block - To avoid unnecessary copying of data and writing of data to restart files, the running-mean calculations of calving and calving_hlfx are now wrapped inside "if (tau_calving>0)" blocks. - No answer changes. --- icebergs.F90 | 8 +++++--- icebergs_io.F90 | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 49c280e..9cdb511 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1191,9 +1191,11 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, *grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec) ! Running means of calving and calving_hflx - call get_running_mean_calving(bergs, grd%calving, grd%calving_hflx) - calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ! Copy back from grd%calving if using running-mean - calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) + if (bergs%tau_calving>0.) then + call get_running_mean_calving(bergs, grd%calving, grd%calving_hflx) + calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ! Copy back from grd%calving if using running-mean + calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) + endif grd%calving(:,:)=grd%calving(:,:)*grd%msk(:,:)*grd%area(:,:) ! Convert to kg/s tmpsum=sum( grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec) ) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index bc0bc76..bd4f994 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -306,10 +306,12 @@ subroutine write_restart(bergs) call write_data(filename, 'stored_heat', bergs%grd%stored_heat, bergs%grd%domain) !call grd_chksum2(bergs%grd, bergs%grd%iceberg_counter_grd, 'write iceberg_counter_grd') call write_data(filename, 'iceberg_counter_grd', bergs%grd%iceberg_counter_grd, bergs%grd%domain) - call grd_chksum2(bergs%grd, bergs%grd%rmean_calving, 'write mean calving') - call write_data(filename, 'rmean_calving', bergs%grd%rmean_calving, bergs%grd%domain) - call grd_chksum2(bergs%grd, bergs%grd%rmean_calving_hflx, 'write mean calving_hflx') - call write_data(filename, 'rmean_calving_hflx', bergs%grd%rmean_calving_hflx, bergs%grd%domain) + if (bergs%tau_calving>0.) then + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving, 'write mean calving') + call write_data(filename, 'rmean_calving', bergs%grd%rmean_calving, bergs%grd%domain) + call grd_chksum2(bergs%grd, bergs%grd%rmean_calving_hflx, 'write mean calving_hflx') + call write_data(filename, 'rmean_calving_hflx', bergs%grd%rmean_calving_hflx, bergs%grd%domain) + endif contains function last_berg(berg) From 87317223c47fd980763def351012af137fc11048 Mon Sep 17 00:00:00 2001 From: Niki Zadeh Date: Fri, 26 Aug 2016 13:30:48 -0400 Subject: [PATCH 158/361] Write bonds only if they are being used -Fix suggested by Alon to turn off writing the bond files if they're not being used --- icebergs_io.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 84d4ff7..8c96195 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -307,7 +307,6 @@ subroutine write_restart(bergs) if (bergs%iceberg_bonds_on) then check_bond_quality=.true. call count_bonds(bergs, nbonds,check_bond_quality) - endif allocate(first_berg_num(nbonds)) allocate(other_berg_num(nbonds)) @@ -369,6 +368,7 @@ subroutine write_restart(bergs) call nullify_domain() + endif !############################################################################################# From 4f920fae95ba2d30e64bbc65924befbd9b203b5b Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Sep 2016 11:33:44 -0400 Subject: [PATCH 159/361] 1) When read_old_restart flag is set to true, the model does not reproduce accross restarts. This bug is fixed by setting iceberg_num to -1 when read_old_restarts is true. In order to used the iceberg_num correctly, read_old_restarts should be set to false. 2) The model was not reproducing accross: restarts in certain situations when fix_restart_date=.true. (default). This is because a minor offset is added to the icebergs start time (to differentiate icebergs with the same start date). This minor offset can make the start date be in the future. When fix_restart_date is true, an iceberg being in the future, makes the code update the start dates, which prevents the model from reproducing across restarts. This has been fixed by making the minor offset be negative, so that iceberg start dates are always before the current date. (I hope that this does not cause any other unforeseen issues). 3) The code which generates icebergs for testing has also been refactored slightly to remove redundant lines and to make it more readable (both in the old and new versions of the read_restart subroutine) --- icebergs.F90 | 6 +++++- icebergs_io.F90 | 55 +++++++++++++++++++------------------------------ 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 522d0cd..87a7f16 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1815,7 +1815,11 @@ subroutine calve_icebergs(bergs) newberg%start_lon=newberg%lon newberg%start_lat=newberg%lat newberg%start_year=bergs%current_year - newberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + if (.not. bergs%read_old_restarts) then + newberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + else + newberg%iceberg_num=-1 + endif newberg%start_day=bergs%current_yearday+ddt/86400. newberg%start_mass=bergs%initial_mass(k) newberg%mass_scaling=bergs%mass_scaling(k) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index e2633c4..7092cb8 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -298,7 +298,6 @@ subroutine write_restart(bergs) ! Write stored ice filename='RESTART/calving.res.nc' - if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(stderrunit,'(2a)') 'diamonds, write_restart: writing ',filename call grd_chksum3(bergs%grd, bergs%grd%stored_ice, 'write stored_ice') call write_data(filename, 'stored_ice', bergs%grd%stored_ice, bergs%grd%domain) @@ -475,10 +474,11 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_year=get_int(ncid, start_yearid, k) if (bergs%read_old_restarts) then ! This emulates the iceberg counter used at calving sites but uses the restart position instead - i = localberg%ine - j = localberg%jne - localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg - grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 + !i = localberg%ine + !j = localberg%jne + !localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + !grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 + localberg%iceberg_num=-1 else localberg%iceberg_num=get_int(ncid, iceberg_numid, k) endif @@ -576,47 +576,34 @@ subroutine generate_bergs(bergs,Time) localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. localberg%heat_density=0. - localberg%uvel=1. - localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon localberg%uvel_old=0. !Alon localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + + !Berg A + localberg%uvel=1. + localberg%vvel=0. localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg B localberg%uvel=-1. localberg%vvel=0. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg C localberg%uvel=0. localberg%vvel=1. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg D localberg%uvel=0. localberg%vvel=-1. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) @@ -812,15 +799,15 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_lon=start_lon(k) localberg%start_lat=start_lat(k) localberg%start_year=start_year(k) - if (bergs%read_old_restarts) then - ! This emulates the iceberg counter used at calving sites but uses the restart position instead - i = localberg%ine - j = localberg%jne - localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg - grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 - else + !if (bergs%read_old_restarts) then + ! ! This emulates the iceberg counter used at calving sites but uses the restart position instead + ! !i = localberg%ine + ! !j = localberg%jne + ! !localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg + ! !grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 + !else localberg%iceberg_num=iceberg_num(k) - endif + !endif localberg%start_day=start_day(k) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) @@ -1013,7 +1000,7 @@ subroutine read_restart_calving(bergs) else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: iceberg_counter_grd WAS NOT FOUND in the file. Setting to 0.' - grd%iceberg_counter_grd(:,:)=0 + grd%iceberg_counter_grd(:,:)=1 endif bergs%restarted=.true. else From 6456f11ed026c51ab5544dad0690d772fdf1da51 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Sep 2016 14:57:24 -0400 Subject: [PATCH 160/361] 1) A line which writes the restart filename to the screen was removed by mistake before the last commit. This has been added again. 2) The changes made in the last commit have been cleaned up a little to remove commented out lines. --- icebergs.F90 | 6 +++++- icebergs_framework.F90 | 5 ++++- icebergs_io.F90 | 43 +++++++++--------------------------------- 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 87a7f16..3f4e762 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1839,7 +1839,11 @@ subroutine calve_icebergs(bergs) grd%stored_ice(i,j,k)=grd%stored_ice(i,j,k)-calved_to_berg calving_to_bergs=calving_to_bergs+calved_to_berg grd%real_calving(i,j,k)=grd%real_calving(i,j,k)+calved_to_berg/bergs%dt - ddt=ddt+bergs%dt*2./17. ! Minor offset to start day + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ddt=ddt-bergs%dt*2./17. ! Minor offset to start day (negative offsets) + !ddt=ddt+bergs%dt*2./17. ! Minor offset to start day + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! icnt=icnt+1 bergs%nbergs_calved=bergs%nbergs_calved+1 bergs%nbergs_calved_by_class(k)=bergs%nbergs_calved_by_class(k)+1 diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d6e6763..628c6db 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -693,6 +693,7 @@ subroutine offset_berg_dates(bergs,Time) type(iceberg), pointer :: this integer :: iyr, imon, iday, ihr, imin, isec, yr_offset real :: latest_start_year, berg_start_year +real :: current_time_val call get_date(Time, iyr, imon, iday, ihr, imin, isec) latest_start_year=iyr-99999 @@ -708,7 +709,9 @@ subroutine offset_berg_dates(bergs,Time) enddo call mpp_max(latest_start_year) - if (latest_start_year<=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367.) return ! No conflicts! + current_time_val=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367. + if (latest_start_year<=current_time_val) return ! No conflicts! + !if (latest_start_year<=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367.) return ! No conflicts! yr_offset=int(latest_start_year+1.)-iyr if (mpp_pe().eq.mpp_root_pe()) write(*,'(a,i8,a)') & diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 7092cb8..1832374 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -298,6 +298,7 @@ subroutine write_restart(bergs) ! Write stored ice filename='RESTART/calving.res.nc' + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(stderrunit,'(2a)') 'diamonds, write_restart: writing ',filename call grd_chksum3(bergs%grd, bergs%grd%stored_ice, 'write stored_ice') call write_data(filename, 'stored_ice', bergs%grd%stored_ice, bergs%grd%domain) @@ -473,11 +474,6 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_lat=get_double(ncid, start_latid, k) localberg%start_year=get_int(ncid, start_yearid, k) if (bergs%read_old_restarts) then - ! This emulates the iceberg counter used at calving sites but uses the restart position instead - !i = localberg%ine - !j = localberg%jne - !localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg - !grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 localberg%iceberg_num=-1 else localberg%iceberg_num=get_int(ncid, iceberg_numid, k) @@ -799,15 +795,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_lon=start_lon(k) localberg%start_lat=start_lat(k) localberg%start_year=start_year(k) - !if (bergs%read_old_restarts) then - ! ! This emulates the iceberg counter used at calving sites but uses the restart position instead - ! !i = localberg%ine - ! !j = localberg%jne - ! !localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg - ! !grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 - !else - localberg%iceberg_num=iceberg_num(k) - !endif + localberg%iceberg_num=iceberg_num(k) localberg%start_day=start_day(k) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) @@ -907,47 +895,34 @@ subroutine generate_bergs(bergs,Time) localberg%mass_scaling=bergs%mass_scaling(1) localberg%mass_of_bits=0. localberg%heat_density=0. - localberg%uvel=1. - localberg%vvel=0. localberg%axn=0. !Alon localberg%ayn=0. !Alon localberg%uvel_old=0. !Alon localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon + + !Berg A + localberg%uvel=1. + localberg%vvel=0. localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg B localberg%uvel=-1. localberg%vvel=0. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg C localberg%uvel=0. localberg%vvel=1. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) + !Berg D localberg%uvel=0. localberg%vvel=-1. - localberg%axn=0. !Alon - localberg%ayn=0. !Alon - localberg%uvel_old=0. !Alon - localberg%vvel_old=0. !Alon - localberg%bxn=0. !Alon - localberg%byn=0. !Alon localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) From bc9cb264c50698f26163f0bf9fe703843a5e1d59 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Sep 2016 15:01:55 -0400 Subject: [PATCH 161/361] A few more lines have been cleaned up to remove commented out lines. --- icebergs.F90 | 4 ---- icebergs_framework.F90 | 1 - 2 files changed, 5 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3f4e762..71b710c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1839,11 +1839,7 @@ subroutine calve_icebergs(bergs) grd%stored_ice(i,j,k)=grd%stored_ice(i,j,k)-calved_to_berg calving_to_bergs=calving_to_bergs+calved_to_berg grd%real_calving(i,j,k)=grd%real_calving(i,j,k)+calved_to_berg/bergs%dt - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ddt=ddt-bergs%dt*2./17. ! Minor offset to start day (negative offsets) - !ddt=ddt+bergs%dt*2./17. ! Minor offset to start day - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! icnt=icnt+1 bergs%nbergs_calved=bergs%nbergs_calved+1 bergs%nbergs_calved_by_class(k)=bergs%nbergs_calved_by_class(k)+1 diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 628c6db..00b54ac 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -711,7 +711,6 @@ subroutine offset_berg_dates(bergs,Time) current_time_val=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367. if (latest_start_year<=current_time_val) return ! No conflicts! - !if (latest_start_year<=float(iyr)+yearday(imon, iday, ihr, imin, isec)/367.) return ! No conflicts! yr_offset=int(latest_start_year+1.)-iyr if (mpp_pe().eq.mpp_root_pe()) write(*,'(a,i8,a)') & From 05f7b6a52dbb13f7c390320127dc04cd9c95e231 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 15 Sep 2016 16:04:37 -0400 Subject: [PATCH 162/361] A variable grd%spread_area has been added to the model and diagnostics. This variable gives the percent of a grid cell which is covered by icebergs. This area covered by icebergs is calculated within the spread_mass_to_ocean subroutine, and the icebergs_incr_mass subrouting (using an optional flag). --- icebergs.F90 | 151 +++++++++++++++++++++++++++++------------ icebergs_framework.F90 | 25 +++++-- 2 files changed, 126 insertions(+), 50 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3b25127..c27c5a0 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1766,7 +1766,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real, intent(in) :: theta real, optional, intent(in) :: static_berg ! Local variables - real :: xL, xC, xR, yD, yC, yU, Mass, L + real :: xL, xC, xR, yD, yC, yU, Mass, L, Area_scaled real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR real :: S, H, origin_x, origin_y, x0, y0 real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex @@ -1912,6 +1912,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling fraction_used=1. !Static icebergs do not share their mass with the boundary (this to initialize icebergs in regular arrangements against boundaries) endif + !Spreading the iceberg mass onto the ocean grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass/fraction_used) grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass/fraction_used) grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass/fraction_used) @@ -1922,6 +1923,17 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass/fraction_used) grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass/fraction_used) + !Spreading the iceberg area onto the ocean + Area_scaled=Area*scaling + grd%area_on_ocean(i,j,1)=grd%area_on_ocean(i,j,1)+(yDxL*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,2)=grd%area_on_ocean(i,j,2)+(yDxC*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,3)=grd%area_on_ocean(i,j,3)+(yDxR*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,4)=grd%area_on_ocean(i,j,4)+(yCxL*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,5)=grd%area_on_ocean(i,j,5)+(yCxC*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,6)=grd%area_on_ocean(i,j,6)+(yCxR*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,7)=grd%area_on_ocean(i,j,7)+(yUxL*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,8)=grd%area_on_ocean(i,j,8)+(yUxC*Area_scaled/fraction_used) + grd%area_on_ocean(i,j,9)=grd%area_on_ocean(i,j,9)+(yUxR*Area_scaled/fraction_used) end subroutine spread_mass_across_ocean_cells @@ -2564,7 +2576,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality -real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass +real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area real :: grdd_u_iceberg, grdd_v_iceberg integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask @@ -2572,7 +2584,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount integer :: nbonds -logical :: within_iceberg_model +!logical :: within_iceberg_model integer :: stderrunit @@ -2597,11 +2609,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. !grd%spread_mass(:,:)=0. !Don't zero this out yet, because we can first use this an add it onto the SSH + grd%spread_area(:,:)=0. grd%u_iceberg(:,:)=0. grd%v_iceberg(:,:)=0. grd%mass(:,:)=0. if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. + if (bergs%add_weight_to_ocean) grd%area_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. ! Manage time @@ -2831,25 +2845,28 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call write_trajectory(bergs%trajectories, bergs%save_short_traj) endif - !Update diagnostic of iceberg mass spread on ocean,MP1 - if ( (grd%id_spread_mass>0) .or. (bergs%find_melt_using_spread_mass) ) then - if ((bergs%find_melt_using_spread_mass) ) then - grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) !Temporarily using the variable calving for storing old mass (not sure better way) - endif + !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) + !within_iceberg_model=.True. + if (bergs%find_melt_using_spread_mass) then + grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) !Temporarily using the variable calving for storing old mass (not sure better way) grd%spread_mass(:,:)=0. - within_iceberg_model=.True. - call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model) - if (bergs%find_melt_using_spread_mass) then - do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec - if (grd%area(i,j)>0.0) then - grd%floating_melt(i,j)=max((grd%floating_melt(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) - !grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. - grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*0.0 !Not 100% sure this is correct. - else - grd%floating_melt(i,j)=0.0 - endif - enddo ;enddo - endif + call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) + do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec + if (grd%area(i,j)>0.0) then + grd%floating_melt(i,j)=max((grd%floating_melt(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) + !grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. + grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*0.0 !Not 100% sure this is correct. + else + grd%floating_melt(i,j)=0.0 + endif + enddo ;enddo + elseif (grd%id_spread_mass>0) then !Update diagnostic of iceberg mass spread on ocean + grd%spread_mass(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) + endif + if ( (grd%id_spread_area>0) ) then !Update diagnostic of iceberg area spread on ocean + grd%spread_area(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,spread_area_not_mass=.True.) endif ! Gridded diagnostics @@ -2893,6 +2910,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_bergy_mass, grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_spread_mass>0) & lerr=send_data(grd%id_spread_mass, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_spread_area>0) & + lerr=send_data(grd%id_spread_area, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_u_iceberg>0) & lerr=send_data(grd%id_u_iceberg, grd%u_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_v_iceberg>0) & @@ -2968,15 +2987,22 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%floating_mass_end=sum_mass(bergs) bergs%icebergs_mass_end=sum_mass(bergs,justbergs=.true.) bergs%bergy_mass_end=sum_mass(bergs,justbits=.true.) - bergs%spread_mass_end=sum_mass(bergs) !Not sure what this is - bergs%u_iceberg_end=sum_mass(bergs) !Not sure what this is - bergs%v_iceberg_end=sum_mass(bergs) !Not sure what this is + !bergs%spread_mass_end=sum_mass(bergs) !Not sure what this is + !bergs%spread_area_end=sum_mass(bergs) !Not sure what this is + !bergs%u_iceberg_end=sum_mass(bergs) !Not sure what this is + !bergs%v_iceberg_end=sum_mass(bergs) !Not sure what this is bergs%floating_heat_end=sum_heat(bergs) grd%tmpc(:,:)=0.; + !Finding spread mass call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r call icebergs_incr_mass(bergs, grd%tmpc) call mpp_clock_begin(bergs%clock_dia); call mpp_clock_begin(bergs%clock) ! To enable calling of public s/r bergs%returned_mass_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) + !Finding spread area + call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r + call icebergs_incr_mass(bergs, grd%tmpc,spread_area_not_mass=.true.) + call mpp_clock_begin(bergs%clock_dia); call mpp_clock_begin(bergs%clock) ! To enable calling of public s/r + bergs%returned_area_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%nbergs_end=count_bergs(bergs) call mpp_sum(bergs%stored_end) call mpp_sum(bergs%stored_heat_end) @@ -2984,6 +3010,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(bergs%icebergs_mass_end) call mpp_sum(bergs%bergy_mass_end) call mpp_sum(bergs%spread_mass_end) + call mpp_sum(bergs%spread_area_end) call mpp_sum(bergs%u_iceberg_end) call mpp_sum(bergs%v_iceberg_end) call mpp_sum(bergs%floating_heat_end) @@ -3014,6 +3041,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(grdd_bergy_mass) grdd_spread_mass=sum( grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) call mpp_sum(grdd_spread_mass) + grdd_spread_area=sum( grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) + call mpp_sum(grdd_spread_area) if (mpp_pe().eq.mpp_root_pe()) then 100 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a12,i8) 200 format("diamonds: ",a19,10(a18,"=",es14.7,x,a2,:,",")) @@ -3022,6 +3051,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call report_state('icebergs','kg','',bergs%icebergs_mass_start,'',bergs%icebergs_mass_end,'') call report_state('bits','kg','',bergs%bergy_mass_start,'',bergs%bergy_mass_end,'') call report_state('spread icebergs','kg','',bergs%spread_mass_start,'',bergs%spread_mass_end,'') + call report_state('spread icebergs','m^2','',bergs%spread_area_start,'',bergs%spread_area_end,'') call report_istate('berg #','',bergs%nbergs_start,'',bergs%nbergs_end,'') call report_ibudget('berg #','calved',bergs%nbergs_calved, & 'melted',bergs%nbergs_melted, & @@ -3044,6 +3074,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%stored_end+bergs%floating_mass_end) call report_consistant('iceberg mass','kg','gridded',grdd_berg_mass,'bergs',bergs%icebergs_mass_end) call report_consistant('spread mass','kg','gridded',grdd_spread_mass,'bergs',bergs%spread_mass_end) + call report_consistant('spread area','kg','gridded',grdd_spread_area,'bergs',bergs%spread_area_end) call report_consistant('bits mass','kg','gridded',grdd_bergy_mass,'bits',bergs%bergy_mass_end) call report_consistant('wieght','kg','returned',bergs%returned_mass_on_ocean,'floating',bergs%floating_mass_end) call report_state('net heat','J','',bergs%stored_heat_start+bergs%floating_heat_start,'',& @@ -3080,6 +3111,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%icebergs_mass_start=bergs%icebergs_mass_end bergs%bergy_mass_start=bergs%bergy_mass_end bergs%spread_mass_start=bergs%spread_mass_end + bergs%spread_area_start=bergs%spread_area_end bergs%net_calving_used=0. bergs%net_calving_to_bergs=0. bergs%net_heat_to_bergs=0. @@ -3186,23 +3218,43 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) +subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time, spread_area_not_mass) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass type(time_type), intent(in), optional :: Time logical, intent(in), optional :: within_iceberg_model -logical :: within_model +logical, intent(in), optional :: spread_area_not_mass ! Local variables +logical :: within_model +logical :: spread_area !Logical flag which allows you to spread area over ocean (instead of mass) integer :: i, j type(icebergs_gridded), pointer :: grd real :: dmda logical :: lerr +real, dimension(bergs%grd%isd:bergs%grd%ied, bergs%grd%jsd:bergs%grd%jed,9) :: var_on_ocean !Variable being spread onto the ocean (mass or area) integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() + ! For convenience + grd=>bergs%grd + + !var_on_ocean(:,:,:)=0. + !Decide whether area of mass are being spread across grid cells (default spread mass) + spread_area=.False. + if (present(spread_area_not_mass)) then + if (spread_area_not_mass) then + spread_area=.True. + endif + endif + if (spread_area) then + var_on_ocean(:,:,:)=grd%area_on_ocean(:,:,:) + else + var_on_ocean(:,:,:)=grd%mass_on_ocean(:,:,:) + endif + within_model=.False. if (present(within_iceberg_model)) then @@ -3216,8 +3268,6 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) call mpp_clock_begin(bergs%clock_int) endif - ! For convenience - grd=>bergs%grd ! Add iceberg+bits mass field to non-haloed SIS field (kg/m^2) !mass(:,:)=mass(:,:)+( grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec) & @@ -3228,7 +3278,7 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) call grd_chksum2(grd, grd%tmp, 'mass in (incr)') endif - call mpp_update_domains(grd%mass_on_ocean, grd%domain) + call mpp_update_domains(var_on_ocean, grd%domain) if (.not. old_bug_rotated_weights) then do j=grd%jsd, grd%jed; do i=grd%isd, grd%ied if (grd%parity_x(i,j)<0.) then @@ -3236,19 +3286,19 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) ! (i.e. a 180 degree rotation). In general, we should handle ! +/- 90 degree rotations as well but in CM2*-class models ! this is not necessary. -aja - dmda=grd%mass_on_ocean(i,j,9); grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,1); grd%mass_on_ocean(i,j,1)=dmda - dmda=grd%mass_on_ocean(i,j,8); grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,2); grd%mass_on_ocean(i,j,2)=dmda - dmda=grd%mass_on_ocean(i,j,7); grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,3); grd%mass_on_ocean(i,j,3)=dmda - dmda=grd%mass_on_ocean(i,j,6); grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,4); grd%mass_on_ocean(i,j,4)=dmda + dmda=var_on_ocean(i,j,9); var_on_ocean(i,j,9)=var_on_ocean(i,j,1); var_on_ocean(i,j,1)=dmda + dmda=var_on_ocean(i,j,8); var_on_ocean(i,j,8)=var_on_ocean(i,j,2); var_on_ocean(i,j,2)=dmda + dmda=var_on_ocean(i,j,7); var_on_ocean(i,j,7)=var_on_ocean(i,j,3); var_on_ocean(i,j,3)=dmda + dmda=var_on_ocean(i,j,6); var_on_ocean(i,j,6)=var_on_ocean(i,j,4); var_on_ocean(i,j,4)=dmda endif enddo; enddo endif do j=grd%jsc, grd%jec; do i=grd%isc, grd%iec - dmda=grd%mass_on_ocean(i,j,5) & - + ( ( (grd%mass_on_ocean(i-1,j-1,9)+grd%mass_on_ocean(i+1,j+1,1)) & - + (grd%mass_on_ocean(i+1,j-1,7)+grd%mass_on_ocean(i-1,j+1,3)) ) & - + ( (grd%mass_on_ocean(i-1,j ,6)+grd%mass_on_ocean(i+1,j ,4)) & - + (grd%mass_on_ocean(i ,j-1,8)+grd%mass_on_ocean(i ,j+1,2)) ) ) + dmda=var_on_ocean(i,j,5) & + + ( ( (var_on_ocean(i-1,j-1,9)+var_on_ocean(i+1,j+1,1)) & + + (var_on_ocean(i+1,j-1,7)+var_on_ocean(i-1,j+1,3)) ) & + + ( (var_on_ocean(i-1,j ,6)+var_on_ocean(i+1,j ,4)) & + + (var_on_ocean(i ,j-1,8)+var_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) if (.not.(within_model)) then @@ -3256,16 +3306,27 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) else mass(i,j)=dmda endif - if (grd%id_mass_on_ocn>0) grd%tmp(i,j)=dmda + if ((grd%id_area_on_ocn>0).and.(spread_area)) grd%tmp(i,j)=dmda + if ((grd%id_mass_on_ocn>0).and.(.not. spread_area)) grd%tmp(i,j)=dmda enddo; enddo - if (present(Time).and. (grd%id_mass_on_ocn>0)) & - lerr=send_data(grd%id_mass_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + + if (spread_area) then + if (present(Time).and. (grd%id_area_on_ocn>0)) & + lerr=send_data(grd%id_area_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + else + if (present(Time).and. (grd%id_mass_on_ocn>0)) & + lerr=send_data(grd%id_mass_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + endif if (debug) then grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass - call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') - call grd_chksum2(grd, grd%tmp, 'mass out (incr)') - + if (.not. spread_area) then + call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') + call grd_chksum2(grd, grd%tmp, 'mass out (incr)') + else + call grd_chksum3(grd, grd%area_on_ocean, 'area bergs (incr)') + call grd_chksum2(grd, grd%tmp, 'area out (incr)') + endif endif if (.not.(within_model)) then @@ -4510,9 +4571,11 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%bergy_melt) deallocate(bergs%grd%bergy_mass) deallocate(bergs%grd%spread_mass) + deallocate(bergs%grd%spread_area) deallocate(bergs%grd%virtual_area) deallocate(bergs%grd%mass) deallocate(bergs%grd%mass_on_ocean) + deallocate(bergs%grd%area_on_ocean) deallocate(bergs%grd%tmp) deallocate(bergs%grd%tmpc) deallocate(bergs%grd%stored_ice) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3d158c7..b8b5f28 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -117,11 +117,13 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/s/m^2) + real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/s/m^2) real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) - real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) + real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) - Alon:I think that this actually has units of kg + real, dimension(:,:,:), pointer :: area_on_ocean=>null() ! Area distribution partitioned by neighbor (m^2/m^2) - Alon:I think that this actually has units of m^2 real, dimension(:,:), pointer :: tmp=>null() ! Temporary work space real, dimension(:,:), pointer :: tmpc=>null() ! Temporary work space real, dimension(:,:,:), pointer :: stored_ice=>null() ! Accumulated ice mass flux at calving locations (kg) @@ -136,8 +138,9 @@ module ice_bergs_framework integer :: id_melt_buoy=-1, id_melt_eros=-1, id_melt_conv=-1, id_virtual_area=-1, id_real_calving=-1 integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 - integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 - integer :: id_mass_on_ocn=-1, id_ssh=-1, id_fax=-1, id_fay=-1, id_spread_mass=-1 + integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 + integer :: id_mass_on_ocn=-1, id_area_on_ocn=-1, id_spread_mass=-1, id_spread_area=-1 + integer :: id_ssh=-1, id_fax=-1, id_fay=-1 integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -263,9 +266,11 @@ module ice_bergs_framework real :: icebergs_mass_start=0., icebergs_mass_end=0. real :: bergy_mass_start=0., bergy_mass_end=0. real :: spread_mass_start=0., spread_mass_end=0. + real :: spread_area_start=0., spread_area_end=0. real :: u_iceberg_start=0., u_iceberg_end=0. real :: v_iceberg_start=0., v_iceberg_end=0. real :: returned_mass_on_ocean=0. + real :: returned_area_on_ocean=0. real :: net_melt=0., berg_melt=0., bergy_src=0., bergy_melt=0. integer :: nbergs_calved=0, nbergs_melted=0, nbergs_start=0, nbergs_end=0 integer :: nspeeding_tickets=0 @@ -501,11 +506,13 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%bergy_melt(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_melt(:,:)=0. allocate( grd%bergy_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_mass(:,:)=0. allocate( grd%spread_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_mass(:,:)=0. + allocate( grd%spread_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_area(:,:)=0. allocate( grd%u_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%u_iceberg(:,:)=0. allocate( grd%v_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%v_iceberg(:,:)=0. allocate( grd%virtual_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%virtual_area(:,:)=0. allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. + allocate( grd%area_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%area_on_ocean(:,:,:)=0. allocate( grd%stored_ice(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%stored_ice(:,:,:)=0. allocate( grd%real_calving(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%real_calving(:,:,:)=0. allocate( grd%uo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%uo(:,:)=0. @@ -819,6 +826,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Bergy bit density field', 'kg/(m^2)') grd%id_spread_mass=register_diag_field('icebergs', 'spread_mass', axes, Time, & 'Iceberg mass after spreading', 'kg/(m^2)') + grd%id_spread_area=register_diag_field('icebergs', 'spread_area', axes, Time, & + 'Iceberg area after spreading', 'm^2/(m^2)') grd%id_u_iceberg=register_diag_field('icebergs', 'u_iceberg', axes, Time, & 'Iceberg u velocity (m/s)') grd%id_v_iceberg=register_diag_field('icebergs', 'v_iceberg', axes, Time, & @@ -829,6 +838,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Iceberg density field', 'kg/(m^2)') grd%id_mass_on_ocn=register_diag_field('icebergs', 'mass_on_ocean', axes, Time, & 'Iceberg density field felt by ocean', 'kg/(m^2)') + grd%id_area_on_ocn=register_diag_field('icebergs', 'area_on_ocean', axes, Time, & + 'Iceberg area field felt by ocean', 'm^2/(m^2)') grd%id_stored_ice=register_diag_field('icebergs', 'stored_ice', axes3d, Time, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & @@ -3792,6 +3803,7 @@ subroutine checksum_gridded(grd, label) ! state call grd_chksum2(grd, grd%mass, 'mass') call grd_chksum3(grd, grd%mass_on_ocean, 'mass_on_ocean') + call grd_chksum3(grd, grd%area_on_ocean, 'area_on_ocean') call grd_chksum3(grd, grd%stored_ice, 'stored_ice') call grd_chksum2(grd, grd%stored_heat, 'stored_heat') call grd_chksum2(grd, grd%melt_buoy, 'melt_b') @@ -3800,9 +3812,10 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%bergy_src, 'bergy_src') call grd_chksum2(grd, grd%bergy_melt, 'bergy_melt') call grd_chksum2(grd, grd%bergy_mass, 'bergy_mass') - call grd_chksum2(grd, grd%bergy_mass, 'spread_mass') - call grd_chksum2(grd, grd%bergy_mass, 'u_iceberg') - call grd_chksum2(grd, grd%bergy_mass, 'v_iceberg') + call grd_chksum2(grd, grd%spread_mass, 'spread_mass') + call grd_chksum2(grd, grd%spread_area, 'spread_area') + call grd_chksum2(grd, grd%u_iceberg, 'u_iceberg') + call grd_chksum2(grd, grd%v_iceberg, 'v_iceberg') call grd_chksum2(grd, grd%virtual_area, 'varea') call grd_chksum2(grd, grd%floating_melt, 'floating_melt') call grd_chksum2(grd, grd%berg_melt, 'berg_melt') From 959bf0e713f821fbab1e88c2689cf62e91d51c8f Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 19 Sep 2016 12:59:58 -0400 Subject: [PATCH 163/361] A variable u_star_icebergs has been added to the iceberg model. This provides the frictional velcoity that should be felt by the ocean boundary layer beneath the icebergs. The u_star_icebergs is a gridded quantity. It is based on the (mass weighted) velocity difference between the iceberg and ocean. The calculation for u_star currently uses the mass rather than the spread_mass to do the velocity weighting. It should used the spread mass. This can be done at a later stage if it is found cause problems. The next step is to pass u_star through the coupler so that it can be felt by the ocean. This has not been done yet. --- icebergs.F90 | 48 ++++++++++++++++++++++++------------------ icebergs_framework.F90 | 19 +++++++++++++++-- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c27c5a0..9fae040 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1114,6 +1114,7 @@ subroutine thermodynamics(bergs) real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb +real :: ustar_h, ustar integer :: i,j, stderrunit type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. @@ -1316,10 +1317,8 @@ subroutine thermodynamics(bergs) if ((grd%id_mass>0 .or. bergs%add_weight_to_ocean) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 !Finding the average iceberg velocity in a grid cell (mass weighted) - if (grd%id_u_iceberg>0 )& - & grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%uvel) ! kg/m2 - if (grd%id_v_iceberg>0 )& - & grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%vvel) ! kg/m2 + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%uvel) ! kg/m2 + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%vvel) ! kg/m2 if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then @@ -1339,15 +1338,23 @@ subroutine thermodynamics(bergs) enddo enddo ; enddo - !Scaling the gridded iceberg velocity by the iceberg mass - if ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0)) then - do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec - if ((grd%id_u_iceberg>0 ).and. (grd%mass(i,j)>0.)) & - & grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) - if ((grd%id_v_iceberg>0 ).and. (grd%mass(i,j)>0.)) & - & grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) - enddo; enddo - endif + !Scaling the gridded iceberg velocity by the iceberg mass + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + if (grd%mass(i,j)>0.) then + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) + else + grd%u_iceberg(i,j)=0. ; grd%v_iceberg(i,j)=0. + endif + enddo; enddo + + !Calculating ustar_iceberg (gridded) + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + dvo=sqrt((grd%u_iceberg(i,j)-grd%uo(i,j))**2+(grd%v_iceberg(i,j)-grd%vo(i,j))**2) + ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) + ustar_h = max(bergs%ustar_icebergs_bg, ustar) + grd%ustar_iceberg(i,j)=ustar_h + enddo; enddo end subroutine thermodynamics @@ -1367,7 +1374,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic logical , intent(in) :: Use_three_equation_model !True uses the 3 equation model, False uses the 2 equation model. ! Local variables - real :: utide, ustar_bg, ustar, f_cori, absf,tfreeze + real :: ustar, f_cori, absf,tfreeze real :: Hml !Mixed layer depth !These could also be useful output variables if needed. @@ -1433,7 +1440,6 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) - real, parameter :: cdrag = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) real, parameter :: gamma_t = 0.0 ! Exchange velcoity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independ of u_star. ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. @@ -1441,8 +1447,6 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! density_ice = bergs%rho_bergs Rho0=rho_seawater !Note that the ice shelf code has a default of Rho0=1035 - utide=0. ! Tidal speeds, set to zero for now. - ustar_bg=0.001 !Background u_star under iceshelf. This should be linked to a value felt by the ocean boundary layer Hml =10. !Mixed layer depth. This is an approximate value. It looks like the code is not sensitive to it (since it enters in log(Hml) p_int= p_atm+(gravity*thickness*density_ice) ! The pressure at the ice-ocean interface, in Pa. @@ -1468,8 +1472,8 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic iDens = 1.0/Rho0 !Preparing the mixed layer properties for use in both 2 and 3 equation version - ustar = cdrag*(dvo + utide) - ustar_h = MAX(ustar_bg, ustar) + ustar = bergs%cdrag_icebergs*(dvo + bergs%utide_icebergs) + ustar_h = max(bergs%ustar_icebergs_bg, ustar) ! Estimate the neutral ocean boundary layer thickness as the minimum of the ! reported ocean mixed layer thickness and the neutral Ekman depth. @@ -2577,7 +2581,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, type(icebergs_gridded), pointer :: grd logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area -real :: grdd_u_iceberg, grdd_v_iceberg +real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp @@ -2612,6 +2616,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%spread_area(:,:)=0. grd%u_iceberg(:,:)=0. grd%v_iceberg(:,:)=0. + grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. @@ -2916,6 +2921,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_u_iceberg, grd%u_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_v_iceberg>0) & lerr=send_data(grd%id_v_iceberg, grd%v_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_ustar_iceberg>0) & + lerr=send_data(grd%id_ustar_iceberg, grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_mass>0) & lerr=send_data(grd%id_mass, grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_stored_ice>0) & @@ -3013,6 +3020,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(bergs%spread_area_end) call mpp_sum(bergs%u_iceberg_end) call mpp_sum(bergs%v_iceberg_end) + call mpp_sum(bergs%ustar_iceberg_end) call mpp_sum(bergs%floating_heat_end) call mpp_sum(bergs%returned_mass_on_ocean) call mpp_sum(bergs%nbergs_end) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index b8b5f28..5e46ee1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -120,6 +120,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/s/m^2) real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) + real, dimension(:,:), pointer :: ustar_iceberg=>null() ! Frictional velocity below icebergs to be passed to ocean (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) - Alon:I think that this actually has units of kg @@ -141,7 +142,7 @@ module ice_bergs_framework integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 integer :: id_mass_on_ocn=-1, id_area_on_ocn=-1, id_spread_mass=-1, id_spread_area=-1 integer :: id_ssh=-1, id_fax=-1, id_fay=-1 - integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1 + integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1, id_ustar_iceberg real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -214,6 +215,9 @@ module ice_bergs_framework real :: lat_ref=0. ! Reference latitude for f-plane (when this option is on) real :: u_override=0.0 ! Overrides the u velocity of icebergs (for ocean testing) real :: v_override=0.0 ! Overrides the v velocity of icebergs (for ocean testing) + real :: utide_icebergs= 0. ! Tidal speeds, set to zero for now. + real :: ustar_icebergs_bg=0.001 ! Background u_star under icebergs. This should be linked to a value felt by the ocean boundary layer + real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) real :: initial_orientation=0. ! Iceberg orientaion relative to this angle (in degrees). Used for hexagonal mass spreading. real, dimension(:), pointer :: initial_mass, distribution, mass_scaling real, dimension(:), pointer :: initial_thickness, initial_width, initial_length @@ -269,6 +273,7 @@ module ice_bergs_framework real :: spread_area_start=0., spread_area_end=0. real :: u_iceberg_start=0., u_iceberg_end=0. real :: v_iceberg_start=0., v_iceberg_end=0. + real :: ustar_iceberg_start=0., ustar_iceberg_end=0. real :: returned_mass_on_ocean=0. real :: returned_area_on_ocean=0. real :: net_melt=0., berg_melt=0., bergy_src=0., bergy_melt=0. @@ -346,6 +351,9 @@ subroutine ice_bergs_framework_init(bergs, & real :: v_override=0.0 ! Overrides the v velocity of icebergs (for ocean testing) real :: Lx=360. ! Length of domain in x direction, used for periodicity (use a huge number for non-periodic) real :: initial_orientation=0. ! Iceberg orientaion relative to this angle (in degrees). Used for hexagonal mass spreading. +real :: utide_icebergs= 0. ! Tidal speeds, set to zero for now. +real :: ustar_icebergs_bg=0.001 ! Background u_star under icebergs. This should be linked to a value felt by the ocean boundary layer +real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) logical :: use_operator_splitting=.true. ! Use first order operator splitting for thermodynamics logical :: add_weight_to_ocean=.true. ! Add weight of icebergs + bits to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean @@ -392,7 +400,7 @@ subroutine ice_bergs_framework_init(bergs, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & - Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo + Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -509,6 +517,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%spread_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_area(:,:)=0. allocate( grd%u_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%u_iceberg(:,:)=0. allocate( grd%v_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%v_iceberg(:,:)=0. + allocate( grd%ustar_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%ustar_iceberg(:,:)=0. allocate( grd%virtual_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%virtual_area(:,:)=0. allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. @@ -758,6 +767,9 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%ustar_icebergs_bg=ustar_icebergs_bg + bergs%utide_icebergs=utide_icebergs + bergs%cdrag_icebergs=cdrag_icebergs bergs%use_mixed_layer_salinity_for_thermo=use_mixed_layer_salinity_for_thermo bergs%find_melt_using_spread_mass=find_melt_using_spread_mass bergs%Use_three_equation_model=Use_three_equation_model @@ -832,6 +844,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Iceberg u velocity (m/s)') grd%id_v_iceberg=register_diag_field('icebergs', 'v_iceberg', axes, Time, & 'Iceberg v velocity (m/s)') + grd%id_ustar_iceberg=register_diag_field('icebergs', 'ustar_iceberg', axes, Time, & + 'Iceberg frictional velocity (m/s)') grd%id_virtual_area=register_diag_field('icebergs', 'virtual_area', axes, Time, & 'Virtual coverage by icebergs', 'm^2') grd%id_mass=register_diag_field('icebergs', 'mass', axes, Time, & @@ -3816,6 +3830,7 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%spread_area, 'spread_area') call grd_chksum2(grd, grd%u_iceberg, 'u_iceberg') call grd_chksum2(grd, grd%v_iceberg, 'v_iceberg') + call grd_chksum2(grd, grd%ustar_iceberg, 'ustar_iceberg') call grd_chksum2(grd, grd%virtual_area, 'varea') call grd_chksum2(grd, grd%floating_melt, 'floating_melt') call grd_chksum2(grd, grd%berg_melt, 'berg_melt') From 495efb7a341e0e640f90400f8a869c25bb3b5f45 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 20 Sep 2016 16:11:57 -0400 Subject: [PATCH 164/361] Added "debug iceberg with id" capability - Setting namelist parameter debug_iceberg_with_id=##### to the iceberg_num of a particular berg allows "tracking" of a single berg. - Only two calls to monitor_a_berg() have been added so far. - print_berg() and check_positions() now have optional arguments for the i,j of the gridded-list they belong to. - Updated error messages in check_position(). - Corrected formatting in print_berg(); id was being formatted as a float. - No answer changes. --- icebergs_framework.F90 | 58 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 37188b1..d366327 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -231,6 +231,7 @@ module ice_bergs_framework logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide + integer :: debug_iceberg_with_id = -1 ! If positive, monitors a berg with this id real :: speed_limit=0. ! CFL speed limit for a berg [m/s] real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs type(buffer), pointer :: obuffer_n=>null(), ibuffer_n=>null() @@ -356,13 +357,15 @@ subroutine ice_bergs_framework_init(bergs, & real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) real, dimension(nclasses) :: initial_thickness=(/40., 67., 133., 175., 250., 250., 250., 250., 250., 250./) ! Total thickness of newly calved bergs (m) +integer :: debug_iceberg_with_id = -1 ! If positive, monitors a berg with this id namelist /icebergs_nml/ verbose, budget, halo, traj_sample_hrs, initial_mass, traj_write_hrs, max_bonds, save_short_traj,Static_icebergs, & distribution, mass_scaling, initial_thickness, verbose_hrs, spring_coef,bond_coef, radial_damping_coef, tangental_damping_coef, only_interactive_forces, & rho_bergs, LoW_ratio, debug, really_debug, use_operator_splitting, bergy_bit_erosion_fraction, iceberg_bonds_on, manually_initialize_bonds, ignore_missing_restart_bergs, & parallel_reprod, use_slow_find, sicn_shift, add_weight_to_ocean, passive_mode, ignore_ij_restart, use_new_predictive_corrective, halo_debugging, hexagonal_icebergs, & time_average_weight, generate_test_icebergs, speed_limit, fix_restart_dates, use_roundoff_fix, Runge_not_Verlet, interactive_icebergs_on, critical_interaction_damping_on, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & - allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_regular,grid_is_latlon,Lx,use_f_plane, use_old_spreading + allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_regular,grid_is_latlon,Lx,use_f_plane, use_old_spreading, & + debug_iceberg_with_id ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -738,6 +741,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean bergs%use_old_spreading=use_old_spreading + bergs%debug_iceberg_with_id=debug_iceberg_with_id allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) allocate( bergs%distribution(nclasses) ); bergs%distribution(:)=distribution(:) allocate( bergs%mass_scaling(nclasses) ); bergs%mass_scaling(:)=mass_scaling(:) @@ -1284,6 +1288,8 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_start=count_bergs(bergs) endif + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (top)') + ! Find number of bergs that headed east/west nbergs_to_send_e=0 nbergs_to_send_w=0 @@ -1467,6 +1473,8 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_rcvd_from_n=0 endif + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (end)') + if (debug) then nbergs_end=count_bergs(bergs) i=nbergs_rcvd_from_n+nbergs_rcvd_from_s+nbergs_rcvd_from_e+nbergs_rcvd_from_w & @@ -2091,6 +2099,32 @@ end subroutine check_for_duplicates ! ############################################################################## +subroutine monitor_a_berg(bergs, label) +! Arguments +type(icebergs), pointer :: bergs +character(len=*) :: label +! Local variables +type(iceberg), pointer :: this +integer :: grdi, grdj +integer :: stderrunit + + if (bergs%debug_iceberg_with_id<0) return + stderrunit=stderr() ! Get the stderr unit number + + do grdj = bergs%grd%jsd,bergs%grd%jed ; do grdi = bergs%grd%isd,bergs%grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + if (this%iceberg_num == bergs%debug_iceberg_with_id) then + call print_berg(stderrunit, this, 'MONITOR: '//label, grdi, grdj) + endif + this=>this%next + enddo + enddo ; enddo + +end subroutine monitor_a_berg + +! ############################################################################## + subroutine insert_berg_into_list(first, newberg, quick) ! Arguments type(iceberg), pointer :: first, newberg @@ -2311,16 +2345,21 @@ end subroutine destroy_iceberg ! ############################################################################## -subroutine print_berg(iochan, berg, label) +subroutine print_berg(iochan, berg, label, il, jl) ! Arguments integer, intent(in) :: iochan type(iceberg), pointer :: berg character(len=*) :: label +integer, optional, intent(in) :: il, jl !< Indices of cell berg should be in ! Local variables - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") start lon,lat,yr,day,mass=",2f10.4,i5,f7.2,es12.4)') & + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") start lon,lat,yr,#,day,mass,hb=",2f10.4,i5,i12,f7.2,es12.4,f5.1)') & label, mpp_pe(), berg%start_lon, berg%start_lat, & - berg%start_year, berg%iceberg_num, berg%start_day, berg%start_mass + berg%start_year, berg%iceberg_num, berg%start_day, berg%start_mass, berg%halo_berg + if (present(il).and.present(jl)) then + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & + label, mpp_pe(), ') List i,j=',il,jl + endif write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & label, mpp_pe(), ') i,j=',berg%ine, berg%jne, & ' xi,yj=', berg%xi, berg%yj, & @@ -3592,11 +3631,12 @@ end function pos_within_cell ! ############################################################################## -subroutine check_position(grd, berg, label) +subroutine check_position(grd, berg, label, il, jl) ! Arguments type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: berg character(len=*) :: label +integer, optional, intent(in) :: il, jl !< Indices of cell berg should be in ! Local variables real :: xi, yj logical :: lret @@ -3609,8 +3649,12 @@ subroutine check_position(grd, berg, label) if (xi.ne.berg%xi.or.yj.ne.berg%yj) then write(stderrunit,'("diamonds: check_position (",i4,") b%x,x,-=",3(es12.4,x),a)') mpp_pe(),berg%xi,xi,berg%xi-xi,label write(stderrunit,'("diamonds: check_position (",i4,") b%y,y,-=",3(es12.4,x),a)') mpp_pe(),berg%yj,yj,berg%yj-yj,label - call print_berg(stderrunit, berg, 'check_position') - call error_mesg('diamonds, check_position','berg has inconsistent xi,yj!',FATAL) + call print_berg(stderrunit, berg, 'check_position', il, jl) + call error_mesg('diamonds, check_position, '//trim(label),'berg has inconsistent xi,yj!',FATAL) + endif + if (grd%msk(berg%ine, berg%jne)==0.) then + call print_berg(stderrunit, berg, 'check_position, '//trim(label), il, jl) + call error_mesg('diamonds, check_position, '//trim(label),'berg is in a land cell!',FATAL) endif end subroutine check_position From 2b9cfd7b0a9fe1f00cb9fc3cc790d5a8830ef827 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 20 Sep 2016 16:18:39 -0400 Subject: [PATCH 165/361] Corrected debugging of halo updates - With debug=true, the existence of persistent bergs in halos needed the budget of bergs within send_bergs_to_other_pes() to include halos. - Also updated args to call check_posiiton(). - No answer changes. --- icebergs_framework.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d366327..3f51efe 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1285,7 +1285,7 @@ subroutine send_bergs_to_other_pes(bergs) grd=>bergs%grd if (debug) then - nbergs_start=count_bergs(bergs) + nbergs_start=count_bergs(bergs, with_halos=.true.) endif if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (top)') @@ -1476,7 +1476,7 @@ subroutine send_bergs_to_other_pes(bergs) if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (end)') if (debug) then - nbergs_end=count_bergs(bergs) + nbergs_end=count_bergs(bergs, with_halos=.true.) i=nbergs_rcvd_from_n+nbergs_rcvd_from_s+nbergs_rcvd_from_e+nbergs_rcvd_from_w & -nbergs_to_send_n-nbergs_to_send_s-nbergs_to_send_e-nbergs_to_send_w if (nbergs_end-(nbergs_start+i).ne.0) then @@ -1501,7 +1501,7 @@ subroutine send_bergs_to_other_pes(bergs) do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec this=>bergs%list(grdi,grdj)%first do while (associated(this)) - call check_position(grd, this, 'exchange (bot)') + call check_position(grd, this, 'exchange (bot)', grdi, grdj) if (this%ine.lt.bergs%grd%isc .or. & this%ine.gt.bergs%grd%iec .or. & this%jne.lt.bergs%grd%jsc .or. & From d5577377b2da0fb70dd8dcd9d88eeae7785e5361 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 20 Sep 2016 16:44:28 -0400 Subject: [PATCH 166/361] Removed "force append" from send_bergs_to_other_pes() - When unpacking bergs during communication we do not want to use the append method for adding bergs to lists. - Also avoid using of "initial values" in insert_berg_into_list() and unpack_berg_into_buffer(). Initial values automatically add the save attribute and the value is not initialized on second calls. - Avoid potential allocation error with nbergs=0. - No answer changes. --- icebergs_framework.F90 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3f51efe..923d7e7 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1274,9 +1274,6 @@ subroutine send_bergs_to_other_pes(bergs) integer :: i, nbergs_start, nbergs_end integer :: stderrunit integer :: grdi, grdj -logical :: force_app - -force_app=.true. ! Get the stderr unit number stderrunit = stderr() @@ -1347,7 +1344,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, force_app, bergs%max_bonds ) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, max_bonds_in=bergs%max_bonds ) enddo endif else @@ -1365,7 +1362,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, force_app, bergs%max_bonds) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, max_bonds_in=bergs%max_bonds) enddo endif else @@ -1440,7 +1437,7 @@ subroutine send_bergs_to_other_pes(bergs) call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd, force_app, bergs%max_bonds ) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd, max_bonds_in=bergs%max_bonds ) enddo endif else @@ -1466,7 +1463,7 @@ subroutine send_bergs_to_other_pes(bergs) call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) endif do i=1, nbergs_rcvd_from_n - call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd,force_app, bergs%max_bonds) + call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd, max_bonds_in=bergs%max_bonds) enddo endif else @@ -1673,7 +1670,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ integer :: other_berg_num, other_berg_ine, other_berg_jne integer :: counter, k, max_bonds integer :: stderrunit - logical :: force_app = .false. + logical :: force_app logical :: quick ! Get the stderr unit number @@ -1682,6 +1679,7 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ quick=.false. max_bonds=0 if (present(max_bonds_in)) max_bonds=max_bonds_in + force_app = .false. if(present(force_append)) force_app = force_append localberg%lon=buff%data(1,n) @@ -2131,8 +2129,9 @@ subroutine insert_berg_into_list(first, newberg, quick) logical, intent(in), optional :: quick ! Local variables type(iceberg), pointer :: this, prev -logical :: quickly = .false. +logical :: quickly + quickly = .false. if (associated(first)) then if (.not. parallel_reprod .or. quickly) then @@ -3943,6 +3942,7 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) nbergs=count_bergs(bergs) call mpp_max(nbergs) + nbergs = max(nbergs, 1) allocate( fld( nbergs, 19 ) ) !Changed from 11 to 19 by Alon allocate( fld2( nbergs, 19 ) ) !Changed from 11 to 19 by Alon allocate( icnt( grd%isd:grd%ied, grd%jsd:grd%jed ) ) From d48eb2fce33aafa5b7d4c8cb2f2dbb5f314ebf50 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 23 Sep 2016 16:43:01 -0400 Subject: [PATCH 167/361] 1) Added spread_uvel and spread_vvel fields, which are the gridded average iceberg velocity. These fields are calculated using the spread_mass_to_ocean routine. These fields are used in order to calculate ustar, which is then passed through to the ocean model. 2) the spread_mass_to_ocean routine has been refactored to allow mass, area, uvel and vvel to be spread across cells. 3) The iceberg_incr_mass routine has been reworked so that it can spread mass, area, uvel and vvel. This is done by taking in an optional argument (string), which tells the routine which variable to update. 4) A flag PASSS_FIELDS_TO_OCEAN_MODEL has been added. When this is true, the spread_area, ustar, and spread_mass are calculated so that they can be passed to the ocean model. 5) The variable spread_mass_old has been added to the icebergs_run routine. This is a temporary variable used when differencing old and new iceberg masses to work out melting (when find_melt_using_spread_mass=.true.) --- icebergs.F90 | 177 +++++++++++++++++++++++++---------------- icebergs_framework.F90 | 42 +++++++--- 2 files changed, 140 insertions(+), 79 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9fae040..d34ba3d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1127,6 +1127,8 @@ subroutine thermodynamics(bergs) !Initializing static_berg static_berg=0. + grd%Uvel_on_ocean(:,:,:)=0. + grd%Vvel_on_ocean(:,:,:)=0. ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 @@ -1331,14 +1333,22 @@ subroutine thermodynamics(bergs) if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,this,orientation) if (bergs%hexagonal_icebergs) static_berg=this%static_berg !Change this to use_old_restart=false when this is merged in call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, & - this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg) + this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg,this%uvel,this%vvel) endif endif this=>next enddo enddo ; enddo - !Scaling the gridded iceberg velocity by the iceberg mass + !Finding the average iceberg velocity in a cell to calculate u_star + grd%spread_uvel(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='Uvel') + grd%spread_vvel(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='Vvel') + grd%spread_area(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') + + !Divdind the gridded iceberg momentum by the iceberg mass to get velocities do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec if (grd%mass(i,j)>0.) then grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) @@ -1349,12 +1359,17 @@ subroutine thermodynamics(bergs) enddo; enddo !Calculating ustar_iceberg (gridded) - do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec - dvo=sqrt((grd%u_iceberg(i,j)-grd%uo(i,j))**2+(grd%v_iceberg(i,j)-grd%vo(i,j))**2) - ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) - ustar_h = max(bergs%ustar_icebergs_bg, ustar) - grd%ustar_iceberg(i,j)=ustar_h - enddo; enddo + grd%ustar_iceberg(:,:)=0. + if ((grd%id_ustar_iceberg>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + !dvo=sqrt((grd%u_iceberg(i,j)-grd%uo(i,j))**2+(grd%v_iceberg(i,j)-grd%vo(i,j))**2) + dvo=sqrt((grd%spread_uvel(i,j)-grd%uo(i,j))**2+(grd%spread_vvel(i,j)-grd%vo(i,j))**2) + ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) + ustar_h = max(bergs%ustar_icebergs_bg, ustar) + if (grd%spread_area(i,j) ==0.0) ustar_h=0. + grd%ustar_iceberg(i,j)=ustar_h + enddo; enddo + endif end subroutine thermodynamics @@ -1760,17 +1775,17 @@ subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) end subroutine find_orientation_using_iceberg_bonds -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading,hexagonal_icebergs,theta,static_berg) +subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading,hexagonal_icebergs,theta,static_berg,uvel,vvel) ! Arguments type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j - real, intent(in) :: x, y, Mberg, Mbits, scaling, Area + real, intent(in) :: x, y, Mberg, Mbits, scaling, Area,uvel,vvel logical, intent(in) :: hexagonal_icebergs logical, intent(in) :: use_old_spreading real, intent(in) :: theta real, optional, intent(in) :: static_berg ! Local variables - real :: xL, xC, xR, yD, yC, yU, Mass, L, Area_scaled + real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR real :: S, H, origin_x, origin_y, x0, y0 real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex @@ -1917,32 +1932,42 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling endif !Spreading the iceberg mass onto the ocean - grd%mass_on_ocean(i,j,1)=grd%mass_on_ocean(i,j,1)+(yDxL*Mass/fraction_used) - grd%mass_on_ocean(i,j,2)=grd%mass_on_ocean(i,j,2)+(yDxC*Mass/fraction_used) - grd%mass_on_ocean(i,j,3)=grd%mass_on_ocean(i,j,3)+(yDxR*Mass/fraction_used) - grd%mass_on_ocean(i,j,4)=grd%mass_on_ocean(i,j,4)+(yCxL*Mass/fraction_used) - grd%mass_on_ocean(i,j,5)=grd%mass_on_ocean(i,j,5)+(yCxC*Mass/fraction_used) - grd%mass_on_ocean(i,j,6)=grd%mass_on_ocean(i,j,6)+(yCxR*Mass/fraction_used) - grd%mass_on_ocean(i,j,7)=grd%mass_on_ocean(i,j,7)+(yUxL*Mass/fraction_used) - grd%mass_on_ocean(i,j,8)=grd%mass_on_ocean(i,j,8)+(yUxC*Mass/fraction_used) - grd%mass_on_ocean(i,j,9)=grd%mass_on_ocean(i,j,9)+(yUxR*Mass/fraction_used) - + call spread_variable_across_cells(grd, grd%mass_on_ocean, Mass, i ,j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) !Spreading the iceberg area onto the ocean - Area_scaled=Area*scaling - grd%area_on_ocean(i,j,1)=grd%area_on_ocean(i,j,1)+(yDxL*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,2)=grd%area_on_ocean(i,j,2)+(yDxC*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,3)=grd%area_on_ocean(i,j,3)+(yDxR*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,4)=grd%area_on_ocean(i,j,4)+(yCxL*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,5)=grd%area_on_ocean(i,j,5)+(yCxC*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,6)=grd%area_on_ocean(i,j,6)+(yCxR*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,7)=grd%area_on_ocean(i,j,7)+(yUxL*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,8)=grd%area_on_ocean(i,j,8)+(yUxC*Area_scaled/fraction_used) - grd%area_on_ocean(i,j,9)=grd%area_on_ocean(i,j,9)+(yUxR*Area_scaled/fraction_used) - + call spread_variable_across_cells(grd, grd%area_on_ocean, Area*scaling , i ,j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,fraction_used) + !Spreading the iceberg x momentum onto the ocean + call spread_variable_across_cells(grd,grd%Uvel_on_ocean, uvel*Area*scaling , i ,j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) + !Spreading the iceberg y momentum onto the ocean + call spread_variable_across_cells(grd,grd%Vvel_on_ocean, vvel*Area*scaling , i ,j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) + end subroutine spread_mass_across_ocean_cells +subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,fraction_used) + ! Arguments + type(icebergs_gridded), pointer, intent(in) :: grd + real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean + real, intent(in) :: Var !Variable to be spread accross cell + real, intent(in) :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR !Weights + real, intent(in) :: fraction_used !Amount of iceberg used + integer, intent(in) :: i, j + !Spreading the iceberg mass onto the ocean + variable_on_ocean(i,j,1)=variable_on_ocean(i,j,1)+(yDxL*Var/fraction_used) + variable_on_ocean(i,j,2)=variable_on_ocean(i,j,2)+(yDxC*Var/fraction_used) + variable_on_ocean(i,j,3)=variable_on_ocean(i,j,3)+(yDxR*Var/fraction_used) + variable_on_ocean(i,j,4)=variable_on_ocean(i,j,4)+(yCxL*Var/fraction_used) + variable_on_ocean(i,j,5)=variable_on_ocean(i,j,5)+(yCxC*Var/fraction_used) + variable_on_ocean(i,j,6)=variable_on_ocean(i,j,6)+(yCxR*Var/fraction_used) + variable_on_ocean(i,j,7)=variable_on_ocean(i,j,7)+(yUxL*Var/fraction_used) + variable_on_ocean(i,j,8)=variable_on_ocean(i,j,8)+(yUxC*Var/fraction_used) + variable_on_ocean(i,j,9)=variable_on_ocean(i,j,9)+(yUxR*Var/fraction_used) +end subroutine spread_variable_across_cells ! ############################################################################## @@ -2581,12 +2606,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, type(icebergs_gridded), pointer :: grd logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area -real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg +real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount +real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec) :: ustar_berg, area_berg, spread_mass_old integer :: nbonds !logical :: within_iceberg_model @@ -2616,8 +2642,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%spread_area(:,:)=0. grd%u_iceberg(:,:)=0. grd%v_iceberg(:,:)=0. + grd%spread_uvel(:,:)=0. + grd%spread_vvel(:,:)=0. grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. + + ustar_berg(:,:)=0. + area_berg(:,:)=0. if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. if (bergs%add_weight_to_ocean) grd%area_on_ocean(:,:,:)=0. @@ -2853,25 +2884,24 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) !within_iceberg_model=.True. if (bergs%find_melt_using_spread_mass) then - grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) !Temporarily using the variable calving for storing old mass (not sure better way) + spread_mass_old=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) grd%spread_mass(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec if (grd%area(i,j)>0.0) then - grd%floating_melt(i,j)=max((grd%floating_melt(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) - !grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. - grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*0.0 !Not 100% sure this is correct. + grd%floating_melt(i,j)=max((spread_mass_old(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) + grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. else grd%floating_melt(i,j)=0.0 endif enddo ;enddo - elseif (grd%id_spread_mass>0) then !Update diagnostic of iceberg mass spread on ocean + elseif ((grd%id_spread_mass>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean grd%spread_mass(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) endif - if ( (grd%id_spread_area>0) ) then !Update diagnostic of iceberg area spread on ocean + if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg area spread on ocean grd%spread_area(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,spread_area_not_mass=.True.) + call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') endif ! Gridded diagnostics @@ -2921,6 +2951,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_u_iceberg, grd%u_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_v_iceberg>0) & lerr=send_data(grd%id_v_iceberg, grd%v_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_spread_uvel>0) & + lerr=send_data(grd%id_spread_uvel, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_spread_vvel>0) & + lerr=send_data(grd%id_spread_vvel, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_ustar_iceberg>0) & lerr=send_data(grd%id_ustar_iceberg, grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_mass>0) & @@ -2966,8 +3000,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, where (grd%area(grd%isc:grd%iec,grd%jsc:grd%jec)>0.) calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)/grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) & +grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec) + ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) + area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) elsewhere calving(:,:)=0. + ustar_berg(:,:)=0. + area_berg(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) endif @@ -3007,7 +3045,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%returned_mass_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) !Finding spread area call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r - call icebergs_incr_mass(bergs, grd%tmpc,spread_area_not_mass=.true.) + call icebergs_incr_mass(bergs, grd%tmpc,field_name_in='area') call mpp_clock_begin(bergs%clock_dia); call mpp_clock_begin(bergs%clock) ! To enable calling of public s/r bergs%returned_area_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%nbergs_end=count_bergs(bergs) @@ -3020,6 +3058,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_sum(bergs%spread_area_end) call mpp_sum(bergs%u_iceberg_end) call mpp_sum(bergs%v_iceberg_end) + call mpp_sum(bergs%spread_uvel_end) + call mpp_sum(bergs%spread_vvel_end) call mpp_sum(bergs%ustar_iceberg_end) call mpp_sum(bergs%floating_heat_end) call mpp_sum(bergs%returned_mass_on_ocean) @@ -3226,16 +3266,16 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time, spread_area_not_mass) +subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time,field_name_in) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass type(time_type), intent(in), optional :: Time logical, intent(in), optional :: within_iceberg_model -logical, intent(in), optional :: spread_area_not_mass +character(len=4), intent(in), optional :: field_name_in ! Local variables logical :: within_model -logical :: spread_area !Logical flag which allows you to spread area over ocean (instead of mass) +character(len=4) :: field_name integer :: i, j type(icebergs_gridded), pointer :: grd real :: dmda @@ -3250,18 +3290,14 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time, spread_ar !var_on_ocean(:,:,:)=0. - !Decide whether area of mass are being spread across grid cells (default spread mass) - spread_area=.False. - if (present(spread_area_not_mass)) then - if (spread_area_not_mass) then - spread_area=.True. - endif - endif - if (spread_area) then - var_on_ocean(:,:,:)=grd%area_on_ocean(:,:,:) - else - var_on_ocean(:,:,:)=grd%mass_on_ocean(:,:,:) - endif + !Deciding which varibale to spread across cells across grid cells (default spread mass) + field_name='mass' + if (present(field_name_in)) field_name=field_name_in + if (field_name=='mass') var_on_ocean(:,:,:)=grd%mass_on_ocean(:,:,:) + if (field_name=='area') var_on_ocean(:,:,:)=grd%area_on_ocean(:,:,:) + if (field_name=='Uvel') var_on_ocean(:,:,:)=grd%Uvel_on_ocean(:,:,:) + if (field_name=='Vvel') var_on_ocean(:,:,:)=grd%Vvel_on_ocean(:,:,:) + within_model=.False. @@ -3309,29 +3345,32 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time, spread_ar + (var_on_ocean(i ,j-1,8)+var_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) + !Make sure that area <=1.0 + if (field_name=='area') dmda=min(dmda,1.0) + if (.not.(within_model)) then if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda else mass(i,j)=dmda endif - if ((grd%id_area_on_ocn>0).and.(spread_area)) grd%tmp(i,j)=dmda - if ((grd%id_mass_on_ocn>0).and.(.not. spread_area)) grd%tmp(i,j)=dmda + if ((grd%id_area_on_ocn>0).and.(field_name=='area')) grd%tmp(i,j)=dmda + if ((grd%id_mass_on_ocn>0).and.(field_name=='mass')) grd%tmp(i,j)=dmda enddo; enddo - if (spread_area) then - if (present(Time).and. (grd%id_area_on_ocn>0)) & - lerr=send_data(grd%id_area_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) - else + if (field_name=='mass') then if (present(Time).and. (grd%id_mass_on_ocn>0)) & lerr=send_data(grd%id_mass_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + elseif (field_name=='area') then + if (present(Time).and. (grd%id_area_on_ocn>0)) & + lerr=send_data(grd%id_area_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) endif if (debug) then grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass - if (.not. spread_area) then + if (field_name=='mass') then call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') call grd_chksum2(grd, grd%tmp, 'mass out (incr)') - else + elseif (field_name=='area') then call grd_chksum3(grd, grd%area_on_ocean, 'area bergs (incr)') call grd_chksum2(grd, grd%tmp, 'area out (incr)') endif @@ -3672,7 +3711,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -3796,7 +3835,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -3835,7 +3874,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -3893,7 +3932,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -4027,7 +4066,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg ) + bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 5e46ee1..24477e9 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -116,15 +116,19 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_src=>null() ! Mass flux from berg erosion into bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) - real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/s/m^2) - real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/s/m^2) + real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/m^2) + real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/m^2) real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) - real, dimension(:,:), pointer :: ustar_iceberg=>null() ! Frictional velocity below icebergs to be passed to ocean (mass weighted - but not spread mass weighted) + real, dimension(:,:), pointer :: spread_uvel=>null() ! Average iceberg velocity in grid cell (spread area weighted) + real, dimension(:,:), pointer :: spread_vvel=>null() ! Average iceberg velocity in grid cell (spread area weighted) + real, dimension(:,:), pointer :: ustar_iceberg=>null() ! Frictional velocity below icebergs to be passed to ocean real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) - real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) - Alon:I think that this actually has units of kg - real, dimension(:,:,:), pointer :: area_on_ocean=>null() ! Area distribution partitioned by neighbor (m^2/m^2) - Alon:I think that this actually has units of m^2 + real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg) + real, dimension(:,:,:), pointer :: area_on_ocean=>null() ! Area distribution partitioned by neighbor (m^2) + real, dimension(:,:,:), pointer :: Uvel_on_ocean=>null() ! zonal velocity distribution partitioned by neighbor (m^2* m/s) + real, dimension(:,:,:), pointer :: Vvel_on_ocean=>null() ! meridional momentum distribution partitioned by neighbor (m^2 m/s) real, dimension(:,:), pointer :: tmp=>null() ! Temporary work space real, dimension(:,:), pointer :: tmpc=>null() ! Temporary work space real, dimension(:,:,:), pointer :: stored_ice=>null() ! Accumulated ice mass flux at calving locations (kg) @@ -143,6 +147,7 @@ module ice_bergs_framework integer :: id_mass_on_ocn=-1, id_area_on_ocn=-1, id_spread_mass=-1, id_spread_area=-1 integer :: id_ssh=-1, id_fax=-1, id_fay=-1 integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1, id_ustar_iceberg + integer :: id_spread_uvel=-1, id_spread_vvel=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -227,6 +232,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. + logical :: pass_fields_to_ocean_model=.False. !Iceberg area, mass and ustar fields are prepared to pass to ocean model logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. @@ -273,6 +279,8 @@ module ice_bergs_framework real :: spread_area_start=0., spread_area_end=0. real :: u_iceberg_start=0., u_iceberg_end=0. real :: v_iceberg_start=0., v_iceberg_end=0. + real :: spread_uvel_start=0., spread_uvel_end=0. + real :: spread_vvel_start=0., spread_vvel_end=0. real :: ustar_iceberg_start=0., ustar_iceberg_end=0. real :: returned_mass_on_ocean=0. real :: returned_area_on_ocean=0. @@ -361,6 +369,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: speed_limit=0. ! CFL speed limit for a berg real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: pass_fields_to_ocean_model=.False. !Iceberg area, mass and ustar fields are prepared to pass to ocean model logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. logical :: Use_three_equation_model=.True. !Uses 3 equation model for melt when ice shelf type thermodynamics are used. @@ -400,7 +409,7 @@ subroutine ice_bergs_framework_init(bergs, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & - Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs + Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -517,11 +526,15 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%spread_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_area(:,:)=0. allocate( grd%u_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%u_iceberg(:,:)=0. allocate( grd%v_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%v_iceberg(:,:)=0. + allocate( grd%spread_uvel(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_uvel(:,:)=0. + allocate( grd%spread_vvel(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_vvel(:,:)=0. allocate( grd%ustar_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%ustar_iceberg(:,:)=0. allocate( grd%virtual_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%virtual_area(:,:)=0. allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. allocate( grd%area_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%area_on_ocean(:,:,:)=0. + allocate( grd%Uvel_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%Uvel_on_ocean(:,:,:)=0. + allocate( grd%Vvel_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%Vvel_on_ocean(:,:,:)=0. allocate( grd%stored_ice(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%stored_ice(:,:,:)=0. allocate( grd%real_calving(grd%isd:grd%ied, grd%jsd:grd%jed, nclasses) ); grd%real_calving(:,:,:)=0. allocate( grd%uo(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%uo(:,:)=0. @@ -767,6 +780,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%pass_fields_to_ocean_model=pass_fields_to_ocean_model bergs%ustar_icebergs_bg=ustar_icebergs_bg bergs%utide_icebergs=utide_icebergs bergs%cdrag_icebergs=cdrag_icebergs @@ -844,16 +858,20 @@ subroutine ice_bergs_framework_init(bergs, & 'Iceberg u velocity (m/s)') grd%id_v_iceberg=register_diag_field('icebergs', 'v_iceberg', axes, Time, & 'Iceberg v velocity (m/s)') + grd%id_spread_uvel=register_diag_field('icebergs', 'spread_uvel', axes, Time, & + 'Iceberg u velocity spread (m/s)') + grd%id_spread_vvel=register_diag_field('icebergs', 'spread_vvel', axes, Time, & + 'Iceberg v velocity spread (m/s)') grd%id_ustar_iceberg=register_diag_field('icebergs', 'ustar_iceberg', axes, Time, & 'Iceberg frictional velocity (m/s)') grd%id_virtual_area=register_diag_field('icebergs', 'virtual_area', axes, Time, & 'Virtual coverage by icebergs', 'm^2') grd%id_mass=register_diag_field('icebergs', 'mass', axes, Time, & 'Iceberg density field', 'kg/(m^2)') - grd%id_mass_on_ocn=register_diag_field('icebergs', 'mass_on_ocean', axes, Time, & - 'Iceberg density field felt by ocean', 'kg/(m^2)') - grd%id_area_on_ocn=register_diag_field('icebergs', 'area_on_ocean', axes, Time, & - 'Iceberg area field felt by ocean', 'm^2/(m^2)') +! grd%id_mass_on_ocn=register_diag_field('icebergs', 'mass_on_ocean', axes, Time, & +! 'Iceberg density field felt by ocean', 'kg/(m^2)') +! grd%id_area_on_ocn=register_diag_field('icebergs', 'area_on_ocean', axes, Time, & +! 'Iceberg area field felt by ocean', 'm^2/(m^2)') grd%id_stored_ice=register_diag_field('icebergs', 'stored_ice', axes3d, Time, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & @@ -3818,6 +3836,8 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%mass, 'mass') call grd_chksum3(grd, grd%mass_on_ocean, 'mass_on_ocean') call grd_chksum3(grd, grd%area_on_ocean, 'area_on_ocean') + call grd_chksum3(grd, grd%Uvel_on_ocean, 'Uvel_on_ocean') + call grd_chksum3(grd, grd%Vvel_on_ocean, 'Vvel_on_ocean') call grd_chksum3(grd, grd%stored_ice, 'stored_ice') call grd_chksum2(grd, grd%stored_heat, 'stored_heat') call grd_chksum2(grd, grd%melt_buoy, 'melt_b') @@ -3830,6 +3850,8 @@ subroutine checksum_gridded(grd, label) call grd_chksum2(grd, grd%spread_area, 'spread_area') call grd_chksum2(grd, grd%u_iceberg, 'u_iceberg') call grd_chksum2(grd, grd%v_iceberg, 'v_iceberg') + call grd_chksum2(grd, grd%spread_uvel, 'spread_uvel') + call grd_chksum2(grd, grd%spread_vvel, 'spread_vvel') call grd_chksum2(grd, grd%ustar_iceberg, 'ustar_iceberg') call grd_chksum2(grd, grd%virtual_area, 'varea') call grd_chksum2(grd, grd%floating_melt, 'floating_melt') From 504779ede5250920db2e619dcdb4762ae8969dee Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 23 Sep 2016 17:18:16 -0400 Subject: [PATCH 168/361] Fields spread_mass, spread_area and ustar_iceberg have been added to the icebergs_gridded type and allocated. This change will allow SIS2 to compile when the new code which passes fields from the icebergs model to the ocean model (through the sea ice model) is added. --- icebergs_framework.F90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d2b6899..85bd6d2 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -105,6 +105,9 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_src=>null() ! Mass flux from berg erosion into bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) + real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/m^2) + real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/m^2) + real, dimension(:,:), pointer :: ustar_iceberg=>null() ! Frictional velocity below icebergs to be passed to ocean real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg/m^2) @@ -419,6 +422,9 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%bergy_src(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_src(:,:)=0. allocate( grd%bergy_melt(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_melt(:,:)=0. allocate( grd%bergy_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_mass(:,:)=0. + allocate( grd%spread_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_mass(:,:)=0. + allocate( grd%spread_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_area(:,:)=0. + allocate( grd%ustar_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) );grd%ustar_iceberg(:,:)=0. allocate( grd%virtual_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%virtual_area(:,:)=0. allocate( grd%mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%mass(:,:)=0. allocate( grd%mass_on_ocean(grd%isd:grd%ied, grd%jsd:grd%jed, 9) ); grd%mass_on_ocean(:,:,:)=0. From 142b593eac25c29bad09c09f6c94dc932f5e05da Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 29 Sep 2016 13:32:40 -0400 Subject: [PATCH 169/361] 1) Added an option in the three equation model to use a fixed value for gamma_T, following what is done in the ice shelf code. (It now looks similar to the ice shelf code, however, I have not explored whether this option gives reasonable answers) 2) The dimensions of ustar_berg, area_berg and spread_mass_old have been changed. This fixed a bug in the calculating melt through spread mass option. 3) Added a diagnostic for melt which has units of m/yr, so that it is more easily comparible with the melt fields in the ocean model --- icebergs.F90 | 36 ++++++++++++++++++++++++++---------- icebergs_framework.F90 | 12 +++++++++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d34ba3d..e161cd8 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1532,9 +1532,14 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic ! on the turbulence. Following H & J '99, this limit also applies ! when the buoyancy flux is destabilizing. - Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) - I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) - I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + if (bergs%const_gamma) then ! if using a constant gamma_T + I_Gam_T = bergs%Gamma_T_3EQ + I_Gam_S = bergs%Gamma_T_3EQ/35. + else + Gam_turb = I_VK * (ln_neut + (0.5 * I_ZETA_N - 1.0)) + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + endif wT_flux = dT_ustar * I_Gam_T wB_flux = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux @@ -1559,8 +1564,14 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic dG_dwB = I_VK * (0.5 * I_ZETA_N) * dIns_dwB endif - I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) - I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + if (bergs%const_gamma) then ! if using a constant gamma_T + I_Gam_T = bergs%Gamma_T_3EQ + I_Gam_S = bergs%Gamma_T_3EQ/35. + else + I_Gam_T = 1.0 / (Gam_mol_t + Gam_turb) + I_Gam_S = 1.0 / (Gam_mol_s + Gam_turb) + endif + wT_flux = dT_ustar * I_Gam_T wB_flux_new = dB_dS * (dS_ustar * I_Gam_S) + dB_dT * wT_flux @@ -2612,7 +2623,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount -real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec) :: ustar_berg, area_berg, spread_mass_old +real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg, area_berg, spread_mass_old integer :: nbonds !logical :: within_iceberg_model @@ -2884,10 +2895,11 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) !within_iceberg_model=.True. if (bergs%find_melt_using_spread_mass) then - spread_mass_old=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + !spread_mass_old=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + spread_mass_old(:,:)=grd%spread_mass(:,:) grd%spread_mass(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) - do i=grd%isc,grd%iec ; do j=grd%jsc,grd%jec + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed if (grd%area(i,j)>0.0) then grd%floating_melt(i,j)=max((spread_mass_old(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. @@ -2927,6 +2939,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, lerr=send_data(grd%id_hi, grd%hi(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_floating_melt>0) & lerr=send_data(grd%id_floating_melt, grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (grd%id_melt_m_per_year>0) & + lerr=send_data(grd%id_melt_m_per_year, grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)* (86400.0*365.0/bergs%rho_bergs), Time) if (grd%id_berg_melt>0) & lerr=send_data(grd%id_berg_melt, grd%berg_melt(grd%isc:grd%iec,grd%jsc:grd%jec), Time) if (grd%id_melt_buoy>0) & @@ -3000,8 +3014,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, where (grd%area(grd%isc:grd%iec,grd%jsc:grd%jec)>0.) calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)/grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) & +grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec) - ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) - area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) + !ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) + !area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) + ustar_berg(:,:)=grd%ustar_iceberg(:,:) + area_berg(:,:)=grd%spread_area(:,:) elsewhere calving(:,:)=0. ustar_berg(:,:)=0. diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 24477e9..96652d6 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -148,6 +148,7 @@ module ice_bergs_framework integer :: id_ssh=-1, id_fax=-1, id_fay=-1 integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1, id_ustar_iceberg integer :: id_spread_uvel=-1, id_spread_vvel=-1 + integer :: id_melt_m_per_year=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -224,6 +225,8 @@ module ice_bergs_framework real :: ustar_icebergs_bg=0.001 ! Background u_star under icebergs. This should be linked to a value felt by the ocean boundary layer real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) real :: initial_orientation=0. ! Iceberg orientaion relative to this angle (in degrees). Used for hexagonal mass spreading. + real :: Gamma_T_3EQ=0.022 ! Nondimensional heat-transfer coefficient + logical :: const_gamma=.True. !If true uses a constant heat tranfer coefficient, from which the salt transfer is calculated real, dimension(:), pointer :: initial_mass, distribution, mass_scaling real, dimension(:), pointer :: initial_thickness, initial_width, initial_length logical :: restarted=.false. ! Indicate whether we read state from a restart or not @@ -362,6 +365,8 @@ subroutine ice_bergs_framework_init(bergs, & real :: utide_icebergs= 0. ! Tidal speeds, set to zero for now. real :: ustar_icebergs_bg=0.001 ! Background u_star under icebergs. This should be linked to a value felt by the ocean boundary layer real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) +real :: Gamma_T_3EQ=0.022 ! Nondimensional heat-transfer coefficient +logical :: const_gamma=.True. !If true uses a constant heat tranfer coefficient, from which the salt transfer is calculated logical :: use_operator_splitting=.true. ! Use first order operator splitting for thermodynamics logical :: add_weight_to_ocean=.true. ! Add weight of icebergs + bits to ocean logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean @@ -409,7 +414,8 @@ subroutine ice_bergs_framework_init(bergs, & old_bug_rotated_weights, make_calving_reproduce,restart_input_dir, orig_read, old_bug_bilin,do_unit_tests,grounding_fraction, input_freq_distribution, force_all_pes_traj, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & - Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model + Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & + const_gamma, Gamma_T_3EQ ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -780,6 +786,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%time_average_weight=time_average_weight bergs%speed_limit=speed_limit bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%const_gamma=const_gamma + bergs%Gamma_T_3EQ=Gamma_T_3EQ bergs%pass_fields_to_ocean_model=pass_fields_to_ocean_model bergs%ustar_icebergs_bg=ustar_icebergs_bg bergs%utide_icebergs=utide_icebergs @@ -836,6 +844,8 @@ subroutine ice_bergs_framework_init(bergs, & 'Unused calving mass rate', 'kg/s') grd%id_floating_melt=register_diag_field('icebergs', 'melt', axes, Time, & 'Melt rate of icebergs + bits', 'kg/(m^2*s)') + grd%id_melt_m_per_year=register_diag_field('icebergs', 'melt_m_per_year', axes, Time, & + 'Melt rate of icebergs + bits (m/yr)', 'm/yr') grd%id_berg_melt=register_diag_field('icebergs', 'berg_melt', axes, Time, & 'Melt rate of icebergs', 'kg/(m^2*s)') grd%id_melt_buoy=register_diag_field('icebergs', 'melt_buoy', axes, Time, & From 1bd85a643998f024cbf98dc3820d8791603d0856 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Fri, 30 Sep 2016 15:13:29 -0400 Subject: [PATCH 170/361] 1) A bug was identified which made the model run slower and slower the longer it ran. This was beceause the model was assigning extra memory in the increase_ibuffer routine (and also in the increase_ibuffer_traj). This bug was resolved by correcting the line in the ibuffer routine so that if the amount of space in the buffer is sufficient, then the buffer size is not increased. 2) The routine increase_ibuffer was also refactored slightly so that it is easier to read. In particular, the variable delta, was renamed nbergs. The routine checks to see if the buffer size is greater than nbergs, and if not the buffer size is increased. 3) The routines increase_buffer, increase_buffer_traj and increase_ibuffer_traj have been removed. The routine increase_ibuffer has been slightly edited so that it can be used instead of these three other routines.This was achievd by the following: i) The buffer_width has been added to the inputs of the routine. This allows the trajetories and the bergs buffers to be increased with the same routine. ii)The role of the increase_buffer routine was to increase the buffer size by a fixed value delta. It was noticed that the increase_ibuffer routine would do the same thing if the size of the buffer was smaller than the current number of bergs. 4) A new flag IGNORE_TRAJ was added. When this flag is true, then iceberg trajectories are not stored at all. This is to make the model run faster when trajectories are not needed. 5) The update_halo() routine is only called when iceberg interactions or iceberg bonds are on. This makes the icebergs module run faster when interactions are not needed. I am 95% sure that this change makes sense, but there could be issues that I am not seeing. 6) Some debugging lines have been added to update_halo() which will display data when the flag debug=.true. 6) An if (save_short_traj)=.true. line has been added to the record_position routine, so that only the relavent variables are record (since save_short_traj means that only a few of the trajectory variables are saved). --- icebergs.F90 | 7 +- icebergs_framework.F90 | 253 ++++++++++++++++++----------------------- icebergs_io.F90 | 4 +- 3 files changed, 117 insertions(+), 147 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index e161cd8..15b5c02 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2671,11 +2671,11 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, bergs%current_yearday=yearday(imon, iday, ihr, imin, isec) ! Turn on sampling of trajectories, verbosity, budgets sample_traj=.false. - if (bergs%traj_sample_hrs>0) then + if ( (bergs%traj_sample_hrs>0) .and. (.not. bergs%ignore_traj) ) then if (mod(24*iday+ihr,bergs%traj_sample_hrs).eq.0) sample_traj=.true. end if write_traj=.false. - if (bergs%traj_write_hrs>0) then + if ((bergs%traj_write_hrs>0) .and. (.not. bergs%ignore_traj)) then if (mod(24*iday+ihr,bergs%traj_write_hrs).eq.0) write_traj=.true. end if lverbose=.false. @@ -2869,7 +2869,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Send bergs to other PEs call mpp_clock_begin(bergs%clock_com) if (bergs%iceberg_bonds_on) call bond_address_update(bergs) + call send_bergs_to_other_pes(bergs) + if ((bergs%interactive_icebergs_on) .or. (bergs%iceberg_bonds_on)) & call update_halo_icebergs(bergs) if (bergs%iceberg_bonds_on) call connect_all_bonds(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') @@ -4609,6 +4611,7 @@ subroutine icebergs_end(bergs) ! Delete bergs and structures call move_all_trajectories(bergs, delete_bergs=.true.) + if (.not. bergs%ignore_traj) & call write_trajectory(bergs%trajectories, bergs%save_short_traj) deallocate(bergs%grd%lon) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 96652d6..8d18fcd 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -59,7 +59,7 @@ module ice_bergs_framework public update_halo_icebergs public pack_berg_into_buffer2, unpack_berg_from_buffer2 public pack_traj_into_buffer2, unpack_traj_from_buffer2 -public increase_buffer, increase_ibuffer, increase_ibuffer_traj, increase_buffer_traj +public increase_ibuffer public add_new_berg_to_list, count_out_of_order, check_for_duplicates public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position @@ -253,6 +253,7 @@ module ice_bergs_framework logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc + logical :: ignore_traj=.False. !If true, then model does not traj trajectory data at all logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon @@ -394,6 +395,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc +logical :: ignore_traj=.False. !If true, then model does not traj trajectory data at all logical :: iceberg_bonds_on=.False. !True=Allow icebergs to have bonds, False=don't allow. logical :: manually_initialize_bonds=.False. !True= Bonds are initialize manually. logical :: use_new_predictive_corrective =.False. !Flag to use Bob's predictive corrective iceberg scheme- Added by Alon @@ -415,7 +417,7 @@ subroutine ice_bergs_framework_init(bergs, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,Lx,use_f_plane,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & - const_gamma, Gamma_T_3EQ + const_gamma, Gamma_T_3EQ, ignore_traj ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -760,6 +762,7 @@ subroutine ice_bergs_framework_init(bergs, & buffer_width=buffer_width+(max_bonds*3) ! Increase buffer width to include bonds being passed between processors endif if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj +if (ignore_traj) buffer_width_traj=0 ! If this is true, then all traj files should be ignored ! Parameters @@ -767,6 +770,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%traj_sample_hrs=traj_sample_hrs bergs%traj_write_hrs=traj_write_hrs bergs%save_short_traj=save_short_traj + bergs%ignore_traj=ignore_traj bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo bergs%grd%Lx=Lx @@ -1070,7 +1074,6 @@ subroutine update_halo_icebergs(bergs) ! For convenience grd=>bergs%grd - !For debugging, MP1 if (halo_debugging) then do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied @@ -1185,7 +1188,7 @@ subroutine update_halo_icebergs(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_w,' from',grd%pe_W,' (W) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_w.gt.0) then - call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) + call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w,buffer_width) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, max_bonds_in=bergs%max_bonds ) @@ -1203,7 +1206,7 @@ subroutine update_halo_icebergs(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_e,' from',grd%pe_E,' (E) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_e.gt.0) then - call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) + call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e,buffer_width) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, max_bonds_in=bergs%max_bonds ) @@ -1282,7 +1285,7 @@ subroutine update_halo_icebergs(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_s,' from',grd%pe_S,' (S) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_s.gt.0) then - call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) + call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s,buffer_width) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd, max_bonds_in=bergs%max_bonds ) @@ -1304,7 +1307,7 @@ subroutine update_halo_icebergs(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_n,' from',grd%pe_N,' (N) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_n.gt.0) then - call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n) + call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n,buffer_width) if(folded_north_on_pe) then call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) else @@ -1333,12 +1336,54 @@ subroutine update_halo_icebergs(bergs) call show_all_bonds(bergs) endif -end subroutine update_halo_icebergs +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 + if (debug) then + nbergs_end=count_bergs(bergs) + i=nbergs_rcvd_from_n+nbergs_rcvd_from_s+nbergs_rcvd_from_e+nbergs_rcvd_from_w & + -nbergs_to_send_n-nbergs_to_send_s-nbergs_to_send_e-nbergs_to_send_w + if (nbergs_end-(nbergs_start+i).ne.0) then + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_end=',nbergs_end,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_start=',nbergs_start,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: delta=',i,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: error=',nbergs_end-(nbergs_start+i),' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_to_send_n=',nbergs_to_send_n,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_to_send_s=',nbergs_to_send_s,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_to_send_e=',nbergs_to_send_e,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_to_send_w=',nbergs_to_send_w,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_rcvd_from_n=',nbergs_rcvd_from_n,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_rcvd_from_s=',nbergs_rcvd_from_s,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_rcvd_from_e=',nbergs_rcvd_from_e,' on PE',mpp_pe() + write(stderrunit,'(a,i4,a,i4)') 'diamonds, update_halos: nbergs_rcvd_from_w=',nbergs_rcvd_from_w,' on PE',mpp_pe() + !call error_mesg('diamonds, update_halos:', 'We lost some bergs!', FATAL) + endif + endif + if (debug) then + i=0 + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + call check_position(grd, this, 'exchange (bot)') + if (this%ine.lt.bergs%grd%isc .or. & + this%ine.gt.bergs%grd%iec .or. & + this%jne.lt.bergs%grd%jsc .or. & + this%jne.gt.bergs%grd%jec) i=i+1 + this=>this%next + enddo ! while + enddo ; enddo + call mpp_sum(i) + if (i>0 .and. mpp_pe()==mpp_root_pe()) then + write(stderrunit,'(a,i4)') 'diamonds, update_halos: # of bergs outside computational domain = ',i + call error_mesg('diamonds, update_halos:', 'there are bergs still in halos!', FATAL) + endif ! root_pe + endif ! debug + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 + +end subroutine update_halo_icebergs -!contains subroutine delete_all_bergs_in_list(bergs,grdj,grdi) type(icebergs), pointer :: bergs ! Local variables @@ -1355,7 +1400,6 @@ subroutine delete_all_bergs_in_list(bergs,grdj,grdi) end subroutine delete_all_bergs_in_list - ! ############################################################################# subroutine send_bergs_to_other_pes(bergs) @@ -1439,7 +1483,7 @@ subroutine send_bergs_to_other_pes(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_w,' from',grd%pe_W,' (W) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_w.gt.0) then - call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w) + call increase_ibuffer(bergs%ibuffer_w, nbergs_rcvd_from_w,buffer_width) call mpp_recv(bergs%ibuffer_w%data, nbergs_rcvd_from_w*buffer_width, grd%pe_W, tag=COMM_TAG_2) do i=1, nbergs_rcvd_from_w call unpack_berg_from_buffer2(bergs, bergs%ibuffer_w, i, grd, force_app, bergs%max_bonds ) @@ -1457,7 +1501,7 @@ subroutine send_bergs_to_other_pes(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_e,' from',grd%pe_E,' (E) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_e.gt.0) then - call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e) + call increase_ibuffer(bergs%ibuffer_e, nbergs_rcvd_from_e,buffer_width) call mpp_recv(bergs%ibuffer_e%data, nbergs_rcvd_from_e*buffer_width, grd%pe_E, tag=COMM_TAG_4) do i=1, nbergs_rcvd_from_e call unpack_berg_from_buffer2(bergs, bergs%ibuffer_e, i, grd, force_app, bergs%max_bonds) @@ -1532,7 +1576,7 @@ subroutine send_bergs_to_other_pes(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_s,' from',grd%pe_S,' (S) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_s.gt.0) then - call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s) + call increase_ibuffer(bergs%ibuffer_s, nbergs_rcvd_from_s,buffer_width) call mpp_recv(bergs%ibuffer_s%data, nbergs_rcvd_from_s*buffer_width, grd%pe_S, tag=COMM_TAG_6) do i=1, nbergs_rcvd_from_s call unpack_berg_from_buffer2(bergs, bergs%ibuffer_s, i, grd, force_app, bergs%max_bonds ) @@ -1554,7 +1598,7 @@ subroutine send_bergs_to_other_pes(bergs) write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_n,' from',grd%pe_N,' (N) !!!!!!!!!!!!!!!!!!!!!!' endif if (nbergs_rcvd_from_n.gt.0) then - call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n) + call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n,buffer_width) if(folded_north_on_pe) then call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) else @@ -1628,8 +1672,8 @@ subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) if (present(max_bonds_in)) max_bonds=max_bonds_in - if (.not.associated(buff)) call increase_buffer(buff,delta_buf) - if (n>buff%size) call increase_buffer(buff,delta_buf) + if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width) + if (n>buff%size) call increase_ibuffer(buff,n,buffer_width) buff%data(1,n)=berg%lon buff%data(2,n)=berg%lat @@ -1720,33 +1764,6 @@ subroutine clear_berg_from_partners_bonds(berg) end subroutine clear_berg_from_partners_bonds - - subroutine increase_buffer(old,delta) - ! Arguments - type(buffer), pointer :: old - integer, intent(in) :: delta - ! Local variables - type(buffer), pointer :: new - integer :: new_size - - if (.not.associated(old)) then - new_size=delta - else - new_size=old%size+delta - endif - allocate(new) - allocate(new%data(buffer_width,new_size)) - new%size=new_size - if (associated(old)) then - new%data(:,1:old%size)=old%data(:,1:old%size) - deallocate(old%data) - deallocate(old) - endif - old=>new - !write(stderr(),*) 'diamonds, increase_buffer',mpp_pe(),' increased to',new_size - - end subroutine increase_buffer - subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_in) ! Arguments type(icebergs), pointer :: bergs @@ -1867,29 +1884,33 @@ subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_ end subroutine unpack_berg_from_buffer2 - subroutine increase_ibuffer(old,delta) + subroutine increase_ibuffer(old,num_bergs,width) ! Arguments type(buffer), pointer :: old - integer, intent(in) :: delta + integer, intent(in) :: num_bergs,width ! Local variables type(buffer), pointer :: new integer :: new_size, old_size + !This routine checks if the buffer size is smaller than nbergs + !If it is, the buffer size is increased by delta_buf + !The buffer increases by more than 1 so that the buffer does not have to increase every time if (.not.associated(old)) then - new_size=delta+delta_buf + new_size=num_bergs+delta_buf old_size=0 else old_size=old%size - if (deltanew - !write(stderr(),*) 'diamonds, increase_ibuffer',mpp_pe(),' increased to',new_size - endif - - end subroutine increase_ibuffer_traj - - subroutine increase_buffer_traj(old,delta) - ! Arguments - type(buffer), pointer :: old - integer, intent(in) :: delta - ! Local variables - type(buffer), pointer :: new - integer :: new_size - - if (.not.associated(old)) then - new_size=delta - else - new_size=old%size+delta - endif - allocate(new) - allocate(new%data(buffer_width_traj,new_size)) - new%size=new_size - if (associated(old)) then - new%data(:,1:old%size)=old%data(:,1:old%size) - deallocate(old%data) - deallocate(old) - endif - old=>new - !write(stderr(),*) 'diamonds, increase_buffer',mpp_pe(),' increased to',new_size - - end subroutine increase_buffer_traj - subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) ! Arguments type(xyt), pointer :: traj @@ -1971,8 +1931,8 @@ subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) logical, intent(in) :: save_short_traj ! Local variables - if (.not.associated(buff)) call increase_buffer_traj(buff,delta_buf) - if (n>buff%size) call increase_buffer_traj(buff,delta_buf) + if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width_traj) + if (n>buff%size) call increase_ibuffer(buff,n,buffer_width_traj) buff%data(1,n)=traj%lon buff%data(2,n)=traj%lat @@ -2855,36 +2815,39 @@ subroutine record_posn(bergs) posn%lat=this%lat posn%year=bergs%current_year posn%day=bergs%current_yearday - posn%uvel=this%uvel - posn%vvel=this%vvel - posn%mass=this%mass - posn%mass_of_bits=this%mass_of_bits - posn%heat_density=this%heat_density - posn%thickness=this%thickness - posn%width=this%width - posn%length=this%length - posn%uo=this%uo - posn%vo=this%vo - posn%ui=this%ui - posn%vi=this%vi - posn%ua=this%ua - posn%va=this%va - posn%ssh_x=this%ssh_x - posn%ssh_y=this%ssh_y - posn%sst=this%sst - posn%sss=this%sss - posn%cn=this%cn - posn%hi=this%hi - posn%axn=this%axn - posn%ayn=this%ayn - posn%bxn=this%bxn - posn%byn=this%byn - posn%uvel_old=this%uvel_old - posn%vvel_old=this%vvel_old - posn%lon_old=this%lon_old - posn%lat_old=this%lat_old - posn%halo_berg=this%halo_berg - posn%static_berg=this%static_berg + posn%iceberg_num=posn%iceberg_num + if (.not. bergs%save_short_traj) then !Not totally sure that this is correct + posn%uvel=this%uvel + posn%vvel=this%vvel + posn%mass=this%mass + posn%mass_of_bits=this%mass_of_bits + posn%heat_density=this%heat_density + posn%thickness=this%thickness + posn%width=this%width + posn%length=this%length + posn%uo=this%uo + posn%vo=this%vo + posn%ui=this%ui + posn%vi=this%vi + posn%ua=this%ua + posn%va=this%va + posn%ssh_x=this%ssh_x + posn%ssh_y=this%ssh_y + posn%sst=this%sst + posn%sss=this%sss + posn%cn=this%cn + posn%hi=this%hi + posn%axn=this%axn + posn%ayn=this%ayn + posn%bxn=this%bxn + posn%byn=this%byn + posn%uvel_old=this%uvel_old + posn%vvel_old=this%vvel_old + posn%lon_old=this%lon_old + posn%lat_old=this%lat_old + posn%halo_berg=this%halo_berg + posn%static_berg=this%static_berg + endif call push_posn(this%trajectory, posn) @@ -2944,6 +2907,8 @@ subroutine move_trajectory(bergs, berg) type(xyt), pointer :: next, last type(xyt) :: vals + if (bergs%ignore_traj) return + ! If the trajectory is empty, ignore it if (.not.associated(berg%trajectory)) return @@ -2985,6 +2950,8 @@ subroutine move_all_trajectories(bergs, delete_bergs) type(iceberg), pointer :: this, next logical :: delete_bergs_after_moving_traj integer :: grdi, grdj + + if (bergs%ignore_traj) return delete_bergs_after_moving_traj = .false. if (present(delete_bergs)) delete_bergs_after_moving_traj = delete_bergs diff --git a/icebergs_io.F90 b/icebergs_io.F90 index ec8017d..8f7ff67 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -29,7 +29,7 @@ module ice_bergs_io use ice_bergs_framework, only: count_bonds, form_a_bond, find_individual_iceberg use ice_bergs_framework, only: push_posn use ice_bergs_framework, only: add_new_berg_to_list,destroy_iceberg -use ice_bergs_framework, only: increase_ibuffer,increase_ibuffer_traj,grd_chksum2,grd_chksum3 +use ice_bergs_framework, only: increase_ibuffer,grd_chksum2,grd_chksum3 use ice_bergs_framework, only: sum_mass,sum_heat,bilin !params !Niki: write a subroutine to get these use ice_bergs_framework, only: nclasses, buffer_width, buffer_width_traj @@ -1444,7 +1444,7 @@ subroutine write_trajectory(trajectory, save_short_traj) from_pe=io_tile_pelist(np) call mpp_recv(ntrajs_rcvd_io, glen=1, from_pe=from_pe, tag=COMM_TAG_11) if (ntrajs_rcvd_io .gt. 0) then - call increase_ibuffer_traj(ibuffer_io, ntrajs_rcvd_io) + call increase_ibuffer(ibuffer_io, ntrajs_rcvd_io,buffer_width_traj) call mpp_recv(ibuffer_io%data, ntrajs_rcvd_io*buffer_width_traj,from_pe=from_pe, tag=COMM_TAG_12) do i=1, ntrajs_rcvd_io call unpack_traj_from_buffer2(traj4io, ibuffer_io, i, save_short_traj) From cb4b2cc00b332a30e0f62a79980d21512f93f3e6 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 13:28:12 -0400 Subject: [PATCH 171/361] 1) Iceberg module now reads in the bottom topography from a file called topog.nc (when the flag is set to true) 2) The bottom topography is used to calculate the thickness of the ocean below the icebergs. When the ocean thickness is less than melt_cutoff, then the icebergs basal melt M_b is set to zero. 3) There is an option to set the basal melt to zero based on the thickness of the iceberg, or based on the average thickness of icebergs in the grid cell. --- icebergs.F90 | 30 ++++++++++++++++++++++++++++-- icebergs_framework.F90 | 25 ++++++++++++++++++++----- icebergs_io.F90 | 31 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 3c9b467..9abf81c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -41,6 +41,7 @@ module ice_bergs use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving use ice_bergs_io, only: read_restart_bonds +use ice_bergs_io, only: read_ocean_depth implicit none ; private @@ -119,6 +120,9 @@ subroutine icebergs_init(bergs, & call mpp_clock_end(bergs%clock_ior) if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') + + !Reading ocean depth from a file + if (bergs%read_ocean_depth_from_file) call read_ocean_depth(bergs%grd) if (bergs%iceberg_bonds_on) then call update_halo_icebergs(bergs) @@ -1172,9 +1176,15 @@ subroutine thermodynamics(bergs) Me=0.0 if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb,this%iceberg_num) - Mb=max(Mb,0.) + Mb=max(Mb,0.) !No refreezing allowed for now + !Set melt to zero if ocean is too thin. + if ((bergs%melt_cutoff >=0.) .and. (bergs%apply_thickness_cutoff_to_bergs_melt)) then + if ((grd%ocean_depth(i,j)-this%thickness) < bergs%melt_cutoff) then + Mb=0. + endif + endif endif - + if (bergs%set_melt_rates_to_zero) then Mv=0.0 Mb=0.0 @@ -2656,6 +2666,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask +real :: ave_thickness real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount @@ -2759,6 +2770,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, tmpsum=sum( grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%net_incoming_calving_heat=bergs%net_incoming_calving_heat+tmpsum*bergs%dt ! Units of J + if (grd%id_ocean_depth>0) & + lerr=send_data(grd%id_ocean_depth, grd%ocean_depth(grd%isc:grd%iec,grd%jsc:grd%jec), Time) + if (vel_stagger == BGRID_NE) then ! Copy ocean and ice velocities. They are already on B-grid u-points. grd%uo(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1) = uo(:,:) @@ -2966,6 +2980,18 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%spread_area(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') endif + if (bergs%apply_thickness_cutoff_to_gridded_melt) then + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed + if ((bergs%melt_cutoff >=0.) .and. (grd%spread_area(i,j)>0.)) then + ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) + if ((grd%ocean_depth(i,j)-ave_thickness) < bergs%melt_cutoff) then + grd%floating_melt(i,j)=0.0 + grd%calving_hflx(i,j)=0.0 + endif + endif + enddo ;enddo + endif + ! Gridded diagnostics if (grd%id_uo>0) & diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 045bf52..071dfaa 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -154,6 +154,7 @@ module ice_bergs_framework integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1, id_ustar_iceberg integer :: id_spread_uvel=-1, id_spread_vvel=-1 integer :: id_melt_m_per_year=-1 + integer :: id_ocean_depth=-1 real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. @@ -231,6 +232,7 @@ module ice_bergs_framework real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) real :: initial_orientation=0. ! Iceberg orientaion relative to this angle (in degrees). Used for hexagonal mass spreading. real :: Gamma_T_3EQ=0.022 ! Nondimensional heat-transfer coefficient + real :: melt_cutoff=-1.0 !Minimum ocean thickness for melting to occur (is not applied for values < 0) logical :: const_gamma=.True. !If true uses a constant heat tranfer coefficient, from which the salt transfer is calculated real, dimension(:), pointer :: initial_mass, distribution, mass_scaling real, dimension(:), pointer :: initial_thickness, initial_width, initial_length @@ -240,6 +242,8 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: apply_thickness_cutoff_to_gridded_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) + logical :: apply_thickness_cutoff_to_bergs_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) logical :: use_updated_rolling_scheme=.false. ! True to use the aspect ratio based rolling scheme rather than incorrect version of WM scheme (set tip_parameter=1000. for correct WM scheme) logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovation logical :: pass_fields_to_ocean_model=.False. !Iceberg area, mass and ustar fields are prepared to pass to ocean model @@ -267,6 +271,7 @@ module ice_bergs_framework logical :: interactive_icebergs_on=.false. !Turn on/off interactions between icebergs - Added by Alon logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide + logical :: read_ocean_depth_from_file=.false. ! If true, ocean depth is read from a file. integer :: debug_iceberg_with_id = -1 ! If positive, monitors a berg with this id real :: speed_limit=0. ! CFL speed limit for a berg [m/s] @@ -380,6 +385,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: ustar_icebergs_bg=0.001 ! Background u_star under icebergs. This should be linked to a value felt by the ocean boundary layer real :: cdrag_icebergs = 1.5e-3 !Momentum Drag coef, taken from HJ99 (Holland and Jenkins 1999) real :: Gamma_T_3EQ=0.022 ! Nondimensional heat-transfer coefficient +real :: melt_cutoff=-1.0 !Minimum ocean thickness for melting to occur (is not applied for values < 0) logical :: const_gamma=.True. !If true uses a constant heat tranfer coefficient, from which the salt transfer is calculated logical :: use_operator_splitting=.true. ! Use first order operator splitting for thermodynamics logical :: add_weight_to_ocean=.true. ! Add weight of icebergs + bits to ocean @@ -390,6 +396,8 @@ subroutine ice_bergs_framework_init(bergs, & real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: apply_thickness_cutoff_to_gridded_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) +logical :: apply_thickness_cutoff_to_bergs_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) logical :: use_updated_rolling_scheme=.false. ! Use the corrected Rolling Scheme rather than the erronios one logical :: pass_fields_to_ocean_model=.False. !Iceberg area, mass and ustar fields are prepared to pass to ocean model logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. @@ -421,6 +429,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: input_freq_distribution=.false. ! Flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovations logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide +logical :: read_ocean_depth_from_file=.false. ! If true, ocean depth is read from a file. real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) real, dimension(nclasses) :: distribution=(/0.24, 0.12, 0.15, 0.18, 0.12, 0.07, 0.03, 0.03, 0.03, 0.02/) ! Fraction of calving to apply to this class (non-dim) , real, dimension(nclasses) :: mass_scaling=(/2000, 200, 50, 20, 10, 5, 2, 1, 1, 1/) ! Ratio between effective and real iceberg mass (non-dim) @@ -437,7 +446,8 @@ subroutine ice_bergs_framework_init(bergs, & allow_bergs_to_roll,set_melt_rates_to_zero,lat_ref,initial_orientation,rotate_icebergs_for_mass_spreading,grid_is_latlon,Lx,use_f_plane,use_old_spreading, & grid_is_regular,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & - const_gamma, Gamma_T_3EQ, ignore_traj, debug_iceberg_with_id,use_updated_rolling_scheme, tip_parameter, read_old_restarts, tau_calving + const_gamma, Gamma_T_3EQ, ignore_traj, debug_iceberg_with_id,use_updated_rolling_scheme, tip_parameter, read_old_restarts, tau_calving, read_ocean_depth_from_file, melt_cutoff,& + apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -614,7 +624,7 @@ subroutine ice_bergs_framework_init(bergs, & if(fractional_area) grd%area(is:ie,js:je)=ice_area(:,:) *(4.*pi*radius*radius) endif if(present(ocean_depth)) grd%ocean_depth(is:ie,js:je)=ocean_depth(:,:) - + ! Copy data declared on ice model data domain is=grd%isc-1; ie=grd%iec+1; js=grd%jsc-1; je=grd%jec+1 grd%dx(is:ie,js:je)=ice_dx(:,:) @@ -815,6 +825,10 @@ subroutine ice_bergs_framework_init(bergs, & bergs%tip_parameter=tip_parameter bergs%use_updated_rolling_scheme=use_updated_rolling_scheme !Alon bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%apply_thickness_cutoff_to_bergs_melt=apply_thickness_cutoff_to_bergs_melt + bergs%apply_thickness_cutoff_to_gridded_melt=apply_thickness_cutoff_to_gridded_melt + bergs%melt_cutoff=melt_cutoff + bergs%read_ocean_depth_from_file=read_ocean_depth_from_file bergs%const_gamma=const_gamma bergs%Gamma_T_3EQ=Gamma_T_3EQ bergs%pass_fields_to_ocean_model=pass_fields_to_ocean_model @@ -952,6 +966,8 @@ subroutine ice_bergs_framework_init(bergs, & 'X-stress on ice from atmosphere', 'N m^-2') grd%id_fay=register_diag_field('icebergs', 'tauy', axes, Time, & 'Y-stress on ice from atmosphere', 'N m^-2') + grd%id_ocean_depth=register_diag_field('icebergs', 'Depth', axes, Time, & + 'Ocean Depth', 'm') ! Static fields id_class=register_static_field('icebergs', 'lon', axes, & @@ -966,8 +982,8 @@ subroutine ice_bergs_framework_init(bergs, & id_class=register_static_field('icebergs', 'mask', axes, & 'wet point mask', 'none') if (id_class>0) lerr=send_data(id_class, grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec)) - id_class=register_static_field('icebergs', 'ocean_depth', axes, & - 'ocean depth', 'm') + id_class=register_static_field('icebergs', 'ocean_depth_static', axes, & + 'ocean depth static', 'm') if (id_class>0) lerr=send_data(id_class, grd%ocean_depth(grd%isc:grd%iec,grd%jsc:grd%jec)) if (debug) then @@ -991,7 +1007,6 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_clock_end(bergs%clock) end subroutine ice_bergs_framework_init - ! ############################################################################## subroutine offset_berg_dates(bergs,Time) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index d53cd9f..0971c06 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -44,6 +44,7 @@ module ice_bergs_io public ice_bergs_io_init public read_restart_bergs,read_restart_bergs_orig,write_restart,write_trajectory public read_restart_calving, read_restart_bonds +public read_ocean_depth !Local Vars integer, parameter :: file_format_major_version=0 @@ -1418,6 +1419,36 @@ end subroutine read_restart_calving ! ############################################################################## +subroutine read_ocean_depth(grd) +! Arguments +! Local variables +character(len=37) :: filename +type(icebergs_gridded), pointer :: grd + + ! Read stored ice + filename=trim(restart_input_dir)//'topog.nc' + if (file_exist(filename)) then + if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') & + 'diamonds, read_ocean_depth: reading ',filename + if (field_exist(filename, 'depth')) then + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: reading stored_heat from restart file.' + call read_data(filename, 'depth', grd%ocean_depth, grd%domain) + else + if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_restart_calving: stored_heat WAS NOT FOUND in the file. Setting to 0.' + !grd%ocean_depth(:,:)=0. + endif + else + if (mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & + 'diamonds, read_ocean_depth: Ocean depth file (topog.nc) not present)' + endif + + !call grd_chksum2(bergs%grd, bergs%grd%ocean_depth, 'read_ocean_depth, ocean_depth') +end subroutine read_ocean_depth + +! ############################################################################## + subroutine write_trajectory(trajectory, save_short_traj) ! Arguments type(xyt), pointer :: trajectory From 20cdf780b2b41e55807a52043fd0afe7cd96d277 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 16:34:53 -0400 Subject: [PATCH 172/361] Added optional arguments in the icebergs_run call which allow the mass_berg, area_berg and ustar_berg to be passed to the sea ice model. --- icebergs.F90 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index d31f9ca..4d8f1d6 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1109,7 +1109,7 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger,sss) + stagger, stress_stagger,sss,mass_berg, ustar_berg, area_berg) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time @@ -1117,6 +1117,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger real, dimension(:,:), optional, intent(in) :: sss +real, dimension(:,:), optional, intent(inout) :: mass_berg, ustar_berg, area_berg ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd @@ -1153,6 +1154,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. + mass_berg(:,:)=3.0 + ustar_berg(:,:)=2.0 + area_berg(:,:)=1.0 + ! Manage time call get_date(time, iyr, imon, iday, ihr, imin, isec) bergs%current_year=iyr From 86782d15ece6c01fd2c8c78db0241c4671ce30d6 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 17:22:49 -0400 Subject: [PATCH 173/361] Optional arguments have been added to icebergs_run so that it can pass the iceberg mass, area and ustar to the sea ice model. These changes have been made in such a way that the sea ice model does not need to call the function icebergs_incr_mass. The fields area_berg and area_berg0, ustar_berg and ustar_berg0 are approximately the same. One of these will be removed later --- icebergs.F90 | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9abf81c..5176c42 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2650,7 +2650,7 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger,sss) + stagger, stress_stagger,sss,mass_berg, ustar_berg, area_berg) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time @@ -2658,6 +2658,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger real, dimension(:,:), optional, intent(in) :: sss +real, dimension(:,:), optional, intent(inout) :: mass_berg, ustar_berg, area_berg + ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd @@ -2670,7 +2672,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount -real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg, area_berg, spread_mass_old +real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg0, area_berg0, spread_mass_old integer :: nbonds !logical :: within_iceberg_model @@ -2705,8 +2707,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. - ustar_berg(:,:)=0. - area_berg(:,:)=0. + ustar_berg0(:,:)=0. + area_berg0(:,:)=0. + + mass_berg(:,:)=3.0 + ustar_berg(:,:)=2.0 + area_berg(:,:)=1.0 + if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. if (bergs%add_weight_to_ocean) grd%area_on_ocean(:,:,:)=0. @@ -2972,10 +2979,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%floating_melt(i,j)=0.0 endif enddo ;enddo - elseif ((grd%id_spread_mass>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean + !elseif ((grd%id_spread_mass>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean + else !Update iceberg mass spread on ocean grd%spread_mass(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) endif + if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg area spread on ocean grd%spread_area(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') @@ -2991,7 +3000,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, endif enddo ;enddo endif - + ! Gridded diagnostics if (grd%id_uo>0) & @@ -3095,16 +3104,19 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, where (grd%area(grd%isc:grd%iec,grd%jsc:grd%jec)>0.) calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)/grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) & +grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec) - !ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) - !area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) - ustar_berg(:,:)=grd%ustar_iceberg(:,:) - area_berg(:,:)=grd%spread_area(:,:) + !ustar_berg0(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) + !area_berg0(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) + ustar_berg0(:,:)=grd%ustar_iceberg(:,:) + area_berg0(:,:)=grd%spread_area(:,:) elsewhere calving(:,:)=0. - ustar_berg(:,:)=0. - area_berg(:,:)=0. + ustar_berg0(:,:)=0. + area_berg0(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) + ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) endif call mpp_clock_end(bergs%clock_int) From d03aa8e1efc1242fc23a845c21ca4c530cbebd4d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 17:28:07 -0400 Subject: [PATCH 174/361] Initializing mass, area and ustar to zero --- icebergs.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5176c42..2fc2855 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2710,9 +2710,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ustar_berg0(:,:)=0. area_berg0(:,:)=0. - mass_berg(:,:)=3.0 - ustar_berg(:,:)=2.0 - area_berg(:,:)=1.0 + mass_berg(:,:)=0.0 + ustar_berg(:,:)=0.0 + area_berg(:,:)=0.0 if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. From 8d248ae2d64f7628ffcfeb36d470f474d2ae1c75 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 18:23:00 -0400 Subject: [PATCH 175/361] Edited incr_mass rountine so that it can be called from inside the iceberg model and out --- icebergs.F90 | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 4d8f1d6..f24ab94 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1154,9 +1154,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. - mass_berg(:,:)=3.0 - ustar_berg(:,:)=2.0 - area_berg(:,:)=1.0 + mass_berg(:,:)=0.0 + ustar_berg(:,:)=1.0 + area_berg(:,:)=2.0 ! Manage time call get_date(time, iyr, imon, iday, ihr, imin, isec) @@ -1405,6 +1405,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_run, status') call mpp_clock_end(bergs%clock_dia) + !Making sure that spread_mass has the correct mass + grd%spread_mass(:,:)=0.0 + call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), within_iceberg_model=.True.) + ! Return what ever calving we did not use and additional icebergs melt call mpp_clock_begin(bergs%clock_int) if (.not. bergs%passive_mode) then @@ -1415,6 +1419,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, calving(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) endif call mpp_clock_end(bergs%clock_int) @@ -1685,23 +1690,37 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, Time) +subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model,Time) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass +logical, intent(in), optional :: within_iceberg_model type(time_type), intent(in), optional :: Time ! Local variables integer :: i, j type(icebergs_gridded), pointer :: grd real :: dmda logical :: lerr +logical :: within_model if (.not. associated(bergs)) return if (.not. bergs%add_weight_to_ocean) return - call mpp_clock_begin(bergs%clock) - call mpp_clock_begin(bergs%clock_int) + within_model=.False. + if (present(within_iceberg_model)) then + within_model=within_iceberg_model + endif + + if (.not.(within_model)) then + if (.not. associated(bergs)) return + if (.not. bergs%add_weight_to_ocean) return + call mpp_clock_begin(bergs%clock) + call mpp_clock_begin(bergs%clock_int) + endif + + !call mpp_clock_begin(bergs%clock) + !call mpp_clock_begin(bergs%clock_int) ! For convenience grd=>bergs%grd @@ -1738,7 +1757,16 @@ subroutine icebergs_incr_mass(bergs, mass, Time) + ( (grd%mass_on_ocean(i-1,j ,6)+grd%mass_on_ocean(i+1,j ,4)) & + (grd%mass_on_ocean(i ,j-1,8)+grd%mass_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) - if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda + + if (.not.(within_model)) then + if (.not. bergs%passive_mode) then + mass(i,j)=mass(i,j)+dmda + else + mass(i,j)=dmda + endif + endif + + !if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda if (grd%id_mass_on_ocn>0) grd%tmp(i,j)=dmda enddo; enddo if (present(Time).and. (grd%id_mass_on_ocn>0)) & @@ -1750,8 +1778,13 @@ subroutine icebergs_incr_mass(bergs, mass, Time) call grd_chksum2(grd, grd%tmp, 'mass out (incr)') endif - call mpp_clock_end(bergs%clock_int) - call mpp_clock_end(bergs%clock) + !call mpp_clock_end(bergs%clock_int) + !call mpp_clock_end(bergs%clock) + + if (.not.(within_model)) then + call mpp_clock_end(bergs%clock_int) + call mpp_clock_end(bergs%clock) + endif end subroutine icebergs_incr_mass From cc9a7a8b3e42f2b1c17357f6fe933ee7b2c4f067 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 18:49:52 -0400 Subject: [PATCH 176/361] mass_berg, area_berg and ustar_berg only edited when they are present --- icebergs.F90 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index f24ab94..7afdc28 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1154,9 +1154,15 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. - mass_berg(:,:)=0.0 - ustar_berg(:,:)=1.0 - area_berg(:,:)=2.0 + if (present(mass_berg)) then + mass_berg(:,:)=0.0 + endif + if (present(ustar_berg)) then + ustar_berg(:,:)=1.0 + endif + if (present(area_berg)) then + area_berg(:,:)=2.0 + endif ! Manage time call get_date(time, iyr, imon, iday, ihr, imin, isec) @@ -1419,7 +1425,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, calving(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) - mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + if (present(mass_berg)) then + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + endif endif call mpp_clock_end(bergs%clock_int) From 68a764463b5d8969576460ef818a71c7959785dd Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 5 Oct 2016 20:18:02 -0400 Subject: [PATCH 177/361] Setting a value for ustar_berg, area_berg and mass_berg. Area_berg must be less than or equal to 1. Note that when these fields are passed through the coupler in the global model, they have a different value on the ocean side, so something is not being done correctly. --- icebergs.F90 | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 7afdc28..c1b16e3 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1154,16 +1154,6 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. grd%virtual_area(:,:)=0. - if (present(mass_berg)) then - mass_berg(:,:)=0.0 - endif - if (present(ustar_berg)) then - ustar_berg(:,:)=1.0 - endif - if (present(area_berg)) then - area_berg(:,:)=2.0 - endif - ! Manage time call get_date(time, iyr, imon, iday, ihr, imin, isec) bergs%current_year=iyr @@ -1429,6 +1419,17 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) endif endif + + if (present(area_berg)) then + area_berg(:,:)=0.5 + endif + !if (present(mass_berg)) then + ! mass_berg(:,:)=0.0 + !endif + if (present(ustar_berg)) then + ustar_berg(:,:)=0.02 + endif + call mpp_clock_end(bergs%clock_int) ! Diagnose budgets From c3a585f97ed8d653cb2b10124c8e1524c42044e7 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 6 Oct 2016 13:33:25 -0400 Subject: [PATCH 178/361] 1) Added if present() qualifier before the optional arguments ustar_berg, mass_berg and area_berg, so that if they are not defined, the road does not try to access them. Note that if allocated qualifier is not included since these are not allocatable fields. 2) The variables ustar_berg0 and area_berg0 have been removed since they are not needed. --- icebergs.F90 | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 2fc2855..f867a62 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2672,7 +2672,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount -real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg0, area_berg0, spread_mass_old +real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: spread_mass_old +!real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg0, area_berg0 integer :: nbonds !logical :: within_iceberg_model @@ -2707,12 +2708,19 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. - ustar_berg0(:,:)=0. - area_berg0(:,:)=0. + !I belive that ustar_berg0 and area_berg0 are no longer needed + !ustar_berg0(:,:)=0. + !area_berg0(:,:)=0. - mass_berg(:,:)=0.0 - ustar_berg(:,:)=0.0 - area_berg(:,:)=0.0 + if (present(mass_berg)) then !; if (allocated(mass_berg)) then + mass_berg(:,:)=0.0 + endif !; endif + if (present(ustar_berg)) then !; if (allocated(ustar_berg)) then + ustar_berg(:,:)=0.0 + endif !; endif + if (present(area_berg)) then !; if (allocated(area_berg)) then + area_berg(:,:)=0.0 + endif !; endif if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. @@ -3104,19 +3112,23 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, where (grd%area(grd%isc:grd%iec,grd%jsc:grd%jec)>0.) calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)/grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) & +grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec) - !ustar_berg0(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) - !area_berg0(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) - ustar_berg0(:,:)=grd%ustar_iceberg(:,:) - area_berg0(:,:)=grd%spread_area(:,:) + !ustar_berg0(:,:)=grd%ustar_iceberg(:,:) + !area_berg0(:,:)=grd%spread_area(:,:) elsewhere calving(:,:)=0. - ustar_berg0(:,:)=0. - area_berg0(:,:)=0. + !ustar_berg0(:,:)=0. + !area_berg0(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) - mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) - area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) - ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) + if (present(mass_berg)) then !; if (allocated(mass_berg)) then + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + endif !; endif + if (present(ustar_berg)) then !; if (allocated(ustar_berg)) then + ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) + endif !; endif + if (present(area_berg)) then !; if (allocated(area_berg)) then + area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) + endif !; endif endif call mpp_clock_end(bergs%clock_int) From 7a2f25e21590e71e224f7626a021fb91687e2d8f Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 7 Oct 2016 13:04:09 -0400 Subject: [PATCH 179/361] Cleaned up logical for passive_mode - Logical for clocks inside icebergs_incr_mass() was simplified and corrected for passive_mode. - Tidied up some white space. - No answer changes. --- icebergs.F90 | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c1b16e3..72b1f87 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1109,7 +1109,7 @@ end subroutine interp_flds ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & - stagger, stress_stagger,sss,mass_berg, ustar_berg, area_berg) + stagger, stress_stagger, sss, mass_berg, ustar_berg, area_berg) ! Arguments type(icebergs), pointer :: bergs type(time_type), intent(in) :: time @@ -1117,7 +1117,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger real, dimension(:,:), optional, intent(in) :: sss -real, dimension(:,:), optional, intent(inout) :: mass_berg, ustar_berg, area_berg +real, dimension(:,:), optional, pointer :: mass_berg, ustar_berg, area_berg ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd @@ -1416,20 +1416,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) if (present(mass_berg)) then - mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + if (associated(mass_berg) .and. .not.bergs%passive_mode) then + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + endif endif endif - if (present(area_berg)) then - area_berg(:,:)=0.5 - endif - !if (present(mass_berg)) then - ! mass_berg(:,:)=0.0 - !endif - if (present(ustar_berg)) then - ustar_berg(:,:)=0.02 - endif - call mpp_clock_end(bergs%clock_int) ! Diagnose budgets @@ -1699,7 +1691,7 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model,Time) +subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time) ! Arguments type(icebergs), pointer :: bergs real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass @@ -1722,15 +1714,10 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model,Time) endif if (.not.(within_model)) then - if (.not. associated(bergs)) return - if (.not. bergs%add_weight_to_ocean) return - call mpp_clock_begin(bergs%clock) - call mpp_clock_begin(bergs%clock_int) + call mpp_clock_begin(bergs%clock) + call mpp_clock_begin(bergs%clock_int) endif - !call mpp_clock_begin(bergs%clock) - !call mpp_clock_begin(bergs%clock_int) - ! For convenience grd=>bergs%grd @@ -1767,12 +1754,10 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model,Time) + (grd%mass_on_ocean(i ,j-1,8)+grd%mass_on_ocean(i ,j+1,2)) ) ) if (grd%area(i,j)>0) dmda=dmda/grd%area(i,j)*grd%msk(i,j) - if (.not.(within_model)) then - if (.not. bergs%passive_mode) then - mass(i,j)=mass(i,j)+dmda - else - mass(i,j)=dmda - endif + if (within_model) then + mass(i,j)=mass(i,j)+dmda + else + if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda endif !if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda @@ -1787,9 +1772,6 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model,Time) call grd_chksum2(grd, grd%tmp, 'mass out (incr)') endif - !call mpp_clock_end(bergs%clock_int) - !call mpp_clock_end(bergs%clock) - if (.not.(within_model)) then call mpp_clock_end(bergs%clock_int) call mpp_clock_end(bergs%clock) From c87016df664b51b4d54ef7d2852a7e75dedfbed4 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 10 Oct 2016 11:38:48 -0400 Subject: [PATCH 180/361] Corrected the ustar calaculation inside the iceberg melt procedure --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index f867a62..a757e8d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1533,7 +1533,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic iDens = 1.0/Rho0 !Preparing the mixed layer properties for use in both 2 and 3 equation version - ustar = bergs%cdrag_icebergs*(dvo + bergs%utide_icebergs) + ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) ustar_h = max(bergs%ustar_icebergs_bg, ustar) ! Estimate the neutral ocean boundary layer thickness as the minimum of the From d7bf5c30c7095494884bb57892be93293ea58f2d Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 11 Oct 2016 09:56:34 -0400 Subject: [PATCH 181/361] 1) print_berg routine has been edited so that more decimal places are displayed for the iceberg fields 2) The spread_mass_across_ocean_cells has been edited so that it is more likely to reproduce. In particular, fraction_used is set equal to exactly 1 when the icebergs spread their mass as rectangles. Previously, fraction_used was equal to the sum of a few terms which added to 1, but now it is set to exactly 1. Also, instead of dividing by fraction_used, we introduce I_fraction_used, which is the invers of fraction_used. This allows us to multiply by I_fraction used which distributing the fields. 3) A routine has been added which calculates the mass on the ocean. This routine is used to calculate the spread_mass_old, which is the spread_mass after the icebergs have been evolved, but before the thermodynamics have been applied. This allows us to correctly differnce these fields to find melt rates. (Previously find_melt_from_spread_mass option did not account for the iceberg movement (since the spread_mass_old was calculated before the iceberg_evolve. --- icebergs.F90 | 104 ++++++++++++++++++++++++++++++----------- icebergs_framework.F90 | 6 +-- 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index a757e8d..a3ff6c8 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1846,7 +1846,8 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR real :: S, H, origin_x, origin_y, x0, y0 real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex - real :: fraction_used + real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) + real :: I_fraction_used !Inverse of fraction used real :: tol real, parameter :: rho_seawater=1035. integer :: stderrunit @@ -1902,6 +1903,8 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yUxR=yU*xR*grd%msk(i+1,j+1) yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) + fraction_used=1. !rectangular bergs do share mass with boundaries (all mass is included in cells) + else !Spread mass as if elements area hexagonal if (grd%area(i,j)>0) then @@ -1976,53 +1979,51 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) endif - endif - !Scale each cell by (1/fraction_used) in order to redisribute ice mass which landed up on the land, back into the ocean - !Note that for the square elements, the mass has already been reassigned, so fraction_used shoule be equal to 1 aready - fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& - +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) - - if ((hexagonal_icebergs) .and. (static_berg .eq. 1)) then - !Change this to use_old_restart=false when this is merged in - fraction_used=1. !Static icebergs do not share their mass with the boundary (this to initialize icebergs in regular arrangements against boundaries) + !Scale each cell by (1/fraction_used) in order to redisribute ice mass which landed up on the land, back into the ocean + !Note that for the square elements, the mass has already been reassigned, so fraction_used shoule be equal to 1 aready + fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& + +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) + if (static_berg .eq. 1) fraction_used=1. !Static icebergs do not share their mass with the boundary + ! (this allows us to easily initialize hexagonal icebergs in regular arrangements against boundaries) endif + I_fraction_used=1./fraction_used !Invert this so that the arithmatec reprocudes !Spreading the iceberg mass onto the ocean call spread_variable_across_cells(grd, grd%mass_on_ocean, Mass, i ,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) !Spreading the iceberg area onto the ocean call spread_variable_across_cells(grd, grd%area_on_ocean, Area*scaling , i ,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,fraction_used) + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,I_fraction_used) !Spreading the iceberg x momentum onto the ocean call spread_variable_across_cells(grd,grd%Uvel_on_ocean, uvel*Area*scaling , i ,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) !Spreading the iceberg y momentum onto the ocean call spread_variable_across_cells(grd,grd%Vvel_on_ocean, vvel*Area*scaling , i ,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, fraction_used) + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) end subroutine spread_mass_across_ocean_cells subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,fraction_used) + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,I_fraction_used) ! Arguments type(icebergs_gridded), pointer, intent(in) :: grd real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean real, intent(in) :: Var !Variable to be spread accross cell real, intent(in) :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR !Weights - real, intent(in) :: fraction_used !Amount of iceberg used + real, intent(in) :: I_fraction_used !Amount of iceberg used (inverse) integer, intent(in) :: i, j !Spreading the iceberg mass onto the ocean - variable_on_ocean(i,j,1)=variable_on_ocean(i,j,1)+(yDxL*Var/fraction_used) - variable_on_ocean(i,j,2)=variable_on_ocean(i,j,2)+(yDxC*Var/fraction_used) - variable_on_ocean(i,j,3)=variable_on_ocean(i,j,3)+(yDxR*Var/fraction_used) - variable_on_ocean(i,j,4)=variable_on_ocean(i,j,4)+(yCxL*Var/fraction_used) - variable_on_ocean(i,j,5)=variable_on_ocean(i,j,5)+(yCxC*Var/fraction_used) - variable_on_ocean(i,j,6)=variable_on_ocean(i,j,6)+(yCxR*Var/fraction_used) - variable_on_ocean(i,j,7)=variable_on_ocean(i,j,7)+(yUxL*Var/fraction_used) - variable_on_ocean(i,j,8)=variable_on_ocean(i,j,8)+(yUxC*Var/fraction_used) - variable_on_ocean(i,j,9)=variable_on_ocean(i,j,9)+(yUxR*Var/fraction_used) + variable_on_ocean(i,j,1)=variable_on_ocean(i,j,1)+(yDxL*Var*I_fraction_used) + variable_on_ocean(i,j,2)=variable_on_ocean(i,j,2)+(yDxC*Var*I_fraction_used) + variable_on_ocean(i,j,3)=variable_on_ocean(i,j,3)+(yDxR*Var*I_fraction_used) + variable_on_ocean(i,j,4)=variable_on_ocean(i,j,4)+(yCxL*Var*I_fraction_used) + variable_on_ocean(i,j,5)=variable_on_ocean(i,j,5)+(yCxC*Var*I_fraction_used) + variable_on_ocean(i,j,6)=variable_on_ocean(i,j,6)+(yCxR*Var*I_fraction_used) + variable_on_ocean(i,j,7)=variable_on_ocean(i,j,7)+(yUxL*Var*I_fraction_used) + variable_on_ocean(i,j,8)=variable_on_ocean(i,j,8)+(yUxC*Var*I_fraction_used) + variable_on_ocean(i,j,9)=variable_on_ocean(i,j,9)+(yUxR*Var*I_fraction_used) end subroutine spread_variable_across_cells @@ -2647,6 +2648,51 @@ end subroutine rotate end subroutine interp_flds +subroutine calculate_mass_on_ocean(bergs, spread_mass_old) +! Arguments +type(icebergs), pointer :: bergs +type(iceberg), pointer :: berg +type(icebergs_gridded), pointer :: grd +real, dimension(:,:), optional, intent(out) :: spread_mass_old +! Local variables +integer :: grdj, grdi +real :: orientation + + ! For convenience + grd=>bergs%grd + + !Initialize fields + grd%mass_on_ocean(:,:,:)=0. + grd%area_on_ocean(:,:,:)=0. + grd%Uvel_on_ocean(:,:,:)=0. + grd%Vvel_on_ocean(:,:,:)=0. + + do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 + berg=>bergs%list(grdi,grdj)%first + do while(associated(berg)) + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) + call spread_mass_across_ocean_cells(grd, grdi, grdj, berg%xi, berg%yj, berg%mass,berg%mass_of_bits, berg%mass_scaling, & + berg%length*berg%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,berg%static_berg,berg%uvel,berg%vvel) + + berg=>berg%next + enddo + enddo ;enddo + call mpp_sync_self() + + grd%spread_mass(:,:)=0. + call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) + spread_mass_old(:,:)=grd%spread_mass(:,:) + + !Reset fields + grd%mass_on_ocean(:,:,:)=0. + grd%area_on_ocean(:,:,:)=0. + grd%Uvel_on_ocean(:,:,:)=0. + grd%Vvel_on_ocean(:,:,:)=0. + +end subroutine calculate_mass_on_ocean + + ! ############################################################################## subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & @@ -2956,6 +3002,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) + + if (bergs%find_melt_using_spread_mass) then + spread_mass_old(:,:)=0. + call calculate_mass_on_ocean(bergs, spread_mass_old) + endif + ! Iceberg thermodynamics (melting) + rolling call mpp_clock_begin(bergs%clock_the) call thermodynamics(bergs) @@ -2975,8 +3027,6 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) !within_iceberg_model=.True. if (bergs%find_melt_using_spread_mass) then - !spread_mass_old=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) - spread_mass_old(:,:)=grd%spread_mass(:,:) grd%spread_mass(:,:)=0. call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 071dfaa..123eee0 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2464,10 +2464,10 @@ subroutine print_berg(iochan, berg, label, il, jl) label, mpp_pe(), berg%start_lon, berg%start_lat, & berg%start_year, berg%iceberg_num, berg%start_day, berg%start_mass, berg%halo_berg if (present(il).and.present(jl)) then - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f14.8),a,2l2)') & label, mpp_pe(), ') List i,j=',il,jl endif - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f10.4),a,2l2)') & + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f14.8),a,2l2)') & label, mpp_pe(), ') i,j=',berg%ine, berg%jne, & ' xi,yj=', berg%xi, berg%yj, & ' lon,lat=', berg%lon, berg%lat, & @@ -2477,7 +2477,7 @@ subroutine print_berg(iochan, berg, label, il, jl) ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old, & ' lon_old,lat_old=', berg%lon_old, berg%lat_old, & ' p,n=', associated(berg%prev), associated(berg%next) - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f10.4))') & + write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f14.8))') & label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi !Two lines above added by Alon end subroutine print_berg From ceb5e10b144176844708892dd0ea07658299650a Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 12 Oct 2016 15:29:25 -0400 Subject: [PATCH 182/361] Parts of the code has been slightly refactored / reorganized to avoid code being duplicated, and to make it easier to read. The changes are: 1) spread_mass_across_ocean_cells now takes in the iceberg pointer, and the bergs icebergs type pointer. This means that fewer arguments need to be passed into this subroutine. The iceberg orientation, static vs non-static and grounding fraction are now taken care of within this subroutine. This means that this code does not have to be duplicated in many places across the model. Similarly, some of the flags are now unpacked from bergs within the subroutine. 2) A subroutine called calculate_mass_on_ocean has been written. This routine loops through all the icebergs and calls spread_mass_across_ocean_cells for each iceberg. It also has an option to calculate other diagnositics which require looping through all the icebergs. 3) A subroutine called create_gridded_icebergs_fields has been added. This subroutine contains most of the code which takes the icebergs and interpolated their data back onto the ocean/sea ice grid. Some code has been removed from the thermodynamics subroutine, and some code has been removed from the icebergs_run subroutine, and instead is called within this subroutine. 4) mass_berg, area_berg, and ustar_berg are not optional inputs for icebergs_run, and are pointers. There are only accessed with they are assosiated. These threee fields are the only way that the iceberg model sends data to the sea ice and ocean model. These are not filled in with values when we are in passive mode, or add_mass_to_ocean is set to zero (mass field). 5) A new subroutine called sum_up_spread_fields has been written. This subroutine is almost the same as what icebergs_incr_mass was. The subroutine icebergs_incr_mass has been significantly shortened. The reason for this is that icebergs_incr_mass is called directly from the SIS model. The purpose of this routine is to add the iceberg mass to the sea ice mass. The icebergs_incr_mass routine is now shorter, and just adds the field spread_mass to the inputed mass field. The subroutine sum_up_spread_fields takes in a field (mass, area, Uvel or Vvel) and sums up the contributions to this field from adjacent grid cells. The clocks and diagnostics have been removed from this routine so that it is now simpler. 6) A spread_mass_old field has been added to the gridded fields. This field is helpful when calculating the melt from changes in spread mass 7) The find_melt_from_spread mass now has been improved in two ways: Firstly, the calculation of the old spread_mass happens after the icebergs have been evolved. This done incorrectly previously Secondly, when the flag melt_without_decay is set to true, the spread mass is calculated inside of the thermodynamics routine before the iceberg is restored to its original size. this means that find_melt_from_spread_mass and melt_without_decay can be used together --- icebergs.F90 | 524 ++++++++++++++++++++++------------------- icebergs_framework.F90 | 8 +- 2 files changed, 287 insertions(+), 245 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index a3ff6c8..d4a79ef 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1119,19 +1119,16 @@ subroutine thermodynamics(bergs) real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb real :: tip_parameter -real :: ustar_h, ustar integer :: i,j, stderrunit type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. integer :: grdi, grdj -real :: orientation, static_berg real :: SSS !Temporarily here ! For convenience grd=>bergs%grd - !Initializing static_berg - static_berg=0. + !Initializing grd%Uvel_on_ocean(:,:,:)=0. grd%Vvel_on_ocean(:,:,:)=0. @@ -1322,6 +1319,16 @@ subroutine thermodynamics(bergs) !This option allows iceberg melt fluxes to enter the ocean without the icebergs changing shape if (bergs%Iceberg_melt_without_decay) then + !In this case, the iceberg dimension are reset to their values before + !the thermodynamics are applied. + !If the spread_mass is being used to calculate melt, we calculate this + !before reseting + if (bergs%find_melt_using_spread_mass) then + if (Mnew>0.) then !If the berg still exists + call spread_mass_across_ocean_cells(bergs,this, i, j, this%xi, this%yj,Mnew , nMbits, this%mass_scaling, Ln*Wn, Tn) + endif + endif + !Reset all the values Mnew=this%mass nMbits=this%mass_of_bits Tn=this%thickness @@ -1329,7 +1336,6 @@ subroutine thermodynamics(bergs) Ln=this%length if (bergs%bergy_bit_erosion_fraction>0.) then Mbits=this%mass_of_bits ! mass of bergy bits (kg) - nMbits=Mbits Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) endif @@ -1348,56 +1354,105 @@ subroutine thermodynamics(bergs) call move_trajectory(bergs, this) call delete_iceberg_from_list(bergs%list(grdi,grdj)%first, this) bergs%nbergs_melted=bergs%nbergs_melted+1 - else ! Diagnose mass distribution on grid - if (grd%id_virtual_area>0)& - & grd%virtual_area(i,j)=grd%virtual_area(i,j)+(Wn*Ln+Abits)*this%mass_scaling ! m^2 - if ((grd%id_mass>0 .or. bergs%add_weight_to_ocean) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & - & grd%mass(i,j)=grd%mass(i,j)+Mnew/grd%area(i,j)*this%mass_scaling ! kg/m2 - !Finding the average iceberg velocity in a grid cell (mass weighted) - grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%uvel) ! kg/m2 - grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((Mnew/grd%area(i,j)*this%mass_scaling)*this%vvel) ! kg/m2 - if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& - & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+nMbits/grd%area(i,j)*this%mass_scaling ! kg/m2 - if (bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) then - if (bergs%grounding_fraction>0.) then - Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) - if (Dn>Hocean) Mnew=Mnew*min(1.,Hocean/Dn) - endif - - orientation=bergs%initial_orientation - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,this,orientation) - if (bergs%hexagonal_icebergs) static_berg=this%static_berg !Change this to use_old_restart=false when this is merged in - call spread_mass_across_ocean_cells(grd, i, j, this%xi, this%yj, Mnew, nMbits, this%mass_scaling, & - this%length*this%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg,this%uvel,this%vvel) - endif endif this=>next enddo enddo ; enddo + + + contains + + subroutine swap_variables(x,y) + ! Arguments + real, intent(inout) :: x, y + real :: temp + temp=x + x=y + y=temp + end subroutine swap_variables + +end subroutine thermodynamics + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +subroutine create_gridded_icebergs_fields(bergs) +! Arguments +type(icebergs), pointer :: bergs +! Local variables +type(icebergs_gridded), pointer :: grd +type(iceberg), pointer :: this +integer i,j +integer :: grdi, grdj +real :: Hocean, Dn,Tn,dvo, mass_tmp +real :: ustar_h, ustar +real :: orientation +real :: ave_thickness +real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: spread_mass_tmp +real :: tmp + + ! For convenience + grd=>bergs%grd + + spread_mass_tmp(:,:)=0. !Initializing temporary variable to use in iceberg melt calculation + + !Special case for icebergs not decaying, but mass diffence being used for melt rates + if ((bergs%find_melt_using_spread_mass) .and. (bergs%Iceberg_melt_without_decay)) then + call sum_up_spread_fields(bergs, spread_mass_tmp(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') + endif + + !Loop through icebergs and spread mass on ocean + call calculate_mass_on_ocean(bergs, with_diagnostics=.true.) - !Finding the average iceberg velocity in a cell to calculate u_star - grd%spread_uvel(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='Uvel') - grd%spread_vvel(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='Vvel') - grd%spread_area(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') + !Finding the spread fields + if ((grd%id_spread_uvel>0) .or. (bergs%pass_fields_to_ocean_model)) then + grd%spread_uvel(:,:)=0. + call sum_up_spread_fields(bergs, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Uvel') + endif + if ( (grd%id_spread_vvel>0) .or. (bergs%pass_fields_to_ocean_model)) then + grd%spread_vvel(:,:)=0. + call sum_up_spread_fields(bergs, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Vvel') + endif + if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then + grd%spread_area(:,:)=0. + call sum_up_spread_fields(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec), 'area') + endif + !Always find spread_mass since it is used for so many things. + grd%spread_mass(:,:)=0. + call sum_up_spread_fields(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') - !Divdind the gridded iceberg momentum by the iceberg mass to get velocities - do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec - if (grd%mass(i,j)>0.) then - grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) - grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) - else - grd%u_iceberg(i,j)=0. ; grd%v_iceberg(i,j)=0. - endif - enddo; enddo + !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) + if (bergs%find_melt_using_spread_mass) then + if (.not. bergs%Iceberg_melt_without_decay) & + spread_mass_tmp(grd%isc:grd%iec,grd%jsc:grd%jec)= grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed + if (grd%area(i,j)>0.0) then + grd%floating_melt(i,j)=max((grd%spread_mass_old(i,j) - spread_mass_tmp(i,j))/(bergs%dt),0.0) + else + grd%floating_melt(i,j)=0.0 + endif + enddo ;enddo + grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. + endif + + !Dividng the gridded iceberg momentum diagnostic by the iceberg mass to get velocities + if ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0)) then + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + if (grd%mass(i,j)>0.) then + if (grd%id_u_iceberg>0) & + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) + if (grd%id_v_iceberg>0) & + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) + else + if (grd%id_u_iceberg>0) grd%u_iceberg(i,j)=0. + if (grd%id_v_iceberg>0) grd%v_iceberg(i,j)=0. + endif + enddo; enddo + endif !Calculating ustar_iceberg (gridded) grd%ustar_iceberg(:,:)=0. if ((grd%id_ustar_iceberg>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec - !dvo=sqrt((grd%u_iceberg(i,j)-grd%uo(i,j))**2+(grd%v_iceberg(i,j)-grd%vo(i,j))**2) dvo=sqrt((grd%spread_uvel(i,j)-grd%uo(i,j))**2+(grd%spread_vvel(i,j)-grd%vo(i,j))**2) ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) ustar_h = max(bergs%ustar_icebergs_bg, ustar) @@ -1406,19 +1461,19 @@ subroutine thermodynamics(bergs) enddo; enddo endif - contains - - subroutine swap_variables(x,y) - ! Arguments - real, intent(inout) :: x, y - real :: temp - temp=x - x=y - y=temp - end subroutine swap_variables - -end subroutine thermodynamics - + !Only allowing melt in ocean above a minimum cutoff thickness + if (bergs%apply_thickness_cutoff_to_gridded_melt) then + do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed + if ((bergs%melt_cutoff >=0.) .and. (grd%spread_area(i,j)>0.)) then + ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) + if ((grd%ocean_depth(i,j)-ave_thickness) < bergs%melt_cutoff) then + grd%floating_melt(i,j)=0.0 + grd%calving_hflx(i,j)=0.0 + endif + endif + enddo ;enddo + endif +end subroutine create_gridded_icebergs_fields !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt,iceberg_num) @@ -1832,15 +1887,14 @@ subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) end subroutine find_orientation_using_iceberg_bonds -subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling, Area, use_old_spreading,hexagonal_icebergs,theta,static_berg,uvel,vvel) +subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, scaling, Area, Tn) ! Arguments + type(icebergs), pointer :: bergs type(icebergs_gridded), pointer :: grd + type(iceberg), pointer :: berg integer, intent(in) :: i, j - real, intent(in) :: x, y, Mberg, Mbits, scaling, Area,uvel,vvel - logical, intent(in) :: hexagonal_icebergs - logical, intent(in) :: use_old_spreading - real, intent(in) :: theta - real, optional, intent(in) :: static_berg + real, intent(in) :: x, y, Mberg, Mbits, scaling, Area + real, intent(in) :: Tn ! Local variables real :: xL, xC, xR, yD, yC, yU, Mass, L real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR @@ -1849,16 +1903,27 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) real :: I_fraction_used !Inverse of fraction used real :: tol + real :: Dn, Hocean real, parameter :: rho_seawater=1035. integer :: stderrunit logical :: debug + real :: orientation, Mass_berg ! Get the stderr unit number stderrunit = stderr() tol=1.e-10 + grd=>bergs%grd + Mass_berg=Mberg - Mass=(Mberg+Mbits)*scaling + !Trimming icebergs to account for grounded fraction. + if (bergs%grounding_fraction>0.) then + Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) + Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) + if (Dn>Hocean) Mass_berg=Mberg*min(1.,Hocean/Dn) + endif + + Mass=(Mass_berg+Mbits)*scaling ! This line attempts to "clip" the weight felt by the ocean. The concept of ! clipping is non-physical and this step should be replaced by grounding. if (grd%clipping_depth>0.) Mass=min(Mass,grd%clipping_depth*grd%area(i,j)*rho_seawater) @@ -1867,7 +1932,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling yDxL=0. ; yDxC=0. ; yDxR=0. ; yCxL=0. ; yCxR=0. yUxL=0. ; yUxC=0. ; yUxR=0. ; yCxC=1. - if (.not. hexagonal_icebergs) then !Treat icebergs as rectangles of size L: (this is the default) + if (.not. bergs%hexagonal_icebergs) then !Treat icebergs as rectangles of size L: (this is the default) !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. if (grd%area(i,j)>0) then @@ -1876,7 +1941,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling L=1. endif - if (use_old_spreading) then + if (bergs%use_old_spreading) then !Old version before icebergs were given size L xL=min(0.5, max(0., 0.5-x)) xR=min(0.5, max(0., x-0.5)) @@ -1906,6 +1971,9 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling fraction_used=1. !rectangular bergs do share mass with boundaries (all mass is included in cells) else !Spread mass as if elements area hexagonal + + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) if (grd%area(i,j)>0) then H = min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ; !Non dimensionalize element length by grid area. (This gives the non-dim Apothen of the hexagon) @@ -1929,7 +1997,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling x0=(x-origin_x) y0=(y-origin_y) - call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) + call Hexagon_into_quadrants_using_triangles(x0,y0,H,orientation,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-tol) then call error_mesg('diamonds, hexagonal spreading', 'Intersection with hexagons should not be negative!!!', WARNING) @@ -1975,7 +2043,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling write(stderrunit,*) 'diamonds, hexagonal, H,x0,y0', H, x0 , y0 write(stderrunit,*) 'diamonds, hexagonal, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 debug=.True. - !call Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4, debug) + !call Hexagon_into_quadrants_using_triangles(x0,y0,H,orientation,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4, debug) call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) endif @@ -1984,7 +2052,7 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling !Note that for the square elements, the mass has already been reassigned, so fraction_used shoule be equal to 1 aready fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& +(yUxL*grd%msk(i-1,j+1)) +(yUxC*grd%msk(i ,j+1)) +(yUxR*grd%msk(i+1,j+1)) + (yCxC**grd%msk(i,j))) - if (static_berg .eq. 1) fraction_used=1. !Static icebergs do not share their mass with the boundary + if (berg%static_berg .eq. 1) fraction_used=1. !Static icebergs do not share their mass with the boundary ! (this allows us to easily initialize hexagonal icebergs in regular arrangements against boundaries) endif I_fraction_used=1./fraction_used !Invert this so that the arithmatec reprocudes @@ -1996,10 +2064,10 @@ subroutine spread_mass_across_ocean_cells(grd, i, j, x, y, Mberg, Mbits, scaling call spread_variable_across_cells(grd, grd%area_on_ocean, Area*scaling , i ,j, & yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,I_fraction_used) !Spreading the iceberg x momentum onto the ocean - call spread_variable_across_cells(grd,grd%Uvel_on_ocean, uvel*Area*scaling , i ,j, & + call spread_variable_across_cells(grd,grd%Uvel_on_ocean, berg%uvel*Area*scaling , i ,j, & yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) !Spreading the iceberg y momentum onto the ocean - call spread_variable_across_cells(grd,grd%Vvel_on_ocean, vvel*Area*scaling , i ,j, & + call spread_variable_across_cells(grd,grd%Vvel_on_ocean, berg%vvel*Area*scaling , i ,j, & yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) end subroutine spread_mass_across_ocean_cells @@ -2648,15 +2716,15 @@ end subroutine rotate end subroutine interp_flds -subroutine calculate_mass_on_ocean(bergs, spread_mass_old) +subroutine calculate_mass_on_ocean(bergs, with_diagnostics) ! Arguments type(icebergs), pointer :: bergs type(iceberg), pointer :: berg type(icebergs_gridded), pointer :: grd -real, dimension(:,:), optional, intent(out) :: spread_mass_old +logical, intent(in) :: with_diagnostics ! Local variables integer :: grdj, grdi -real :: orientation +integer :: j, i ! For convenience grd=>bergs%grd @@ -2670,28 +2738,61 @@ subroutine calculate_mass_on_ocean(bergs, spread_mass_old) do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 berg=>bergs%list(grdi,grdj)%first do while(associated(berg)) - orientation=bergs%initial_orientation - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) - call spread_mass_across_ocean_cells(grd, grdi, grdj, berg%xi, berg%yj, berg%mass,berg%mass_of_bits, berg%mass_scaling, & - berg%length*berg%width, bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,berg%static_berg,berg%uvel,berg%vvel) + i=berg%ine ; j=berg%jne + if (grd%area(i,j) > 0.) then + + !Increasing Mass on ocean + if ((bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) .or.(bergs%find_melt_using_spread_mass)) then + call spread_mass_across_ocean_cells(bergs, berg, berg%ine, berg%jne, berg%xi, berg%yj, berg%mass,berg%mass_of_bits, berg%mass_scaling, & + berg%length*berg%width, berg%thickness) + endif + !Calculated some iceberg diagnositcs + if (with_diagnostics) call calculate_sum_over_bergs_diagnositcs(bergs,grd,berg,i,j) + + endif berg=>berg%next enddo enddo ;enddo - call mpp_sync_self() - grd%spread_mass(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) - spread_mass_old(:,:)=grd%spread_mass(:,:) + contains - !Reset fields - grd%mass_on_ocean(:,:,:)=0. - grd%area_on_ocean(:,:,:)=0. - grd%Uvel_on_ocean(:,:,:)=0. - grd%Vvel_on_ocean(:,:,:)=0. + subroutine calculate_sum_over_bergs_diagnositcs(bergs,grd,berg,i,j) + ! Arguments + type(icebergs), pointer :: bergs + type(iceberg), pointer :: berg + type(icebergs_gridded), pointer :: grd + integer, intent(in) :: i, j + ! Local variables + real :: Abits, Lbits, Mbits + + !Virtual area diagnostic + if (grd%id_virtual_area>0) then + if (bergs%bergy_bit_erosion_fraction>0.) then + Lbits=min(berg%length,berg%width,berg%thickness,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(berg%mass_of_bits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + else + Abits=0.0 + endif + grd%virtual_area(i,j)=grd%virtual_area(i,j)+(berg%width*berg%length+Abits)*berg%mass_scaling ! m^2 + endif -end subroutine calculate_mass_on_ocean + !Mass diagnostic (also used in u_iceberg, v_iceberg + if ((grd%id_mass>0 ) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & + & grd%mass(i,j)=grd%mass(i,j)+berg%mass/grd%area(i,j)*berg%mass_scaling ! kg/m2 + !Finding the average iceberg velocity in a grid cell (mass weighted) + if (grd%id_u_iceberg>0) & + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%uvel) ! kg/m2 + if (grd%id_v_iceberg>0) & + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%vvel) ! kg/m2 + + !Mass of bergy bits + if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& + & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+berg%mass_of_bits/grd%area(i,j)*berg%mass_scaling ! kg/m2 + end subroutine calculate_sum_over_bergs_diagnositcs + +end subroutine calculate_mass_on_ocean ! ############################################################################## @@ -2704,7 +2805,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi integer, optional, intent(in) :: stagger, stress_stagger real, dimension(:,:), optional, intent(in) :: sss -real, dimension(:,:), optional, intent(inout) :: mass_berg, ustar_berg, area_berg +real, dimension(:,:), optional, pointer :: mass_berg, ustar_berg, area_berg ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k @@ -2718,11 +2819,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real, dimension(:,:), allocatable :: uC_tmp, vC_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount -real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: spread_mass_old -!real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: ustar_berg0, area_berg0 integer :: nbonds -!logical :: within_iceberg_model - integer :: stderrunit ! Get the stderr unit number @@ -2745,6 +2842,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_src(:,:)=0. grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. + grd%spread_mass_old(:,:)=0. !grd%spread_mass(:,:)=0. !Don't zero this out yet, because we can first use this an add it onto the SSH grd%spread_area(:,:)=0. grd%u_iceberg(:,:)=0. @@ -2753,25 +2851,21 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%spread_vvel(:,:)=0. grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. - - !I belive that ustar_berg0 and area_berg0 are no longer needed - !ustar_berg0(:,:)=0. - !area_berg0(:,:)=0. + grd%virtual_area(:,:)=0. + + !Initializing _on_ocean_fields + grd%mass_on_ocean(:,:,:)=0. ; grd%area_on_ocean(:,:,:)=0. + grd%Uvel_on_ocean(:,:,:)=0. ; grd%Vvel_on_ocean(:,:,:)=0. - if (present(mass_berg)) then !; if (allocated(mass_berg)) then + if (present(mass_berg)) then ; if (associated(mass_berg)) then mass_berg(:,:)=0.0 - endif !; endif - if (present(ustar_berg)) then !; if (allocated(ustar_berg)) then + endif ; endif + if (present(ustar_berg)) then ; if (associated(ustar_berg)) then ustar_berg(:,:)=0.0 - endif !; endif - if (present(area_berg)) then !; if (allocated(area_berg)) then + endif ; endif + if (present(area_berg)) then ; if (associated(area_berg)) then area_berg(:,:)=0.0 - endif !; endif - - - if (bergs%add_weight_to_ocean) grd%mass_on_ocean(:,:,:)=0. - if (bergs%add_weight_to_ocean) grd%area_on_ocean(:,:,:)=0. - grd%virtual_area(:,:)=0. + endif ; endif ! Manage time call get_date(time, iyr, imon, iday, ihr, imin, isec) @@ -3002,10 +3096,14 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) - + !Caculate mass on ocean before thermodynamics, to use in melt rate calculation if (bergs%find_melt_using_spread_mass) then - spread_mass_old(:,:)=0. - call calculate_mass_on_ocean(bergs, spread_mass_old) + call calculate_mass_on_ocean(bergs, with_diagnostics=.false.) + grd%spread_mass_old(:,:)=0. + call sum_up_spread_fields(bergs,grd%spread_mass_old(grd%isc:grd%iec,grd%jsc:grd%jec), 'mass') + !Reset fields + grd%mass_on_ocean(:,:,:)=0. ; grd%area_on_ocean(:,:,:)=0. + grd%Uvel_on_ocean(:,:,:)=0. ; grd%Vvel_on_ocean(:,:,:)=0. endif ! Iceberg thermodynamics (melting) + rolling @@ -3015,6 +3113,8 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) + !Creating gridded fields from new icebergs + call create_gridded_icebergs_fields(bergs) ! For each berg, record call mpp_clock_begin(bergs%clock_dia) @@ -3024,42 +3124,6 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call write_trajectory(bergs%trajectories, bergs%save_short_traj) endif - !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) - !within_iceberg_model=.True. - if (bergs%find_melt_using_spread_mass) then - grd%spread_mass(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) - do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed - if (grd%area(i,j)>0.0) then - grd%floating_melt(i,j)=max((spread_mass_old(i,j) - grd%spread_mass(i,j))/(bergs%dt),0.0) - grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. - else - grd%floating_melt(i,j)=0.0 - endif - enddo ;enddo - !elseif ((grd%id_spread_mass>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean - else !Update iceberg mass spread on ocean - grd%spread_mass(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.) - endif - - if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg area spread on ocean - grd%spread_area(:,:)=0. - call icebergs_incr_mass(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec),within_iceberg_model=.True.,field_name_in='area') - endif - if (bergs%apply_thickness_cutoff_to_gridded_melt) then - do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed - if ((bergs%melt_cutoff >=0.) .and. (grd%spread_area(i,j)>0.)) then - ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) - if ((grd%ocean_depth(i,j)-ave_thickness) < bergs%melt_cutoff) then - grd%floating_melt(i,j)=0.0 - grd%calving_hflx(i,j)=0.0 - endif - endif - enddo ;enddo - endif - - ! Gridded diagnostics if (grd%id_uo>0) & lerr=send_data(grd%id_uo, grd%uo(grd%isc:grd%iec,grd%jsc:grd%jec), Time) @@ -3156,29 +3220,28 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_clock_end(bergs%clock_dia) - ! Return what ever calving we did not use and additional icebergs melt + !This is the point in the algorithem which determines which fields get passed to the ice model + !Return what ever calving we did not use and additional icebergs melt call mpp_clock_begin(bergs%clock_int) if (.not. bergs%passive_mode) then where (grd%area(grd%isc:grd%iec,grd%jsc:grd%jec)>0.) calving(:,:)=grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)/grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) & +grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec) - !ustar_berg0(:,:)=grd%ustar_iceberg(:,:) - !area_berg0(:,:)=grd%spread_area(:,:) elsewhere calving(:,:)=0. - !ustar_berg0(:,:)=0. - !area_berg0(:,:)=0. end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) - if (present(mass_berg)) then !; if (allocated(mass_berg)) then - mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) - endif !; endif - if (present(ustar_berg)) then !; if (allocated(ustar_berg)) then + !Return iceberg mass, area and ustar to pass on to ocean model + if (present(mass_berg)) then ; if (associated(mass_berg)) then + if (bergs%add_weight_to_ocean) & + mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) + endif ; endif + if (present(ustar_berg)) then ; if (associated(ustar_berg)) then ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) - endif !; endif - if (present(area_berg)) then !; if (allocated(area_berg)) then + endif ; endif + if (present(area_berg)) then ; if (associated(area_berg)) then area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) - endif !; endif + endif ; endif endif call mpp_clock_end(bergs%clock_int) @@ -3213,12 +3276,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%tmpc(:,:)=0.; !Finding spread mass call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r - call icebergs_incr_mass(bergs, grd%tmpc) + call sum_up_spread_fields(bergs, grd%tmpc, 'mass') call mpp_clock_begin(bergs%clock_dia); call mpp_clock_begin(bergs%clock) ! To enable calling of public s/r bergs%returned_mass_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) !Finding spread area call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r - call icebergs_incr_mass(bergs, grd%tmpc,field_name_in='area') + call sum_up_spread_fields(bergs, grd%tmpc, 'area') call mpp_clock_begin(bergs%clock_dia); call mpp_clock_begin(bergs%clock) ! To enable calling of public s/r bergs%returned_area_on_ocean=sum( grd%tmpc(grd%isc:grd%iec,grd%jsc:grd%jec)*grd%area(grd%isc:grd%iec,grd%jsc:grd%jec) ) bergs%nbergs_end=count_bergs(bergs) @@ -3482,21 +3545,53 @@ end subroutine icebergs_run ! ############################################################################## -subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time,field_name_in) + +subroutine icebergs_incr_mass(bergs, mass, Time) ! Arguments type(icebergs), pointer :: bergs -real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass type(time_type), intent(in), optional :: Time -logical, intent(in), optional :: within_iceberg_model -character(len=4), intent(in), optional :: field_name_in +type(icebergs_gridded), pointer :: grd +integer :: i, j +logical :: lerr +real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass + +!This routine is called from SIS, (and older versions of SIS2), but not within +!the iceberg model. The routine adds the spread iceberg mass to mass provided +!the add weight to ocean flag is on, and passive mode is off. It also appears to +!play some role in diagnostics + + if (.not. associated(bergs)) return + if (.not. bergs%add_weight_to_ocean) return + + ! For convenience + grd=>bergs%grd + + !Start the clocks + call mpp_clock_begin(bergs%clock) + call mpp_clock_begin(bergs%clock_int) + + do j=grd%jsc, grd%jec; do i=grd%isc, grd%iec + if (.not. bergs%passive_mode) mass(i,j)=mass(i,j) + grd%spread_mass(i,j) + enddo ;enddo + + !Stop the clocks + call mpp_clock_end(bergs%clock_int) + call mpp_clock_end(bergs%clock) + +end subroutine icebergs_incr_mass + + +subroutine sum_up_spread_fields(bergs, field, field_name) +! Arguments +type(icebergs), pointer :: bergs +real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(out) :: field +character(len=4), intent(in) :: field_name ! Local variables -logical :: within_model -character(len=4) :: field_name integer :: i, j type(icebergs_gridded), pointer :: grd real :: dmda logical :: lerr -real, dimension(bergs%grd%isd:bergs%grd%ied, bergs%grd%jsd:bergs%grd%jed,9) :: var_on_ocean !Variable being spread onto the ocean (mass or area) +real, dimension(bergs%grd%isd:bergs%grd%ied, bergs%grd%jsd:bergs%grd%jed,9) :: var_on_ocean !Variable being spread onto the ocean (mass, area, Uvel, Vvel) integer :: stderrunit ! Get the stderr unit number @@ -3504,41 +3599,20 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time,field_name ! For convenience grd=>bergs%grd - !var_on_ocean(:,:,:)=0. - - !Deciding which varibale to spread across cells across grid cells (default spread mass) - field_name='mass' - if (present(field_name_in)) field_name=field_name_in + field(:,:)=0. + + !Deciding which varibale to spread across cells across grid cells if (field_name=='mass') var_on_ocean(:,:,:)=grd%mass_on_ocean(:,:,:) if (field_name=='area') var_on_ocean(:,:,:)=grd%area_on_ocean(:,:,:) if (field_name=='Uvel') var_on_ocean(:,:,:)=grd%Uvel_on_ocean(:,:,:) if (field_name=='Vvel') var_on_ocean(:,:,:)=grd%Vvel_on_ocean(:,:,:) - - - within_model=.False. - if (present(within_iceberg_model)) then - within_model=within_iceberg_model - endif - - if (.not.(within_model)) then - if (.not. associated(bergs)) return - if (.not. bergs%add_weight_to_ocean) return - call mpp_clock_begin(bergs%clock) - call mpp_clock_begin(bergs%clock_int) - endif - - - ! Add iceberg+bits mass field to non-haloed SIS field (kg/m^2) - !mass(:,:)=mass(:,:)+( grd%mass(grd%isc:grd%iec,grd%jsc:grd%jec) & - ! + grd%bergy_mass(grd%isc:grd%iec,grd%jsc:grd%jec) ) - - if (debug) then - grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass - call grd_chksum2(grd, grd%tmp, 'mass in (incr)') - endif + !if (.not. bergs%add_weight_to_ocean) return + !Update the halos of the var_on_ocean call mpp_update_domains(var_on_ocean, grd%domain) + + !Rotatine when old_bug_rotated_weights is on - we should remove this. if (.not. old_bug_rotated_weights) then do j=grd%jsd, grd%jed; do i=grd%isd, grd%ied if (grd%parity_x(i,j)<0.) then @@ -3553,6 +3627,8 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time,field_name endif enddo; enddo endif + + !Here we add the contribution of the 9 cells. This is the heart of the routine. do j=grd%jsc, grd%jec; do i=grd%isc, grd%iec dmda=var_on_ocean(i,j,5) & + ( ( (var_on_ocean(i-1,j-1,9)+var_on_ocean(i+1,j+1,1)) & @@ -3564,39 +3640,20 @@ subroutine icebergs_incr_mass(bergs, mass, within_iceberg_model, Time,field_name !Make sure that area <=1.0 if (field_name=='area') dmda=min(dmda,1.0) - if (.not.(within_model)) then - if (.not. bergs%passive_mode) mass(i,j)=mass(i,j)+dmda - else - mass(i,j)=dmda - endif - if ((grd%id_area_on_ocn>0).and.(field_name=='area')) grd%tmp(i,j)=dmda - if ((grd%id_mass_on_ocn>0).and.(field_name=='mass')) grd%tmp(i,j)=dmda + field(i,j)=dmda enddo; enddo - if (field_name=='mass') then - if (present(Time).and. (grd%id_mass_on_ocn>0)) & - lerr=send_data(grd%id_mass_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) - elseif (field_name=='area') then - if (present(Time).and. (grd%id_area_on_ocn>0)) & - lerr=send_data(grd%id_area_on_ocn, grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec), Time) - endif - if (debug) then - grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=mass + grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=field if (field_name=='mass') then call grd_chksum3(grd, grd%mass_on_ocean, 'mass bergs (incr)') call grd_chksum2(grd, grd%tmp, 'mass out (incr)') - elseif (field_name=='area') then + elseif (field_name=='area') then call grd_chksum3(grd, grd%area_on_ocean, 'area bergs (incr)') call grd_chksum2(grd, grd%tmp, 'area out (incr)') endif - endif - - if (.not.(within_model)) then - call mpp_clock_end(bergs%clock_int) - call mpp_clock_end(bergs%clock) - endif -end subroutine icebergs_incr_mass + endif +end subroutine sum_up_spread_fields ! ############################################################################## @@ -3891,7 +3948,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) real :: xdot3, ydot3 real :: xdotn, ydotn real :: dt, dt_2, dt_6, dydl -real :: static_berg, orientation +real :: orientation logical :: bounced, on_tangential_plane, error_flag integer :: i, j integer :: stderrunit @@ -3914,11 +3971,8 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) dt=bergs%dt dt_2=0.5*dt - static_berg=0. !Initializing orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) - if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in - lonn = berg%lon ; latn = berg%lat axn = berg%axn ; ayn = berg%ayn @@ -3934,8 +3988,7 @@ subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since !this is only called once in Verlet stepping. if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, berg%thickness) ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon @@ -4017,7 +4070,6 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n real :: xn, xdotn, xddotn, yn, ydotn, yddotn, xddotnn, yddotnn real :: dt, dt_2, dt_6, dydl -real :: static_berg,orientation integer :: i1,j1,i2,j2,i3,j3,i4,j4 integer :: stderrunit logical :: bounced, on_tangential_plane, error_flag @@ -4044,11 +4096,6 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo dt_2=0.5*dt dt_6=dt/6. - static_berg=0. !Initializing - orientation=bergs%initial_orientation - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) !Not sure if this works with Runge Kutta - if (bergs%hexagonal_icebergs) static_berg=berg%static_berg !Change this to use_old_restart=false when this is merged in - i=berg%ine j=berg%jne xi=berg%xi @@ -4058,8 +4105,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. i1=i;j1=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) ! Loading past accelerations - Alon axn=berg%axn; ayn=berg%ayn !Alon @@ -4097,8 +4143,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i2=i; j2=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. @@ -4155,8 +4200,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) i3=i; j3=j if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) if (.not.error_flag) then if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. @@ -4289,8 +4333,7 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo i=i1;j=j1;xi=berg%xi;yj=berg%yj call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(grd, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, & - bergs%use_old_spreading, bergs%hexagonal_icebergs,orientation,static_berg, berg%uvel, berg%vvel) + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) if (.not.error_flag) then if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. @@ -4848,6 +4891,7 @@ subroutine icebergs_end(bergs) deallocate(bergs%grd%bergy_melt) deallocate(bergs%grd%bergy_mass) deallocate(bergs%grd%spread_mass) + deallocate(bergs%grd%spread_mass_old) deallocate(bergs%grd%spread_area) deallocate(bergs%grd%virtual_area) deallocate(bergs%grd%mass) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 123eee0..b04b063 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -117,6 +117,7 @@ module ice_bergs_framework real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/m^2) + real, dimension(:,:), pointer :: spread_mass_old=>null() ! Mass of icebergs after spreading old (kg/m^2) real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/m^2) real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) @@ -149,7 +150,7 @@ module ice_bergs_framework integer :: id_mass=-1, id_ui=-1, id_vi=-1, id_ua=-1, id_va=-1, id_sst=-1, id_cn=-1, id_hi=-1 integer :: id_bergy_src=-1, id_bergy_melt=-1, id_bergy_mass=-1, id_berg_melt=-1 integer :: id_rmean_calving=-1, id_rmean_calving_hflx=-1 - integer :: id_mass_on_ocn=-1, id_area_on_ocn=-1, id_spread_mass=-1, id_spread_area=-1 + integer :: id_spread_mass=-1, id_spread_area=-1 integer :: id_ssh=-1, id_fax=-1, id_fay=-1 integer :: id_count=-1, id_chksum=-1, id_u_iceberg=-1, id_v_iceberg=-1, id_sss=-1, id_ustar_iceberg integer :: id_spread_uvel=-1, id_spread_vvel=-1 @@ -561,6 +562,7 @@ subroutine ice_bergs_framework_init(bergs, & allocate( grd%bergy_melt(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_melt(:,:)=0. allocate( grd%bergy_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%bergy_mass(:,:)=0. allocate( grd%spread_mass(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_mass(:,:)=0. + allocate( grd%spread_mass_old(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_mass_old(:,:)=0. allocate( grd%spread_area(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%spread_area(:,:)=0. allocate( grd%u_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%u_iceberg(:,:)=0. allocate( grd%v_iceberg(grd%isd:grd%ied, grd%jsd:grd%jed) ); grd%v_iceberg(:,:)=0. @@ -924,10 +926,6 @@ subroutine ice_bergs_framework_init(bergs, & 'Virtual coverage by icebergs', 'm^2') grd%id_mass=register_diag_field('icebergs', 'mass', axes, Time, & 'Iceberg density field', 'kg/(m^2)') -! grd%id_mass_on_ocn=register_diag_field('icebergs', 'mass_on_ocean', axes, Time, & -! 'Iceberg density field felt by ocean', 'kg/(m^2)') -! grd%id_area_on_ocn=register_diag_field('icebergs', 'area_on_ocean', axes, Time, & -! 'Iceberg area field felt by ocean', 'm^2/(m^2)') grd%id_stored_ice=register_diag_field('icebergs', 'stored_ice', axes3d, Time, & 'Accumulated ice mass by class', 'kg') grd%id_real_calving=register_diag_field('icebergs', 'real_calving', axes3d, Time, & From 74e5f1937b3996fa80c00442982cb3ee4fd16ce4 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 13 Oct 2016 13:38:18 -0400 Subject: [PATCH 183/361] Fixed the part of the code which restricts melting to ocean thicknesses less than a threshold value. The ocean thickness is now calculated by subtracting the ocean depth from the iceshelf draft (while previously we were subtracting ocean depth from ice shelf thickness) --- icebergs.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d4a79ef..53162b7 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1176,7 +1176,8 @@ subroutine thermodynamics(bergs) Mb=max(Mb,0.) !No refreezing allowed for now !Set melt to zero if ocean is too thin. if ((bergs%melt_cutoff >=0.) .and. (bergs%apply_thickness_cutoff_to_bergs_melt)) then - if ((grd%ocean_depth(i,j)-this%thickness) < bergs%melt_cutoff) then + Dn=(bergs%rho_bergs/rho_seawater)*this%thickness ! draught (keel depth) + if ((grd%ocean_depth(i,j)-Dn) < bergs%melt_cutoff) then Mb=0. endif endif @@ -1386,7 +1387,7 @@ subroutine create_gridded_icebergs_fields(bergs) real :: Hocean, Dn,Tn,dvo, mass_tmp real :: ustar_h, ustar real :: orientation -real :: ave_thickness +real :: ave_thickness, ave_draft real, dimension(bergs%grd%isd:bergs%grd%ied,bergs%grd%jsd:bergs%grd%jed) :: spread_mass_tmp real :: tmp @@ -1466,7 +1467,8 @@ subroutine create_gridded_icebergs_fields(bergs) do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed if ((bergs%melt_cutoff >=0.) .and. (grd%spread_area(i,j)>0.)) then ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) - if ((grd%ocean_depth(i,j)-ave_thickness) < bergs%melt_cutoff) then + ave_draft=ave_thickness*(bergs%rho_bergs/rho_seawater) + if ((grd%ocean_depth(i,j)-ave_draft) < bergs%melt_cutoff) then grd%floating_melt(i,j)=0.0 grd%calving_hflx(i,j)=0.0 endif From ac7556eecff13b7632db01fbbb4fe8a1f7f3f917 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 17 Oct 2016 11:16:40 -0400 Subject: [PATCH 184/361] Replaced initialization of logical force_app - The line "logical :: force_app = .false." only set force_app=.false. the very first time a send_bergs_to_other_pes() was called. This is bad practice. Replaced with explicit line 'force_app=.false.' - No answer changes (luckily). --- icebergs_framework.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 85bd6d2..f2253d6 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1072,10 +1072,11 @@ subroutine unpack_berg_from_buffer2(first, buff, n,grd, force_append) logical :: lres type(iceberg) :: localberg integer :: stderrunit - logical :: force_app = .false. + logical :: force_app ! Get the stderr unit number stderrunit = stderr() + force_app = .false. if(present(force_append)) force_app = force_append localberg%lon=buff%data(1,n) From 2b7b4d2275ba035903bd98d2a6a7db7dd19f94fc Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 17 Oct 2016 16:03:03 -0400 Subject: [PATCH 185/361] (*)Fixed logic for xi,yj coord calc in polar cells - Some logic used when calculation the non-dimensional position within a cell with a corner at the norht pole seemed to be back to front. Reversed the logic and was able pass bergs over PE boundaries in the northern hemisphere. - Tests do not change answers but this should matter if bergs are ever at the north pole. --- icebergs_framework.F90 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index f2253d6..c845941 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2350,7 +2350,7 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) if (max(y1,y2,y3,y4)<89.999) then call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, explain=explain) else - if (debug) write(stderrunit,*) 'diamonds, pos_within_cell: working in tangential plane!' +! if (debug) write(stderrunit,*) 'diamonds, pos_within_cell: working in tangential plane!' xx=(90.-y)*cos(x*pi_180) yy=(90.-y)*sin(x*pi_180) x1=(90.-y1)*cos(grd%lon(i-1,j-1)*pi_180) @@ -2370,7 +2370,8 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) endif endif call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, xx, yy, xi, yj, explain=explain) - if (is_point_in_cell(grd, x, y, i, j)) then + if (.not. is_point_in_cell(grd, x, y, i, j)) then +!was if (is_point_in_cell(grd, x, y, i, j)) then if (abs(xi-0.5)>0.5.or.abs(yj-0.5)>0.5) then ! Scale internal coordinates to be consistent with is_point_in_cell() ! Note: this is intended to fix the inconsistency between the tangent plane @@ -2378,11 +2379,11 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) fac=2.*max( abs(xi-0.5), abs(yj-0.5) ); fac=max(1., fac) xi=0.5+(xi-0.5)/fac yj=0.5+(yj-0.5)/fac - if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell so scaling internal coordinates!', WARNING) + ! if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell so scaling internal coordinates!', WARNING) endif else - if (abs(xi-0.5)<=0.5.and.abs(yj-0.5)<=0.5) then - if (debug) call error_mesg('diamonds, pos_within_cell', 'out of cell but coordinates <=0.5!', WARNING) + if (abs(xi-0.5)>0.5.and.abs(yj-0.5)>0.5) then + if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell but coordinates >0.5!', WARNING) endif endif endif From ee793fe49b48b06f74894fc316fc469534ffcc93 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 17 Oct 2016 16:04:48 -0400 Subject: [PATCH 186/361] Modified generate_bergs() used in testing - Cleaned up artificial generation of bergs which was not setting the lon.lat consistently with xi,yj. - No answer changes since this routine is only used to generate lots of bergs when debugging. --- icebergs_io.F90 | 58 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 60ed182..4c12449 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -871,6 +871,7 @@ subroutine generate_bergs(bergs,Time) integer :: iNg, jNg !Total number of points gloablly in i and j direction type(iceberg) :: localberg ! NOT a pointer but an actual local variable integer :: iyr, imon, iday, ihr, imin, isec + logical :: lres ! For convenience grd=>bergs%grd @@ -880,15 +881,16 @@ subroutine generate_bergs(bergs,Time) call get_date(Time, iyr, imon, iday, ihr, imin, isec) do j=grd%jsc,grd%jec; do i=grd%isc,grd%iec - if (grd%msk(i,j)>0. .and. abs(grd%latc(i,j))>60.) then - localberg%xi=0.5 - localberg%yj=0.5 + if (grd%msk(i,j)>0. .and. abs(grd%latc(i,j))>80.0) then + if (max(grd%lat(i,j),grd%lat(i-1,j),grd%lat(i,j-1),grd%lat(i-1,j-1))>89.999) cycle ! Cannot use this at Pole cells + localberg%xi=-999. + localberg%yj=-999. localberg%ine=i localberg%jne=j - localberg%lon=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) - localberg%lat=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) - localberg%lon_old=bilin(grd, grd%lon, i, j, localberg%xi, localberg%yj) !Alon - localberg%lat_old=bilin(grd, grd%lat, i, j, localberg%xi, localberg%yj) !Alon + localberg%lon=grd%lonc(i,j) + localberg%lat=grd%latc(i,j) + localberg%lon_old=localberg%lon + localberg%lat_old=localberg%lat localberg%mass=bergs%initial_mass(1) localberg%thickness=bergs%initial_thickness(1) localberg%width=bergs%initial_width(1) @@ -909,26 +911,22 @@ subroutine generate_bergs(bergs,Time) localberg%byn=0. !Alon !Berg A - localberg%uvel=1. - localberg%vvel=0. + call loc_set_berg_pos(grd, 0.9, 0.5, 1., 0., localberg) localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) !Berg B - localberg%uvel=-1. - localberg%vvel=0. + call loc_set_berg_pos(grd, 0.1, 0.5, -1., 0., localberg) localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) !Berg C - localberg%uvel=0. - localberg%vvel=1. + call loc_set_berg_pos(grd, 0.5, 0.9, 0., 1., localberg) localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) !Berg D - localberg%uvel=0. - localberg%vvel=-1. + call loc_set_berg_pos(grd, 0.5, 0.1, 0., -1., localberg) localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 call add_new_berg_to_list(bergs%first, localberg) @@ -941,6 +939,36 @@ subroutine generate_bergs(bergs,Time) write(*,'(a,i8,a)') 'diamonds, generate_bergs: ',bergs%nbergs_start,' were generated' end subroutine generate_bergs + + subroutine loc_set_berg_pos(grd, xi, yj, uvel, vvel, berg) + type(icebergs_gridded), pointer :: grd + real, intent(in) :: xi, yj, uvel, vvel + type(iceberg), intent(inout) :: berg + integer :: i, j + logical :: lres + i = berg%ine ; j = berg%jne + if (max(grd%lat(i,j),grd%lat(i-1,j),grd%lat(i,j-1),grd%lat(i-1,j-1))>89.999) then + berg%lon=grd%lonc(i,j) + berg%lat=grd%latc(i,j) + berg%xi=0.5 ; berg%yj=0.5 + else + berg%lon=bilin(grd, grd%lon, i, j, xi, yj) + berg%lat=bilin(grd, grd%lat, i, j, xi, yj) + berg%xi=xi ; berg%yj=yj + endif + berg%uvel=uvel ; berg%vvel=vvel + berg%lon_old=berg%lon ; berg%lat_old=berg%lat + berg%start_lon=berg%lon ; berg%start_lat=berg%lat + lres=pos_within_cell(grd, berg%lon, berg%lat, berg%ine, berg%jne, berg%xi, berg%yj) + if (.not. lres) then + lres=pos_within_cell(grd, berg%lon, berg%lat, berg%ine, berg%jne, berg%xi, berg%yj, explain=.true.) + write(0,*) lres, i, j, xi, yj, uvel, vvel + write(0,*) lres, berg%ine, berg%jne, berg%xi, berg%yj + write(0,*) 'bx=',berg%lon, 'gx=',grd%lon(i-1,j-1), grd%lon(i,j-1), grd%lon(i,j), grd%lon(i-1,j),'cx=', grd%lonc(i,j) + write(0,*) 'by=',berg%lat, 'gy=',grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i,j), grd%lat(i-1,j),'cy=', grd%latc(i,j) + stop 'generate_bergs, loc_set_berg_pos(): VERY FATAL!' + endif + end subroutine loc_set_berg_pos end subroutine read_restart_bergs ! ############################################################################## From aef8a359008d078c1c72d4399c1dcc83cff8e1ad Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 18 Oct 2016 11:51:13 -0400 Subject: [PATCH 187/361] *Bug fix: Interpolated ice velocity used ocean velocity - Commit cfa98aa42bf84ee196bf0678fa4dbbfde593654f included a bug fix where the meridional ice velocity component interpolated from a C grid was using the ocean velocity instead of the ice velocity. - Re-implementing on dev/master in order to merge in other branches which already have the fix. - Changes answers (only detected in SIS2_bergs_cgrid). --- icebergs.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 72b1f87..9844826 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1233,7 +1233,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%uo(I,J) = mask * 0.5*(uo(Iu,ju)+uo(Iu,ju+1)) grd%ui(I,J) = mask * 0.5*(ui(Iu,ju)+ui(Iu,ju+1)) grd%vo(I,J) = mask * 0.5*(vo(iv,Jv)+vo(iv+1,Jv)) - grd%vi(I,J) = mask * 0.5*(vi(iv,Jv)+vo(iv+1,Jv)) + grd%vi(I,J) = mask * 0.5*(vi(iv,Jv)+vi(iv+1,Jv)) enddo ; enddo else call error_mesg('diamonds, iceberg_run', 'Unrecognized value of stagger!', FATAL) From 447fe502f9f42bdf68b243e7505d8109ae3931db Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 18 Oct 2016 13:13:11 -0400 Subject: [PATCH 188/361] Fixed syntax issue with PGI line continuation - A "\" escape character was being used instead of "&" line continuation that gnu and intel were letting through but which PGI complained. - No answer changes. --- icebergs_framework.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e333c2e..fdf0c54 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2618,7 +2618,7 @@ subroutine show_all_bonds(bergs) !print *, 'Current:', berg%iceberg_num, berg%ine, berg%jne,berg%halo_berg, mpp_pe() if (associated(current_bond%other_berg)) then if (current_bond%other_berg%iceberg_num .ne. current_bond%other_berg_num) then - print *, 'Bond matching', berg%iceberg_num,current_bond%other_berg%iceberg_num, current_bond%other_berg_num,\ + print *, 'Bond matching', berg%iceberg_num,current_bond%other_berg%iceberg_num, current_bond%other_berg_num,& berg%halo_berg,current_bond%other_berg%halo_berg ,mpp_pe() call error_mesg('diamonds, show all bonds:', 'The bonds are not matching properly!', FATAL) endif From 109b1f9c2558a7c4ed1a62b2cd471c10fde27a03 Mon Sep 17 00:00:00 2001 From: Robert Hallberg Date: Thu, 27 Oct 2016 15:05:02 -0400 Subject: [PATCH 189/361] +Added code to handle A-grid wind stresses Added code to interpolate A-grid wind stresses to the B-grid locations used by the iceberg code. This new option is only triggered if the optional argument str_stagger=AGRID, which would have previously caused an error. The answers in all existing test cases are unchanged, but they do not use this new option. --- icebergs.F90 | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9844826..2a8257b 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1125,7 +1125,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off real :: mask -real, dimension(:,:), allocatable :: uC_tmp, vC_tmp +real, dimension(:,:), allocatable :: uC_tmp, vC_tmp, uA_tmp, vA_tmp integer :: vel_stagger, str_stagger integer :: stderrunit @@ -1269,6 +1269,26 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%va(I,J) = mask * 0.5*(vC_tmp(i,J)+vC_tmp(i+1,J)) enddo ; enddo deallocate(uC_tmp, vC_tmp) + elseif (str_stagger == AGRID) then + ! Copy into arrays with local index conventions and halos. + allocate(uA_tmp(grd%isd:grd%ied,grd%jsd:grd%jed), & + vA_tmp(grd%isd:grd%ied,grd%jsd:grd%jed)) + uA_tmp(:,:) = 0.0 ! This avoids uninitialized values that might remain in halo + vA_tmp(:,:) = 0.0 ! regions after the call to mpp_update_domains() below. + uA_tmp(grd%isc:grd%iec,grd%jsc:grd%jec) = tauxa(:,:) + vA_tmp(grd%isc:grd%iec,grd%jsc:grd%jec) = tauya(:,:) + call mpp_update_domains(uA_tmp, vA_tmp, grd%domain, gridtype=AGRID) + do I=grd%isc-1,grd%iec ; do J=grd%jsc-1,grd%jec + ! Interpolate wind stresses from A-grid tracer points to the corner B-grid points. + ! This masking is needed for now to prevent icebergs from running up on to land. + mask = min(grd%msk(i,j), grd%msk(i+1,j), grd%msk(i,j+1), grd%msk(i+1,j+1)) + grd%ua(I,J) = mask * 0.25*((uA_tmp(i,j) + uA_tmp(i+1,j+1)) + & + (uA_tmp(i+1,j) + uA_tmp(i,j+1))) + grd%va(I,J) = mask * 0.25*((vA_tmp(i,j) + vA_tmp(i+1,j+1)) + & + (vA_tmp(i+1,j) + vA_tmp(i,j+1))) + enddo ; enddo + + deallocate(uA_tmp, vA_tmp) else call error_mesg('diamonds, iceberg_run', 'Unrecognized value of stress_stagger!', FATAL) endif From 839a09fd53a37b4bbe571ee068122f5dd460e259 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 3 Nov 2016 16:01:20 -0400 Subject: [PATCH 190/361] Added multiple points for calling monitor_a_berg() - Run-time option debug_a_berg_with_id was only enabling debugging/ monitoring of a berg within the send_bergs_to_other_pes() routine. Now we can monitor a berg at the icebergs_run() level and watch a berg evolve through each step of the algorithm. - No answer changes. --- icebergs.F90 | 17 +++++++++++++---- icebergs_framework.F90 | 6 +----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index c6f7e7f..910ea95 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -37,6 +37,7 @@ module ice_bergs use ice_bergs_framework, only: grd_chksum2,grd_chksum3 use ice_bergs_framework, only: fix_restart_dates, offset_berg_dates use ice_bergs_framework, only: orig_read ! Remove when backward compatibility no longer needed +use ice_bergs_framework, only: monitor_a_berg use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving @@ -3088,18 +3089,22 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_clock_begin(bergs%clock_cal) ! Calve excess stored ice into icebergs + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, before calving() ') call calve_icebergs(bergs) if (debug) call bergs_chksum(bergs, 'run bergs (calved)') if (debug) call checksum_gridded(bergs%grd, 's/r run after calving') + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after calving() ') call mpp_clock_end(bergs%clock_cal) ! For each berg, evolve call mpp_clock_begin(bergs%clock_mom) if (.not.bergs%Static_icebergs) then - call evolve_icebergs(bergs) + call evolve_icebergs(bergs) + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after evolve() ') endif call move_berg_between_cells(bergs) !Markpoint6 + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after move_lists() ') if (debug) call bergs_chksum(bergs, 'run bergs (evolved)',ignore_halo_violation=.true.) if (debug) call checksum_gridded(bergs%grd, 's/r run after evolve') call mpp_clock_end(bergs%clock_mom) @@ -3109,9 +3114,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (bergs%iceberg_bonds_on) call bond_address_update(bergs) call send_bergs_to_other_pes(bergs) - if ((bergs%interactive_icebergs_on) .or. (bergs%iceberg_bonds_on)) & - call update_halo_icebergs(bergs) - if (bergs%iceberg_bonds_on) call connect_all_bonds(bergs) + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after send_bergs() ') + if ((bergs%interactive_icebergs_on) .or. (bergs%iceberg_bonds_on)) then + call update_halo_icebergs(bergs) + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after update_halo()') + if (bergs%iceberg_bonds_on) call connect_all_bonds(bergs) + endif if (debug) call bergs_chksum(bergs, 'run bergs (exchanged)') if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) @@ -3129,6 +3137,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Iceberg thermodynamics (melting) + rolling call mpp_clock_begin(bergs%clock_the) call thermodynamics(bergs) + if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'icebergs_run, after thermodyn() ') if (debug) call bergs_chksum(bergs, 'run bergs (thermo)') if (debug) call checksum_gridded(bergs%grd, 's/r run after thermodynamics') call mpp_clock_end(bergs%clock_the) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 78ae317..4411a45 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -72,7 +72,7 @@ module ice_bergs_framework public fix_restart_dates, offset_berg_dates public move_berg_between_cells public find_individual_iceberg - +public monitor_a_berg type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -1473,8 +1473,6 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_start=count_bergs(bergs, with_halos=.true.) endif - if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (top)') - ! Find number of bergs that headed east/west nbergs_to_send_e=0 nbergs_to_send_w=0 @@ -1658,8 +1656,6 @@ subroutine send_bergs_to_other_pes(bergs) nbergs_rcvd_from_n=0 endif - if (bergs%debug_iceberg_with_id>0) call monitor_a_berg(bergs, 'send_bergs_to_other_pes (end)') - if (debug) then nbergs_end=count_bergs(bergs, with_halos=.true.) i=nbergs_rcvd_from_n+nbergs_rcvd_from_s+nbergs_rcvd_from_e+nbergs_rcvd_from_w & From 5c80ddbfc797dce7d3df781c091f8d80c34b532a Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 3 Nov 2016 16:03:15 -0400 Subject: [PATCH 191/361] Tidied up formatting of print_berg() and warnings - print_berg() now adds %iceberg_num to every line. - formatted diagnostics from pos_within_cell() such that we can cut and paste into a python window. - No answer changes. --- icebergs_framework.F90 | 55 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 4411a45..77976d1 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -2455,26 +2455,35 @@ subroutine print_berg(iochan, berg, label, il, jl) integer, optional, intent(in) :: il, jl !< Indices of cell berg should be in ! Local variables - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") start lon,lat,yr,#,day,mass,hb=",2f10.4,i5,i12,f7.2,es12.4,f5.1)') & - label, mpp_pe(), berg%start_lon, berg%start_lat, & - berg%start_year, berg%iceberg_num, berg%start_day, berg%start_mass, berg%halo_berg + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,a,2f10.4,i5,f7.2,es12.4,f5.1)') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, ' start lon,lat,yr,day,mass,hb=', & + berg%start_lon, berg%start_lat, berg%start_year, berg%start_day, berg%start_mass, berg%halo_berg if (present(il).and.present(jl)) then - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f14.8),a,2l2)') & - label, mpp_pe(), ') List i,j=',il,jl + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,a,2i5)') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, ' List i,j=',il,jl endif - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,a,2i5,3(a,2f14.8),a,2l2)') & - label, mpp_pe(), ') i,j=',berg%ine, berg%jne, & + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,a,2i5,a,2l2)') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, & + ' i,j=', berg%ine, berg%jne, & + ' p,n=', associated(berg%prev), associated(berg%next) + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,3(a,2f14.8))') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, & ' xi,yj=', berg%xi, berg%yj, & ' lon,lat=', berg%lon, berg%lat, & + ' lon_old,lat_old=', berg%lon_old, berg%lat_old + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,2(a,2f14.8))') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, & ' u,v=', berg%uvel, berg%vvel, & + ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,2(a,2f14.8))') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, & ' axn,ayn=', berg%axn, berg%ayn, & - ' bxn,byn=', berg%bxn, berg%byn, & - ' uvel_old,vvel_old=', berg%uvel_old, berg%vvel_old, & - ' lon_old,lat_old=', berg%lon_old, berg%lat_old, & - ' p,n=', associated(berg%prev), associated(berg%next) - write(iochan,'("diamonds, print_berg: ",a," pe=(",i3,") ",6(a,2f14.8))') & - label, mpp_pe(), 'uo,vo=', berg%uo, berg%vo, 'ua,va=', berg%ua, berg%va, 'ui,vi=', berg%ui, berg%vi -!Two lines above added by Alon + ' bxn,byn=', berg%bxn, berg%byn + write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,3(a,2f14.8))') & + label, 'pe=(', mpp_pe(), ') #=', berg%iceberg_num, & + ' uo,vo=', berg%uo, berg%vo, & + ' ua,va=', berg%ua, berg%va, & + ' ui,vi=', berg%ui, berg%vi end subroutine print_berg ! ############################################################################## @@ -3594,10 +3603,9 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) if (present(explain)) then if(explain) then - write(stderrunit,'(a,4f12.6)') 'pos_within_cell: x1..x4 ',x1, x2, x3, x4 - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: x ',x - write(stderrunit,'(a,4f12.6)') 'pos_within_cell: y1..y4 ',y1, y2, y3, y4 - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: y ',y + write(stderrunit,'(a,4(f12.6,a))') 'pos_within_cell: lon=[',x1,',',x2,',',x3,',',x4,']' + write(stderrunit,'(a,4(f12.6,a))') 'pos_within_cell: lat=[',y1,',',y2,',',y3,',',y4,']' + write(stderrunit,'(2(a,f12.6))') 'pos_within_cell: x,y=',x,',',y endif endif @@ -3627,10 +3635,9 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) y4=(90.-y4)*sin(grd%lon(i-1,j )*pi_180) if (present(explain)) then if(explain) then - write(stderrunit,'(a,4f12.6)') 'pos_within_cell: x1..x4 ',x1,x2,x3,x4 - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: x',xx - write(stderrunit,'(a,4f12.6)') 'pos_within_cell: y1..y4 ',y1,y2,y3,y4 - write(stderrunit,'(a,2f12.6)') 'pos_within_cell: y',yy + write(stderrunit,'(a,4(f12.6,a))') 'pos_within_cell: lon=[',x1,',',x2,',',x3,',',x4,']' + write(stderrunit,'(a,4(f12.6,a))') 'pos_within_cell: lat=[',y1,',',y2,',',y3,',',y4,']' + write(stderrunit,'(2(a,f12.6))') 'pos_within_cell: x,y=',xx,',',yy endif endif call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, xx, yy, xi, yj, Lx,explain=explain) @@ -3717,9 +3724,9 @@ subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) if (abs(yy1-0.5).lt.abs(yy2-0.5)) then; yj=yy1; else; yj=yy2; endif if (expl) write(stderrunit,'(a,1p3e12.4)') 'Roots for y = ',yy1,yy2,yj else - write(stderrunit,'(a,i3,4f8.2)') 'calc_xiyj: x1..x4 ',mpp_pe(),x1,x2,x3,x4 + write(stderrunit,'(a,i3,a,4(f8.2,a))') 'calc_xiyj: ',mpp_pe(),'lon=[',x1,',',x2,',',x3,',',x4,']' write(stderrunit,'(a,i3,3f8.2)') 'calc_xiyj: x2..x4 - x1',mpp_pe(),x2-x1,x3-x1,x4-x1 - write(stderrunit,'(a,i3,4f8.2)') 'calc_xiyj: y1..y4 ',mpp_pe(),y1,y2,y3,y4 + write(stderrunit,'(a,i3,a,4(f8.2,a))') 'calc_xiyj: ',mpp_pe(),'lat=[',y1,',',y2,',',y3,',',y4,']' write(stderrunit,'(a,i3,3f8.2)') 'calc_xiyj: y2..y4 - x1',mpp_pe(),y2-y1,y3-y1,y4-y1 write(stderrunit,'(a,i3,1p6e12.4)') 'calc_xiyj: coeffs alpha..kappa',mpp_pe(),alpha,beta,gamma,delta,epsilon,kappa write(stderrunit,'(a,i3)') 'calc_xiyj: b<0 in quadratic root solver!!!!',mpp_pe() From 98c2f3b40cabbe349106df45ee0bf5e979d1d720 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Fri, 4 Nov 2016 15:50:55 -0400 Subject: [PATCH 192/361] *Revert previous logic update for polar cells - In commit 2b7b4d2275b we updated the code and broke things! We've reverted and added a lot more comments explaining what the logic is doing. It's right this time! :) - Changes answers in ice_ocean_SIS2/SIS2_bergs_cgrid because we are generating bergs where as we weren't when we made the bad update (2b7b4d2275b). --- icebergs_framework.F90 | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 77976d1..d87596f 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3599,7 +3599,6 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) y3=grd%lat(i ,j ) x4=grd%lon(i-1,j ) y4=grd%lat(i-1,j ) - if (present(explain)) then if(explain) then @@ -3620,9 +3619,11 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) yj=((y-y1)/dy)+0.5 elseif ((max(y1,y2,y3,y4)<89.999) .or.(.not. grd%grid_is_latlon)) then + ! This returns non-dimensional position xi,yj for quad cells (not at a pole) call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, Lx, explain=explain) else -! if (debug) write(stderrunit,*) 'diamonds, pos_within_cell: working in tangential plane!' + ! One of the cell corners is at the north pole so we switch to a tangent plane with + ! co-latitude as a radial coordinate. xx=(90.-y)*cos(x*pi_180) yy=(90.-y)*sin(x*pi_180) x1=(90.-y1)*cos(grd%lon(i-1,j-1)*pi_180) @@ -3640,21 +3641,29 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) write(stderrunit,'(2(a,f12.6))') 'pos_within_cell: x,y=',xx,',',yy endif endif + ! Calculate non-dimensional position xi,yj within a quad in the tangent plane. + ! This quad has straight sides in the plane and so is not the same on the + ! projection of the spherical quad. call calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, xx, yy, xi, yj, Lx,explain=explain) - if (.not. is_point_in_cell(grd, x, y, i, j)) then -!was if (is_point_in_cell(grd, x, y, i, j)) then + if (is_point_in_cell(grd, x, y, i, j)) then + ! The point is within the spherical quad if (abs(xi-0.5)>0.5.or.abs(yj-0.5)>0.5) then - ! Scale internal coordinates to be consistent with is_point_in_cell() + ! If the non-dimensional position is found to be outside (possible because the + ! projection of the spherical quad and the quad in the tangent plane are different) + ! then scale non-dimensional coordinates to be consistent with is_point_in_cell() ! Note: this is intended to fix the inconsistency between the tangent plane - ! and lat-lon calculations - fac=2.*max( abs(xi-0.5), abs(yj-0.5) ); fac=max(1., fac) + ! and lat-lon calculations and is a work around only for the four polar cells. + fac=2.1*max( abs(xi-0.5), abs(yj-0.5) ); fac=max(1., fac) xi=0.5+(xi-0.5)/fac yj=0.5+(yj-0.5)/fac - ! if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell so scaling internal coordinates!', WARNING) + if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell but scaling internal coordinates!', WARNING) endif else - if (abs(xi-0.5)>0.5.and.abs(yj-0.5)>0.5) then - if (debug) call error_mesg('diamonds, pos_within_cell', 'in cell but coordinates >0.5!', WARNING) + ! The point is not inside the spherical quad + if (abs(xi-0.5)<0.5.and.abs(yj-0.5)<0.5) then + ! The projection of the spherical quad onto the tangent plane should be larger than + ! quad in the tangent plane so we should never be able to get here. + call error_mesg('diamonds, pos_within_cell', 'not in cell but coordinates <0.5!', FATAL) endif endif endif @@ -3663,17 +3672,20 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) if(explain) write(stderrunit,'(a,2f12.6)') 'pos_within_cell: xi,yj=',xi,yj endif - !if (.not. is_point_in_cell(grd, x, y, i, j) ) then - ! write(stderrunit,'(a,i3,a,8f8.2,a)') 'diamonds, pos_within_cell: (',mpp_pe(),') ', & - ! x1, y1, x2, y2, x3, y3, x4, y4, ' NOT IN CELL!' - !endif - + ! Check for consistency with test for whether point is inside a polygon + pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=explain) if (xi.ge.0. .and. xi.le.1. .and. yj.ge.0. .and. yj.le.1.) then - pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=explain) + ! Based on coordinate, the point is out of cell + if (pos_within_cell .and. verbose) then + ! Based on is_point_in_cell() the point is within cell so we have an inconsistency + if (debug) call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is in cell BUT is_point_in_cell disagrees!', WARNING) + endif + else + ! Based on coordinate, the point is within cell if (.not. pos_within_cell .and. verbose) then + ! Based on is_point_in_cell() the point is out of cell so we have an inconsistency if (debug) call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is in cell BUT is_point_in_cell disagrees!', WARNING) endif - !pos_within_cell=.true. ! commenting this out makes pos_within_cell agree with is_point_in_cell endif contains From 1f201f80ec9669e23acda611550556c0dcfcdc9f Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Sun, 6 Nov 2016 11:48:33 -0500 Subject: [PATCH 193/361] Support reading of old restarts on a field-by-field basis - Fields axn, ayn, bxn, byn, iceberg_num, mass_of_bits, heat_density, halo_berg and static_berg are now optional in the restarts and are filled with a default value if missing on a read. - Fields are only written if being used. - No answer changes. --- icebergs_io.F90 | 142 +++++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 56 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index e176b15..2fe0766 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -209,10 +209,12 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_restart,filename,'uvel',uvel,longname='zonal velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'vvel',vvel,longname='meridional velocity',units='m/s') id = register_restart_field(bergs_restart,filename,'mass',mass,longname='mass',units='kg') - id = register_restart_field(bergs_restart,filename,'axn',axn,longname='explicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'ayn',ayn,longname='explicit meridional acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'bxn',bxn,longname='inplicit zonal acceleration',units='m/s^2') !Alon - id = register_restart_field(bergs_restart,filename,'byn',byn,longname='implicit meridional acceleration',units='m/s^2') !Alon + if (.not. bergs%Runge_not_Verlet) then + id = register_restart_field(bergs_restart,filename,'axn',axn,longname='explicit zonal acceleration',units='m/s^2') + id = register_restart_field(bergs_restart,filename,'ayn',ayn,longname='explicit meridional acceleration',units='m/s^2') + id = register_restart_field(bergs_restart,filename,'bxn',bxn,longname='inplicit zonal acceleration',units='m/s^2') + id = register_restart_field(bergs_restart,filename,'byn',byn,longname='implicit meridional acceleration',units='m/s^2') + endif id = register_restart_field(bergs_restart,filename,'ine',ine,longname='i index',units='none') id = register_restart_field(bergs_restart,filename,'jne',jne,longname='j index',units='none') id = register_restart_field(bergs_restart,filename,'thickness',thickness,longname='thickness',units='m') @@ -236,11 +238,12 @@ subroutine write_restart(bergs) longname='mass of bergy bits',units='kg') id = register_restart_field(bergs_restart,filename,'heat_density',heat_density, & longname='heat density',units='J/kg') - id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & - longname='halo_berg',units='dimensionless') - id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & - longname='static_berg',units='dimensionless') - + if (bergs%interactive_icebergs_on .or. bergs%iceberg_bonds_on) & + id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & + longname='halo_berg',units='dimensionless') + if (bergs%static_icebergs) & + id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & + longname='static_berg',units='dimensionless') ! Write variables @@ -479,28 +482,24 @@ subroutine read_restart_bergs_orig(bergs,Time) uvelid=inq_var(ncid, 'uvel') vvelid=inq_var(ncid, 'vvel') massid=inq_var(ncid, 'mass') - axnid=inq_var(ncid, 'axn') !Alon - aynid=inq_var(ncid, 'ayn') !Alon - bxnid=inq_var(ncid, 'bxn') !Alon - bynid=inq_var(ncid, 'byn') !Alon + axnid=inq_var(ncid, 'axn', unsafe=.true.) + aynid=inq_var(ncid, 'ayn', unsafe=.true.) + bxnid=inq_var(ncid, 'bxn', unsafe=.true.) + bynid=inq_var(ncid, 'byn', unsafe=.true.) thicknessid=inq_var(ncid, 'thickness') widthid=inq_var(ncid, 'width') lengthid=inq_var(ncid, 'length') start_lonid=inq_var(ncid, 'start_lon') start_latid=inq_var(ncid, 'start_lat') start_yearid=inq_var(ncid, 'start_year') - if (bergs%read_old_restarts) then - iceberg_numid=-1 - else - iceberg_numid=inq_var(ncid, 'icberg_num') - endif + iceberg_numid=inq_var(ncid, 'icberg_num', unsafe=.true.) start_dayid=inq_var(ncid, 'start_day') start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') - halo_bergid=inq_var(ncid, 'halo_berg') - static_bergid=inq_var(ncid, 'static_berg') - mass_of_bits_id=inq_var(ncid, 'mass_of_bits',unsafe=.true.) - heat_density_id=inq_var(ncid, 'heat_density',unsafe=.true.) + halo_bergid=inq_var(ncid, 'halo_berg', unsafe=.true.) + static_bergid=inq_var(ncid, 'static_berg', unsafe=.true.) + mass_of_bits_id=inq_var(ncid, 'mass_of_bits', unsafe=.true.) + heat_density_id=inq_var(ncid, 'heat_density', unsafe=.true.) ineid=inq_var(ncid, 'ine',unsafe=.true.) jneid=inq_var(ncid, 'jne',unsafe=.true.) @@ -539,36 +538,29 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%uvel=get_double(ncid, uvelid, k) localberg%vvel=get_double(ncid, vvelid, k) localberg%mass=get_double(ncid, massid, k) - localberg%axn=get_double(ncid, axnid, k) !Alon - localberg%ayn=get_double(ncid, aynid, k) !Alon - localberg%bxn=get_double(ncid, bxnid, k) !Alon - localberg%byn=get_double(ncid, bynid, k) !Alon + localberg%axn=get_real_from_file(ncid, axnid, k, value_if_not_in_file=0.) + localberg%ayn=get_real_from_file(ncid, aynid, k, value_if_not_in_file=0.) + localberg%bxn=get_real_from_file(ncid, bxnid, k, value_if_not_in_file=0.) + localberg%byn=get_real_from_file(ncid, bynid, k, value_if_not_in_file=0.) localberg%thickness=get_double(ncid, thicknessid, k) localberg%width=get_double(ncid, widthid, k) localberg%length=get_double(ncid, lengthid, k) localberg%start_lon=get_double(ncid, start_lonid, k) localberg%start_lat=get_double(ncid, start_latid, k) localberg%start_year=get_int(ncid, start_yearid, k) - if (bergs%read_old_restarts) then - localberg%iceberg_num=-1 - else + if (iceberg_numid>0) then localberg%iceberg_num=get_int(ncid, iceberg_numid, k) + else + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i +(iNg*(j-1))) ! unique number for each iceberg + grd%iceberg_counter_grd(i,j)=grd%iceberg_counter_grd(i,j)+1 endif localberg%start_day=get_double(ncid, start_dayid, k) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) - localberg%halo_berg=get_double(ncid, halo_bergid, k) - localberg%static_berg=get_double(ncid, static_bergid, k) - if (mass_of_bits_id>0) then ! Allow reading of older restart with no bergy bits - localberg%mass_of_bits=get_double(ncid, mass_of_bits_id, k) - else - localberg%mass_of_bits=0. - endif - if (heat_density_id>0) then ! Allow reading of older restart with no heat content - localberg%heat_density=get_double(ncid, heat_density_id, k) - else - localberg%heat_density=0. - endif + localberg%halo_berg=get_real_from_file(ncid, halo_bergid, k, value_if_not_in_file=0.) + localberg%static_berg=get_real_from_file(ncid, static_bergid, k, value_if_not_in_file=0.) + localberg%mass_of_bits=get_real_from_file(ncid, mass_of_bits_id, k, value_if_not_in_file=0.) + localberg%heat_density=get_real_from_file(ncid, heat_density_id, k, value_if_not_in_file=0.) if (really_debug) lres=is_point_in_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, explain=.true.) lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) @@ -610,6 +602,17 @@ subroutine read_restart_bergs_orig(bergs,Time) if (mpp_pe().eq.mpp_root_pe().and.verbose) write(*,'(a)') 'diamonds, read_restart_bergs: completed' contains + + real function get_real_from_file(ncid, varid, k, value_if_not_in_file) + integer, intent(in) :: ncid, varid, k + real, optional :: value_if_not_in_file + + if (varid<1.and.present(value_if_not_in_file)) then + get_real_from_file=value_if_not_in_file + else + get_real_from_file=get_double(ncid, ncid, k) + endif + end function get_real_from_file subroutine generate_bergs(bergs,Time) ! Arguments @@ -797,10 +800,10 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'uvel',uvel,domain=grd%domain) call read_unlimited_axis(filename,'vvel',vvel,domain=grd%domain) call read_unlimited_axis(filename,'mass',mass,domain=grd%domain) - call read_unlimited_axis(filename,'axn',axn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'ayn',ayn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'bxn',bxn,domain=grd%domain) !Alon - call read_unlimited_axis(filename,'byn',byn,domain=grd%domain) !Alon + call read_real_vector(filename,'axn',axn,grd%domain,value_if_not_in_file=0.) + call read_real_vector(filename,'ayn',ayn,grd%domain,value_if_not_in_file=0.) + call read_real_vector(filename,'bxn',bxn,grd%domain,value_if_not_in_file=0.) + call read_real_vector(filename,'byn',byn,grd%domain,value_if_not_in_file=0.) call read_unlimited_axis(filename,'thickness',thickness,domain=grd%domain) call read_unlimited_axis(filename,'width',width,domain=grd%domain) call read_unlimited_axis(filename,'length',length,domain=grd%domain) @@ -809,18 +812,14 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'start_day',start_day,domain=grd%domain) call read_unlimited_axis(filename,'start_mass',start_mass,domain=grd%domain) call read_unlimited_axis(filename,'mass_scaling',mass_scaling,domain=grd%domain) - call read_unlimited_axis(filename,'mass_of_bits',mass_of_bits,domain=grd%domain) - call read_unlimited_axis(filename,'halo_berg',halo_berg,domain=grd%domain) - call read_unlimited_axis(filename,'static_berg',static_berg,domain=grd%domain) - call read_unlimited_axis(filename,'heat_density',heat_density,domain=grd%domain) + call read_real_vector(filename,'mass_of_bits',mass_of_bits,domain=grd%domain,value_if_not_in_file=0.) + call read_real_vector(filename,'heat_density',heat_density,domain=grd%domain,value_if_not_in_file=0.) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) - if (bergs%read_old_restarts) then - iceberg_num(:)=-1 - else - call read_unlimited_axis(filename,'iceberg_num',iceberg_num,domain=grd%domain) - endif + call read_real_vector(filename,'halo_berg',halo_berg,grd%domain,value_if_not_in_file=0.) + call read_int_vector(filename,'iceberg_num',iceberg_num,grd%domain,value_if_not_in_file=-1) + call read_real_vector(filename,'static_berg',static_berg,grd%domain,value_if_not_in_file=0.) endif ! Find approx outer bounds for tile @@ -915,7 +914,11 @@ subroutine read_restart_bergs(bergs,Time) !call add_new_berg_to_list(bergs%first, localberg, quick=.true.) if (bergs%grd%area(localberg%ine,localberg%jne) .ne. 0) then - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) + if (iceberg_num(k)==-1) then ! If using an old_restart then iceberg_num needs to be generated + localberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(localberg%ine,localberg%jne))+(localberg%ine+(iNg*(localberg%jne-1))) + grd%iceberg_counter_grd(localberg%ine,localberg%jne)=grd%iceberg_counter_grd(localberg%ine,localberg%jne)+1 + endif + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg) else if (mpp_pe().eq.mpp_root_pe()) then print * , 'Grounded iceberg: ', lat(k),lon(k), iceberg_num(k) @@ -988,8 +991,35 @@ subroutine read_restart_bergs(bergs,Time) call mpp_sum( bergs%bergy_mass_start ) if (mpp_pe().eq.mpp_root_pe().and.verbose) write(*,'(a)') 'diamonds, read_restart_bergs: completed' - contains + + subroutine read_real_vector(filename, varname, values, domain, value_if_not_in_file) + character(len=*), intent(in) :: filename + character(len=*), intent(in) :: varname + real, intent(out) :: values(:) + type(domain2D), intent(in) :: domain + real, optional, intent(in) :: value_if_not_in_file + + if (present(value_if_not_in_file).and..not.field_exist(filename, varname)) then + values(:)=value_if_not_in_file + else + call read_unlimited_axis(filename,varname,values,domain=domain) + endif + end subroutine read_real_vector + + subroutine read_int_vector(filename, varname, values, domain, value_if_not_in_file) + character(len=*), intent(in) :: filename + character(len=*), intent(in) :: varname + integer, intent(out) :: values(:) + type(domain2D), intent(in) :: domain + integer, optional, intent(in) :: value_if_not_in_file + + if (present(value_if_not_in_file).and..not.field_exist(filename, varname)) then + values(:)=value_if_not_in_file + else + call read_unlimited_axis(filename,varname,values,domain=domain) + endif + end subroutine read_int_vector subroutine generate_bergs(bergs,Time) ! Arguments From dbad95b3644f26ecdcdb0675540c94d0781342f7 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Sun, 6 Nov 2016 11:51:24 -0500 Subject: [PATCH 194/361] Obsoleted parameter read_old_restarts - Now that old restarts are read/written optionally on a field-by-field basis, there is no need for the run-time parameter "read_old_restarts". - The namelist is still present (for backwards compatibility) but it does nothing except issue a warning about being obsolete. - No answer changes. --- icebergs.F90 | 6 +----- icebergs_framework.F90 | 6 ++---- icebergs_io.F90 | 8 ++++---- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 910ea95..f6bef1a 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -3826,11 +3826,7 @@ subroutine calve_icebergs(bergs) newberg%start_lon=newberg%lon newberg%start_lat=newberg%lat newberg%start_year=bergs%current_year - if (.not. bergs%read_old_restarts) then - newberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg - else - newberg%iceberg_num=-1 - endif + newberg%iceberg_num=((iNg*jNg)*grd%iceberg_counter_grd(i,j))+(i+(iNg*(j-1))) ! unique number for each iceberg newberg%start_day=bergs%current_yearday+ddt/86400. newberg%start_mass=bergs%initial_mass(k) newberg%mass_scaling=bergs%mass_scaling(k) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index d87596f..e21e0cd 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -246,7 +246,6 @@ module ice_bergs_framework logical :: apply_thickness_cutoff_to_gridded_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) logical :: apply_thickness_cutoff_to_bergs_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) logical :: use_updated_rolling_scheme=.false. ! True to use the aspect ratio based rolling scheme rather than incorrect version of WM scheme (set tip_parameter=1000. for correct WM scheme) - logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovation logical :: pass_fields_to_ocean_model=.False. !Iceberg area, mass and ustar fields are prepared to pass to ocean model logical :: use_mixed_layer_salinity_for_thermo=.False. !If true, then model uses ocean salinity for 3 and 2 equation melt model. logical :: find_melt_using_spread_mass=.False. !If true, then the model calculates ice loss by looping at the spread_mass before and after. @@ -428,7 +427,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: critical_interaction_damping_on=.true. !Sets the damping on relative iceberg velocity to critical value - Added by Alon logical :: do_unit_tests=.false. ! Conduct some unit tests logical :: input_freq_distribution=.false. ! Flag to show if input distribution is freq or mass dist (=1 if input is a freq dist, =0 to use an input mass dist) -logical :: read_old_restarts=.true. ! If true, read restarts prior to grid_of_lists and iceberg_num innovations +logical :: read_old_restarts=.false. ! Legacy option that does nothing logical :: use_old_spreading=.true. ! If true, spreads iceberg mass as if the berg is one grid cell wide logical :: read_ocean_depth_from_file=.false. ! If true, ocean depth is read from a file. real, dimension(nclasses) :: initial_mass=(/8.8e7, 4.1e8, 3.3e9, 1.8e10, 3.8e10, 7.5e10, 1.2e11, 2.2e11, 3.9e11, 7.4e11/) ! Mass thresholds between iceberg classes (kg) @@ -864,7 +863,6 @@ subroutine ice_bergs_framework_init(bergs, & bergs%use_new_predictive_corrective=use_new_predictive_corrective !Alon bergs%grounding_fraction=grounding_fraction bergs%add_weight_to_ocean=add_weight_to_ocean - bergs%read_old_restarts=read_old_restarts bergs%use_old_spreading=use_old_spreading bergs%debug_iceberg_with_id=debug_iceberg_with_id allocate( bergs%initial_mass(nclasses) ); bergs%initial_mass(:)=initial_mass(:) @@ -876,7 +874,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%initial_width(:)=sqrt(initial_mass(:)/(LoW_ratio*rho_bergs*initial_thickness(:))) bergs%initial_length(:)=LoW_ratio*bergs%initial_width(:) - if (bergs%read_old_restarts) call error_mesg('diamonds, ice_bergs_framework_init', 'Setting "read_old_restarts=.true." can lead to non-reproducing checksums in restarts!', WARNING) + if (read_old_restarts) call error_mesg('diamonds, ice_bergs_framework_init', 'Setting "read_old_restarts=.true." is obsolete and does nothing!', WARNING) ! Diagnostics id_class = diag_axis_init('mass_class', initial_mass, 'kg','Z', 'iceberg mass') diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 2fe0766..f3eff4a 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -433,8 +433,8 @@ subroutine read_restart_bergs_orig(bergs,Time) ! For convenience grd=>bergs%grd - iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction, used with read_old_restarts=.true. - jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction, used with read_old_restarts=.true. + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction ! Find a restart file multiPErestart=.false. @@ -749,8 +749,8 @@ subroutine read_restart_bergs(bergs,Time) ! For convenience grd=>bergs%grd - iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction, used with read_old_restarts=.true. - jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction, used with read_old_restarts=.true. + iNg=(grd%ieg-grd%isg+1) ! Total number of points globally in i direction + jNg=(grd%jeg-grd%jsg+1) ! Total number of points globally in j direction ! Zero out nbergs_in_file nbergs_in_file = 0 From dc0a56140d8d07d86f7665e0ea17a7051dec44ac Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 16 Nov 2016 19:08:31 -0500 Subject: [PATCH 195/361] Weeks and Mellor Rolling scheme has been fixed --- icebergs.F90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index f6bef1a..cfa33ed 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1120,6 +1120,7 @@ subroutine thermodynamics(bergs) real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb real :: tip_parameter +real :: Delta, q integer :: i,j, stderrunit type(iceberg), pointer :: this, next real, parameter :: perday=1./86400. @@ -1298,7 +1299,9 @@ subroutine thermodynamics(bergs) if (Wn>Ln) call swap_variables(Ln,Wn) !Make sure that Wn is the smaller dimension if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter>=999.) ) then !Use Rolling Scheme 2 - if ( Wn Date: Wed, 23 Nov 2016 16:38:41 -0500 Subject: [PATCH 196/361] The model was writing to the icebergs_trajectories.nc file too many times. This was because the condition for sampling and writing the trajectory data did not account for the minutes and seconds. This means that when the time step is shorter than an hour, the modle sampled the trajectory many times. This bug is corrected by adding the minutes and seconds to the condition for traj_sample and traj_write. --- icebergs.F90 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index cfa33ed..5dc31a1 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2878,21 +2878,20 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Turn on sampling of trajectories, verbosity, budgets sample_traj=.false. if ( (bergs%traj_sample_hrs>0) .and. (.not. bergs%ignore_traj) ) then - if (mod(24*iday+ihr,bergs%traj_sample_hrs).eq.0) sample_traj=.true. - end if + if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_sample_hrs).eq.0) & sample_traj=.true. + endif write_traj=.false. if ((bergs%traj_write_hrs>0) .and. (.not. bergs%ignore_traj)) then - if (mod(24*iday+ihr,bergs%traj_write_hrs).eq.0) write_traj=.true. - end if + if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_write_hrs).eq.0) & write_traj=.true. + endif lverbose=.false. if (bergs%verbose_hrs>0) then - if (mod(24*iday+ihr,bergs%verbose_hrs).eq.0) lverbose=verbose - end if + if (mod(24*iday+ihr+(imin/60.),float(bergs%verbose_hrs)).eq.0) lverbose=verbose + endif lbudget=.false. if (bergs%verbose_hrs>0) then - !if (mod(24*iday+ihr,bergs%verbose_hrs).eq.0) lbudget=budget if (mod(24*iday+ihr+(imin/60.),float(bergs%verbose_hrs)).eq.0) lbudget=budget !Added minutes, so that it does not repeat when smaller time steps are used.:q - end if + endif if (mpp_pe()==mpp_root_pe().and.lverbose) write(*,'(a,3i5,a,3i5,a,i5,f8.3)') & 'diamonds: y,m,d=',iyr, imon, iday,' h,m,s=', ihr, imin, isec, & ' yr,yrdy=', bergs%current_year, bergs%current_yearday From ddbcdbc23e8c42acdad6827d5487fece53cf4be1 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 29 Nov 2016 10:39:31 -0500 Subject: [PATCH 197/361] Fixing is_point_in_cell routine for points near cell edge A bug was found in the routine is_point_in_cell. For icebergs with a longitude very close to the edge of a the cell, the modulo arithemtic inside sum_sign_prod4 rounds off the berg position to be exactly on the edge of the cell. However, the one edge of the cell actually belows to the next cell over. Therefore after roundoff, the berg is found not to be inside the cell. However, the 'crude bounds' inside is_point_in_cell mean that the adjacent cell (which the berg will be in after roundoff) does not make it through. This means that the icebergs is not found in either cell, and is not found at all. This problem has been solved by weakening the crude bound test. A tolorance has been added to the crude bounds inside the routine is_point_in_cell. This tol=0.1 avoids excluding points which are very near to the edge of the cell. This is a bit of an hack solution since the tolorance is in longitude coordinates. However it works for now. --- icebergs_framework.F90 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index e21e0cd..fe65935 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3360,6 +3360,7 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) real :: Lx_2 integer :: stderrunit real :: Lx +real :: tol ! Get the stderr unit number stderrunit=stderr() @@ -3386,11 +3387,14 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) modulo(grd%lon(i-1,j )-(x-Lx_2),Lx)+(x-Lx_2), & modulo(grd%lon(i ,j )-(x-Lx_2),Lx)+(x-Lx_2) ) - if (x.lt.xlo .or. x.gt.xhi) return + ! The modolo function inside sum_sign_dot_prod leads to a roundoff. + !Adding adding a tolorance to the crude bounds avoids excluding the cell which + !would be correct after roundoff. This is a bit of a hack. + tol=0.1 + if (x.lt.(xlo-tol) .or. x.gt.(xhi+tol)) return + ylo=min( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) yhi=max( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) - - if (y.lt.ylo .or. y.gt.yhi) return if ((grd%lat(i,j).gt.89.999).and. (grd%grid_is_latlon)) then From 5b058b25a6d55cf5ff1884a2715672b75d1740df Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Tue, 29 Nov 2016 11:15:52 -0500 Subject: [PATCH 198/361] Added the posibility for periodic boundary conditions in the x-direction when using grid_is_regular. This is done by adding modulo Lx to the routine which finds the position of an iceberg inside a cell. --- icebergs_framework.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index fe65935..fe57976 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3583,10 +3583,12 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) real :: x1,y1,x2,y2,x3,y3,x4,y4,xx,yy,fac integer :: stderrunit real :: Lx, dx,dy +real :: Delta_x, Lx_2 ! Get the stderr unit number stderrunit=stderr() Lx=grd%Lx + Lx_2=Lx/2 pos_within_cell=.false.; xi=-999.; yj=-999. if (i-1 Date: Thu, 1 Dec 2016 13:06:04 -0500 Subject: [PATCH 199/361] Corrected joined lines - Code would not compile due to syntax errors! --- icebergs.F90 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 5dc31a1..73077eb 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2878,11 +2878,13 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Turn on sampling of trajectories, verbosity, budgets sample_traj=.false. if ( (bergs%traj_sample_hrs>0) .and. (.not. bergs%ignore_traj) ) then - if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_sample_hrs).eq.0) & sample_traj=.true. + if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_sample_hrs).eq.0) & + sample_traj=.true. endif write_traj=.false. if ((bergs%traj_write_hrs>0) .and. (.not. bergs%ignore_traj)) then - if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_write_hrs).eq.0) & write_traj=.true. + if (mod(60*60*24*iday+ 60*60*ihr + 60*imin + isec ,60*60*bergs%traj_write_hrs).eq.0) & + write_traj=.true. endif lverbose=.false. if (bergs%verbose_hrs>0) then @@ -2890,7 +2892,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, endif lbudget=.false. if (bergs%verbose_hrs>0) then - if (mod(24*iday+ihr+(imin/60.),float(bergs%verbose_hrs)).eq.0) lbudget=budget !Added minutes, so that it does not repeat when smaller time steps are used.:q + if (mod(24*iday+ihr+(imin/60.),float(bergs%verbose_hrs)).eq.0) lbudget=budget !Added minutes, so that it does not repeat when smaller time steps are used. endif if (mpp_pe()==mpp_root_pe().and.lverbose) write(*,'(a,3i5,a,3i5,a,i5,f8.3)') & 'diamonds: y,m,d=',iyr, imon, iday,' h,m,s=', ihr, imin, isec, & From ec431c6c53cb54d59490ac9c2b7bfa2d4d770f38 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 8 Dec 2016 13:06:54 -0500 Subject: [PATCH 200/361] Added a flag which forces static_berg to be saved in the restart file. Previously, static_berg was being saved when Static_icebergs was set to true. However, the flag Static_icebergs makes all icebergs static, while static_berg is a property of an individual iceberg, whcih makes it not move. --- icebergs_framework.F90 | 5 ++++- icebergs_io.F90 | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index fe57976..324463b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -261,6 +261,7 @@ module ice_bergs_framework logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move + logical :: save_static_berg_field_in_restart=.False. !If true, then static_berg is saved in restarts logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -416,6 +417,7 @@ subroutine ice_bergs_framework_init(bergs, & logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move +logical :: save_static_berg_field_in_restart=.False. !If true, then static_berg is saved in restarts logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -447,7 +449,7 @@ subroutine ice_bergs_framework_init(bergs, & grid_is_regular,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & const_gamma, Gamma_T_3EQ, ignore_traj, debug_iceberg_with_id,use_updated_rolling_scheme, tip_parameter, read_old_restarts, tau_calving, read_ocean_depth_from_file, melt_cutoff,& - apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt + apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt, save_static_berg_field_in_restart ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -854,6 +856,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%hexagonal_icebergs=hexagonal_icebergs bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs + bergs%save_static_berg_field_in_restart=save_static_berg_field_in_restart bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon diff --git a/icebergs_io.F90 b/icebergs_io.F90 index f3eff4a..823067f 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -241,7 +241,7 @@ subroutine write_restart(bergs) if (bergs%interactive_icebergs_on .or. bergs%iceberg_bonds_on) & id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & longname='halo_berg',units='dimensionless') - if (bergs%static_icebergs) & + if (bergs%save_static_berg_field_in_restart) & id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & longname='static_berg',units='dimensionless') From 6be7dd4551048422e5904cdef1a436c5a3553158 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Mon, 12 Dec 2016 10:34:06 -0500 Subject: [PATCH 201/361] Removing halo_berg from restart_read The variable halo_berg does not need to be read in from restart files since it should always have the value halo_berg=0 when being read in. The option to read in this variable has been removed. --- icebergs_io.F90 | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 823067f..64e7fbb 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -131,7 +131,6 @@ subroutine write_restart(bergs) start_mass, & mass_scaling, & mass_of_bits, & - halo_berg, & static_berg, & heat_density @@ -185,7 +184,6 @@ subroutine write_restart(bergs) allocate(mass_scaling(nbergs)) allocate(mass_of_bits(nbergs)) allocate(heat_density(nbergs)) - allocate(halo_berg(nbergs)) allocate(static_berg(nbergs)) allocate(ine(nbergs)) @@ -238,9 +236,6 @@ subroutine write_restart(bergs) longname='mass of bergy bits',units='kg') id = register_restart_field(bergs_restart,filename,'heat_density',heat_density, & longname='heat density',units='J/kg') - if (bergs%interactive_icebergs_on .or. bergs%iceberg_bonds_on) & - id = register_restart_field(bergs_restart,filename,'halo_berg',halo_berg, & - longname='halo_berg',units='dimensionless') if (bergs%save_static_berg_field_in_restart) & id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & longname='static_berg',units='dimensionless') @@ -262,7 +257,6 @@ subroutine write_restart(bergs) start_lon(i) = this%start_lon; start_lat(i) = this%start_lat start_year(i) = this%start_year; start_day(i) = this%start_day start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling - halo_berg(i) = this%halo_berg static_berg(i) = this%static_berg iceberg_num(i) = this%iceberg_num; mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density @@ -420,7 +414,7 @@ subroutine read_restart_bergs_orig(bergs,Time) integer :: axnid, aynid, uvel_oldid, vvel_oldid, bxnid, bynid integer :: massid, thicknessid, widthid, lengthid integer :: start_lonid, start_latid, start_yearid, iceberg_numid, start_dayid, start_massid -integer :: scaling_id, mass_of_bits_id, heat_density_id, halo_bergid, static_bergid +integer :: scaling_id, mass_of_bits_id, heat_density_id, static_bergid logical :: lres, found_restart, multiPErestart real :: lon0, lon1, lat0, lat1 character(len=33) :: filename, filename_base @@ -496,7 +490,6 @@ subroutine read_restart_bergs_orig(bergs,Time) start_dayid=inq_var(ncid, 'start_day') start_massid=inq_var(ncid, 'start_mass') scaling_id=inq_var(ncid, 'mass_scaling') - halo_bergid=inq_var(ncid, 'halo_berg', unsafe=.true.) static_bergid=inq_var(ncid, 'static_berg', unsafe=.true.) mass_of_bits_id=inq_var(ncid, 'mass_of_bits', unsafe=.true.) heat_density_id=inq_var(ncid, 'heat_density', unsafe=.true.) @@ -557,7 +550,7 @@ subroutine read_restart_bergs_orig(bergs,Time) localberg%start_day=get_double(ncid, start_dayid, k) localberg%start_mass=get_double(ncid, start_massid, k) localberg%mass_scaling=get_double(ncid, scaling_id, k) - localberg%halo_berg=get_real_from_file(ncid, halo_bergid, k, value_if_not_in_file=0.) + localberg%halo_berg=0. localberg%static_berg=get_real_from_file(ncid, static_bergid, k, value_if_not_in_file=0.) localberg%mass_of_bits=get_real_from_file(ncid, mass_of_bits_id, k, value_if_not_in_file=0.) localberg%heat_density=get_real_from_file(ncid, heat_density_id, k, value_if_not_in_file=0.) @@ -734,7 +727,6 @@ subroutine read_restart_bergs(bergs,Time) start_mass, & mass_scaling, & mass_of_bits, & - halo_berg, & static_berg, & heat_density integer, allocatable, dimension(:) :: ine, & @@ -785,7 +777,6 @@ subroutine read_restart_bergs(bergs,Time) allocate(start_mass(nbergs_in_file)) allocate(mass_scaling(nbergs_in_file)) allocate(mass_of_bits(nbergs_in_file)) - allocate(halo_berg(nbergs_in_file)) allocate(static_berg(nbergs_in_file)) allocate(heat_density(nbergs_in_file)) allocate(ine(nbergs_in_file)) @@ -817,7 +808,6 @@ subroutine read_restart_bergs(bergs,Time) call read_unlimited_axis(filename,'ine',ine,domain=grd%domain) call read_unlimited_axis(filename,'jne',jne,domain=grd%domain) call read_unlimited_axis(filename,'start_year',start_year,domain=grd%domain) - call read_real_vector(filename,'halo_berg',halo_berg,grd%domain,value_if_not_in_file=0.) call read_int_vector(filename,'iceberg_num',iceberg_num,grd%domain,value_if_not_in_file=-1) call read_real_vector(filename,'static_berg',static_berg,grd%domain,value_if_not_in_file=0.) endif @@ -904,7 +894,7 @@ subroutine read_restart_bergs(bergs,Time) localberg%start_mass=start_mass(k) localberg%mass_scaling=mass_scaling(k) localberg%mass_of_bits=mass_of_bits(k) - localberg%halo_berg=halo_berg(k) + localberg%halo_berg=0. localberg%static_berg=static_berg(k) localberg%heat_density=heat_density(k) localberg%first_bond=>null() @@ -952,7 +942,6 @@ subroutine read_restart_bergs(bergs,Time) start_mass, & mass_scaling, & mass_of_bits, & - halo_berg, & static_berg, & heat_density ) deallocate( & From b511e5ba8483beccf4ec9d4d58d8da9a01ab1fb5 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Dec 2016 15:46:30 -0500 Subject: [PATCH 202/361] Applying modulo and point_within_xi_yj_bounds When periodic boundary conditions are used, the modulo procedure is used a number of times. One consequence is that for large domains, applying modulo rounds off the iceberg position. This results in the iceberg position being found to be in a certain cell when is_point_in_cell is used, but not found to be in cell when considering xi, yi. This bug was fixed by A) Being more careful when looking at the inconsistancy between is_point_in_cell() and pos_within_cell() B) Introducing code which only applies modulo (and hense roundoff) when Lx>0. (This probably should have been two (or more) commits) A) Addressing inconsistancy between is_point_in_cell and pos_within_cell: 1) A rountine subroutine is_point_within_xi_yj_bounds is been written which checks whether the calculated xi, yj have 0<=xi<1 and 0<=yi<1. If so, this means that the iceberg is in the cell according to its local variables. This subroutine has been included so that we can remove if statements in other places in the code, to avoid using the wrong inequalities or strict inequalities. 1b) A few inequalities within the code have been replaced by is_point_within_xi_yj_bounds. This includes an inequality within pos_within_cell (inside the special case for the north pole), which was previously using a symetric inequality (inconsistant with in_point_in_cell). 2) Inside the pos_within_cell routine, the logic inside the check for consistancy was reversed. 2) Inside the pos_within_cell routine, the error message assosiated with an inconsistany was changed to a FATAL error, and is appied whenever debug is true. Some explanation output have also been added. B) Addressing modulo arithemetic 1) A function has been written called apply_modulo_around_point(x, y, Lx). This function returns modulo(x-(y-Lx_2),Lx)+(y-Lx_2) if Lx>0 , and x otherwise. (ie: gives the modula value of x within the interval [y-(Lx/2) y+(Lx/2)] , modulo Lx. 2) This function has been used to replace the modula arithemtic in almost all places in the code. 3) There is one remaining place where modlua arithmetic is used. This will be changed in a seperate commit to avoid making a mistake (since it is a little bit complicated). For this, we include an "if Lx>0", so that the code will run with Lx<0. 4) When grid_is_lat_lon =False, and Lx=360., Lx is set to -1, so that it will not be periodic. (Previously it was set to 1E14, which was assumed to be larger than the domain. --- icebergs.F90 | 8 +- icebergs_framework.F90 | 167 +++++++++++++++++++++++------------------ 2 files changed, 101 insertions(+), 74 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 73077eb..9b07a90 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -38,6 +38,7 @@ module ice_bergs use ice_bergs_framework, only: fix_restart_dates, offset_berg_dates use ice_bergs_framework, only: orig_read ! Remove when backward compatibility no longer needed use ice_bergs_framework, only: monitor_a_berg +use ice_bergs_framework, only: is_point_within_xi_yj_bounds use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving @@ -4579,6 +4580,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun integer :: icount, i0, j0, inm, jnm real :: xi0, yj0, lon0, lat0 integer :: stderrunit +logical :: point_in_cell_using_xi_yj ! Get the stderr unit number stderrunit = stderr() @@ -4596,7 +4598,9 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (debug) then !Sanity check lret, xi and yj lret=is_point_in_cell(grd, lon, lat, i, j) - if (xi<0. .or. xi>1. .or. yj<0. .or. yj>1.) then + point_in_cell_using_xi_yj=is_point_within_xi_yj_bounds(xi,yj) + if (.not. point_in_cell_using_xi_yj) then + if (lret) then write(stderrunit,*) 'diamonds, adjust: WARNING!!! lret=T but |xi,yj|>1',mpp_pe() write(stderrunit,*) 'diamonds, adjust: xi=',xi,' lon=',lon @@ -4610,6 +4614,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj,explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' + call error_mesg('adjust index, ','Iceberg is_point_in_cell=True but xi, yi are out of cell',FATAL) error=.true.; return endif else @@ -4626,6 +4631,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun lret=pos_within_cell(grd, lon, lat, i, j, xi, yj, explain=.true.) write(stderrunit,*) 'diamonds, adjust: fn pos_within_cell=',lret write(0,*) 'This should never happen!' + call error_mesg('adjust index, ','Iceberg is_point_in_cell=False but xi, yi are out of cell',FATAL) error=.true.; return endif endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 324463b..41ca386 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -73,6 +73,7 @@ module ice_bergs_framework public move_berg_between_cells public find_individual_iceberg public monitor_a_berg +public is_point_within_xi_yj_bounds type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -688,33 +689,33 @@ subroutine ice_bergs_framework_init(bergs, & if (mpp_pe().eq.mpp_root_pe()) then call error_mesg('diamonds, framework', 'Since the lat/lon grid is off, the x-direction is being set as non-periodic. Set Lx not equal to 360 override.', WARNING) endif - Lx=1E14 + Lx=-1. endif + !The fix to reproduce across PE layout change, from AJA - j=grd%jsc; do i=grd%isc+1,grd%ied - minl=grd%lon(i-1,j)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl - enddo - j=grd%jsc; do i=grd%isc-1,grd%isd,-1 - minl=grd%lon(i+1,j)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl - enddo - do j=grd%jsc+1,grd%jed; do i=grd%isd,grd%ied + if (Lx>0.) then + j=grd%jsc; do i=grd%isc+1,grd%ied + minl=grd%lon(i-1,j)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + enddo + j=grd%jsc; do i=grd%isc-1,grd%isd,-1 + minl=grd%lon(i+1,j)-(Lx/2.) + if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & + grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + enddo + do j=grd%jsc+1,grd%jed; do i=grd%isd,grd%ied minl=grd%lon(i,j-1)-(Lx/2.) if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl - enddo; enddo - do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied + enddo; enddo + do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied minl=grd%lon(i,j+1)-(Lx/2.) if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl - enddo; enddo - - - + enddo; enddo + endif @@ -3197,7 +3198,7 @@ real function dcost(x1, y1, x2, y2,Lx) ! Local variables real :: x1m - x1m=modulo(x1-(x2-(Lx/2.)),Lx)+(x2-(Lx/2.)) + x1m=apply_modulo_around_point(x1,x2,Lx) ! dcost=(x2-x1)**2+(y2-y1)**2 dcost=(x2-x1m)**2+(y2-y1)**2 end function dcost @@ -3360,7 +3361,6 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) logical, intent(in), optional :: explain ! Local variables real :: xlo, xhi, ylo, yhi -real :: Lx_2 integer :: stderrunit real :: Lx real :: tol @@ -3368,7 +3368,6 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) ! Get the stderr unit number stderrunit=stderr() Lx=grd%Lx - Lx_2=Lx/2. ! Safety check index bounds if (i-1.lt.grd%isd.or.i.gt.grd%ied.or.j-1.lt.grd%jsd.or.j.gt.grd%jed) then @@ -3381,14 +3380,14 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) is_point_in_cell=.false. ! Test crude bounds - xlo=min( modulo(grd%lon(i-1,j-1)-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i ,j-1)-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i-1,j )-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i ,j )-(x-Lx_2),Lx)+(x-Lx_2) ) - xhi=max( modulo(grd%lon(i-1,j-1)-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i ,j-1)-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i-1,j )-(x-Lx_2),Lx)+(x-Lx_2), & - modulo(grd%lon(i ,j )-(x-Lx_2),Lx)+(x-Lx_2) ) + xlo=min( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & + apply_modulo_around_point(grd%lon(i ,j-1) ,x, Lx), & + apply_modulo_around_point(grd%lon(i-1,j ) ,x, Lx), & + apply_modulo_around_point(grd%lon(i ,j ) ,x, Lx) ) + xhi=max( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & + apply_modulo_around_point(grd%lon(i ,j-1) ,x, Lx), & + apply_modulo_around_point(grd%lon(i-1,j ) ,x, Lx), & + apply_modulo_around_point(grd%lon(i ,j ) ,x, Lx) ) ! The modolo function inside sum_sign_dot_prod leads to a roundoff. !Adding adding a tolorance to the crude bounds avoids excluding the cell which @@ -3449,26 +3448,17 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp real :: l0,l1,l2,l3 real :: xx0,xx1,xx2,xx3 integer :: stderrunit -real :: Lx_2 ! Get the stderr unit number stderrunit=stderr() - Lx_2=Lx/2. sum_sign_dot_prod4=.false. - if (Lx .ge. 1E14 ) then - xx=x - xx0=x0 - xx1=x1 - xx2=x2 - xx3=x3 - else - xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2 of x0 - xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2of xx - xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2of xx - xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2of xx - xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2of xx - endif + xx= apply_modulo_around_point(x,x0,Lx) + xx0= apply_modulo_around_point(x0,x0,Lx) + xx1= apply_modulo_around_point(x1,x0,Lx) + xx2= apply_modulo_around_point(x2,x0,Lx) + xx3= apply_modulo_around_point(x3,x0,Lx) + l0=(xx-xx0)*(y1-y0)-(y-y0)*(xx1-xx0) l1=(xx-xx1)*(y2-y1)-(y-y1)*(xx2-xx1) @@ -3517,28 +3507,18 @@ logical function sum_sign_dot_prod5(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x, y real :: l0,l1,l2,l3,l4 real :: xx0,xx1,xx2,xx3,xx4 integer :: stderrunit -real :: Lx_2 ! Get the stderr unit number stderrunit=stderr() - Lx_2=Lx/2. sum_sign_dot_prod5=.false. - if (Lx .ge. 1E14 ) then - xx=x - xx0=x0 - xx1=x1 - xx2=x2 - xx3=x3 - xx4=x4 - else - xx=modulo(x-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x to within Lx_2of x0 - xx0=modulo(x0-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x0 to within Lx_2 of xx - xx1=modulo(x1-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x1 to within Lx_2 of xx - xx2=modulo(x2-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x2 to within Lx_2 of xx - xx3=modulo(x3-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x3 to within Lx_2 of xx - xx4=modulo(x4-(x0-Lx_2),Lx)+(x0-Lx_2) ! Reference x4 to within Lx_2 of xx - endif + xx= apply_modulo_around_point(x,x0,Lx) + xx0= apply_modulo_around_point(x0,x0,Lx) + xx1= apply_modulo_around_point(x1,x0,Lx) + xx2= apply_modulo_around_point(x2,x0,Lx) + xx3= apply_modulo_around_point(x3,x0,Lx) + xx4= apply_modulo_around_point(x4,x0,Lx) + l0=(xx-xx0)*(y1-y0)-(y-y0)*(xx1-xx0) l1=(xx-xx1)*(y2-y1)-(y-y1)*(xx2-xx1) @@ -3586,12 +3566,12 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) real :: x1,y1,x2,y2,x3,y3,x4,y4,xx,yy,fac integer :: stderrunit real :: Lx, dx,dy -real :: Delta_x, Lx_2 +real :: Delta_x +logical :: is_point_in_cell_using_xi_yj ! Get the stderr unit number stderrunit=stderr() Lx=grd%Lx - Lx_2=Lx/2 pos_within_cell=.false.; xi=-999.; yj=-999. if (i-10.5.or.abs(yj-0.5)>0.5) then + is_point_in_cell_using_xi_yj=is_point_within_xi_yj_bounds(xi,yj) + if (.not. is_point_in_cell_using_xi_yj) then ! If the non-dimensional position is found to be outside (possible because the ! projection of the spherical quad and the quad in the tangent plane are different) ! then scale non-dimensional coordinates to be consistent with is_point_in_cell() @@ -3683,17 +3666,26 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) ! Check for consistency with test for whether point is inside a polygon pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=explain) - if (xi.ge.0. .and. xi.le.1. .and. yj.ge.0. .and. yj.le.1.) then + is_point_in_cell_using_xi_yj=is_point_within_xi_yj_bounds(xi,yj) + if (is_point_in_cell_using_xi_yj) then ! Based on coordinate, the point is out of cell - if (pos_within_cell .and. verbose) then + if (.not. pos_within_cell) then ! Based on is_point_in_cell() the point is within cell so we have an inconsistency - if (debug) call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is in cell BUT is_point_in_cell disagrees!', WARNING) + if (debug) then + write(stderrunit,'(a,1p6e12.4)') 'values of xi, yj ',xi, yj + pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=.True.) + call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is False BUT is_point_in_cell disagrees!', FATAL) + endif endif else ! Based on coordinate, the point is within cell - if (.not. pos_within_cell .and. verbose) then + if (pos_within_cell) then ! Based on is_point_in_cell() the point is out of cell so we have an inconsistency - if (debug) call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is in cell BUT is_point_in_cell disagrees!', WARNING) + if (debug) then + write(stderrunit,'(a,1p6e12.4)') 'values of xi, yj ',xi, yj + pos_within_cell=is_point_in_cell(grd, x, y, i, j,explain=.True.) + call error_mesg('diamonds, pos_within_cell', 'pos_within_cell is True BUT is_point_in_cell disagrees!', FATAL) + endif endif endif @@ -3708,11 +3700,9 @@ subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) real :: alpha, beta, gamma, delta, epsilon, kappa, a, b, c, d, dx, dy, yy1, yy2 logical :: expl=.false. integer :: stderrunit - real :: Lx_2 ! Get the stderr unit number stderrunit=stderr() - Lx_2=Lx/2. expl=.false. if (present(explain)) then @@ -3729,7 +3719,8 @@ subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) if (expl) write(stderrunit,'(a,1p6e12.4)') 'calc_xiyj: coeffs delta,epsilon,kappa',alpha,beta,gamma,delta,epsilon,kappa a=(kappa*beta-gamma*epsilon) - dx=modulo(x-(x1-Lx_2),Lx)+(x1-Lx_2)-x1 + dx= apply_modulo_around_point(x,x1,Lx)-x1 + dy=y-y1 b=(delta*beta-alpha*epsilon)-(kappa*dx-gamma*dy) c=(alpha*dy-delta*dx) @@ -3790,6 +3781,36 @@ end function pos_within_cell ! ############################################################################## +real function is_point_within_xi_yj_bounds(xi,yj) +! Arguments +real, intent(in) :: xi, yj +! Local variables +!Includes South and East boundaries, and excludes North and West (double check this is the way that is needed) + is_point_within_xi_yj_bounds=.False. + if ((xi .ge. 0 ) .and. (xi .lt. 1)) then + if ((yj .ge. 0 ) .and. (yj .lt. 1)) then + is_point_within_xi_yj_bounds=.True. + endif + endif +end function is_point_within_xi_yj_bounds + +real function apply_modulo_around_point(x,y,Lx) +! Arguments +real, intent(in) :: x ,y ,Lx +!Local_variables +real ::Lx_2 +!Gives the modula value of x in an interval [y-(Lx/2) y+(Lx/2)] , modulo Lx +!If Lx<=0, then it returns x without applying modulo arithmetic. + + if (Lx>0.) then + Lx_2=Lx/2. + apply_modulo_around_point=modulo(x-(y-Lx_2),Lx)+(y-Lx_2) + else + apply_modulo_around_point=x + endif + +end function apply_modulo_around_point + subroutine check_position(grd, berg, label, il, jl) ! Arguments type(icebergs_gridded), pointer :: grd From d73e935ac8a1a44c23a0efa5d4a7c969763e8f4a Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 14 Dec 2016 16:24:43 -0500 Subject: [PATCH 203/361] Refactoring a section of the code which uses modulo. A small section of code has been refactored to use the apply_modulo_around_point function. The code should do exactly what it did before, but is now easier to read. --- icebergs_framework.F90 | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 41ca386..d034352 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -455,7 +455,7 @@ subroutine ice_bergs_framework_init(bergs, & ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np type(icebergs_gridded), pointer :: grd -real :: minl, big_number +real :: lon_mod, big_number logical :: lerr integer :: stdlogunit, stderrunit real :: Total_mass !Added by Alon @@ -696,24 +696,24 @@ subroutine ice_bergs_framework_init(bergs, & !The fix to reproduce across PE layout change, from AJA if (Lx>0.) then j=grd%jsc; do i=grd%isc+1,grd%ied - minl=grd%lon(i-1,j)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + lon_mod = apply_modulo_around_point(grd%lon(i,j),grd%lon(i-1,j),Lx) + if (abs(grd%lon(i,j)-lon_mod)>(Lx/2.)) & + grd%lon(i,j)= lon_mod enddo j=grd%jsc; do i=grd%isc-1,grd%isd,-1 - minl=grd%lon(i+1,j)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + lon_mod = apply_modulo_around_point(grd%lon(i,j),grd%lon(i+1,j) ,Lx) + if (abs(grd%lon(i,j)- lon_mod )>(Lx/2.)) & + grd%lon(i,j)= lon_mod enddo do j=grd%jsc+1,grd%jed; do i=grd%isd,grd%ied - minl=grd%lon(i,j-1)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + lon_mod = apply_modulo_around_point(grd%lon(i,j),grd%lon(i,j-1) ,Lx) + if (abs(grd%lon(i,j)-(lon_mod ))>(Lx/2.)) & + grd%lon(i,j)= lon_mod enddo; enddo do j=grd%jsc-1,grd%jsd,-1; do i=grd%isd,grd%ied - minl=grd%lon(i,j+1)-(Lx/2.) - if (abs(grd%lon(i,j)-(modulo(grd%lon(i,j)-minl,Lx)+minl))>(Lx/2.)) & - grd%lon(i,j)=modulo(grd%lon(i,j)-minl,Lx)+minl + lon_mod = apply_modulo_around_point(grd%lon(i,j),grd%lon(i,j+1) ,Lx) + if (abs(grd%lon(i,j)- lon_mod )>(Lx/2.)) & + grd%lon(i,j)= lon_mod enddo; enddo endif From fbb0feb58441e7c9d54915e4965b35e2303429b9 Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Thu, 15 Dec 2016 10:20:02 -0500 Subject: [PATCH 204/361] Removed the flag save_static_berg_field_in_restart The flag save_static_berg_field_in_restart has been removed since it was frustrating to have to remember to include this flag every time in order to get a useable restart file. Instead, the field static_berg is included in the restart file whenever there exists an iceberg which has static_berg > 0. This means that in Production runs where this field is not being used, the field will not be saved. --- icebergs_framework.F90 | 5 +---- icebergs_io.F90 | 14 +++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 324463b..05bfb31 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -261,7 +261,6 @@ module ice_bergs_framework logical :: allow_bergs_to_roll=.True. !Allows icebergs to roll over when rolling conditions are met logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move - logical :: save_static_berg_field_in_restart=.False. !If true, then static_berg is saved in restarts logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -417,7 +416,6 @@ subroutine ice_bergs_framework_init(bergs, & logical :: hexagonal_icebergs=.False. !True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) logical :: ignore_missing_restart_bergs=.False. !True Allows the model to ignorm icebergs missing in the restart. logical :: Static_icebergs=.False. !True= icebergs do no move -logical :: save_static_berg_field_in_restart=.False. !If true, then static_berg is saved in restarts logical :: only_interactive_forces=.False. !Icebergs only feel interactive forces, and not ocean, wind... logical :: halo_debugging=.False. !Use for debugging halos (remove when its working) logical :: save_short_traj=.True. !True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc @@ -449,7 +447,7 @@ subroutine ice_bergs_framework_init(bergs, & grid_is_regular,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & const_gamma, Gamma_T_3EQ, ignore_traj, debug_iceberg_with_id,use_updated_rolling_scheme, tip_parameter, read_old_restarts, tau_calving, read_ocean_depth_from_file, melt_cutoff,& - apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt, save_static_berg_field_in_restart + apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -856,7 +854,6 @@ subroutine ice_bergs_framework_init(bergs, & bergs%hexagonal_icebergs=hexagonal_icebergs bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs bergs%Static_icebergs=Static_icebergs - bergs%save_static_berg_field_in_restart=save_static_berg_field_in_restart bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon diff --git a/icebergs_io.F90 b/icebergs_io.F90 index 64e7fbb..ef3b82d 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -111,6 +111,7 @@ subroutine write_restart(bergs) type(restart_file_type) :: bergs_restart type(restart_file_type) :: bergs_bond_restart integer :: nbergs, nbonds +integer :: n_static_bergs logical :: check_bond_quality type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & @@ -236,7 +237,18 @@ subroutine write_restart(bergs) longname='mass of bergy bits',units='kg') id = register_restart_field(bergs_restart,filename,'heat_density',heat_density, & longname='heat density',units='J/kg') - if (bergs%save_static_berg_field_in_restart) & + + !Checking if any icebergs are static in order to decide whether to save static_berg + n_static_bergs = 0 + do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + n_static_bergs=n_static_bergs+this%static_berg + this=>this%next + enddo + enddo ; enddo + call mpp_sum(n_static_bergs) + if (n_static_bergs .gt. 0) & id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & longname='static_berg',units='dimensionless') From f789d232d393c33005c459355f8080baf19b7764 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 20 Dec 2016 11:51:48 -0500 Subject: [PATCH 205/361] Changed data type for is_point_within_xi_yj_bounds() - Function is_point_within_xi_yj_bounds() was cast as a real but should have been/is now a logical. --- icebergs_framework.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 116551e..fcc4949 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -3778,7 +3778,7 @@ end function pos_within_cell ! ############################################################################## -real function is_point_within_xi_yj_bounds(xi,yj) +logical function is_point_within_xi_yj_bounds(xi,yj) ! Arguments real, intent(in) :: xi, yj ! Local variables From a92391b8e380d52db6b4db4c925c62f5992b2c8c Mon Sep 17 00:00:00 2001 From: Robert Hallberg Date: Tue, 20 Dec 2016 15:22:55 -0500 Subject: [PATCH 206/361] +Allow icebergs_run(sst) to be in Celsius or Kelvin Added code to allow the sst argument to icebergs_run to be in either degrees Celsius or degrees Kelvin, using whether the maximum value in an array is less than or greater than 120 degrees as a test. All answers are bitwise identical to the previous behavior when the sst input array is in Kelvin, and there are no interface changes. (Pretty cool, huh!) --- icebergs.F90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9b07a90..86d987c 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -2820,7 +2820,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off -real :: mask +real :: mask, max_SST real, dimension(:,:), allocatable :: uC_tmp, vC_tmp, uA_tmp, vA_tmp integer :: vel_stagger, str_stagger real, dimension(:,:), allocatable :: iCount @@ -3036,7 +3036,12 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, endif call mpp_update_domains(grd%ssh, grd%domain) - grd%sst(grd%isc:grd%iec,grd%jsc:grd%jec)=sst(:,:)-273.15 ! Note convert from Kelvin to Celsius + max_SST = maxval(sst(:,:)) + if (max_SST > 120.0) then ! The input sst is in degrees Kelvin, otherwise the water would be boiling. + grd%sst(grd%isc:grd%iec,grd%jsc:grd%jec) = sst(:,:)-273.15 ! Note convert from Kelvin to Celsius + else ! The input sst is already in degrees Celsius. + grd%sst(grd%isc:grd%iec,grd%jsc:grd%jec) = sst(:,:) ! Note no conversion necessary. + endif call mpp_update_domains(grd%sst, grd%domain) ! Copy sea-ice concentration and thickness (resides on A grid) grd%cn(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=cn(:,:) From 4dcc6d159f5b6de6e882d2533f2b6be3d2d1c1ad Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 21 Dec 2016 17:34:42 -0500 Subject: [PATCH 207/361] Added check_for_duplicates_in_parallel() - New function check_for_duplicates_in_parallel() checks for duplicate icebergs on and between PEs. - The above calls check_for_duplicate_ids_in_list() which has unit tests which are always called during initialization. --- icebergs.F90 | 2 + icebergs_framework.F90 | 128 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/icebergs.F90 b/icebergs.F90 index 9b07a90..e21108d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -39,6 +39,7 @@ module ice_bergs use ice_bergs_framework, only: orig_read ! Remove when backward compatibility no longer needed use ice_bergs_framework, only: monitor_a_berg use ice_bergs_framework, only: is_point_within_xi_yj_bounds +use ice_bergs_framework, only: test_check_for_duplicate_ids_in_list use ice_bergs_io, only: ice_bergs_io_init,write_restart,write_trajectory use ice_bergs_io, only: read_restart_bergs,read_restart_bergs_orig,read_restart_calving @@ -151,6 +152,7 @@ subroutine unit_testing(bergs) call hexagon_test() call point_in_triangle_test() call basal_melt_test(bergs) +call test_check_for_duplicate_ids_in_list() end subroutine unit_testing diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index fcc4949..957846b 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -49,7 +49,6 @@ module ice_bergs_framework public ignore_ij_restart, use_slow_find,generate_test_icebergs,old_bug_rotated_weights,budget public orig_read, force_all_pes_traj - !Public types public icebergs_gridded, xyt, iceberg, icebergs, buffer, bond @@ -74,6 +73,8 @@ module ice_bergs_framework public find_individual_iceberg public monitor_a_berg public is_point_within_xi_yj_bounds +public test_check_for_duplicate_ids_in_list +public check_for_duplicates_in_parallel type :: icebergs_gridded type(domain2D), pointer :: domain ! MPP domain @@ -4366,4 +4367,129 @@ end function unitTests ! ############################################################################## +!> Check for duplicates of icebergs on and across processors and issue an error +!! if any are detected +subroutine check_for_duplicates_in_parallel(bergs) + type(icebergs), pointer :: bergs !< Icebergs + ! Local variables + type(icebergs_gridded), pointer :: grd + type(iceberg), pointer :: this + integer :: stderrunit, i, j, k, nbergs, nbergs_total + integer, dimension(:), allocatable :: ids ! List of ids of all bergs on this processor + + stderrunit=stderr() + grd=>bergs%grd + nbergs = count_bergs(bergs) + nbergs_total = nbergs + call mpp_sum(nbergs_total) ! Total number of bergs + if (nbergs_total==0) return ! Skip the rest of the test + + k = 0 + if (nbergs>0) then + allocate(ids(nbergs)) + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + this=>bergs%list(i,j)%first + do while (associated(this)) + k = k + 1 + ids(k) = this%iceberg_num + this=>this%next + enddo + enddo ; enddo + endif + if (k /= nbergs) then + write(stderrunit,*) 'counted bergs=',k,'count_bergs()=',nbergs + call error_mesg('diamonds, check_for_duplicates:', 'Mismatch between concatenation of lists and count_bergs()!', FATAL) + endif + k = check_for_duplicate_ids_in_list(nbergs, ids, verbose=.true.) + if (k /= 0) call error_mesg('diamonds, check_for_duplicates:', 'Duplicate berg detected across PEs!', FATAL) + if (nbergs>0) deallocate(ids) +end subroutine check_for_duplicates_in_parallel + +!> Returns error count of duplicates of integer values in a distributed list +integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) + integer, intent(in) :: nbergs !< Length of ids + integer, dimension(:), intent(inout) :: ids !< List of ids + logical, intent(in) :: verbose !< True if messages should be written + integer :: stderrunit, i, j, k, l, nbergs_total, ii + + stderrunit=stderr() + nbergs_total = nbergs + call mpp_sum(nbergs_total) ! Total number of bergs + ! Sort the list "ids" (largest first) + do j = 1, nbergs-1 + do i = j+1, nbergs + if (ids(j) < ids(i)) then + ! Swap + k = ids(i) + ids(i) = ids(j) + ids(j) = k + endif + enddo + enddo + ! Check for duplicates on processor + check_for_duplicate_ids_in_list = 0 + do k = 1, nbergs-1 + if (ids(k) == ids(k+1)) then + if (verbose) write(stderrunit,*) 'Duplicated berg on PE with id=',ids(k),'pe=',mpp_pe() + check_for_duplicate_ids_in_list = check_for_duplicate_ids_in_list + 1 + endif + enddo + ! Check for duplicates across processor + j = 1 ! Pointer to first berg in my list + do k = 1, nbergs_total + ! Set i to first id in my list + if (j <= nbergs) then + i = ids(j) + else + i = 0 + endif + l = i + call mpp_max(l) + if (i == l) then + ii = 1 ! This berg is mine + j = j + 1 + else + ii = 0 ! This berg is not mine + endif + call mpp_sum(ii) + if (ii > 1) then + if (verbose) write(stderrunit,*) 'Duplicated berg across PEs with id=',i,l,' seen',ii,' times pe=',mpp_pe(),k + check_for_duplicate_ids_in_list = check_for_duplicate_ids_in_list + 1 + endif + enddo + +end function check_for_duplicate_ids_in_list + +subroutine test_check_for_duplicate_ids_in_list() + integer :: k + integer, dimension(:), allocatable :: ids + integer :: error_count + + allocate(ids(5)) + do k = 1,5 + ids(k) = k + 5*mpp_pe() + enddo + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.false.) + call mpp_sum(error_count) + if (error_count /= 0) then + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.true.) + call error_mesg('diamonds, test_check_for_duplicate_ids_in_list:', 'Unit test for clean list failed!', FATAL) + endif + if (mpp_pe() == mpp_root_pe()) ids(5) = ids(4) + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.false.) + call mpp_sum(error_count) + if (error_count == 0) then + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.true.) + call error_mesg('diamonds, test_check_for_duplicate_ids_in_list:', 'Unit test for dirty list failed!', FATAL) + endif + if (mpp_pe() == mpp_root_pe()) ids(5) = 7 + 5*mpp_pe() + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.false.) + call mpp_sum(error_count) + if (error_count == 0) then + error_count = check_for_duplicate_ids_in_list(5, ids, verbose=.true.) + call error_mesg('diamonds, test_check_for_duplicate_ids_in_list:', 'Unit test for a really dirty list failed!', FATAL) + endif + deallocate(ids) +end subroutine test_check_for_duplicate_ids_in_list + end module From 7be78bfc82358b0bf86f169af493741fcf4a8d2c Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 21 Dec 2016 17:37:08 -0500 Subject: [PATCH 208/361] Replaced restart sanity checks with check_for_duplicates_in_parallel() - The sanity checks made after reading a restart were only correct for i/o layouts of 1,1 or 0,0. These have been removed. - Note that we don't have equivalent tests for arbitrary layouts. - Call check_for_duplicates_in_parallel() always after reading a restart. - Closes #47 --- icebergs_io.F90 | 133 ++++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 78 deletions(-) diff --git a/icebergs_io.F90 b/icebergs_io.F90 index ef3b82d..b8bee75 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -36,6 +36,7 @@ module ice_bergs_io use ice_bergs_framework, only: verbose, really_debug, debug, restart_input_dir,make_calving_reproduce use ice_bergs_framework, only: ignore_ij_restart, use_slow_find,generate_test_icebergs,print_berg use ice_bergs_framework, only: force_all_pes_traj +use ice_bergs_framework, only: check_for_duplicates_in_parallel implicit none ; private @@ -845,39 +846,10 @@ subroutine read_restart_bergs(bergs,Time) else ! i,j are not available from the file so we search the grid to find out if we reside on this PE if (use_slow_find) then lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - else - lres=find_cell_by_search(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - endif - endif - ! The next few lines are a check to see whether the icebergs are all found. - - ! The next few lines are a check to see whether the icebergs are all found. - pos_is_good=0.0 - if (lres) then - pos_is_good=1.0 - endif - pos_is_good_all_pe=pos_is_good - call mpp_sum(pos_is_good_all_pe) - !Check to see if any iceberg in the restart file was not found - if (pos_is_good_all_pe .lt. 0.5) then - if (bergs%ignore_missing_restart_bergs) then - if (mpp_pe().eq.mpp_root_pe()) then - print * , 'Iceberg not located: ', lon(k),lat(k), iceberg_num(k) - call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', WARNING) - endif - else - call error_mesg('diamonds, read_restart_bergs', 'Iceberg positions was not found', FATAL) - endif - - endif - !Check to see if any iceberg was found more than once. - if (pos_is_good_all_pe .gt. 1.5) then - if (mpp_pe().eq.mpp_root_pe()) then - print * , 'Iceberg was found more than once: ', lon(k),lat(k), iceberg_num(k) - call error_mesg('diamonds, read_restart_bergs', 'Iceberg copied twice', FATAL) - endif - endif - + else + lres=find_cell_by_search(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + endif + endif if (really_debug) then write(stderrunit,'(a,i8,a,2f9.4,a,i8)') 'diamonds, read_restart_bergs: berg ',k,' is at ',localberg%lon,localberg%lat,& & ' on PE ',mpp_pe() @@ -935,55 +907,60 @@ subroutine read_restart_bergs(bergs,Time) enddo if(nbergs_in_file > 0) then - deallocate( & - lon, & - lat, & - uvel, & - vvel, & - mass, & - axn, & - ayn, & - bxn, & - byn, & - thickness, & - width, & - length, & - start_lon, & - start_lat, & - start_day, & - start_mass, & - mass_scaling, & - mass_of_bits, & - static_berg, & - heat_density ) - deallocate( & - ine, & - jne, & - iceberg_num, & - start_year ) - - !Checking the total number of icebergs read from the restart file. - nbergs_read=count_bergs(bergs) - call mpp_sum(nbergs_read) - if (mpp_pe().eq.mpp_root_pe()) then - write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of Icebergs in restart file=',nbergs_in_file,' Number of Icebergs read=', nbergs_read - if (nbergs_read .gt. nbergs_in_file) then - call error_mesg('diamonds, read_restart_bergs', 'More icebergs read than exist in restart file.', FATAL) - elseif (nbergs_read .lt. nbergs_in_file) then - if (bergs%ignore_missing_restart_bergs) then - call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found (ignore_missing flag is on)', WARNING) - else - call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found', FATAL) - endif - elseif (nbergs_read .eq. nbergs_in_file) then - write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of icebergs read (#',nbergs_read,') matches the number of icebergs in the file' - endif - endif + deallocate( & + lon, & + lat, & + uvel, & + vvel, & + mass, & + axn, & + ayn, & + bxn, & + byn, & + thickness, & + width, & + length, & + start_lon, & + start_lat, & + start_day, & + start_mass, & + mass_scaling, & + mass_of_bits, & + static_berg, & + heat_density ) + deallocate( & + ine, & + jne, & + iceberg_num, & + start_year ) + + ! This block only works for IO_LAYOUT=1,1 or 0,0 but not for arbitrary layouts. + ! I'm commenting this out until we find a way to implement the same sorts of checks + ! that work for all i/o layouts. -AJA + !Checking the total number of icebergs read from the restart file. + !nbergs_read=count_bergs(bergs) + !call mpp_sum(nbergs_read) + !if (mpp_pe().eq.mpp_root_pe()) then + ! write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of Icebergs in restart file=',nbergs_in_file,' Number of Icebergs read=', nbergs_read + ! if (nbergs_read .gt. nbergs_in_file) then + ! call error_mesg('diamonds, read_restart_bergs', 'More icebergs read than exist in restart file.', FATAL) + ! elseif (nbergs_read .lt. nbergs_in_file) then + ! if (bergs%ignore_missing_restart_bergs) then + ! call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found (ignore_missing flag is on)', WARNING) + ! else + ! call error_mesg('diamonds, read_restart_bergs', 'Some Icebergs from restart file were not found', FATAL) + ! endif + ! elseif (nbergs_read .eq. nbergs_in_file) then + ! write(*,'(a,i8,a,i8,a)') 'diamonds, read_restart_bergs: Number of icebergs read (#',nbergs_read,') matches the number of icebergs in the file' + ! endif + !endif elseif(.not. found_restart .and. bergs%nbergs_start==0 .and. generate_test_icebergs) then - call generate_bergs(bergs,Time) + call generate_bergs(bergs,Time) endif + call check_for_duplicates_in_parallel(bergs) + bergs%floating_mass_start=sum_mass(bergs) call mpp_sum( bergs%floating_mass_start ) bergs%icebergs_mass_start=sum_mass(bergs,justbergs=.true.) From 6009017c248745f5fb4dfb5a71b39d2fecb14724 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Wed, 18 Jan 2017 11:29:14 -0500 Subject: [PATCH 209/361] Fix for when iceberg ids are negative - check_for_duplicates_in_parallel() was incorrectly detecting duplicates when an iceberg has a negative id (iceberg_num). We were assuming all ids were positive and using '0' as a nonexistent id. We now find the lowest id and subtract 1 from it to create a nonexistent id. - Fixes restart problems in CM4 --- icebergs_framework.F90 | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 957846b..61d29cc 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -4410,11 +4410,22 @@ integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) integer, intent(in) :: nbergs !< Length of ids integer, dimension(:), intent(inout) :: ids !< List of ids logical, intent(in) :: verbose !< True if messages should be written - integer :: stderrunit, i, j, k, l, nbergs_total, ii + integer :: stderrunit, i, j, k, l, nbergs_total, ii, lowest_id, nonexistent_id + logical :: have_berg stderrunit=stderr() nbergs_total = nbergs call mpp_sum(nbergs_total) ! Total number of bergs + + ! Establish lowest id or 0 across all PEs + lowest_id = 0 + if (nbergs>0) lowest_id = minval(ids) + call mpp_min(lowest_id) + i = lowest_id + nonexistent_id = lowest_id - 1 + if (nonexistent_id >= lowest_id) then + write(stderrunit,*) 'Underflow in iceberg ids!',nonexistent_id,lowest_id,mpp_pe() + endif ! Sort the list "ids" (largest first) do j = 1, nbergs-1 do i = j+1, nbergs @@ -4440,12 +4451,14 @@ integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) ! Set i to first id in my list if (j <= nbergs) then i = ids(j) + have_berg = .true. else - i = 0 + i = nonexistent_id + have_berg = .false. endif l = i call mpp_max(l) - if (i == l) then + if (have_berg .and. i == l) then ii = 1 ! This berg is mine j = j + 1 else @@ -4453,8 +4466,10 @@ integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) endif call mpp_sum(ii) if (ii > 1) then - if (verbose) write(stderrunit,*) 'Duplicated berg across PEs with id=',i,l,' seen',ii,' times pe=',mpp_pe(),k + if (verbose) write(stderrunit,*) 'Duplicated berg across PEs with id=',i,l,' seen',ii,' times pe=',mpp_pe(),k,j,nbergs check_for_duplicate_ids_in_list = check_for_duplicate_ids_in_list + 1 + elseif (ii == 0) then + if (verbose) write(stderrunit,*) 'Berg not accounted for on all PEs with id=',i,l,' seen',ii,' times pe=',mpp_pe(),k,j,nbergs endif enddo From 6e8c31cf44996e1fc0b00f59fe2aa8f2ce45caaa Mon Sep 17 00:00:00 2001 From: Alon Stern Date: Wed, 1 Feb 2017 03:53:32 -0500 Subject: [PATCH 210/361] Mixed ice shelf / iceberg melting option A runtime flag use_mixed_melting has been added. When this flag is true, then the iceberg melt done partly using iceberg melt parametrizations, and parly using ice shelf melt paramtrizations (3 equation model). The decision whether to melt as an ice shelf or iceberg is based on the number of bonds. --- icebergs.F90 | 37 +++++++++++++++++++++++++++++-------- icebergs_framework.F90 | 5 ++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index aac15a0..d03e8b3 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1118,11 +1118,13 @@ subroutine thermodynamics(bergs) type(icebergs), pointer :: bergs ! Local variables type(icebergs_gridded), pointer :: grd +type(bond), pointer :: current_bond real :: M, T, W, L, SST, Vol, Ln, Wn, Tn, nVol, IC, Dn real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv real :: Mnew, Mnew1, Mnew2, Hocean real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb real :: tip_parameter +real :: Ms, N_bonds, N_max !Ice shelf melt, Number of bonds, Max_number of bonds real :: Delta, q integer :: i,j, stderrunit type(iceberg), pointer :: this, next @@ -1170,21 +1172,40 @@ subroutine thermodynamics(bergs) *perday ! convert to m/s Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion *perday ! convert to m/s - + !For icebergs acting as ice shelves - if (bergs%melt_icebergs_as_ice_shelf) then - Mv=0.0 - Mb=0.0 - Me=0.0 + if ((bergs%melt_icebergs_as_ice_shelf) .or.(bergs%use_mixed_melting)) then if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 - call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Mb,this%iceberg_num) - Mb=max(Mb,0.) !No refreezing allowed for now + call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Ms,this%iceberg_num) + Ms=max(Ms,0.) !No refreezing allowed for now !Set melt to zero if ocean is too thin. if ((bergs%melt_cutoff >=0.) .and. (bergs%apply_thickness_cutoff_to_bergs_melt)) then Dn=(bergs%rho_bergs/rho_seawater)*this%thickness ! draught (keel depth) if ((grd%ocean_depth(i,j)-Dn) < bergs%melt_cutoff) then - Mb=0. + Ms=0. + endif + endif + + if (bergs%use_mixed_melting) then + N_bonds=0. + N_max=4.0 !Maximum number of bonds that element can form based on shape + if (bergs%hexagonal_icebergs) N_max=6.0 + if (bergs%iceberg_bonds_on) then + ! Determining number of bonds + current_bond=>this%first_bond + do while (associated(current_bond)) ! loop over all bonds + N_bonds=N_bonds+1.0 + current_bond=>current_bond%next_bond + enddo endif + if (this%static_berg .eq. 1) N_bonds=N_max !Static icebergs melt like ice shelves + Me=((N_max-N_bonds)/N_max)*(Mv+Me) + Mv=0.0 + Mb=(((N_max-N_bonds)/N_max)*(Mb)) + (N_bonds/N_max)*Ms + else !Using Three equation model only. + Mv=0.0 + Me=0.0 + Mb=Ms endif endif diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 61d29cc..3477dd0 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -245,6 +245,7 @@ module ice_bergs_framework logical :: passive_mode=.false. ! Add weight of icebergs + bits to ocean logical :: time_average_weight=.false. ! Time average the weight on the ocean logical :: Runge_not_Verlet=.True. !True=Runge Kuttai, False=Verlet. - Added by Alon + logical :: use_mixed_melting=.False. !If true, then the melt is determined partly using 3 eq model partly using iceberg parametrizations (according to iceberg bond number) logical :: apply_thickness_cutoff_to_gridded_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) logical :: apply_thickness_cutoff_to_bergs_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) logical :: use_updated_rolling_scheme=.false. ! True to use the aspect ratio based rolling scheme rather than incorrect version of WM scheme (set tip_parameter=1000. for correct WM scheme) @@ -398,6 +399,7 @@ subroutine ice_bergs_framework_init(bergs, & real :: tip_parameter=0. ! parameter to override iceberg rollilng critica ratio (use zero to get parameter directly from ice and seawater densities real :: grounding_fraction=0. ! Fraction of water column depth at which grounding occurs logical :: Runge_not_Verlet=.True. !True=Runge Kutta, False=Verlet. - Added by Alon +logical :: use_mixed_melting=.False. !If true, then the melt is determined partly using 3 eq model partly using iceberg parametrizations (according to iceberg bond number) logical :: apply_thickness_cutoff_to_gridded_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) logical :: apply_thickness_cutoff_to_bergs_melt=.False. !Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) logical :: use_updated_rolling_scheme=.false. ! Use the corrected Rolling Scheme rather than the erronios one @@ -449,7 +451,7 @@ subroutine ice_bergs_framework_init(bergs, & grid_is_regular,override_iceberg_velocities,u_override,v_override,add_iceberg_thickness_to_SSH,Iceberg_melt_without_decay,melt_icebergs_as_ice_shelf, & Use_three_equation_model,find_melt_using_spread_mass,use_mixed_layer_salinity_for_thermo,utide_icebergs,ustar_icebergs_bg,cdrag_icebergs, pass_fields_to_ocean_model, & const_gamma, Gamma_T_3EQ, ignore_traj, debug_iceberg_with_id,use_updated_rolling_scheme, tip_parameter, read_old_restarts, tau_calving, read_ocean_depth_from_file, melt_cutoff,& - apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt + apply_thickness_cutoff_to_gridded_melt, apply_thickness_cutoff_to_bergs_melt,use_mixed_melting ! Local variables integer :: ierr, iunit, i, j, id_class, axes3d(3), is,ie,js,je,np @@ -828,6 +830,7 @@ subroutine ice_bergs_framework_init(bergs, & bergs%tip_parameter=tip_parameter bergs%use_updated_rolling_scheme=use_updated_rolling_scheme !Alon bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%use_mixed_melting=use_mixed_melting bergs%apply_thickness_cutoff_to_bergs_melt=apply_thickness_cutoff_to_bergs_melt bergs%apply_thickness_cutoff_to_gridded_melt=apply_thickness_cutoff_to_gridded_melt bergs%melt_cutoff=melt_cutoff From 06d2074ea8e94f131ac55dffb9e26b08466c6d56 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Thu, 2 Mar 2017 13:15:11 -0500 Subject: [PATCH 211/361] Partially doxygenized APIs - icebergs_io APIs are fully documented. - icebergs_framework APIs are mostly documented (some bond routines outstanding). - icebergs are mostly undocumented but indenting has been mostly fixed. Todo: - Finish documentation of APIs. - Add docs directory for building documentation. --- icebergs.F90 | 2629 ++++++++++++++++++++-------------------- icebergs_framework.F90 | 2171 +++++++++++++++++---------------- icebergs_io.F90 | 300 ++--- 3 files changed, 2616 insertions(+), 2484 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index d03e8b3..693b55d 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -1,5 +1,8 @@ +!> Top-level/entry functions that step forward the governing equations module ice_bergs +! This file is part of NOAA-GFDL/icebergs. See LICENSE.md for the license. + use constants_mod, only: pi, omega, HLF use fms_mod, only: open_namelist_file, check_nml_error, close_file use fms_mod, only: field_exist, get_global_att_value @@ -51,20 +54,20 @@ module ice_bergs public icebergs_init, icebergs_end, icebergs_run, icebergs_stock_pe, icebergs public icebergs_incr_mass, icebergs_save_restart -real, parameter :: pi_180=pi/180. ! Converts degrees to radians -real, parameter :: r180_pi=180./pi ! Converts radians to degrees -real, parameter :: Rearth=6360000. ! Radius of earth (m) -real, parameter :: rho_ice=916.7 ! Density of fresh ice @ 0oC (kg/m^3) -real, parameter :: rho_water=999.8 ! Density of fresh water @ 0oC (kg/m^3) -real, parameter :: rho_air=1.1 ! Density of air @ 0oC (kg/m^3) ??? -real, parameter :: rho_seawater=1025. ! Approx. density of surface sea water @ 0oC (kg/m^3) -real, parameter :: gravity=9.8 ! Gravitational acceleratio (m/s^2) -real, parameter :: Cd_av=1.3 ! (Vertical) Drag coefficient between bergs and atmos (?) -real, parameter :: Cd_ah=0.0055 ! (Horizontal) Drag coefficient between bergs and atmos (?) -real, parameter :: Cd_wv=0.9 ! (Vertical) Drag coefficient between bergs and ocean (?) -real, parameter :: Cd_wh=0.0012 ! (Horizontal) Drag coefficient between bergs and ocean (?) -real, parameter :: Cd_iv=0.9 ! (Vertical) Drag coefficient between bergs and sea-ice (?) -!TOM> no horizontal drag for sea ice! real, parameter :: Cd_ih=0.0012 ! (Horizontal) Drag coefficient between bergs and sea-ice (?) +real, parameter :: pi_180=pi/180. !< Converts degrees to radians +real, parameter :: r180_pi=180./pi !< Converts radians to degrees +real, parameter :: Rearth=6360000. !< Radius of earth (m) +real, parameter :: rho_ice=916.7 !< Density of fresh ice @ 0oC (kg/m^3) +real, parameter :: rho_water=999.8 !< Density of fresh water @ 0oC (kg/m^3) +real, parameter :: rho_air=1.1 !< Density of air @ 0oC (kg/m^3) ??? +real, parameter :: rho_seawater=1025. !< Approx. density of surface sea water @ 0oC (kg/m^3) +real, parameter :: gravity=9.8 !< Gravitational acceleratio (m/s^2) +real, parameter :: Cd_av=1.3 !< (Vertical) Drag coefficient between bergs and atmos (?) +real, parameter :: Cd_ah=0.0055 !< (Horizontal) Drag coefficient between bergs and atmos (?) +real, parameter :: Cd_wv=0.9 !< (Vertical) Drag coefficient between bergs and ocean (?) +real, parameter :: Cd_wh=0.0012 !< (Horizontal) Drag coefficient between bergs and ocean (?) +real, parameter :: Cd_iv=0.9 !< (Vertical) Drag coefficient between bergs and sea-ice (?) +!TOM> no horizontal drag for sea ice! real, parameter :: Cd_ih=0.0012 !< (Horizontal) Drag coefficient between bergs and sea-ice (?) #ifdef _FILE_VERSION character(len=128) :: version = _FILE_VERSION @@ -74,27 +77,37 @@ module ice_bergs contains -! ############################################################################## +!> Initializes icebergs container "bergs" subroutine icebergs_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & cos_rot, sin_rot, ocean_depth, maskmap, fractional_area) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory +integer, intent(in) :: gni !< Number of global points in i-direction +integer, intent(in) :: gnj !< Number of global points in j-direction +integer, intent(in) :: layout(2) !< Parallel decomposition of computational processors in i/j direction +integer, intent(in) :: io_layout(2) !< Parallel decomposition of i/o processors in i/j direction +integer, intent(in) :: axes(2) !< Diagnostic axes +integer, intent(in) :: dom_x_flags !< Decomposition flags for i-direction +integer, intent(in) :: dom_y_flags !< Decomposition flags for j-direction +real, intent(in) :: dt !< Time step (s) +type (time_type), intent(in) :: Time !< Model time +real, dimension(:,:), intent(in) :: ice_lon !< Longitude of cell corners using NE convention (degree E) +real, dimension(:,:), intent(in) :: ice_lat !< Latitude of cell corners using NE conventino (degree N) +real, dimension(:,:), intent(in) :: ice_wet !< Wet/dry mask (1 is wet, 0 is dry) of cell centers +real, dimension(:,:), intent(in) :: ice_dx !< Zonal length of cell on northern side (m) +real, dimension(:,:), intent(in) :: ice_dy !< Meridional length of cell on eastern side (m) +real, dimension(:,:), intent(in) :: ice_area !< Area of cells (m^2, or non-dim is fractional_area=True) +real, dimension(:,:), intent(in) :: cos_rot !< Cosine from rotation matrix to lat-lon coords +real, dimension(:,:), intent(in) :: sin_rot !< Sine from rotation matrix to lat-lon coords +real, dimension(:,:), intent(in),optional :: ocean_depth !< Depth of ocean bottom (m) +logical, intent(in), optional :: maskmap(:,:) !< Masks out parallel cores +logical, intent(in), optional :: fractional_area !< If true, ice_area contains cell area as fraction of entire spherical surface +! Local variables type(icebergs_gridded), pointer :: grd => null() -integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) -integer, intent(in) :: dom_x_flags, dom_y_flags -real, intent(in) :: dt -type (time_type), intent(in) :: Time ! current time -real, dimension(:,:), intent(in) :: ice_lon, ice_lat, ice_wet -real, dimension(:,:), intent(in) :: ice_dx, ice_dy, ice_area -real, dimension(:,:), intent(in) :: cos_rot, sin_rot -real, dimension(:,:), intent(in), optional :: ocean_depth -logical, intent(in), optional :: maskmap(:,:) -logical, intent(in), optional :: fractional_area integer :: nbonds logical :: check_bond_quality - integer :: stdlogunit, stderrunit ! Get the stderr and stdlog unit numbers @@ -123,7 +136,7 @@ subroutine icebergs_init(bergs, & call mpp_clock_end(bergs%clock_ior) if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_init, initial status') - + !Reading ocean depth from a file if (bergs%read_ocean_depth_from_file) call read_ocean_depth(bergs%grd) @@ -143,11 +156,10 @@ subroutine icebergs_init(bergs, & end subroutine icebergs_init - -! ############################################################################## +!> Invoke some unit testing subroutine unit_testing(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory call hexagon_test() call point_in_triangle_test() @@ -156,12 +168,14 @@ subroutine unit_testing(bergs) end subroutine unit_testing +!> Test find_basal_melt() subroutine basal_melt_test(bergs) - ! Arguments - type(icebergs), pointer :: bergs - real :: dvo,lat,salt,temp, basal_melt, thickness - integer :: iceberg_num - logical :: Use_three_equation_model +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +! Local variables +real :: dvo,lat,salt,temp, basal_melt, thickness +integer :: iceberg_num +logical :: Use_three_equation_model if (mpp_pe() .eq. mpp_root_pe() ) print *, 'Begining Basal Melting Unit Test' dvo=0.2 ;lat=0.0 ; salt=35.0 ; temp=2.0 ;thickness=100.; iceberg_num=0 @@ -175,12 +189,13 @@ subroutine basal_melt_test(bergs) end subroutine basal_melt_test +!> Test point_in_triangle() subroutine point_in_triangle_test() ! Arguments real :: Ax,Ay,Bx,By,Cx,Cy !Position of icebergs logical :: fail_unit_test integer :: stderrunit - + ! Get the stderr unit number. stderrunit = stderr() Ax= -2.695732526092343E-012 @@ -195,6 +210,7 @@ subroutine point_in_triangle_test() end subroutine point_in_triangle_test +!> Test Hexagon_into_quadrants_using_triangles() subroutine hexagon_test() ! Arguments real :: x0,y0 !Position of icebergs @@ -203,7 +219,7 @@ subroutine hexagon_test() real :: tol logical :: fail_unit_test integer :: stderrunit - + ! Get the stderr unit number. stderrunit = stderr() @@ -261,7 +277,7 @@ subroutine hexagon_test() call error_mesg('diamonds, hexagon unit testing:', 'Hexagon split btw 3 and 4!', WARNING) fail_unit_test=.True. endif - + ! Test 3: Two corners of hex on the axis !Test 3a: center on x>0 axis x0=S/2. ; y0=0. @@ -304,11 +320,11 @@ subroutine hexagon_test() end subroutine hexagon_test -! ############################################################################## - +!> Initializes bonds subroutine initialize_iceberg_bonds(bergs) - -type(icebergs), pointer :: bergs +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +! Local variables type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd @@ -320,22 +336,21 @@ subroutine initialize_iceberg_bonds(bergs) integer :: grdi_outer, grdj_outer integer :: grdi_inner, grdj_inner - ! For convenience - grd=>bergs%grd - !Should update halos before doing this + grd=>bergs%grd + !Should update halos before doing this do grdj_outer = grd%jsc,grd%jec ; do grdi_outer = grd%isc,grd%iec !Should you be on the data domain?? berg=>bergs%list(grdi_outer,grdj_outer)%first do while (associated(berg)) ! loop over all bergs - + lon1=berg%lon; lat1=berg%lat !call rotpos_to_tang(lon1,lat1,x1,y1) !Is this correct? Shouldn't it only be on tangent plane? do grdj_inner = grd%jsc,grd%jec ; do grdi_inner = grd%isc,grd%iec !This line uses n^2 steps ! do grdj_inner = berg%jne-1,berg%jne+1 ; do grdi_inner = berg%ine-1,berg%ine+1 !Only looping through adjacent cells. other_berg=>bergs%list(grdi_inner,grdj_inner)%first - do while (associated(other_berg)) ! loop over all other bergs - + do while (associated(other_berg)) ! loop over all other bergs + if (berg%iceberg_num .ne. other_berg%iceberg_num) then lon2=other_berg%lon; lat2=other_berg%lat !call rotpos_to_tang(lon2,lat2,x2,y2) !Is this correct? Shouldn't it only be on tangent plane? @@ -349,10 +364,10 @@ subroutine initialize_iceberg_bonds(bergs) r_dist_x=dlon*dx_dlon r_dist_y=dlat*dy_dlat r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) - + !if (r_dist.gt.1000.) then ! If the bergs are close together, then form a bond call form_a_bond(berg, other_berg%iceberg_num, other_berg%ine, other_berg%jne, other_berg) - !endif + !endif endif other_berg=>other_berg%next enddo ! End of looping through all other bergs in the inner list @@ -361,82 +376,98 @@ subroutine initialize_iceberg_bonds(bergs) enddo ! End of looping through all bergs in the outer list enddo ; enddo; !End of outer loop. - end subroutine initialize_iceberg_bonds -subroutine convert_from_grid_to_meters(lat_ref,grid_is_latlon ,dx_dlon,dy_dlat) - ! Arguments - real, intent(in) :: lat_ref - logical, intent(in) :: grid_is_latlon - real, intent(out) :: dx_dlon,dy_dlat +! Returns metric converting grid distances to meters +subroutine convert_from_grid_to_meters(lat_ref, grid_is_latlon, dx_dlon, dy_dlat) +! Arguments +real, intent(in) :: lat_ref +logical, intent(in) :: grid_is_latlon +real, intent(out) :: dx_dlon +real, intent(out) :: dy_dlat if (grid_is_latlon) then dx_dlon=(pi/180.)*Rearth*cos((lat_ref)*(pi/180.)) dy_dlat=(pi/180.)*Rearth - else dx_dlon=1. dy_dlat=1. - endif + end subroutine convert_from_grid_to_meters +! Returns metric converting distance in meters to grid distance subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) - ! Arguments - real, intent(in) :: lat_ref - logical, intent(in) :: grid_is_latlon - real, intent(out) :: dlon_dx,dlat_dy +! Arguments +real, intent(in) :: lat_ref +logical, intent(in) :: grid_is_latlon +real, intent(out) :: dlon_dx +real, intent(out) :: dlat_dy if (grid_is_latlon) then dlon_dx=(180./pi)/(Rearth*cos((lat_ref)*(pi/180.))) dlat_dy=(180./pi)/Rearth - else dlon_dx=1. dlat_dy=1. - endif + end subroutine convert_from_meters_to_grid -! ############################################################################## -subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) !Calculating interactive force between icebergs. Alon, Markpoint_4 -type(icebergs), pointer :: bergs +subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& + P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) +!Calculating interactive force between icebergs. Alon, Markpoint_4 +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(bond), pointer :: current_bond -real, intent(in) :: u0,v0, u1, v1 +real, intent(in) :: u0 +real, intent(in) :: v0 +real, intent(in) :: u1 +real, intent(in) :: v1 +real, intent(out) :: IA_x +real, intent(out) :: IA_y +real, intent(out) :: P_ia_11 +real, intent(out) :: P_ia_12 +real, intent(out) :: P_ia_22 +real, intent(out) :: P_ia_21 +real, intent(out) :: P_ia_times_u_x +real, intent(out) :: P_ia_times_u_y +! Local variables real :: u2, v2 logical :: critical_interaction_damping_on -real, intent(out) :: IA_x, IA_y -real, intent(out) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y integer :: grdi, grdj logical :: iceberg_bonds_on logical :: bonded -iceberg_bonds_on=bergs%iceberg_bonds_on + + iceberg_bonds_on=bergs%iceberg_bonds_on IA_x=0. IA_y=0. - P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. + P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. P_ia_times_u_x=0. ; P_ia_times_u_y=0. bonded=.false. !Unbonded iceberg interactions do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 !Note: need to make sure this is wide enough, but less than the halo width other_berg=>bergs%list(grdi,grdj)%first - do while (associated(other_berg)) ! loop over all other bergs - call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) + do while (associated(other_berg)) ! loop over all other bergs + call calculate_force(bergs,berg,other_berg, IA_x, IA_y, u0, v0, u1, v1, & + P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) other_berg=>other_berg%next enddo ! loop over all bergs enddo ; enddo bonded=.true. !Interactions due to iceberg bonds - if (iceberg_bonds_on) then ! MP1 + if (iceberg_bonds_on) then ! MP1 current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds other_berg=>current_bond%other_berg if (.not. associated(other_berg)) then call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated berg!' ,FATAL) else - call calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) + call calculate_force(bergs,berg,other_berg, IA_x, IA_y, u0, v0, u1, v1, & + P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) endif current_bond=>current_bond%next_bond enddo @@ -445,165 +476,170 @@ subroutine interactive_force(bergs,berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_i !print *,'IA_x=',IA_x,'IA_y',IA_y, berg%iceberg_num !print *,'P_ia_11',P_ia_11,'P_ia_12',P_ia_12, 'P_ia_21',P_ia_21,'P_ia_22', P_ia_22 !print *, 'P_ia_times_u_x', P_ia_times_u_x, 'P_ia_times_u_y', P_ia_times_u_y + contains + subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, & + P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) + !Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(iceberg), pointer :: berg + type(iceberg), pointer :: other_berg + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg + real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg + real :: dlon, dlat + real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min + real, intent(in) :: u0,v0, u1, v1 + real :: P_11, P_12, P_21, P_22 + real :: M1, M2, M_min + real :: u2, v2 + real :: lat_ref, dx_dlon, dy_dlat + logical :: critical_interaction_damping_on + real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef + real, intent(inout) :: IA_x, IA_y + real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y + logical ,intent(in) :: bonded + + spring_coef=bergs%spring_coef + !bond_coef=bergs%bond_coef + radial_damping_coef=bergs%radial_damping_coef + tangental_damping_coef=bergs%tangental_damping_coef + critical_interaction_damping_on=bergs%critical_interaction_damping_on + + !Using critical values for damping rather than manually setting the damping. + if (critical_interaction_damping_on) then + radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping + tangental_damping_coef=(2.*sqrt(spring_coef))/4 ! Critical damping (just a guess) + endif - subroutine calculate_force(bergs,berg,other_berg,IA_x, IA_y, u0, v0, u1, v1, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) - !Arguments - type(icebergs), pointer :: bergs - type(iceberg), pointer :: berg - type(iceberg), pointer :: other_berg - real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg - real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg - real :: dlon, dlat - real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min - real, intent(in) :: u0,v0, u1, v1 - real :: P_11, P_12, P_21, P_22 - real :: M1, M2, M_min - real :: u2, v2 - real :: lat_ref, dx_dlon, dy_dlat - logical :: critical_interaction_damping_on - real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef - real, intent(inout) :: IA_x, IA_y - real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y - logical ,intent(in) :: bonded - - spring_coef=bergs%spring_coef - !bond_coef=bergs%bond_coef - radial_damping_coef=bergs%radial_damping_coef - tangental_damping_coef=bergs%tangental_damping_coef - critical_interaction_damping_on=bergs%critical_interaction_damping_on - - !Using critical values for damping rather than manually setting the damping. - if (critical_interaction_damping_on) then - radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping - tangental_damping_coef=(2.*sqrt(spring_coef))/4 ! Critical damping (just a guess) + if (berg%iceberg_num .ne. other_berg%iceberg_num) then + !From Berg 1 + L1=berg%length + W1=berg%width + T1=berg%thickness + M1=berg%mass + A1=L1*W1 + lon1=berg%lon_old; lat1=berg%lat_old + !call rotpos_to_tang(lon1,lat1,x1,y1) + + !From Berg 1 + L2=other_berg%length + W2=other_berg%width + T2=other_berg%thickness + M2=other_berg%mass + u2=other_berg%uvel_old !Old values are used to make it order invariant + v2=other_berg%vvel_old !Old values are used to make it order invariant + A2=L2*W2 + lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant + + !call rotpos_to_tang(lon2,lat2,x2,y2) + + dlon=lon1-lon2 + dlat=lat1-lat2 + + !Note that this is not the exact distance along a great circle. + !Approximation for small distances. Should be fine. + !r_dist_x=x1-x2 ; r_dist_y=y1-y2 + !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) + lat_ref=0.5*(lat1+lat2) + call convert_from_grid_to_meters(lat_ref,bergs%grd%grid_is_latlon,dx_dlon,dy_dlat) + + r_dist_x=dlon*dx_dlon + r_dist_y=dlat*dy_dlat + r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) + + if (bergs%hexagonal_icebergs) then + R1=sqrt(A1/(2.*sqrt(3.))) + R2=sqrt(A2/(2.*sqrt(3.))) + else !square packing + R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) + R2=sqrt(A2/pi) ! Interaction radius of the other iceberg endif + !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!!MP1 + ! if (berg%iceberg_num .eq. 1) then + ! print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon + ! print *, 'Comparing latitudes: ', lat1, lat2, r_dist_y, dlat + ! print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded + ! print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg + ! endif + ! print *, 'outside the loop',R1, R2,r_dist, bonded + !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!! + + + !call overlap_area(R1,R2,r_dist,A_o,trapped) + !T_min=min(T1,T2) + !A_min = min((pi*R1**R1),(pi*R2*R2)) + M_min=min(M1,M2) + !Calculating spring force (later this should only be done on the first time around) + if ((r_dist>0.) .AND. ((r_dist< (R1+R2).AND. (.not. bonded)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then + !Spring force + !accel_spring=spring_coef*(T_min/T1)*(A_o/A1) ! Old version dependent on area + accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) + IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) + IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - if (berg%iceberg_num .ne. other_berg%iceberg_num) then - !From Berg 1 - L1=berg%length - W1=berg%width - T1=berg%thickness - M1=berg%mass - A1=L1*W1 - lon1=berg%lon_old; lat1=berg%lat_old - !call rotpos_to_tang(lon1,lat1,x1,y1) - - !From Berg 1 - L2=other_berg%length - W2=other_berg%width - T2=other_berg%thickness - M2=other_berg%mass - u2=other_berg%uvel_old !Old values are used to make it order invariant - v2=other_berg%vvel_old !Old values are used to make it order invariant - A2=L2*W2 - lon2=other_berg%lon_old; lat2=other_berg%lat_old !Old values are used to make it order invariant - - !call rotpos_to_tang(lon2,lat2,x2,y2) - - dlon=lon1-lon2 - dlat=lat1-lat2 - - !Note that this is not the exact distance along a great circle. - !Approximation for small distances. Should be fine. - !r_dist_x=x1-x2 ; r_dist_y=y1-y2 - !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) - lat_ref=0.5*(lat1+lat2) - call convert_from_grid_to_meters(lat_ref,bergs%grd%grid_is_latlon,dx_dlon,dy_dlat) - - r_dist_x=dlon*dx_dlon - r_dist_y=dlat*dy_dlat - r_dist=sqrt( (r_dist_x**2) + (r_dist_y**2) ) - - if (bergs%hexagonal_icebergs) then - R1=sqrt(A1/(2.*sqrt(3.))) - R2=sqrt(A2/(2.*sqrt(3.))) - else !square packing - R1=sqrt(A1/pi) ! Interaction radius of the iceberg (assuming circular icebergs) - R2=sqrt(A2/pi) ! Interaction radius of the other iceberg - endif - !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!!MP1 - ! if (berg%iceberg_num .eq. 1) then - ! print *, 'Comparing longitudes: ', lon1, lon2, r_dist_x, dlon - ! print *, 'Comparing latitudes: ', lat1, lat2, r_dist_y, dlat - ! print *, 'Outside, iceberg_num, r_dist', berg%iceberg_num, r_dist,bonded - ! print *, 'Halo_status', berg%halo_berg,other_berg%halo_berg - ! endif - ! print *, 'outside the loop',R1, R2,r_dist, bonded - !!!!!!!!!!!!!!!!!!!!!!!!!!!debugging!!!!!!!!!!!!!!!!!!!!!!!!!! - - - !call overlap_area(R1,R2,r_dist,A_o,trapped) - !T_min=min(T1,T2) - !A_min = min((pi*R1**R1),(pi*R2*R2)) - M_min=min(M1,M2) - !Calculating spring force (later this should only be done on the first time around) - if ((r_dist>0.) .AND. ((r_dist< (R1+R2).AND. (.not. bonded)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then - !Spring force - !accel_spring=spring_coef*(T_min/T1)*(A_o/A1) ! Old version dependent on area - accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) - IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) - IA_y=IA_y+(accel_spring*(r_dist_y/r_dist)) - if (r_dist < 5*(R1+R2)) then - + !MP1 !if (berg%iceberg_num .eq. 1) then ! !print *, '************************************************************' ! print *, 'INSIDE, r_dist', berg%iceberg_num, other_berg%iceberg_num, r_dist, bonded !endif - !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) + !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num !Damping force: !Paralel velocity - P_11=(r_dist_x*r_dist_x)/(r_dist**2) - P_12=(r_dist_x*r_dist_y)/(r_dist**2) - P_21=(r_dist_x*r_dist_y)/(r_dist**2) - P_22=(r_dist_y*r_dist_y)/(r_dist**2) - !p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=radial_damping_coef*(M_min/M1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - !print *, 'Paralel: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 - - !Normal velocities - P_11=1-P_11 ; P_12=-P_12 ; P_21= -P_21 ; P_22=1-P_22 - !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) - p_ia_coef=tangental_damping_coef*(M_min/M1) - p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & - + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) - P_ia_11=P_ia_11+p_ia_coef*P_11 - P_ia_12=P_ia_12+p_ia_coef*P_12 - P_ia_21=P_ia_21+p_ia_coef*P_21 - P_ia_22=P_ia_22+p_ia_coef*P_22 - P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) - P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) - !print *, 'Perp: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 - !print *, 'P_11',P_11 - !print *, 'P_21',P_21 - !print *, 'P_12',P_12 - !print *, 'P_22',P_22 - endif + P_11=(r_dist_x*r_dist_x)/(r_dist**2) + P_12=(r_dist_x*r_dist_y)/(r_dist**2) + P_21=(r_dist_x*r_dist_y)/(r_dist**2) + P_22=(r_dist_y*r_dist_y)/(r_dist**2) + !p_ia_coef=radial_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=radial_damping_coef*(M_min/M1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + !print *, 'Paralel: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 + + !Normal velocities + P_11=1-P_11 ; P_12=-P_12 ; P_21= -P_21 ; P_22=1-P_22 + !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) + p_ia_coef=tangental_damping_coef*(M_min/M1) + p_ia_coef=p_ia_coef*(0.5*(sqrt((((P_11*(u2-u1))+(P_12*(v2-v1)))**2)+ (((P_12*(u2-u1))+(P_22*(v2-v1)))**2)) & + + sqrt((((P_11*(u2-u0))+(P_12*(v2-v0)))**2)+(((P_12*(u2-u0)) +(P_22*(v2-v0)))**2)))) + P_ia_11=P_ia_11+p_ia_coef*P_11 + P_ia_12=P_ia_12+p_ia_coef*P_12 + P_ia_21=P_ia_21+p_ia_coef*P_21 + P_ia_22=P_ia_22+p_ia_coef*P_22 + P_ia_times_u_x=P_ia_times_u_x+ (p_ia_coef* ((P_11*u2) +(P_12*v2))) + P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) + !print *, 'Perp: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 + !print *, 'P_11',P_11 + !print *, 'P_21',P_21 + !print *, 'P_12',P_12 + !print *, 'P_22',P_22 endif endif + endif + end subroutine calculate_force - end subroutine calculate_force - + subroutine overlap_area(R1, R2, d, A, trapped) + ! Arguments + real, intent(in) :: R1 + real, intent(in) :: R2 + real, intent(in) :: d + real, intent(out) :: A + real, intent(out) :: Trapped + ! Local variables + real :: R1_sq, R2_sq, d_sq - subroutine overlap_area(R1,R2,d,A,trapped) - real, intent(in) :: R1, R2, d - real, intent(out) :: A, Trapped - real :: R1_sq, R2_sq, d_sq R1_sq=R1**2 R2_sq=R2**2 d_sq=d**2 @@ -614,7 +650,7 @@ subroutine overlap_area(R1,R2,d,A,trapped) if (d>abs(R1-R2)) then A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) else - A=min(pi*R1_sq,pi*R2_sq) + A=min(pi*R1_sq,pi*R2_sq) Trapped=1. endif else @@ -626,25 +662,31 @@ subroutine overlap_area(R1,R2,d,A,trapped) end subroutine overlap_area - - - end subroutine interactive_force - -! ############################################################################## - - +!> Calculates the instantaneous acceleration of an iceberg subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon MP1 !subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon ! Arguments -type(icebergs), pointer :: bergs -type(iceberg), pointer :: berg -integer, intent(in) :: i, j -real, intent(in) :: xi, yj, lat, uvel, vvel, uvel0, vvel0, dt -real, intent(out) :: ax, ay -real, intent(inout) :: axn, ayn, bxn, byn ! Added implicit and explicit accelerations to output -Alon -logical, optional :: debug_flag +type(icebergs), pointer :: bergs !< Container for all types and memory +type(iceberg), pointer :: berg !< An iceberg +integer, intent(in) :: i !< i-index of cell berg is in +integer, intent(in) :: j !< j-index of cell berg is in +real, intent(in) :: xi !< Non-dimensional x-position within cell of berg +real, intent(in) :: yj !< Non-dimensional y-position within cell of berg +real, intent(in) :: lat !< Latitude of berg (degree N) +real, intent(in) :: uvel !< Zonal velocity of berg (m/s) +real, intent(in) :: vvel !< Meridional velocity of berg (m/s) +real, intent(in) :: uvel0 +real, intent(in) :: vvel0 +real, intent(in) :: dt !< Time step (s) +real, intent(out) :: ax !< Zonal acceleration (m/s2) +real, intent(out) :: ay !< Meridional acceleration (m/s2) +real, intent(inout) :: axn +real, intent(inout) :: ayn +real, intent(inout) :: bxn +real, intent(inout) :: byn ! Added implicit and explicit accelerations to output -Alon +logical, optional :: debug_flag !< If true, print debugging ! Local variables type(icebergs_gridded), pointer :: grd real :: uo, vo, ui, vi, ua, va, uwave, vwave, ssh_x, ssh_y, sst, sss, cn, hi @@ -654,7 +696,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop real, parameter :: accel_lim=1.e-2, Cr0=0.06, vel_lim=15. real :: alpha, beta, C_N -real :: lambda, detA, A11, A12, A21, A22, RHS_x, RHS_y, D_hi +real :: lambda, detA, A11, A12, A21, A22, RHS_x, RHS_y, D_hi real :: uveln, vveln, us, vs, speed, loc_dx, new_speed real :: u_star, v_star !Added by Alon real :: IA_x, IA_y !Added by Alon @@ -666,27 +708,25 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a integer :: itloop integer :: stderrunit -Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon -interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon -use_new_predictive_corrective=bergs%use_new_predictive_corrective ! Loading directly from namelist/default , Alon - -!These values are no longer set as parameters, but rather can be changed as variables. -alpha=0.0 -beta=1.0 -C_N=0.0 - - -!Alon: Verlet requires implicit Coriolis and implicit drag. -!Alon: Also, I think that the implicit Coriolis with RK gives icebergs which do not complete inertial circles. -if (.not.Runge_not_Verlet) then -alpha=1.0 -C_N=1.0 -beta=1.0 -use_new_predictive_corrective=.True. -endif - + Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon + interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon + use_new_predictive_corrective=bergs%use_new_predictive_corrective ! Loading directly from namelist/default , Alon + + !These values are no longer set as parameters, but rather can be changed as variables. + alpha=0.0 + beta=1.0 + C_N=0.0 + + !Alon: Verlet requires implicit Coriolis and implicit drag. + !Alon: Also, I think that the implicit Coriolis with RK gives icebergs which do not complete inertial circles. + if (.not.Runge_not_Verlet) then + alpha=1.0 + C_N=1.0 + beta=1.0 + use_new_predictive_corrective=.True. + endif -!print *, 'axn=',axn,'ayn=',ayn + !print *, 'axn=',axn,'ayn=',ayn u_star=uvel0+(axn*(dt/2.)) !Alon v_star=vvel0+(ayn*(dt/2.)) !Alon @@ -704,7 +744,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a else f_cori=(2.*omega)*sin(pi_180*bergs%lat_ref) endif -! f_cori=0. + !f_cori=0. M=berg%mass T=berg%thickness ! total thickness @@ -713,7 +753,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a W=berg%width L=berg%length -!Initializing accelerations - Alon. (I am not 100% sure this is needed). I'm not sure what is output if variable is not defined in the subroutine. + ! Initializing accelerations - Alon. (I am not 100% sure this is needed). I'm not sure what is output if variable is not defined in the subroutine. axn=0. ayn=0. bxn=0. @@ -725,14 +765,14 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Wave radiation uwave=ua-uo; vwave=va-vo ! Use wind speed rel. to ocean for wave model (aja)? wmod=uwave*uwave+vwave*vwave ! The wave amplitude and length depend on the wind speed relative to the ocean current; - ! actually wmod is wmod**2 here. + ! actually wmod is wmod**2 here. ampl=0.5*0.02025*wmod ! This is "a", the wave amplitude Lwavelength=0.32*wmod ! Surface wave length fitted to data in table at - ! http://www4.ncsu.edu/eos/users/c/ceknowle/public/chapter10/part2.html + ! http://www4.ncsu.edu/eos/users/c/ceknowle/public/chapter10/part2.html Lcutoff=0.125*Lwavelength Ltop=0.25*Lwavelength - Cr=Cr0*min(max(0.,(L-Lcutoff)/((Ltop-Lcutoff)+1.e-30)),1.) ! Wave radiation coefficient - ! fitted to graph from Carrieres et al., POAC Drift Model. + Cr=Cr0*min(max(0.,(L-Lcutoff)/((Ltop-Lcutoff)+1.e-30)),1.) ! Wave radiation coefficient fitted to + ! graph from Carrieres et al., POAC Drift Model. wave_rad=0.5*rho_seawater/M*Cr*gravity*ampl*min(ampl,F)*(2.*W*L)/(W+L) wmod = sqrt(ua*ua+va*va) ! Wind speed if (wmod.ne.0.) then @@ -758,53 +798,50 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !c_ice=0. ! Half half accelerations - axn, ayn - if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave - ayn=-gravity*ssh_y +wave_rad*vwave + if (.not.Runge_not_Verlet) then + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave else - ! Not half half accelerations - for RK - bxn=-gravity*ssh_x +wave_rad*uwave - byn=-gravity*ssh_y +wave_rad*vwave - endif - - -! Interactive spring acceleration - (Does the spring part need to be called twice?) -if (interactive_icebergs_on) then - call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. - if (.not.Runge_not_Verlet) then - axn=axn + IA_x - ayn=ayn + IA_y - else - bxn=bxn + IA_x - byn=byn + IA_y - endif - -endif + ! Not half half accelerations - for RK + bxn=-gravity*ssh_x +wave_rad*uwave + byn=-gravity*ssh_y +wave_rad*vwave + endif + ! Interactive spring acceleration - (Does the spring part need to be called twice?) + if (interactive_icebergs_on) then + call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, uvel0, vvel0, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + if (.not.Runge_not_Verlet) then + axn=axn + IA_x + ayn=ayn + IA_y + else + bxn=bxn + IA_x + byn=byn + IA_y + endif + endif if (alpha>0.) then ! If implicit Coriolis, use u_star rather than RK4 latest !Alon - if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon - axn=axn+f_cori*v_star - ayn=ayn-f_cori*u_star - else - bxn=bxn+f_cori*v_star - byn=byn-f_cori*u_star - endif + if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon + axn=axn+f_cori*v_star + ayn=ayn-f_cori*u_star + else + bxn=bxn+f_cori*v_star + byn=byn-f_cori*u_star + endif else - bxn=bxn+f_cori*vvel - byn=byn-f_cori*uvel + bxn=bxn+f_cori*vvel + byn=byn-f_cori*uvel endif - + if (use_new_predictive_corrective) then - uveln=uvel0; vveln=vvel0 ! Discuss this change with Alistair. Alon thinks that it is needed. + uveln=uvel0; vveln=vvel0 ! Discuss this change with Alistair. Alon thinks that it is needed. else - uveln=uvel; vveln=vvel + uveln=uvel; vveln=vvel endif - + us=uvel0 ; vs=vvel0 do itloop=1,2 ! Iterate on drag coefficients if (itloop .eq. 2) then - us=uveln ; vs=vveln + us=uveln ; vs=vveln endif if (use_new_predictive_corrective) then !Alon's proposed change - using Bob's improved scheme. @@ -819,68 +856,66 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a drag_ice=c_ice*sqrt( (us-ui)**2+(vs-vi)**2 ) endif - RHS_x=(axn/2) + bxn - RHS_y=(ayn/2) + byn + RHS_x=(axn/2) + bxn + RHS_y=(ayn/2) + byn - if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest - RHS_x=RHS_x - drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) - RHS_y=RHS_y - drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) - else - RHS_x=RHS_x - drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) - RHS_y=RHS_y - drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) - endif + if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest + RHS_x=RHS_x - drag_ocn*(u_star-uo) -drag_atm*(u_star-ua) -drag_ice*(u_star-ui) + RHS_y=RHS_y - drag_ocn*(v_star-vo) -drag_atm*(v_star-va) -drag_ice*(v_star-vi) + else + RHS_x=RHS_x - drag_ocn*(uvel-uo) -drag_atm*(uvel-ua) -drag_ice*(uvel-ui) + RHS_y=RHS_y - drag_ocn*(vvel-vo) -drag_atm*(vvel-va) -drag_ice*(vvel-vi) + endif -if (interactive_icebergs_on) then - if (itloop>1) then - call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, us,vs, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. + if (interactive_icebergs_on) then + if (itloop>1) then + call interactive_force(bergs, berg, IA_x, IA_y, uvel0, vvel0, us,vs, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Spring forces, Made by Alon. endif - if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest - RHS_x=RHS_x -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) - RHS_y=RHS_y -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) + if (beta>0.) then ! If implicit, use u_star, v_star rather than RK4 latest + RHS_x=RHS_x -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) + RHS_y=RHS_y -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) else - RHS_x=RHS_x - (((P_ia_11*uvel)+(P_ia_12*vvel))-P_ia_times_u_x) - RHS_y=RHS_y - (((P_ia_21*uvel)+(P_ia_22*vvel))-P_ia_times_u_y) + RHS_x=RHS_x - (((P_ia_11*uvel)+(P_ia_12*vvel))-P_ia_times_u_x) + RHS_y=RHS_y - (((P_ia_21*uvel)+(P_ia_22*vvel))-P_ia_times_u_y) endif !print *,'Before calculation:', berg%iceberg_num, IA_x, IA_y, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y -endif + endif ! Solve for implicit accelerations - if (alpha+beta.gt.0.) then - lambda=drag_ocn+drag_atm+drag_ice - A11=1.+beta*dt*lambda - A22=1.+beta*dt*lambda - A12=-alpha*dt*f_cori - A21=alpha*dt*f_cori - !A12=dt*f_cori !Removed by ALon (in order to have the entire matrix. I hope the sign is correct) - - if (C_N>0.) then !For Crank-Nicolson Coriolis term. - A12=A12/2. - A21=A21/2. - endif + if (alpha+beta.gt.0.) then + lambda=drag_ocn+drag_atm+drag_ice + A11=1.+beta*dt*lambda + A22=1.+beta*dt*lambda + A12=-alpha*dt*f_cori + A21=alpha*dt*f_cori + !A12=dt*f_cori !Removed by ALon (in order to have the entire matrix. I hope the sign is correct) + + if (C_N>0.) then ! For Crank-Nicolson Coriolis term. + A12=A12/2. + A21=A21/2. + endif - if (interactive_icebergs_on) then - A11=A11+(dt*P_ia_11) - A12=A12+(dt*P_ia_12) - A21=A21+(dt*P_ia_21) - A22=A22+(dt*P_ia_22) - endif + if (interactive_icebergs_on) then + A11=A11+(dt*P_ia_11) + A12=A12+(dt*P_ia_12) + A21=A21+(dt*P_ia_21) + A22=A22+(dt*P_ia_22) + endif - !This is for testing the code using only interactive forces - if (bergs%only_interactive_forces) then - RHS_x=(IA_x/2) -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) - RHS_y=(IA_y/2) -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) + ! This is for testing the code using only interactive forces + if (bergs%only_interactive_forces) then + RHS_x=(IA_x/2) -(((P_ia_11*u_star)+(P_ia_12*v_star))-P_ia_times_u_x) + RHS_y=(IA_y/2) -(((P_ia_21*u_star)+(P_ia_22*v_star))-P_ia_times_u_y) A11=1+(dt*P_ia_11) A12=(dt*P_ia_12) A21=(dt*P_ia_21) A22=1+(dt*P_ia_22) - endif - - + endif - detA=1./((A11*A22)-(A12*A21)) - ax=detA*(A22*RHS_x-A12*RHS_y) - ay=detA*(A11*RHS_y-A21*RHS_x) + detA=1./((A11*A22)-(A12*A21)) + ax=detA*(A22*RHS_x-A12*RHS_y) + ay=detA*(A11*RHS_y-A21*RHS_x) !Alistair's version removed by Alon ! detA=1./(A11**2+A12**2) @@ -890,43 +925,43 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ax=RHS_x; ay=RHS_y endif - uveln=u_star+dt*ax ! Alon - vveln=v_star+dt*ay ! Alon + uveln=u_star+dt*ax ! Alon + vveln=v_star+dt*ay ! Alon !MP4 ! if (berg%iceberg_num .eq. 1) then ! print *, '***************************************************' ! print *,'Iceberg_num, itloop', berg%iceberg_num, itloop - ! print *, 'P matrix:', P_ia_11, P_ia_12,P_ia_21,P_ia_22,P_ia_times_u_x, P_ia_times_u_x - ! print *,'A_matrix', A11, A12, A21, A22 - ! print *,'IA_x IA_y', IA_x, IA_y + ! print *, 'P matrix:', P_ia_11, P_ia_12,P_ia_21,P_ia_22,P_ia_times_u_x, P_ia_times_u_x + ! print *,'A_matrix', A11, A12, A21, A22 + ! print *,'IA_x IA_y', IA_x, IA_y ! print *, 'RHS, ustar, uvel,ax: ', RHS_x, u_star,uveln, ax ! endif enddo ! itloop -!Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon - axn=0. - ayn=0. - if (.not.Runge_not_Verlet) then - axn=-gravity*ssh_x +wave_rad*uwave - ayn=-gravity*ssh_y +wave_rad*vwave - if (interactive_icebergs_on) then - axn=axn + IA_x - ayn=ayn + IA_y - endif - endif - if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon - axn=axn+f_cori*vveln - ayn=ayn-f_cori*uveln + !Saving the totally explicit part of the acceleration to use in finding the next position and u_star -Alon + axn=0. + ayn=0. + if (.not.Runge_not_Verlet) then + axn=-gravity*ssh_x +wave_rad*uwave + ayn=-gravity*ssh_y +wave_rad*vwave + if (interactive_icebergs_on) then + axn=axn + IA_x + ayn=ayn + IA_y endif + endif + if (C_N>0.) then ! C_N=1 for Crank Nicolson Coriolis, C_N=0 for full implicit Coriolis !Alon + axn=axn+f_cori*vveln + ayn=ayn-f_cori*uveln + endif - !This is for testing the code using only interactive forces - if (bergs%only_interactive_forces) then - axn=IA_x - ayn=IA_y - endif + !This is for testing the code using only interactive forces + if (bergs%only_interactive_forces) then + axn=IA_x + ayn=IA_y + endif - bxn= ax-(axn/2) !Alon - byn= ay-(ayn/2) !Alon + bxn= ax-(axn/2) !Alon + byn= ay-(ayn/2) !Alon ! Limit speed of bergs based on a CFL criteria if ((bergs%speed_limit>0.) .or. (bergs%speed_limit .eq.-1.)) then @@ -934,13 +969,13 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a if (speed>0.) then loc_dx=min(0.5*(grd%dx(i,j)+grd%dx(i,j-1)),0.5*(grd%dy(i,j)+grd%dy(i-1,j))) ! min(dx,dy) !new_speed=min(loc_dx/dt*bergs%speed_limit,speed) ! Restrict speed to dx/dt x factor - new_speed=loc_dx/dt*bergs%speed_limit ! Speed limit as a factor of dx / dt + new_speed=loc_dx/dt*bergs%speed_limit ! Speed limit as a factor of dx / dt if (new_speed0.) then uveln=uveln*(new_speed/speed) ! Scale velocity to reduce speed vveln=vveln*(new_speed/speed) ! without changing the direction bergs%nspeeding_tickets=bergs%nspeeding_tickets+1 - else + else call error_mesg('diamonds, Speeding icebergs', 'Faster than the CFL!', WARNING) write(stderrunit,*) 'diamonds, Speeding berg1! =',mpp_pe(), berg%iceberg_num write(stderrunit,*) 'diamonds, Speeding berg2, speed =',speed, loc_dx/dt @@ -1084,7 +1119,7 @@ subroutine dump_locfld(grd,i0,j0,A,lbl) write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,1) enddo end subroutine dump_locfld - + subroutine dump_locvel(grd,i0,j0,A,lbl) ! Arguments type(icebergs_gridded), pointer :: grd @@ -1108,14 +1143,14 @@ subroutine dump_locvel(grd,i0,j0,A,lbl) write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,0) enddo end subroutine dump_locvel - + end subroutine accel ! ############################################################################## subroutine thermodynamics(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd type(bond), pointer :: current_bond @@ -1134,13 +1169,13 @@ subroutine thermodynamics(bergs) ! For convenience grd=>bergs%grd - - !Initializing + + !Initializing grd%Uvel_on_ocean(:,:,:)=0. grd%Vvel_on_ocean(:,:,:)=0. ! Thermodynamics of first halo row is calculated, so that spread mass to ocean works correctly - do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 + do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 this=>bergs%list(grdi,grdj)%first do while(associated(this)) if (debug) call check_position(grd, this, 'thermodynamics (top)') @@ -1149,7 +1184,7 @@ subroutine thermodynamics(bergs) this%sss,this%cn, this%hi) SST=this%sst SSS=this%sss - IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration + IC=min(1.,this%cn+bergs%sicn_shift) ! Shift sea-ice concentration M=this%mass T=this%thickness ! total thickness !D=(bergs%rho_bergs/rho_seawater)*T ! draught (keel depth) @@ -1159,12 +1194,12 @@ subroutine thermodynamics(bergs) i=this%ine j=this%jne Vol=T*W*L - + ! Environment dvo=sqrt((this%uvel-this%uo)**2+(this%vvel-this%vo)**2) dva=sqrt((this%ua-this%uo)**2+(this%va-this%vo)**2) Ss=1.5*(dva**0.5)+0.1*dva ! Sea state - + ! Melt rates in m/s Mv=max( 7.62e-3*SST+1.29e-3*(SST**2), 0.) &! Buoyant convection at sides *perday ! convert to m/s @@ -1172,10 +1207,10 @@ subroutine thermodynamics(bergs) *perday ! convert to m/s Me=max( 1./12.*(SST+2.)*Ss*(1+cos(pi*(IC**3))) ,0.) &! Wave erosion *perday ! convert to m/s - - !For icebergs acting as ice shelves + + !For icebergs acting as ice shelves if ((bergs%melt_icebergs_as_ice_shelf) .or.(bergs%use_mixed_melting)) then - if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 + if (.not. bergs%use_mixed_layer_salinity_for_thermo) SSS=35.0 call find_basal_melt(bergs,dvo,this%lat,SSS,SST,bergs%Use_three_equation_model,T,Ms,this%iceberg_num) Ms=max(Ms,0.) !No refreezing allowed for now !Set melt to zero if ocean is too thin. @@ -1188,7 +1223,7 @@ subroutine thermodynamics(bergs) if (bergs%use_mixed_melting) then N_bonds=0. - N_max=4.0 !Maximum number of bonds that element can form based on shape + N_max=4.0 !Maximum number of bonds that element can form based on shape if (bergs%hexagonal_icebergs) N_max=6.0 if (bergs%iceberg_bonds_on) then ! Determining number of bonds @@ -1198,7 +1233,7 @@ subroutine thermodynamics(bergs) current_bond=>current_bond%next_bond enddo endif - if (this%static_berg .eq. 1) N_bonds=N_max !Static icebergs melt like ice shelves + if (this%static_berg .eq. 1) N_bonds=N_max !Static icebergs melt like ice shelves Me=((N_max-N_bonds)/N_max)*(Mv+Me) Mv=0.0 Mb=(((N_max-N_bonds)/N_max)*(Mb)) + (N_bonds/N_max)*Ms @@ -1208,26 +1243,26 @@ subroutine thermodynamics(bergs) Mb=Ms endif endif - + if (bergs%set_melt_rates_to_zero) then Mv=0.0 Mb=0.0 Me=0.0 endif - + if (bergs%use_operator_splitting) then ! Operator split update of volume/mass Tn=max(T-Mb*bergs%dt,0.) ! new total thickness (m) nVol=Tn*W*L ! new volume (m^3) Mnew1=(nVol/Vol)*M ! new mass (kg) dMb=M-Mnew1 ! mass lost to basal melting (>0) (kg) - + Ln=max(L-Mv*bergs%dt,0.) ! new length (m) Wn=max(W-Mv*bergs%dt,0.) ! new width (m) nVol=Tn*Wn*Ln ! new volume (m^3) Mnew2=(nVol/Vol)*M ! new mass (kg) dMv=Mnew1-Mnew2 ! mass lost to buoyant convection (>0) (kg) - + Ln=max(Ln-Me*bergs%dt,0.) ! new length (m) Wn=max(Wn-Me*bergs%dt,0.) ! new width (m) nVol=Tn*Wn*Ln ! new volume (m^3) @@ -1247,7 +1282,7 @@ subroutine thermodynamics(bergs) dMe=(M/Vol)*(T*(W+L))*Me*bergs%dt ! approx. mass lost to erosion (kg) dMv=(M/Vol)*(T*(W+L))*Mv*bergs%dt ! approx. mass loss to buoyant convection (kg) endif - + ! Bergy bits if (bergs%bergy_bit_erosion_fraction>0.) then Mbits=this%mass_of_bits ! mass of bergy bits (kg) @@ -1260,7 +1295,7 @@ subroutine thermodynamics(bergs) Mbb=bergs%rho_bergs*Abits*Mbb ! in kg/s dMbitsM=min(Mbb*bergs%dt,nMbits) ! bergy bits mass lost to melting (kg) nMbits=nMbits-dMbitsM ! remove mass lost to bergy bits melt - if (Mnew==0.) then ! if parent berg has completely melted then + if (Mnew==0.) then ! if parent berg has completely melted then dMbitsM=dMbitsM+nMbits ! instantly melt all the bergy bits nMbits=0. endif @@ -1270,7 +1305,7 @@ subroutine thermodynamics(bergs) dMbitsM=0. nMbits=this%mass_of_bits ! retain previous value incase non-zero endif - + ! Add melting to the grid and field diagnostics if (grd%area(i,j).ne.0.) then melt=(dM-(dMbitsE-dMbitsM))/bergs%dt ! kg/s @@ -1305,69 +1340,68 @@ subroutine thermodynamics(bergs) write(stderrunit,*) 'msk=',grd%msk(i,j),grd%area(i,j) call error_mesg('diamonds, thermodynamics', 'berg appears to have grounded!', FATAL) endif - - - ! Rolling - !There are now 3 iceberg rolling schemes: - !1) Rolling based on aspect ratio threshold (iceberg of constant density) - !2) Rolling based on corrected Weeks and Mellor scheme - !3) Rolling based on incorrect Weeks and Mellor scheme - kept for legacy reasons - if (bergs%allow_bergs_to_roll) then - Dn=(bergs%rho_bergs/rho_seawater)*Tn ! draught (keel depth) - if ( Dn>0. ) then - if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter<999.) ) then !Use Rolling Scheme 3 - if ( max(Wn,Ln)Ln) call swap_variables(Ln,Wn) !Make sure that Wn is the smaller dimension - - if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter>=999.) ) then !Use Rolling Scheme 2 - q=bergs%rho_bergs/rho_seawater - Delta=6.0 - if (Wn0. ) then + if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter<999.) ) then !Use Rolling Scheme 3 + if ( max(Wn,Ln)Ln) call swap_variables(Ln,Wn) !Make sure that Wn is the smaller dimension + + if ( (.not.bergs%use_updated_rolling_scheme) .and. (bergs%tip_parameter>=999.) ) then !Use Rolling Scheme 2 + q=bergs%rho_bergs/rho_seawater + Delta=6.0 + if (Wn0.) then - tip_parameter=bergs%tip_parameter - else - ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density - tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 - endif - if ((tip_parameter*Tn)>Wn) then !note that we use the Thickness instead of the Draft - call swap_variables(Tn,Wn) + if (bergs%use_updated_rolling_scheme) then !Use Rolling Scheme 1 + if (bergs%tip_parameter>0.) then + tip_parameter=bergs%tip_parameter + else + ! Equation 27 from Burton et al 2012, or equivolently, Weeks and Mellor 1979 with constant density + tip_parameter=sqrt(6*(bergs%rho_bergs/rho_seawater)*(1-(bergs%rho_bergs/rho_seawater))) !using default values gives 0.92 + endif + if ((tip_parameter*Tn)>Wn) then !note that we use the Thickness instead of the Draft + call swap_variables(Tn,Wn) + endif endif endif + Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) for grounding endif - Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) for grounding endif - endif - !This option allows iceberg melt fluxes to enter the ocean without the icebergs changing shape - if (bergs%Iceberg_melt_without_decay) then - !In this case, the iceberg dimension are reset to their values before - !the thermodynamics are applied. - !If the spread_mass is being used to calculate melt, we calculate this - !before reseting - if (bergs%find_melt_using_spread_mass) then - if (Mnew>0.) then !If the berg still exists - call spread_mass_across_ocean_cells(bergs,this, i, j, this%xi, this%yj,Mnew , nMbits, this%mass_scaling, Ln*Wn, Tn) - endif - endif - !Reset all the values - Mnew=this%mass - nMbits=this%mass_of_bits - Tn=this%thickness - Wn=this%width - Ln=this%length - if (bergs%bergy_bit_erosion_fraction>0.) then - Mbits=this%mass_of_bits ! mass of bergy bits (kg) - Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters - Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) - endif + !This option allows iceberg melt fluxes to enter the ocean without the icebergs changing shape + if (bergs%Iceberg_melt_without_decay) then + !In this case, the iceberg dimension are reset to their values before + !the thermodynamics are applied. + !If the spread_mass is being used to calculate melt, we calculate this + !before reseting + if (bergs%find_melt_using_spread_mass) then + if (Mnew>0.) then !If the berg still exists + call spread_mass_across_ocean_cells(bergs,this, i, j, this%xi, this%yj,Mnew , nMbits, this%mass_scaling, Ln*Wn, Tn) + endif + endif + !Reset all the values + Mnew=this%mass + nMbits=this%mass_of_bits + Tn=this%thickness + Wn=this%width + Ln=this%length + if (bergs%bergy_bit_erosion_fraction>0.) then + Mbits=this%mass_of_bits ! mass of bergy bits (kg) + Lbits=min(L,W,T,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(Mbits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + endif else ! Store the new state of iceberg (with L>W) this%mass=Mnew @@ -1377,7 +1411,7 @@ subroutine thermodynamics(bergs) this%length=max(Wn,Ln) endif next=>this%next - + ! Did berg completely melt? if (Mnew<=0.) then ! Delete the berg call move_trajectory(bergs, this) @@ -1388,31 +1422,28 @@ subroutine thermodynamics(bergs) enddo enddo ; enddo - contains subroutine swap_variables(x,y) ! Arguments real, intent(inout) :: x, y real :: temp - temp=x - x=y - y=temp + temp=x + x=y + y=temp end subroutine swap_variables end subroutine thermodynamics - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine create_gridded_icebergs_fields(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: this integer i,j integer :: grdi, grdj -real :: Hocean, Dn,Tn,dvo, mass_tmp +real :: Hocean, Dn,Tn,dvo, mass_tmp real :: ustar_h, ustar real :: orientation real :: ave_thickness, ave_draft @@ -1422,33 +1453,33 @@ subroutine create_gridded_icebergs_fields(bergs) ! For convenience grd=>bergs%grd - spread_mass_tmp(:,:)=0. !Initializing temporary variable to use in iceberg melt calculation + spread_mass_tmp(:,:)=0. !Initializing temporary variable to use in iceberg melt calculation !Special case for icebergs not decaying, but mass diffence being used for melt rates if ((bergs%find_melt_using_spread_mass) .and. (bergs%Iceberg_melt_without_decay)) then - call sum_up_spread_fields(bergs, spread_mass_tmp(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') + call sum_up_spread_fields(bergs, spread_mass_tmp(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') endif - - !Loop through icebergs and spread mass on ocean + + !Loop through icebergs and spread mass on ocean call calculate_mass_on_ocean(bergs, with_diagnostics=.true.) - - !Finding the spread fields - if ((grd%id_spread_uvel>0) .or. (bergs%pass_fields_to_ocean_model)) then + + !Finding the spread fields + if ((grd%id_spread_uvel>0) .or. (bergs%pass_fields_to_ocean_model)) then grd%spread_uvel(:,:)=0. - call sum_up_spread_fields(bergs, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Uvel') + call sum_up_spread_fields(bergs, grd%spread_uvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Uvel') endif - if ( (grd%id_spread_vvel>0) .or. (bergs%pass_fields_to_ocean_model)) then + if ( (grd%id_spread_vvel>0) .or. (bergs%pass_fields_to_ocean_model)) then grd%spread_vvel(:,:)=0. - call sum_up_spread_fields(bergs, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Vvel') + call sum_up_spread_fields(bergs, grd%spread_vvel(grd%isc:grd%iec,grd%jsc:grd%jec), 'Vvel') endif - if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then + if ( (grd%id_spread_area>0) .or. (bergs%pass_fields_to_ocean_model)) then grd%spread_area(:,:)=0. - call sum_up_spread_fields(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec), 'area') + call sum_up_spread_fields(bergs, grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec), 'area') endif - !Always find spread_mass since it is used for so many things. + !Always find spread_mass since it is used for so many things. grd%spread_mass(:,:)=0. - call sum_up_spread_fields(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') - + call sum_up_spread_fields(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec),'mass') + !Using spread_mass_to_ocean to calculate melt rates (if this option is chosen) if (bergs%find_melt_using_spread_mass) then if (.not. bergs%Iceberg_melt_without_decay) & @@ -1463,25 +1494,25 @@ subroutine create_gridded_icebergs_fields(bergs) grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=grd%floating_melt(grd%isc:grd%iec,grd%jsc:grd%jec)*HLF !Not 100% sure this is correct. endif - !Dividng the gridded iceberg momentum diagnostic by the iceberg mass to get velocities + ! Dividing the gridded iceberg momentum diagnostic by the iceberg mass to get velocities if ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0)) then - do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec if (grd%mass(i,j)>0.) then if (grd%id_u_iceberg>0) & grd%u_iceberg(i,j)=grd%u_iceberg(i,j)/grd%mass(i,j) if (grd%id_v_iceberg>0) & grd%v_iceberg(i,j)=grd%v_iceberg(i,j)/grd%mass(i,j) else - if (grd%id_u_iceberg>0) grd%u_iceberg(i,j)=0. - if (grd%id_v_iceberg>0) grd%v_iceberg(i,j)=0. + if (grd%id_u_iceberg>0) grd%u_iceberg(i,j)=0. + if (grd%id_v_iceberg>0) grd%v_iceberg(i,j)=0. endif enddo; enddo endif - + !Calculating ustar_iceberg (gridded) grd%ustar_iceberg(:,:)=0. if ((grd%id_ustar_iceberg>0) .or. (bergs%pass_fields_to_ocean_model)) then !Update diagnostic of iceberg mass spread on ocean - do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec + do j = grd%jsc,grd%jec ; do i = grd%isc,grd%iec dvo=sqrt((grd%spread_uvel(i,j)-grd%uo(i,j))**2+(grd%spread_vvel(i,j)-grd%vo(i,j))**2) ustar = sqrt(bergs%cdrag_icebergs*(dvo**2 + bergs%utide_icebergs**2)) ustar_h = max(bergs%ustar_icebergs_bg, ustar) @@ -1494,7 +1525,7 @@ subroutine create_gridded_icebergs_fields(bergs) if (bergs%apply_thickness_cutoff_to_gridded_melt) then do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed if ((bergs%melt_cutoff >=0.) .and. (grd%spread_area(i,j)>0.)) then - ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) + ave_thickness=grd%spread_mass(i,j)/(grd%spread_area(i,j)*bergs%rho_bergs) ave_draft=ave_thickness*(bergs%rho_bergs/rho_seawater) if ((grd%ocean_depth(i,j)-ave_draft) < bergs%melt_cutoff) then grd%floating_melt(i,j)=0.0 @@ -1505,103 +1536,100 @@ subroutine create_gridded_icebergs_fields(bergs) endif end subroutine create_gridded_icebergs_fields -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thickness,basal_melt,iceberg_num) - ! Arguments - type(icebergs), pointer :: bergs - ! Local variables - real , intent(out) :: basal_melt !Melt rate underneath the icebergs - real , intent(in) :: dvo !Speed of iceberg relative to ocean mixed layer - real , intent(in) :: salt !Salinity of mixed layer - real , intent(in) :: temp !Temperature of mixed layer - real , intent(in) :: lat !Latitude (for boundary layer calculation) - integer , intent(in) :: iceberg_num !Iceberg number, used for debugging (error messages) - real , intent(in) :: thickness !Ice thickness - needed to work out the pressure below the ice - logical , intent(in) :: Use_three_equation_model !True uses the 3 equation model, False uses the 2 equation model. - - ! Local variables - real :: ustar, f_cori, absf,tfreeze - real :: Hml !Mixed layer depth - - !These could also be useful output variables if needed. - real :: t_flux, exch_vel_t, exch_vel_s,tflux_shelf,lprec - - real :: Rhoml ! Ocean mixed layer density in kg m-3. - real :: p_int ! The pressure at the ice-ocean interface, in Pa. - - real, parameter :: VK = 0.40 ! Von Karman's constant - dimensionless - real :: ZETA_N = 0.052 ! The fraction of the boundary layer over which the - ! viscosity is linearly increasing. (Was 1/8. Why?) - real, parameter :: RC = 0.20 ! critical flux Richardson number. - real :: I_ZETA_N ! The inverse of ZETA_N. - real :: I_LF ! Inverse of Latent Heat of fusion (J kg-1) - real :: I_VK ! The inverse of VK. - real :: PR, SC ! The Prandtl number and Schmidt number, nondim. -! - ! 3 equation formulation variables - real :: Sbdry ! Salinities in the ocean at the interface with the - real :: Sbdry_it ! the ice shelf, in PSU. - real :: dS_it ! The interface salinity change during an iteration, in PSU. - real :: hBL_neut ! The neutral boundary layer thickness, in m. - real :: hBL_neut_h_molec ! The ratio of the neutral boundary layer thickness - ! to the molecular boundary layer thickness, ND. - real :: wT_flux ! The vertical fluxes of heat and buoyancy just inside the - real :: wB_flux ! ocean, in C m s-1 and m2 s-3, ###CURRENTLY POSITIVE UPWARD. - real :: dB_dS ! The derivative of buoyancy with salinity, in m s-2 PSU-1. - real :: dB_dT ! The derivative of buoyancy with temperature, in m s-2 C-1. - real :: I_n_star, n_star_term - real :: dIns_dwB ! The partial derivative of I_n_star with wB_flux, in ???. - real :: dT_ustar, dS_ustar - real :: ustar_h - real :: Gam_turb - real :: Gam_mol_t, Gam_mol_s - real :: RhoCp - real :: I_RhoLF - real :: Rho0 - real :: ln_neut - real :: mass_exch - real :: Sb_min, Sb_max - real :: dS_min, dS_max - real :: density_ice -! - ! Variables used in iterating for wB_flux. - real :: wB_flux_new, DwB, dDwB_dwB_in - real :: I_Gam_T, I_Gam_S - real :: dG_dwB, iDens - logical :: Sb_min_set, Sb_max_set - logical :: out_of_bounds - - real, parameter :: c2_3 = 2.0/3.0 - integer :: it1, it3 - - !Parameters copied ice shelf module defaults (could be entered in the namelist later) - real, parameter :: dR0_dT = -0.038357 ! Partial derivative of the mixed layer density with temperature, in units of kg m-3 K-1. - real, parameter :: dR0_dS = 0.805876 ! Partial derivative of the mixed layer density with salinity, in units of kg m-3 psu-1. - real, parameter :: RHO_T0_S0 = 999.910681 ! Density of water with T=0, S=0 for linear EOS - real, parameter :: Salin_Ice =0.0 !Salinity of ice - real, parameter :: Temp_Ice = -15.0 !Salinity of ice - real, parameter :: kd_molec_salt= 8.02e-10 !The molecular diffusivity of salt in sea water at the freezing point - real, parameter :: kd_molec_temp= 1.41e-7 !The molecular diffusivity of heat in sea water at the freezing point - real, parameter :: kv_molec= 1.95e-6 !The molecular molecular kinimatic viscosity of sea water at the freezing point - real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) - real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) - real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) - real, parameter :: gamma_t = 0.0 ! Exchange velcoity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independ of u_star. - ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. - real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. - +subroutine find_basal_melt(bergs, dvo, lat, salt, temp, Use_three_equation_model, thickness, basal_melt, iceberg_num) +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +real, intent(in) :: dvo !< Speed of iceberg relative to ocean mixed layer +real, intent(in) :: lat !< Latitude (for boundary layer calculation) +real, intent(in) :: salt !< Salinity of mixed layer +real, intent(in) :: temp !< Temperature of mixed layer +logical, intent(in) :: Use_three_equation_model !< True uses the 3 equation model, False uses the 2 equation model. +real, intent(in) :: thickness !< Ice thickness - needed to work out the pressure below the ice +real, intent(out) :: basal_melt !< Melt rate underneath the icebergs +integer, intent(in) :: iceberg_num !< Iceberg number, used for debugging (error messages) +! Local variables +real :: ustar, f_cori, absf,tfreeze +real :: Hml !Mixed layer depth + +!These could also be useful output variables if needed. +real :: t_flux, exch_vel_t, exch_vel_s,tflux_shelf,lprec + +real :: Rhoml ! Ocean mixed layer density in kg m-3. +real :: p_int ! The pressure at the ice-ocean interface, in Pa. + +real, parameter :: VK = 0.40 ! Von Karman's constant - dimensionless +real :: ZETA_N = 0.052 ! The fraction of the boundary layer over which the + ! viscosity is linearly increasing. (Was 1/8. Why?) +real, parameter :: RC = 0.20 ! critical flux Richardson number. +real :: I_ZETA_N ! The inverse of ZETA_N. +real :: I_LF ! Inverse of Latent Heat of fusion (J kg-1) +real :: I_VK ! The inverse of VK. +real :: PR, SC ! The Prandtl number and Schmidt number, nondim. + +! 3 equation formulation variables +real :: Sbdry ! Salinities in the ocean at the interface with the +real :: Sbdry_it ! the ice shelf, in PSU. +real :: dS_it ! The interface salinity change during an iteration, in PSU. +real :: hBL_neut ! The neutral boundary layer thickness, in m. +real :: hBL_neut_h_molec ! The ratio of the neutral boundary layer thickness + ! to the molecular boundary layer thickness, ND. +real :: wT_flux ! The vertical fluxes of heat and buoyancy just inside the +real :: wB_flux ! ocean, in C m s-1 and m2 s-3, ###CURRENTLY POSITIVE UPWARD. +real :: dB_dS ! The derivative of buoyancy with salinity, in m s-2 PSU-1. +real :: dB_dT ! The derivative of buoyancy with temperature, in m s-2 C-1. +real :: I_n_star, n_star_term +real :: dIns_dwB ! The partial derivative of I_n_star with wB_flux, in ???. +real :: dT_ustar, dS_ustar +real :: ustar_h +real :: Gam_turb +real :: Gam_mol_t, Gam_mol_s +real :: RhoCp +real :: I_RhoLF +real :: Rho0 +real :: ln_neut +real :: mass_exch +real :: Sb_min, Sb_max +real :: dS_min, dS_max +real :: density_ice + +! Variables used in iterating for wB_flux. +real :: wB_flux_new, DwB, dDwB_dwB_in +real :: I_Gam_T, I_Gam_S +real :: dG_dwB, iDens +logical :: Sb_min_set, Sb_max_set +logical :: out_of_bounds + +real, parameter :: c2_3 = 2.0/3.0 +integer :: it1, it3 + +!Parameters copied ice shelf module defaults (could be entered in the namelist later) +real, parameter :: dR0_dT = -0.038357 ! Partial derivative of the mixed layer density with temperature, in units of kg m-3 K-1. +real, parameter :: dR0_dS = 0.805876 ! Partial derivative of the mixed layer density with salinity, in units of kg m-3 psu-1. +real, parameter :: RHO_T0_S0 = 999.910681 ! Density of water with T=0, S=0 for linear EOS +real, parameter :: Salin_Ice =0.0 !Salinity of ice +real, parameter :: Temp_Ice = -15.0 !Salinity of ice +real, parameter :: kd_molec_salt= 8.02e-10 !The molecular diffusivity of salt in sea water at the freezing point +real, parameter :: kd_molec_temp= 1.41e-7 !The molecular diffusivity of heat in sea water at the freezing point +real, parameter :: kv_molec= 1.95e-6 !The molecular molecular kinematic viscosity of sea water at the freezing point +real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) +real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) +real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) +real, parameter :: gamma_t = 0.0 ! Exchange velocity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independent of u_star. + ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. +real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! density_ice = bergs%rho_bergs Rho0=rho_seawater !Note that the ice shelf code has a default of Rho0=1035 Hml =10. !Mixed layer depth. This is an approximate value. It looks like the code is not sensitive to it (since it enters in log(Hml) p_int= p_atm+(gravity*thickness*density_ice) ! The pressure at the ice-ocean interface, in Pa. - + ! Find the ocean mixed layer density in kg m-3. call calculate_density(temp, salt, p_int, Rhoml, Rho_T0_S0, dR0_dT, dR0_dS) ! This routine finds the melt at the base of the icebergs using the 2 equation ! model or 3 equation model. This code is adapted from the ice shelf code. Once - ! the iceberg model is inside the ocean model, we should use the same code. + ! the iceberg model is inside the ocean model, we should use the same code. I_ZETA_N = 1.0 / ZETA_N I_RhoLF = 1.0/(Rho0*LF) @@ -1611,7 +1639,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic I_VK = 1.0/VK RhoCp = Rho0 * Cp_ml - !first calculate molecular component + !first calculate molecular component Gam_mol_t = 12.5 * (PR**c2_3) - 6 Gam_mol_s = 12.5 * (SC**c2_3) - 6 @@ -1630,25 +1658,24 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic f_cori=(2.*omega)*sin(pi_180*bergs%lat_ref) endif absf = abs(f_cori) !Absolute value of the Coriolis parameter - if ((absf*Hml <= VK*ustar_h) .or. (absf.eq.0.)) then + if ((absf*Hml <= VK*ustar_h) .or. (absf.eq.0.)) then hBL_neut = Hml - else - hBL_neut = (VK*ustar_h) / absf + else + hBL_neut = (VK*ustar_h) / absf endif hBL_neut_h_molec = ZETA_N * ((hBL_neut * ustar_h) / (5.0 * Kv_molec)) ln_neut = 0.0 ; if (hBL_neut_h_molec > 1.0) ln_neut = log(hBL_neut_h_molec) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (Use_three_equation_model) then ! Use 3 equation model - ! 3 equation model solves for the melt rates iteratively. This is not working right now, because we don't have access to the mixed layer - ! temperature and salinty gradients - + ! 3 equation model solves for the melt rates iteratively. This is not working right now, because we don't have access to the mixed layer + ! temperature and salinity gradients ! Guess sss as the iteration starting point for the boundary salinity. Sbdry = salt ; Sb_max_set = .false. ; Sb_min_set = .false. out_of_bounds=.false. - ! Determine the mixed layer buoyancy flux, wB_flux. + ! Determine the mixed layer buoyancy flux, wB_flux. dB_dS = (gravity / Rhoml) * dR0_dS dB_dT = (gravity / Rhoml) * dR0_dT @@ -1781,7 +1808,7 @@ subroutine find_basal_melt(bergs,dvo,lat,salt,temp,Use_three_equation_model,thic ! In the 2-equation form, the mixed layer turbulent exchange velocity ! is specified and large enough that the ocean salinity at the interface ! is about the same as the boundary layer salinity. - ! Alon: I have adapted the code so that the turbulent exchange velocoty is not constant, but rather proportional to the frictional velocity. + ! Alon: I have adapted the code so that the turbulent exchange velocoty is not constant, but rather proportional to the frictional velocity. ! This should give you the same answers as the 3 equation model when salinity gradients in the mixed layer are zero (I think/hope) ! Use 2-equation model when 3 equation version fails. @@ -1850,37 +1877,36 @@ subroutine calculate_density(T, S, pressure, rho, Rho_T0_S0, dRho_dT, dRho_dS) end subroutine calculate_density end subroutine find_basal_melt -! -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) - ! Arguments - type(iceberg), pointer :: berg - real, intent(inout) :: orientation - type(icebergs_gridded), pointer :: grd - type(iceberg), pointer :: other_berg - type(bond), pointer :: current_bond - real :: angle, lat1,lat2,lon1,lon2,dlat,dlon - real :: r_dist_x, r_dist_y - real :: lat_ref, dx_dlon, dy_dlat - real :: theta, bond_count, Average_angle - +subroutine find_orientation_using_iceberg_bonds(grd, berg, orientation) +! Arguments +type(icebergs_gridded), pointer :: grd +type(iceberg), pointer :: berg +real, intent(inout) :: orientation +! Local variables +type(iceberg), pointer :: other_berg +type(bond), pointer :: current_bond +real :: angle, lat1,lat2,lon1,lon2,dlat,dlon +real :: r_dist_x, r_dist_y +real :: lat_ref, dx_dlon, dy_dlat +real :: theta, bond_count, Average_angle + bond_count=0. Average_angle=0. - !Don't check orientation of the edges of halo, since they can contain unassosiated bonds (this is why halo width must be larger >= 2 to use bonds) - if ( ((berg%ine .gt. grd%isd) .and. (berg%ine .lt. grd%ied)) .and. ((berg%jne .ge. grd%jsd) .and. (berg%jne .le. grd%jed) ) ) then + !Don't check orientation of the edges of halo, since they can contain unassosiated bonds (this is why halo width must be larger >= 2 to use bonds) + if ( ((berg%ine .gt. grd%isd) .and. (berg%ine .lt. grd%ied)) .and. ((berg%jne .ge. grd%jsd) .and. (berg%jne .le. grd%jed) ) ) then current_bond=>berg%first_bond lat1=berg%lat lon1=berg%lon do while (associated(current_bond)) ! loop over all bonds other_berg=>current_bond%other_berg - if (.not. associated(other_berg)) then !good place for debugging + if (.not. associated(other_berg)) then !good place for debugging !One valid option: current iceberg is on the edge of halo, with other berg on the next pe (not influencing mass spreading) - !print *, 'Iceberg bond details:',berg%iceberg_num, current_bond%other_berg_num,berg%halo_berg, mpp_pe() - !print *, 'Iceberg bond details2:',berg%ine, berg%jne, current_bond%other_berg_ine, current_bond%other_berg_jne - !print *, 'Iceberg isd,ied,jsd,jed:',grd%isd, grd%ied, grd%jsd, grd%jed - !print *, 'Iceberg isc,iec,jsc,jec:',grd%isc, grd%iec, grd%jsc, grd%jec - !call error_mesg('diamonds,calculating orientation', 'Looking at bond interactions of unassosiated berg!' ,FATAL) + !print *, 'Iceberg bond details:',berg%iceberg_num, current_bond%other_berg_num,berg%halo_berg, mpp_pe() + !print *, 'Iceberg bond details2:',berg%ine, berg%jne, current_bond%other_berg_ine, current_bond%other_berg_jne + !print *, 'Iceberg isd,ied,jsd,jed:',grd%isd, grd%ied, grd%jsd, grd%jed + !print *, 'Iceberg isc,iec,jsc,jec:',grd%isc, grd%iec, grd%jsc, grd%jec + !call error_mesg('diamonds,calculating orientation', 'Looking at bond interactions of unassosiated berg!' ,FATAL) !endif else lat2=other_berg%lat @@ -1888,7 +1914,7 @@ subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) dlat=lat2-lat1 dlon=lon2-lon1 - + lat_ref=0.5*(lat1+lat2) call convert_from_grid_to_meters(lat_ref,grd%grid_is_latlon,dx_dlon,dy_dlat) r_dist_x=dlon*dx_dlon @@ -1918,26 +1944,26 @@ subroutine find_orientation_using_iceberg_bonds(grd,berg,orientation) end subroutine find_orientation_using_iceberg_bonds subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, scaling, Area, Tn) - ! Arguments - type(icebergs), pointer :: bergs - type(icebergs_gridded), pointer :: grd - type(iceberg), pointer :: berg - integer, intent(in) :: i, j - real, intent(in) :: x, y, Mberg, Mbits, scaling, Area - real, intent(in) :: Tn - ! Local variables - real :: xL, xC, xR, yD, yC, yU, Mass, L - real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR - real :: S, H, origin_x, origin_y, x0, y0 - real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex - real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) - real :: I_fraction_used !Inverse of fraction used - real :: tol - real :: Dn, Hocean - real, parameter :: rho_seawater=1035. - integer :: stderrunit - logical :: debug - real :: orientation, Mass_berg +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +type(icebergs_gridded), pointer :: grd +type(iceberg), pointer :: berg +integer, intent(in) :: i, j +real, intent(in) :: x, y, Mberg, Mbits, scaling, Area +real, intent(in) :: Tn +! Local variables +real :: xL, xC, xR, yD, yC, yU, Mass, L +real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR +real :: S, H, origin_x, origin_y, x0, y0 +real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex +real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) +real :: I_fraction_used !Inverse of fraction used +real :: tol +real :: Dn, Hocean +real, parameter :: rho_seawater=1035. +integer :: stderrunit +logical :: debug +real :: orientation, Mass_berg ! Get the stderr unit number stderrunit = stderr() @@ -1957,20 +1983,20 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, ! This line attempts to "clip" the weight felt by the ocean. The concept of ! clipping is non-physical and this step should be replaced by grounding. if (grd%clipping_depth>0.) Mass=min(Mass,grd%clipping_depth*grd%area(i,j)*rho_seawater) - - !Initialize weights for each cell + + !Initialize weights for each cell yDxL=0. ; yDxC=0. ; yDxR=0. ; yCxL=0. ; yCxR=0. yUxL=0. ; yUxC=0. ; yUxR=0. ; yCxC=1. if (.not. bergs%hexagonal_icebergs) then !Treat icebergs as rectangles of size L: (this is the default) - + !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. if (grd%area(i,j)>0) then L=min( sqrt(Area / grd%area(i,j)),1.0) - else + else L=1. endif - + if (bergs%use_old_spreading) then !Old version before icebergs were given size L xL=min(0.5, max(0., 0.5-x)) @@ -1997,17 +2023,17 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, yUxC=yU*xC*grd%msk(i ,j+1) yUxR=yU*xR*grd%msk(i+1,j+1) yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) - + fraction_used=1. !rectangular bergs do share mass with boundaries (all mass is included in cells) else !Spread mass as if elements area hexagonal - + orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) if (grd%area(i,j)>0) then H = min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ; !Non dimensionalize element length by grid area. (This gives the non-dim Apothen of the hexagon) - else + else H= (sqrt(3.)/2)*(0.49) !Largest allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) endif S=(2/sqrt(3.))*H !Side of the hexagon @@ -2022,13 +2048,13 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, origin_x=1. ; origin_y=1. if (x<0.5) origin_x=0. if (y<0.5) origin_y=0. - + !Position of the hexagon center, relative to origin at the nearest vertex x0=(x-origin_x) y0=(y-origin_y) call Hexagon_into_quadrants_using_triangles(x0,y0,H,orientation,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4) - + if (min(min(Area_Q1,Area_Q2),min(Area_Q3, Area_Q4)) <-tol) then call error_mesg('diamonds, hexagonal spreading', 'Intersection with hexagons should not be negative!!!', WARNING) write(stderrunit,*) 'diamonds, yU,yC,yD', Area_Q1, Area_Q2, Area_Q3, Area_Q4 @@ -2061,23 +2087,22 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, yDxC=Area_Q3 yDxR=Area_Q4 endif - + !Temporary for debugging reasons. - if (mpp_pe()==mpp_root_pe()) then - !write(stderrunit,*) 'diamonds, You are in the hexagonal domain now!!!' + if (mpp_pe()==mpp_root_pe()) then + !write(stderrunit,*) 'diamonds, You are in the hexagonal domain now!!!' endif - !Double check that all the mass is being used. - if ((abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>tol) .and. (mpp_pe().eq. mpp_root_pe())) then - !call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', WARNING) - write(stderrunit,*) 'diamonds, hexagonal, H,x0,y0', H, x0 , y0 - write(stderrunit,*) 'diamonds, hexagonal, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 - debug=.True. - !call Hexagon_into_quadrants_using_triangles(x0,y0,H,orientation,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4, debug) - call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) - endif + !Double check that all the mass is being used. + if ((abs(yCxC-(1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) )))>tol) .and. (mpp_pe().eq. mpp_root_pe())) then + !call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', WARNING) + write(stderrunit,*) 'diamonds, hexagonal, H,x0,y0', H, x0 , y0 + write(stderrunit,*) 'diamonds, hexagonal, Areas',(Area_Q1+Area_Q2 + Area_Q3+Area_Q4), Area_Q1, Area_Q2 , Area_Q3, Area_Q4 + debug=.True. + !call Hexagon_into_quadrants_using_triangles(x0,y0,H,orientation,Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4, debug) + call error_mesg('diamonds, hexagonal spreading', 'All the mass is not being used!!!', FATAL) + endif - !Scale each cell by (1/fraction_used) in order to redisribute ice mass which landed up on the land, back into the ocean !Note that for the square elements, the mass has already been reassigned, so fraction_used shoule be equal to 1 aready fraction_used= ((yDxL*grd%msk(i-1,j-1)) + (yDxC*grd%msk(i ,j-1)) +(yDxR*grd%msk(i+1,j-1)) +(yCxL*grd%msk(i-1,j )) + (yCxR*grd%msk(i+1,j ))& @@ -2099,14 +2124,14 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, !Spreading the iceberg y momentum onto the ocean call spread_variable_across_cells(grd,grd%Vvel_on_ocean, berg%vvel*Area*scaling , i ,j, & yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) - + end subroutine spread_mass_across_ocean_cells subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,I_fraction_used) ! Arguments type(icebergs_gridded), pointer, intent(in) :: grd - real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean + real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean real, intent(in) :: Var !Variable to be spread accross cell real, intent(in) :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR !Weights real, intent(in) :: I_fraction_used !Amount of iceberg used (inverse) @@ -2125,26 +2150,23 @@ subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & end subroutine spread_variable_across_cells - -! ############################################################################## - -real function Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) - ! Arguments - real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy +real function Area_of_triangle(Ax, Ay, Bx, By, Cx, Cy) +! Arguments +real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy Area_of_triangle = abs( 0.5*((Ax*(By-Cy))+(Bx*(Cy-Ay))+(Cx*(Ay-By))) ); end function Area_of_triangle real function roundoff(x,sig_fig) - ! Arguments - real, intent(in) :: x - integer, intent(in) :: sig_fig - !roundoff=round(x*(10**(sig_fig)) - roundoff=(FLOAT (INT(x * (10.**sig_fig) + 0.5)) / (10.**sig_fig)) +! Arguments +real, intent(in) :: x +integer, intent(in) :: sig_fig + !roundoff=round(x*(10**(sig_fig)) + roundoff=(FLOAT (INT(x * (10.**sig_fig) + 0.5)) / (10.**sig_fig)) end function roundoff -logical function point_in_interval(Ax,Ay,Bx,By,px,py) - ! Arguments - real, intent(in) :: Ax,Ay,Bx,By,px,py +logical function point_in_interval(Ax, Ay, Bx, By, px, py) +! Arguments +real, intent(in) :: Ax,Ay,Bx,By,px,py point_in_interval=.False. if ((px <= max(Ax,Bx)) .and. (px >= min(Ax,Bx))) then if ((py <= max(Ay,By)) .and. (py >= min(Ay,By))) then @@ -2153,33 +2175,33 @@ logical function point_in_interval(Ax,Ay,Bx,By,px,py) endif end function point_in_interval - logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) - ! Arguments - real, intent(in) :: Ax,Ay,Bx,By,qx,qy - real :: tol, dxc,dyc,dxl,dyl,cross - !tol=1.e-12; - tol=0.0; - dxc = qx - Ax; - dyc = qy - Ay; - dxl = Bx - Ax; - dyl = By - Ay; - cross = dxc * dyl - dyc * dxl; - if (abs(cross)<=tol) then - point_is_on_the_line=.True. - else - point_is_on_the_line=.False. - endif +! Arguments +real, intent(in) :: Ax,Ay,Bx,By,qx,qy +real :: tol, dxc,dyc,dxl,dyl,cross + !tol=1.e-12; + tol=0.0; + dxc = qx - Ax; + dyc = qy - Ay; + dxl = Bx - Ax; + dyl = By - Ay; + cross = dxc * dyl - dyc * dxl; + if (abs(cross)<=tol) then + point_is_on_the_line=.True. + else + point_is_on_the_line=.False. + endif end function point_is_on_the_line logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy) - !This function decides whether a point (qx,qy) is inside the triangle ABC. - !There is also the option to include the boundary of the triangle. - ! Arguments - real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy - real :: l0,l1,l2,p0,p1,p2 - real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 - +!This function decides whether a point (qx,qy) is inside the triangle ABC. +!There is also the option to include the boundary of the triangle. +! Arguments +real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy +! Local variables +real :: l0,l1,l2,p0,p1,p2 +real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 + point_in_triangle = .False. if ((Ax==qx .and. Ay==qy) .or. (Bx==qx .and. By==qy) .or. (Cx==qx .and. Cy==qy)) then !Exclude the pathelogical case point_in_triangle = .False. @@ -2201,16 +2223,15 @@ logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy) endif end function point_in_triangle - subroutine Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axis1,Area_positive, Area_negative) !You should change this name a little, so that it not similar the other routine. !This function calculates the area of a triangle on opposited sides of an axis when the triangle is split with two points on one side, and one point on the other. !In this fuction, A is the point on one side of the axis, and B,C are on the opposite sides - ! Arguments - real , intent(in) :: Ax,Ay,Bx,By,Cx,Cy - character , intent(in) :: axis1 - real, intent(out) :: Area_positive, Area_negative - real :: pABx, pABy, pACx, pACy, A0 - real :: A_half_triangle, A_triangle +! Arguments +real , intent(in) :: Ax,Ay,Bx,By,Cx,Cy +character , intent(in) :: axis1 +real, intent(out) :: Area_positive, Area_negative +real :: pABx, pABy, pACx, pACy, A0 +real :: A_half_triangle, A_triangle A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); @@ -2234,17 +2255,16 @@ end subroutine Area_of_triangle_across_axes subroutine intercept_of_a_line(Ax,Ay,Bx,By,axes1,x0,y0) !This routine returns the position (x0,y0) at which a line AB intercepts the x or y axis !The value No_intercept_val is returned when the line does not intercept the axis - !Arguments - real, intent(in) :: Ax,Ay,Bx,By - character, intent(in) ::axes1 - real, intent(out) :: x0,y0 - real :: No_intercept_val !Huge value used to make sure that the intercept is outside the triange in the parralel case. - +!Arguments +real, intent(in) :: Ax,Ay,Bx,By +character, intent(in) ::axes1 +real, intent(out) :: x0,y0 +real :: No_intercept_val !Huge value used to make sure that the intercept is outside the triange in the parralel case. - No_intercept_val=100000000000.; !Huge value used to make sure that the intercept is outside the triange in the parralel case. + No_intercept_val=100000000000.; !Huge value used to make sure that the intercept is outside the triange in the parralel case. x0=No_intercept_val y0=No_intercept_val - + if (axes1=='x') then !x intercept if (Ay.ne.By) then x0=Ax -(((Ax-Bx)/(Ay-By))*Ay) @@ -2260,18 +2280,16 @@ subroutine intercept_of_a_line(Ax,Ay,Bx,By,axes1,x0,y0) endif end subroutine intercept_of_a_line - subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative) -!This routine gives you the area of a triangle on opposite sides of the axis specified. +!This routine gives you the area of a triangle on opposite sides of the axis specified. !It also takes care of the special case where the triangle is totally on one side !This routine calls Area_of_triangle_across_axes to calculate the areas when the triangles are split. - - !Arguments - real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy - character, intent(in) ::axes1 - real, intent(out) :: Area_positive, Area_negative - real :: A0,B0,C0 - real A_triangle +!Arguments +real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy +character, intent(in) ::axes1 +real, intent(out) :: Area_positive, Area_negative +real :: A0,B0,C0 +real A_triangle if (axes1=='x') then !Use the y-coordinates for if statements to see which side of the line you are on A0=Ay @@ -2283,7 +2301,7 @@ subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, A B0=Bx C0=Cx endif - + A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); if ((B0*C0)>0.) then !B and C are on the same side (and non-zero) if ((A0*B0).ge.0.) then !all three on the the same side (if it equals zero, then A0=0 and the otehrs are not) @@ -2339,23 +2357,23 @@ end subroutine divding_triangle_across_axes subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4) !This routine takes a triangle, and finds the intersection with the four quadrants - !Arguments - real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy - real, intent(out) :: Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4 - real :: Area_Upper, Area_Lower, Area_Right, Area_Left - real :: px, py , qx , qy - real :: Area_key_quadrant,Error - real :: tol - integer :: Key_quadrant - integer ::sig_fig - integer :: stderrunit +!Arguments +real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy +real, intent(out) :: Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4 +real :: Area_Upper, Area_Lower, Area_Right, Area_Left +real :: px, py , qx , qy +real :: Area_key_quadrant,Error +real :: tol +integer :: Key_quadrant +integer ::sig_fig +integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() tol=1.e-10 Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); - + !Calculating area across axes call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'x',Area_Upper ,Area_Lower); call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'y',Area_Right ,Area_Left); @@ -2391,14 +2409,14 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, elseif ((px.lt.0.) .and. (qy.ge. 0.)) then !Second quadrant Key_quadrant=2 elseif ((px.lt. 0.) .and. (qy.lt. 0.)) then !Third quadrant - Key_quadrant=3; + Key_quadrant=3; elseif ((px.ge. 0.) .and. (qy.lt. 0.)) then !Forth quadrant - Key_quadrant=4 + Key_quadrant=4 else ! call error_mesg('diamonds, iceberg_run', 'None of the quadrants are Key', WARNING) write(stderrunit,*) 'diamonds, Triangle, px,qy', px,qy endif - + else !At least one quadrant is empty, and this can be used to find the areas in the other quadrant. Assigning quadrants. Key_quadrant is the empty quadrant. Area_key_quadrant=0; if ( (.not. ((((Ax>0.) .and. (Ay>0.)) .or. ((Bx>0.) .and. (By> 0.))) .or. ((Cx>0.) .and. (Cy> 0.)))) .and. ((Area_Upper+Area_Right).le.Area_triangle) ) then @@ -2420,7 +2438,7 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q2=Area_Upper-Area_Q1; Area_Q4=Area_Right-Area_Q1; !Area_Q3=Area_Left-Area_Q2; !These lines have been changes so that the sum of the 4 quadrants exactly matches the triangle area. - Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); elseif (Key_quadrant .eq. 2) then Area_Q2=Area_key_quadrant; Area_Q1=Area_Upper-Area_Q2; @@ -2464,7 +2482,6 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, endif endif - end subroutine Triangle_divided_into_four_quadrants subroutine rotate_and_translate(px,py,theta,x0,y0) @@ -2477,7 +2494,7 @@ subroutine rotate_and_translate(px,py,theta,x0,y0) !Rotation px_temp = ( cos(theta*pi/180)*px) + (sin(theta*pi/180)*py) py_temp = (-sin(theta*pi/180)*px) + (cos(theta*pi/180)*py) - + !Translation px= px_temp + x0 py= py_temp + y0 @@ -2508,7 +2525,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q !Length of side of Hexagon S=(2/sqrt(3.))*H - + !Finding positions of corners C1x=S ; C1y=0. !Corner 1 (right) C2x=H/sqrt(3.) ; C2y=H; !Corner 2 (top right) @@ -2538,8 +2555,8 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q Area_Q1=T12_Q1+T23_Q1+T34_Q1+T45_Q1+T56_Q1+T61_Q1; Area_Q2=T12_Q2+T23_Q2+T34_Q2+T45_Q2+T56_Q2+T61_Q2; Area_Q3=T12_Q3+T23_Q3+T34_Q3+T45_Q3+T56_Q3+T61_Q3; - Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; - + Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; + Area_Q1=max(Area_Q1,0.); Area_Q2=max(Area_Q2,0.); Area_Q3=max(Area_Q3,0.); @@ -2588,7 +2605,6 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q end subroutine Hexagon_into_quadrants_using_triangles - subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi) ! Arguments type(icebergs_gridded), pointer :: grd @@ -2643,7 +2659,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sss=grd%sss(i,j) ! A-grid cn=grd%cn(i,j) ! A-grid hi=grd%hi(i,j) ! A-grid - + ! Estimate SSH gradient in X direction #ifdef USE_OLD_SSH_GRADIENT dxp=0.5*(grd%dx(i+1,j)+grd%dx(i+1,j-1)) @@ -2685,7 +2701,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, #endif ! ssh_y is at the v-point on a C-grid ssh_y=yj*hxp+(1.-yj)*hxm - + ! Rotate vectors from local grid to lat/lon coordinates call rotate(uo, vo, cos_rot, sin_rot) call rotate(ui, vi, cos_rot, sin_rot) @@ -2704,7 +2720,7 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, write(stderrunit,*) 'diamonds, Error in interpolate: sst,cn,hi', sst, sss, cn, hi, mpp_pe() call error_mesg('diamonds, interp fields', 'field interpaolations has NaNs', FATAL) - endif + endif contains real function ddx_ssh(grd,i,j) @@ -2748,13 +2764,13 @@ end subroutine interp_flds subroutine calculate_mass_on_ocean(bergs, with_diagnostics) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg type(icebergs_gridded), pointer :: grd logical, intent(in) :: with_diagnostics ! Local variables -integer :: grdj, grdi -integer :: j, i +integer :: grdj, grdi +integer :: j, i ! For convenience grd=>bergs%grd @@ -2765,19 +2781,19 @@ subroutine calculate_mass_on_ocean(bergs, with_diagnostics) grd%Uvel_on_ocean(:,:,:)=0. grd%Vvel_on_ocean(:,:,:)=0. - do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 + do grdj = grd%jsc-1,grd%jec+1 ; do grdi = grd%isc-1,grd%iec+1 berg=>bergs%list(grdi,grdj)%first do while(associated(berg)) i=berg%ine ; j=berg%jne if (grd%area(i,j) > 0.) then - + !Increasing Mass on ocean if ((bergs%add_weight_to_ocean .and. .not. bergs%time_average_weight) .or.(bergs%find_melt_using_spread_mass)) then call spread_mass_across_ocean_cells(bergs, berg, berg%ine, berg%jne, berg%xi, berg%yj, berg%mass,berg%mass_of_bits, berg%mass_scaling, & berg%length*berg%width, berg%thickness) endif - !Calculated some iceberg diagnositcs + !Calculated some iceberg diagnositcs if (with_diagnostics) call calculate_sum_over_bergs_diagnositcs(bergs,grd,berg,i,j) endif @@ -2789,47 +2805,45 @@ subroutine calculate_mass_on_ocean(bergs, with_diagnostics) subroutine calculate_sum_over_bergs_diagnositcs(bergs,grd,berg,i,j) ! Arguments - type(icebergs), pointer :: bergs + type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg type(icebergs_gridded), pointer :: grd integer, intent(in) :: i, j ! Local variables real :: Abits, Lbits, Mbits - !Virtual area diagnostic - if (grd%id_virtual_area>0) then - if (bergs%bergy_bit_erosion_fraction>0.) then - Lbits=min(berg%length,berg%width,berg%thickness,40.) ! assume bergy bits are smallest dimension or 40 meters - Abits=(berg%mass_of_bits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) - else - Abits=0.0 - endif - grd%virtual_area(i,j)=grd%virtual_area(i,j)+(berg%width*berg%length+Abits)*berg%mass_scaling ! m^2 - endif - - !Mass diagnostic (also used in u_iceberg, v_iceberg - if ((grd%id_mass>0 ) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & - & grd%mass(i,j)=grd%mass(i,j)+berg%mass/grd%area(i,j)*berg%mass_scaling ! kg/m2 - - !Finding the average iceberg velocity in a grid cell (mass weighted) - if (grd%id_u_iceberg>0) & - grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%uvel) ! kg/m2 - if (grd%id_v_iceberg>0) & - grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%vvel) ! kg/m2 - - !Mass of bergy bits - if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& - & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+berg%mass_of_bits/grd%area(i,j)*berg%mass_scaling ! kg/m2 + !Virtual area diagnostic + if (grd%id_virtual_area>0) then + if (bergs%bergy_bit_erosion_fraction>0.) then + Lbits=min(berg%length,berg%width,berg%thickness,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(berg%mass_of_bits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + else + Abits=0.0 + endif + grd%virtual_area(i,j)=grd%virtual_area(i,j)+(berg%width*berg%length+Abits)*berg%mass_scaling ! m^2 + endif + + !Mass diagnostic (also used in u_iceberg, v_iceberg + if ((grd%id_mass>0 ) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & + & grd%mass(i,j)=grd%mass(i,j)+berg%mass/grd%area(i,j)*berg%mass_scaling ! kg/m2 + + !Finding the average iceberg velocity in a grid cell (mass weighted) + if (grd%id_u_iceberg>0) & + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%uvel) ! kg/m2 + if (grd%id_v_iceberg>0) & + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%vvel) ! kg/m2 + + !Mass of bergy bits + if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& + & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+berg%mass_of_bits/grd%area(i,j)*berg%mass_scaling ! kg/m2 end subroutine calculate_sum_over_bergs_diagnositcs end subroutine calculate_mass_on_ocean -! ############################################################################## - subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & stagger, stress_stagger, sss, mass_berg, ustar_berg, area_berg) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(time_type), intent(in) :: time real, dimension(:,:), intent(inout) :: calving, calving_hflx real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi @@ -2839,7 +2853,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Local variables integer :: iyr, imon, iday, ihr, imin, isec, k type(icebergs_gridded), pointer :: grd -logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality +logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off @@ -2870,9 +2884,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%bergy_src(:,:)=0. grd%bergy_melt(:,:)=0. grd%bergy_mass(:,:)=0. - grd%spread_mass_old(:,:)=0. + grd%spread_mass_old(:,:)=0. !grd%spread_mass(:,:)=0. !Don't zero this out yet, because we can first use this an add it onto the SSH - grd%spread_area(:,:)=0. + grd%spread_area(:,:)=0. grd%u_iceberg(:,:)=0. grd%v_iceberg(:,:)=0. grd%spread_uvel(:,:)=0. @@ -2880,18 +2894,18 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%ustar_iceberg(:,:)=0. grd%mass(:,:)=0. grd%virtual_area(:,:)=0. - + !Initializing _on_ocean_fields grd%mass_on_ocean(:,:,:)=0. ; grd%area_on_ocean(:,:,:)=0. grd%Uvel_on_ocean(:,:,:)=0. ; grd%Vvel_on_ocean(:,:,:)=0. - if (present(mass_berg)) then ; if (associated(mass_berg)) then + if (present(mass_berg)) then ; if (associated(mass_berg)) then mass_berg(:,:)=0.0 endif ; endif - if (present(ustar_berg)) then ; if (associated(ustar_berg)) then + if (present(ustar_berg)) then ; if (associated(ustar_berg)) then ustar_berg(:,:)=0.0 endif ; endif - if (present(area_berg)) then ; if (associated(area_berg)) then + if (present(area_berg)) then ; if (associated(area_berg)) then area_berg(:,:)=0.0 endif ; endif @@ -2930,7 +2944,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Adapt calving heat flux from coupler grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec)=calving_hflx(:,:) & ! Units of W/m2 *grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec) - + ! Adapt calving flux from coupler for use here grd%calving(grd%isc:grd%iec,grd%jsc:grd%jec)=calving(:,:) & ! Units of kg/m2/s *grd%msk(grd%isc:grd%iec,grd%jsc:grd%jec) @@ -3033,7 +3047,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%va(I,J) = mask * 0.25*((vA_tmp(i,j) + vA_tmp(i+1,j+1)) + & (vA_tmp(i+1,j) + vA_tmp(i,j+1))) enddo ; enddo - + deallocate(uA_tmp, vA_tmp) else call error_mesg('diamonds, iceberg_run', 'Unrecognized value of stress_stagger!', FATAL) @@ -3071,7 +3085,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_update_domains(grd%cn, grd%domain) grd%hi(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=hi(:,:) call mpp_update_domains(grd%hi, grd%domain) - + !Adding gridded salinity. if (present(sss)) then grd%sss(grd%isc:grd%iec,grd%jsc:grd%jec)=sss(:,:) @@ -3089,7 +3103,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%ua(i,j) = 0.0 ; grd%va(i,j) = 0.0 grd%uo(i,j) = 0.0 ; grd%vo(i,j) = 0.0 grd%ui(i,j) = 0.0 ; grd%vi(i,j) = 0.0 - grd%sst(i,j)= 0.0; grd%sss(i,j)= 0.0 + grd%sst(i,j)= 0.0; grd%sss(i,j)= 0.0 grd%cn(i,j) = 0.0 ; grd%hi(i,j) = 0.0 endif if (grd%ua(i,j) .ne. grd%ua(i,j)) grd%ua(i,j)=0. @@ -3106,7 +3120,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call bergs_chksum(bergs, 'run bergs (top)') if (debug) call checksum_gridded(bergs%grd, 'top of s/r run') - + ! Accumulate ice from calving call accumulate_calving(bergs) @@ -3158,10 +3172,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_clock_end(bergs%clock_com) !Caculate mass on ocean before thermodynamics, to use in melt rate calculation - if (bergs%find_melt_using_spread_mass) then + if (bergs%find_melt_using_spread_mass) then call calculate_mass_on_ocean(bergs, with_diagnostics=.false.) grd%spread_mass_old(:,:)=0. - call sum_up_spread_fields(bergs,grd%spread_mass_old(grd%isc:grd%iec,grd%jsc:grd%jec), 'mass') + call sum_up_spread_fields(bergs,grd%spread_mass_old(grd%isc:grd%iec,grd%jsc:grd%jec), 'mass') !Reset fields grd%mass_on_ocean(:,:,:)=0. ; grd%area_on_ocean(:,:,:)=0. grd%Uvel_on_ocean(:,:,:)=0. ; grd%Vvel_on_ocean(:,:,:)=0. @@ -3276,7 +3290,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, ! Dump icebergs to screen if (really_debug) call print_bergs(stderrunit,bergs,'icebergs_run, status') - + ! Dump icebergs bonds to screen if (really_debug) call show_all_bonds(bergs) @@ -3284,7 +3298,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !This is the point in the algorithem which determines which fields get passed to the ice model !Return what ever calving we did not use and additional icebergs melt - + !Making sure that spread_mass has the correct mass !grd%spread_mass(:,:)=0.0 !call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), within_iceberg_model=.True.) @@ -3301,24 +3315,24 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, end where calving_hflx(:,:)=grd%calving_hflx(grd%isc:grd%iec,grd%jsc:grd%jec) !Return iceberg mass, area and ustar to pass on to ocean model - if (present(mass_berg)) then + if (present(mass_berg)) then if (associated(mass_berg)) then if (bergs%add_weight_to_ocean) & mass_berg(:,:)=grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec) endif endif - if (present(ustar_berg)) then + if (present(ustar_berg)) then if (associated(ustar_berg)) then ustar_berg(:,:)=grd%ustar_iceberg(grd%isc:grd%iec,grd%jsc:grd%jec) - endif + endif endif - if (present(area_berg)) then + if (present(area_berg)) then if (associated(area_berg)) then area_berg(:,:)=grd%spread_area(grd%isc:grd%iec,grd%jsc:grd%jec) - endif + endif endif endif - + call mpp_clock_end(bergs%clock_int) ! Diagnose budgets @@ -3576,7 +3590,7 @@ end subroutine report_ibudget subroutine get_running_mean_calving(bergs,calving,calving_hflx) ! Arguments - type(icebergs), pointer :: bergs + type(icebergs), pointer :: bergs !< Container for all types and memory real, dimension(:,:), intent(inout) :: calving, calving_hflx ! Local variables real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) @@ -3619,11 +3633,9 @@ end subroutine get_running_mean_calving end subroutine icebergs_run -! ############################################################################## - subroutine icebergs_incr_mass(bergs, mass, Time) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(time_type), intent(in), optional :: Time type(icebergs_gridded), pointer :: grd integer :: i, j @@ -3635,30 +3647,29 @@ subroutine icebergs_incr_mass(bergs, mass, Time) !the add weight to ocean flag is on, and passive mode is off. It also appears to !play some role in diagnostics - if (.not. associated(bergs)) return - if (.not. bergs%add_weight_to_ocean) return - - ! For convenience - grd=>bergs%grd + if (.not. associated(bergs)) return + if (.not. bergs%add_weight_to_ocean) return + + ! For convenience + grd=>bergs%grd + + !Start the clocks + call mpp_clock_begin(bergs%clock) + call mpp_clock_begin(bergs%clock_int) - !Start the clocks - call mpp_clock_begin(bergs%clock) - call mpp_clock_begin(bergs%clock_int) + do j=grd%jsc, grd%jec; do i=grd%isc, grd%iec + if (.not. bergs%passive_mode) mass(i,j)=mass(i,j) + grd%spread_mass(i,j) + enddo ;enddo - do j=grd%jsc, grd%jec; do i=grd%isc, grd%iec - if (.not. bergs%passive_mode) mass(i,j)=mass(i,j) + grd%spread_mass(i,j) - enddo ;enddo - !Stop the clocks call mpp_clock_end(bergs%clock_int) call mpp_clock_end(bergs%clock) end subroutine icebergs_incr_mass - subroutine sum_up_spread_fields(bergs, field, field_name) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(out) :: field character(len=4), intent(in) :: field_name ! Local variables @@ -3681,7 +3692,7 @@ subroutine sum_up_spread_fields(bergs, field, field_name) if (field_name=='area') var_on_ocean(:,:,:)=grd%area_on_ocean(:,:,:) if (field_name=='Uvel') var_on_ocean(:,:,:)=grd%Uvel_on_ocean(:,:,:) if (field_name=='Vvel') var_on_ocean(:,:,:)=grd%Vvel_on_ocean(:,:,:) - + !This line has been removed, for that routine can be used for other fields !if (.not. bergs%add_weight_to_ocean) return @@ -3718,7 +3729,7 @@ subroutine sum_up_spread_fields(bergs, field, field_name) field(i,j)=dmda enddo; enddo - + if (debug) then grd%tmp(:,:)=0.; grd%tmp(grd%isc:grd%iec,grd%jsc:grd%jec)=field if (field_name=='mass') then @@ -3735,7 +3746,7 @@ end subroutine sum_up_spread_fields subroutine accumulate_calving(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd real :: remaining_dist, net_calving_used @@ -3797,7 +3808,7 @@ end subroutine accumulate_calving subroutine calve_icebergs(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd integer :: i,j,k,icnt,icntmax @@ -3895,22 +3906,20 @@ subroutine calve_icebergs(bergs) end subroutine calve_icebergs -! ############################################################################## - subroutine evolve_icebergs(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: berg -real :: uveln, vveln, lonn, latn +real :: uveln, vveln, lonn, latn real :: axn, ayn, bxn, byn ! Added by Alon - explicit and implicit accelations from the previous step real :: xi, yj integer :: i, j integer :: grdi, grdj integer :: stderrunit -logical :: bounced, interactive_icebergs_on, Runge_not_Verlet - +logical :: bounced, interactive_icebergs_on, Runge_not_Verlet + ! Get the stderr unit number stderrunit = stderr() @@ -3925,7 +3934,7 @@ subroutine evolve_icebergs(bergs) berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve - + !Checking it everything is ok: if (.not. is_point_in_cell(bergs%grd, berg%lon, berg%lat, berg%ine, berg%jne) ) then write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) @@ -3945,12 +3954,12 @@ subroutine evolve_icebergs(bergs) if (debug) call check_position(grd, berg, 'evolve_iceberg (top)') !Time stepping schemes: - if (Runge_not_Verlet) then + if (Runge_not_Verlet) then call Runge_Kutta_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) - endif - if (.not.Runge_not_Verlet) then + endif + if (.not.Runge_not_Verlet) then call verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) - endif + endif !Used for testing the ocean response to fixed iceberg motion. if (bergs%override_iceberg_velocities) then @@ -3959,10 +3968,10 @@ subroutine evolve_icebergs(bergs) endif ! Saving all the iceberg variables. - berg%axn=axn - berg%ayn=ayn - berg%bxn=bxn - berg%byn=byn + berg%axn=axn + berg%ayn=ayn + berg%bxn=bxn + berg%byn=byn berg%uvel=uveln berg%vvel=vveln @@ -3971,7 +3980,7 @@ subroutine evolve_icebergs(bergs) berg%ine=i ; berg%jne=j berg%xi=xi ; berg%yj=yj else - if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) + if (.not. interactive_icebergs_on) call update_verlet_position(bergs,berg) endif !call interp_flds(grd, i, j, xi, yj, berg%uo, berg%vo, berg%ui, berg%vi, berg%ua, berg%va, berg%ssh_x, berg%ssh_y, berg%sst) @@ -3982,15 +3991,14 @@ subroutine evolve_icebergs(bergs) enddo ! loop over all bergs enddo ; enddo - ! When we are using interactive icebergs, we update the (old) iceberg positions and velocities in a second loop, all together (to make code order invarient) if (interactive_icebergs_on) then do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%iec berg=>bergs%list(grdi,grdj)%first do while (associated(berg)) ! loop over all bergs if (berg%static_berg .lt. 0.5) then !Only allow non-static icebergs to evolve - if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) - + if (.not. Runge_not_Verlet) call update_verlet_position(bergs,berg) + !Updating old velocities (for use in iceberg interactions) berg%uvel_old=berg%uvel berg%vvel_old=berg%vvel @@ -4005,138 +4013,134 @@ subroutine evolve_icebergs(bergs) !contains end subroutine evolve_icebergs -!###################################################################### - subroutine verlet_stepping(bergs,berg, axn, ayn, bxn, byn, uveln, vveln) -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer, intent(inout) :: berg type(icebergs_gridded), pointer :: grd ! Local variables real, intent(out) :: axn, ayn, bxn, byn, uveln, vveln real :: lonn, latn real :: uvel1, vvel1, uvel2, vvel2, uvel3, vvel3 -real :: ax1, ay1 -real :: x1, y1, xddot1, yddot1, xi, yj +real :: ax1, ay1 +real :: x1, y1, xddot1, yddot1, xi, yj real :: xdot3, ydot3 real :: xdotn, ydotn real :: dt, dt_2, dt_6, dydl real :: orientation logical :: bounced, on_tangential_plane, error_flag -integer :: i, j +integer :: i, j integer :: stderrunit !Initialize variables - ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step - ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting - ! Positions and velocity is updated by - ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n - ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax - - !************************************************************************************************* + ! In this scheme a_n and b_n are saved from the previous timestep, giving the explicit and implicit parts of the acceleration, and a_np1, b_np1 are for the next time step + ! Note that ax1=a_np1/2 +b_np1, as calculated by the acceleration subrouting + ! Positions and velocity is updated by + ! X2 = X1+dt*V1+((dt^2)/2)*a_n +((dt^2)/2)*b_n = X1+dt*u_star +((dt^2)/2)*b_n + ! V2 = V1+dt/2*a_n +dt/2*a_np1 +dt*b_n = u_star + dt/2*a_np1 + dt*b_np1 = u_star +dt*ax + + !************************************************************************************************* ! Get the stderr unit number - stderrunit = stderr() + stderrunit = stderr() ! For convenience - grd=>bergs%grd + grd=>bergs%grd ! Common constants - dt=bergs%dt - dt_2=0.5*dt + dt=bergs%dt + dt_2=0.5*dt - orientation=bergs%initial_orientation - if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) + orientation=bergs%initial_orientation + if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) + + lonn = berg%lon ; latn = berg%lat + axn = berg%axn ; ayn = berg%ayn + bxn= berg%bxn ; byn = berg%byn + uvel1=berg%uvel ; vvel1=berg%vvel + i=berg%ine ; j=berg%jne + xi=berg%xi ; yj=berg%yj + + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon + + !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since + !this is only called once in Verlet stepping. + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, berg%thickness) + + ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) + call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + + !Solving for the new velocity + on_tangential_plane=.false. + if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. + if (on_tangential_plane) then + call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) + call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) + xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + else + uveln=uvel3+(dt*ax1); vveln=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln + endif - lonn = berg%lon ; latn = berg%lat - axn = berg%axn ; ayn = berg%ayn - bxn= berg%bxn ; byn = berg%byn - uvel1=berg%uvel ; vvel1=berg%vvel - i=berg%ine ; j=berg%jne - xi=berg%xi ; yj=berg%yj - - ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) - uvel3=uvel1+(dt_2*axn) !Alon - vvel3=vvel1+(dt_2*ayn) !Alon - - !Note, the mass scaling is equal to 1 (rather than 0.25 as in RK), since - !this is only called once in Verlet stepping. - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 1.0*berg%mass_scaling,berg%length*berg%width, berg%thickness) - - ! Calling the acceleration (note that the velocity is converted to u_star inside the accel script) - call accel(bergs, berg, i, j, xi, yj, latn, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn, ayn, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - - !Solving for the new velocity - on_tangential_plane=.false. - if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. - if (on_tangential_plane) then - call rotvec_to_tang(lonn,uvel3,vvel3,xdot3,ydot3) - call rotvec_to_tang(lonn,ax1,ay1,xddot1,yddot1) - xdotn=xdot3+(dt*xddot1); ydotn=ydot3+(dt*yddot1) !Alon - call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) - else - uveln=uvel3+(dt*ax1); vveln=vvel3+(dt*ay1) !Alon , we call it uvel3, vvel3 until it is put into lat/long co-ordinates, where it becomes uveln, vveln - endif + !if (berg%iceberg_num .eq. 1) print *, 'New velocity: ', uveln, vveln - !if (berg%iceberg_num .eq. 1) print *, 'New velocity: ', uveln, vveln - - !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! - error_flag=.false. - if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%sss, 'sss') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lonn=',lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: iceberg_num=',berg%iceberg_num - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& - & dt*ax1 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& - & dt*ay1 - write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj) - call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,explain=.true.) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - endif + !!!!!!!!!!!!!!! Debugging !!!!!!!!!!!!!!!!!!!!!!!!!!! + error_flag=.false. + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lonn=',lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: latn=',latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u3,un,u0=',uvel3,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v3,vn,v0=',vvel3,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: iceberg_num=',berg%iceberg_num + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1=',& + & dt*ax1 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1=',& + & dt*ay1 + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lonn, latn, i, j, xi, yj) + call accel(bergs, berg, i, j, xi, yj, latn, uvel3, vvel3, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j,explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif end subroutine verlet_stepping -!###################################################################### - subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lonn, latn, i, j, xi, yj) -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer, intent(inout) :: berg type(icebergs_gridded), pointer :: grd real , intent(out) :: axn, ayn, bxn, byn, uveln, vveln,lonn, latn, xi, yj integer, intent(out) :: i, j -real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axn1, ayn1 +real :: uvel1, vvel1, lon1, lat1, u1, v1, dxdl1, ax1, ay1, axn1, ayn1 real :: uvel2, vvel2, lon2, lat2, u2, v2, dxdl2, ax2, ay2, axn2, ayn2 real :: uvel3, vvel3, lon3, lat3, u3, v3, dxdl3, ax3, ay3, axn3, ayn3 real :: uvel4, vvel4, lon4, lat4, u4, v4, dxdl4, ax4, ay4, axn4, ayn4 -real :: x1, xdot1, xddot1, y1, ydot1, yddot1, xddot1n, yddot1n +real :: x1, xdot1, xddot1, y1, ydot1, yddot1, xddot1n, yddot1n real :: x2, xdot2, xddot2, y2, ydot2, yddot2, xddot2n, yddot2n real :: x3, xdot3, xddot3, y3, ydot3, yddot3, xddot3n, yddot3n real :: x4, xdot4, xddot4, y4, ydot4, yddot4, xddot4n, yddot4n @@ -4160,317 +4164,313 @@ subroutine Runge_Kutta_stepping(bergs, berg, axn, ayn, bxn, byn, uveln, vveln,lo ! Get the stderr unit number - stderrunit = stderr() + stderrunit = stderr() ! For convenience - grd=>bergs%grd + grd=>bergs%grd ! Common constants - dt=bergs%dt - dt_2=0.5*dt - dt_6=dt/6. - - i=berg%ine - j=berg%jne - xi=berg%xi - yj=berg%yj - bounced=.false. - on_tangential_plane=.false. - if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. - i1=i;j1=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) - - ! Loading past accelerations - Alon - axn=berg%axn; ayn=berg%ayn !Alon - axn1=axn; axn2=axn; axn3=axn; axn4=axn - ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn - - ! A1 = A(X1) - lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) - - call convert_from_meters_to_grid(lat1,bergs%grd%grid_is_latlon ,dxdl1,dydl) - !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - !dydl=r180_pi/Rearth - uvel1=berg%uvel; vvel1=berg%vvel - if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) - u1=uvel1*dxdl1; v1=vvel1*dydl - - call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon - !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 - if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) - if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon - - ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) - !if (debug) write(stderr(),*) 'diamonds, evolve: x2=...' - if (on_tangential_plane) then - x2=x1+dt_2*xdot1; y2=y1+dt_2*ydot1 - xdot2=xdot1+dt_2*xddot1; ydot2=ydot1+dt_2*yddot1 - call rotpos_from_tang(x2,y2,lon2,lat2) - call rotvec_from_tang(lon2,xdot2,ydot2,uvel2,vvel2) - else - lon2=lon1+dt_2*u1; lat2=lat1+dt_2*v1 - uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) - i2=i; j2=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%sss, 'sss') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2=',lon1,lon2,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2=',lat1,lat2,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u0=',uvel1,uvel2,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v0=',vvel1,vvel2,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2=',dt*ax1,dt*ax2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2=',dt*ay1,dt*ay2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u0=',dt*uvel1,dt*uvel2,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v0=',dt*vvel1,dt*vvel2,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) - endif - call convert_from_meters_to_grid(lat2,bergs%grd%grid_is_latlon ,dxdl2,dydl) - !dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) - u2=uvel2*dxdl2; v2=vvel2*dydl - call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 - if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) - if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon - - ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) - !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' - if (on_tangential_plane) then - x3=x1+dt_2*xdot2; y3=y1+dt_2*ydot2 - xdot3=xdot1+dt_2*xddot2; ydot3=ydot1+dt_2*yddot2 - call rotpos_from_tang(x3,y3,lon3,lat3) - call rotvec_from_tang(lon3,xdot3,ydot3,uvel3,vvel3) - else - lon3=lon1+dt_2*u2; lat3=lat1+dt_2*v2 - uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) - i3=i; j3=j - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%sss, 'sss') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i=',i1,i2,i3,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j=',j1,j2,j3,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3=',lon1,lon2,lon3,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3=',lat1,lat2,lat3,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u0=',uvel1,uvel2,uvel3,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v0=',vvel1,vvel2,vvel3,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3=',dt*ax1,dt*ax2,dt*ax3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3=',dt*ay1,dt*ay2,dt*ay3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) - endif - call convert_from_meters_to_grid(lat3,bergs%grd%grid_is_latlon ,dxdl3,dydl) - !dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) - u3=uvel3*dxdl3; v3=vvel3*dydl - call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) - if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon - - ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) - !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' - if (on_tangential_plane) then - x4=x1+dt*xdot3; y4=y1+dt*ydot3 - xdot4=xdot1+dt*xddot3; ydot4=ydot1+dt*yddot3 - call rotpos_from_tang(x4,y4,lon4,lat4) - call rotvec_from_tang(lon4,xdot4,ydot4,uvel4,vvel4) - else - lon4=lon1+dt*u3; lat4=lat1+dt*v3 - uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 - endif - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) - i4=i; j4=j - ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) - if (.not.error_flag) then - if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%sss, 'sss') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4=',lon1,lon2,lon3,lon4,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4=',lat1,lat2,lat3,lat4,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,u0=',uvel1,uvel2,uvel3,uvel4,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,v0=',vvel1,vvel2,vvel3,vvel4,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4=',dt*ax1,dt*ax2,dt*ax3,dt*ax4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4=',dt*ay1,dt*ay2,dt*ay3,dt*ay4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon - call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) - call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) - endif - call convert_from_meters_to_grid(lat4,bergs%grd%grid_is_latlon ,dxdl4,dydl) - !dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) - u4=uvel4*dxdl4; v4=vvel4*dydl - call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon - if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) - if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) - - ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 - ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 - if (on_tangential_plane) then - xn=x1+dt_6*( (xdot1+xdot4)+2.*(xdot2+xdot3) ) - yn=y1+dt_6*( (ydot1+ydot4)+2.*(ydot2+ydot3) ) - xdotn=xdot1+dt_6*( (xddot1+xddot4)+2.*(xddot2+xddot3) ) - ydotn=ydot1+dt_6*( (yddot1+yddot4)+2.*(yddot2+yddot3) ) - xddotn=( (xddot1n+xddot4n)+2.*(xddot2n+xddot3n) )/6. !Alon - yddotn=( (yddot1n+yddot4n)+2.*(yddot2n+yddot3n) )/6. !Alon - call rotpos_from_tang(xn,yn,lonn,latn) - call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) - call rotvec_from_tang(lonn,xddotn,yddotn,axn,ayn) !Alon - else - lonn=berg%lon+dt_6*( (u1+u4)+2.*(u2+u3) ) - latn=berg%lat+dt_6*( (v1+v4)+2.*(v2+v3) ) - uveln=berg%uvel+dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) - vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) - axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon - ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon - bxn=(((ax1+ax4)+2.*(ax2+ax3) )/6) - (axn/2) - byn=(((ay1+ay4)+2.*(ay2+ay3) )/6) - (ayn/2) - - endif - - - - i=i1;j=j1;xi=berg%xi;yj=berg%yj - call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) - if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & - call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) - - if (.not.error_flag) then - if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. - endif - if (error_flag) then - call print_fld(grd, grd%msk, 'msk') - call print_fld(grd, grd%ssh, 'ssh') - call print_fld(grd, grd%sst, 'sst') - call print_fld(grd, grd%sss, 'sss') - call print_fld(grd, grd%hi, 'hi') - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i - write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4,lonn=',lon1,lon2,lon3,lon4,lonn,berg%lon - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4,latn=',lat1,lat2,lat3,lat4,latn,berg%lat - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,un,u0=',uvel1,uvel2,uvel3,uvel4,uveln,berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,vn,v0=',vvel1,vvel2,vvel3,vvel4,vveln,berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4,axn=',& - & dt*ax1,dt*ax2,dt*ax3,dt*ax4,dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4,ayn=',& - & dt*ay1,dt*ay2,dt*ay3,dt*ay4,dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,un,u0=',& - & dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*uveln,dt*berg%uvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,vn,v0=',& - & dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*vveln,dt*berg%vvel - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u_rk (deg)=',& - & dt*u1,dt*u2,dt*u3,dt*u4,dt_6*( (u1+u4)+2.*(u2+u3) ) - write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v_rk (deg)=',& - & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) - write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane - write(stderrunit,*) 'Acceleration terms for position 1' - error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) - call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 2' - error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) - call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 3' - error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) - call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,*) 'Acceleration terms for position 4' - error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) - call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon - write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj - write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) - call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') - bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) - if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) - enddo - write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) - do j=grd%jed,grd%jsd,-1 - write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) - enddo - endif -end subroutine Runge_Kutta_stepping + dt=bergs%dt + dt_2=0.5*dt + dt_6=dt/6. + + i=berg%ine + j=berg%jne + xi=berg%xi + yj=berg%yj + bounced=.false. + on_tangential_plane=.false. + if ((berg%lat>89.) .and. (bergs%grd%grid_is_latlon)) on_tangential_plane=.true. + i1=i;j1=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) + + ! Loading past accelerations - Alon + axn=berg%axn; ayn=berg%ayn !Alon + axn1=axn; axn2=axn; axn3=axn; axn4=axn + ayn1=ayn; ayn2=ayn; ayn3=ayn; ayn4=ayn + + ! A1 = A(X1) + lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1) + + call convert_from_meters_to_grid(lat1,bergs%grd%grid_is_latlon ,dxdl1,dydl) + !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + !dydl=r180_pi/Rearth + uvel1=berg%uvel; vvel1=berg%vvel + if (on_tangential_plane) call rotvec_to_tang(lon1,uvel1,vvel1,xdot1,ydot1) + u1=uvel1*dxdl1; v1=vvel1*dydl + + call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn) !axn,ayn, bxn, byn - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt, ax1, ay1, axn1, ayn1, bxn, byn) !Note change to dt. Markpoint_1 + if (on_tangential_plane) call rotvec_to_tang(lon1,ax1,ay1,xddot1,yddot1) + if (on_tangential_plane) call rotvec_to_tang(lon1,axn1,ayn1,xddot1n,yddot1n) !Alon + + ! X2 = X1+dt/2*V1 ; V2 = V1+dt/2*A1; A2=A(X2) + !if (debug) write(stderr(),*) 'diamonds, evolve: x2=...' + if (on_tangential_plane) then + x2=x1+dt_2*xdot1; y2=y1+dt_2*ydot1 + xdot2=xdot1+dt_2*xddot1; ydot2=ydot1+dt_2*yddot1 + call rotpos_from_tang(x2,y2,lon2,lat2) + call rotvec_from_tang(lon2,xdot2,ydot2,uvel2,vvel2) + else + lon2=lon1+dt_2*u1; lat2=lat1+dt_2*v1 + uvel2=uvel1+dt_2*ax1; vvel2=vvel1+dt_2*ay1 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon2, lat2, uvel2, vvel2, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) + i2=i; j2=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon2,lat2,x2,y2) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon2, lat2, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i=',i1,i2,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j=',j1,j2,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2=',lon1,lon2,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2=',lat1,lat2,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u0=',uvel1,uvel2,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v0=',vvel1,vvel2,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2=',dt*ax1,dt*ax2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2=',dt*ay1,dt*ay2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u0=',dt*uvel1,dt*uvel2,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v0=',dt*vvel1,dt*vvel2,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2 (deg)=',dt*u1,dt*u2 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2 (deg)=',dt*v1,dt*v2 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn,- Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 2') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos2 i,j,lon,lat,xi,yj=',i,j,lon2,lat2,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos2 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 2!',FATAL) + endif + call convert_from_meters_to_grid(lat2,bergs%grd%grid_is_latlon ,dxdl2,dydl) + !dxdl2=r180_pi/(Rearth*cos(lat2*pi_180)) + u2=uvel2*dxdl2; v2=vvel2*dydl + call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + !call accel(bergs, berg, i, j, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt, ax2, ay2, axn2, ayn2, bxn, byn) !Note change to dt. Markpoint_1 + if (on_tangential_plane) call rotvec_to_tang(lon2,ax2,ay2,xddot2,yddot2) + if (on_tangential_plane) call rotvec_to_tang(lon2,axn2,ayn2,xddot2n,yddot2n) !Alon + + ! X3 = X1+dt/2*V2 ; V3 = V1+dt/2*A2; A3=A(X3) + !if (debug) write(stderr(),*) 'diamonds, evolve: x3=...' + if (on_tangential_plane) then + x3=x1+dt_2*xdot2; y3=y1+dt_2*ydot2 + xdot3=xdot1+dt_2*xddot2; ydot3=ydot1+dt_2*yddot2 + call rotpos_from_tang(x3,y3,lon3,lat3) + call rotvec_from_tang(lon3,xdot3,ydot3,uvel3,vvel3) + else + lon3=lon1+dt_2*u2; lat3=lat1+dt_2*v2 + uvel3=uvel1+dt_2*ax2; vvel3=vvel1+dt_2*ay2 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon3, lat3, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) + i3=i; j3=j + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon3,lat3,x3,y3) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon3, lat3, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i=',i1,i2,i3,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j=',j1,j2,j3,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3=',lon1,lon2,lon3,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3=',lat1,lat2,lat3,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u0=',uvel1,uvel2,uvel3,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v0=',vvel1,vvel2,vvel3,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3=',dt*ax1,dt*ax2,dt*ax3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3=',dt*ay1,dt*ay2,dt*ay3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3 (deg)=',dt*u1,dt*u2,dt*u3 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3 (deg)=',dt*v1,dt*v2,dt*v3 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 3') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos3 i,j,lon,lat,xi,yj=',i,j,lon3,lat3,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos3 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j,explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 3!',FATAL) + endif + call convert_from_meters_to_grid(lat3,bergs%grd%grid_is_latlon ,dxdl3,dydl) + !dxdl3=r180_pi/(Rearth*cos(lat3*pi_180)) + u3=uvel3*dxdl3; v3=vvel3*dydl + call accel(bergs, berg, i, j, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + if (on_tangential_plane) call rotvec_to_tang(lon3,ax3,ay3,xddot3,yddot3) + if (on_tangential_plane) call rotvec_to_tang(lon3,axn3,ayn3,xddot3n,yddot3n) !Alon + + ! X4 = X1+dt*V3 ; V4 = V1+dt*A3; A4=A(X4) + !if (debug) write(stderr(),*) 'diamonds, evolve: x4=...' + if (on_tangential_plane) then + x4=x1+dt*xdot3; y4=y1+dt*ydot3 + xdot4=xdot1+dt*xddot3; ydot4=ydot1+dt*yddot3 + call rotpos_from_tang(x4,y4,lon4,lat4) + call rotvec_from_tang(lon4,xdot4,ydot4,uvel4,vvel4) + else + lon4=lon1+dt*u3; lat4=lat1+dt*v3 + uvel4=uvel1+dt*ax3; vvel4=vvel1+dt*ay3 + endif + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lon4, lat4, uvel4, vvel4, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) + i4=i; j4=j + ! if (bounced.and.on_tangential_plane) call rotpos_to_tang(lon4,lat4,x4,y4) + if (.not.error_flag) then + if (debug .and. .not. is_point_in_cell(bergs%grd, lon4, lat4, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4=',lon1,lon2,lon3,lon4,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4=',lat1,lat2,lat3,lat4,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,u0=',uvel1,uvel2,uvel3,uvel4,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,v0=',vvel1,vvel2,vvel3,vvel4,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4=',dt*ax1,dt*ax2,dt*ax3,dt*ax4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4=',dt*ay1,dt*ay2,dt*ay3,dt*ay4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u0=',dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v0=',dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4 (deg)=',dt*u1,dt*u2,dt*u3,dt*u4 + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4 (deg)=',dt*v1,dt*v2,dt*v3,dt*v4 + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn1, ayn1, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn2, ayn2, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 3' + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn3, ayn3, bxn, byn, debug_flag=.true.) !axn, ayn, bxn, byn - Added by Alon + call print_berg(stderrunit, berg, 'evolve_iceberg, out of position at 4') + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'pos4 i,j,lon,lat,xi,yj=',i,j,lon4,lat4,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'pos4 box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + bounced=is_point_in_cell(bergs%grd, lon2, lat2, i, j, explain=.true.) + call error_mesg('diamonds, evolve_iceberg','berg is out of posn at 4!',FATAL) + endif + call convert_from_meters_to_grid(lat4,bergs%grd%grid_is_latlon ,dxdl4,dydl) + !dxdl4=r180_pi/(Rearth*cos(lat4*pi_180)) + u4=uvel4*dxdl4; v4=vvel4*dydl + call accel(bergs, berg, i, j, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn4, ayn4, bxn, byn) !axn, ayn, bxn, byn - Added by Alon + if (on_tangential_plane) call rotvec_to_tang(lon4,ax4,ay4,xddot4,yddot4) + if (on_tangential_plane) call rotvec_to_tang(lon4,axn4,ayn4,xddot4n,yddot4n) + + ! Xn = X1+dt*(V1+2*V2+2*V3+V4)/6 + ! Vn = V1+dt*(A1+2*A2+2*A3+A4)/6 + if (on_tangential_plane) then + xn=x1+dt_6*( (xdot1+xdot4)+2.*(xdot2+xdot3) ) + yn=y1+dt_6*( (ydot1+ydot4)+2.*(ydot2+ydot3) ) + xdotn=xdot1+dt_6*( (xddot1+xddot4)+2.*(xddot2+xddot3) ) + ydotn=ydot1+dt_6*( (yddot1+yddot4)+2.*(yddot2+yddot3) ) + xddotn=( (xddot1n+xddot4n)+2.*(xddot2n+xddot3n) )/6. !Alon + yddotn=( (yddot1n+yddot4n)+2.*(yddot2n+yddot3n) )/6. !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + call rotvec_from_tang(lonn,xdotn,ydotn,uveln,vveln) + call rotvec_from_tang(lonn,xddotn,yddotn,axn,ayn) !Alon + else + lonn=berg%lon+dt_6*( (u1+u4)+2.*(u2+u3) ) + latn=berg%lat+dt_6*( (v1+v4)+2.*(v2+v3) ) + uveln=berg%uvel+dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) + vveln=berg%vvel+dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) + axn=( (axn1+axn4)+2.*(axn2+axn3) )/6. !Alon + ayn=( (ayn1+ayn4)+2.*(ayn2+ayn3) )/6. !Alon + bxn=(((ax1+ax4)+2.*(ax2+ax3) )/6) - (axn/2) + byn=(((ay1+ay4)+2.*(ay2+ay3) )/6) - (ayn/2) + endif + + i=i1;j=j1;xi=berg%xi;yj=berg%yj + call adjust_index_and_ground(grd, lonn, latn, uveln, vveln, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) + if (bergs%add_weight_to_ocean .and. bergs%time_average_weight) & + call spread_mass_across_ocean_cells(bergs, berg, i, j, xi, yj, berg%mass, berg%mass_of_bits, 0.25*berg%mass_scaling,berg%length*berg%width, berg%thickness) + if (.not.error_flag) then + if (.not. is_point_in_cell(bergs%grd, lonn, latn, i, j)) error_flag=.true. + endif + if (error_flag) then + call print_fld(grd, grd%msk, 'msk') + call print_fld(grd, grd%ssh, 'ssh') + call print_fld(grd, grd%sst, 'sst') + call print_fld(grd, grd%sss, 'sss') + call print_fld(grd, grd%hi, 'hi') + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: isd,isc,iec,ied=',grd%isd,grd%isc,grd%iec,grd%ied + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: jsd,jsc,jec,jed=',grd%jsd,grd%jsc,grd%jec,grd%jed + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: i1,i2,i3,i4,i=',i1,i2,i3,i4,i + write(stderrunit,'(a,6i5)') 'diamonds, evolve_iceberg: j1,j2,j3,j4,j=',j1,j2,j3,j4,j + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lon1,lon2,lon3,lon4,lonn=',lon1,lon2,lon3,lon4,lonn,berg%lon + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: lat1,lat2,lat3,lat4,latn=',lat1,lat2,lat3,lat4,latn,berg%lat + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: u1,u2,u3,u4,un,u0=',uvel1,uvel2,uvel3,uvel4,uveln,berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: v1,v2,v3,v4,vn,v0=',vvel1,vvel2,vvel3,vvel4,vveln,berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ax1,ax2,ax3,ax4,axn=',& + & dt*ax1,dt*ax2,dt*ax3,dt*ax4,dt_6*( (ax1+ax4)+2.*(ax2+ax3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* ay1,ay2,ay3,ay4,ayn=',& + & dt*ay1,dt*ay2,dt*ay3,dt*ay4,dt_6*( (ay1+ay4)+2.*(ay2+ay3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,un,u0=',& + & dt*uvel1,dt*uvel2,dt*uvel3,dt*uvel4,dt*uveln,dt*berg%uvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,vn,v0=',& + & dt*vvel1,dt*vvel2,dt*vvel3,dt*vvel4,dt*vveln,dt*berg%vvel + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* u1,u2,u3,u4,u_rk (deg)=',& + & dt*u1,dt*u2,dt*u3,dt*u4,dt_6*( (u1+u4)+2.*(u2+u3) ) + write(stderrunit,'(a,6es9.3)') 'diamonds, evolve_iceberg: dt* v1,v2,v3,v4,v_rk (deg)=',& + & dt*v1,dt*v2,dt*v3,dt*v4,dt_6*( (v1+v4)+2.*(v2+v3) ) + write(stderrunit,*) 'diamonds, evolve_iceberg: on_tangential_plane=',on_tangential_plane + write(stderrunit,*) 'Acceleration terms for position 1' + error_flag=pos_within_cell(grd, lon1, lat1, i1, j1, xi, yj) + call accel(bergs, berg, i1, j1, xi, yj, lat1, uvel1, vvel1, uvel1, vvel1, dt_2, ax1, ay1, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 2' + error_flag=pos_within_cell(grd, lon2, lat2, i2, j2, xi, yj) + call accel(bergs, berg, i2, j2, xi, yj, lat2, uvel2, vvel2, uvel1, vvel1, dt_2, ax2, ay2, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 3' + error_flag=pos_within_cell(grd, lon3, lat3, i3, j3, xi, yj) + call accel(bergs, berg, i3, j3, xi, yj, lat3, uvel3, vvel3, uvel1, vvel1, dt, ax3, ay3, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,*) 'Acceleration terms for position 4' + error_flag=pos_within_cell(grd, lon4, lat4, i4, j4, xi, yj) + call accel(bergs, berg, i4, j4, xi, yj, lat4, uvel4, vvel4, uvel1, vvel1, dt, ax4, ay4, axn, ayn, bxn, byn, debug_flag=.true.) !axn, ayn - Added by Alon + write(stderrunit,'(a,i3,a,2i4,4f8.3)') 'pe=',mpp_pe(),'posn i,j,lon,lat,xi,yj=',i,j,lonn,latn,xi,yj + write(stderrunit,'(a,i3,a,4f8.3)') 'pe=',mpp_pe(),'posn box=',grd%lon(i-1,j-1),grd%lon(i,j),grd%lat(i-1,j-1),grd%lat(i,j) + call print_berg(stderrunit, berg, 'evolve_iceberg, out of cell at end!') + bounced=is_point_in_cell(bergs%grd, lonn, latn, i, j, explain=.true.) + if (debug) call error_mesg('diamonds, evolve_iceberg','berg is out of posn at end!',FATAL) + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lon',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lon(i,j),i=grd%isd,grd%ied) + enddo + write(stderrunit,'(i4,a4,32i7)') mpp_pe(),'Lat',(i,i=grd%isd,grd%ied) + do j=grd%jed,grd%jsd,-1 + write(stderrunit,'(2i4,32f7.1)') mpp_pe(),j,(grd%lat(i,j),i=grd%isd,grd%ied) + enddo + endif +end subroutine Runge_Kutta_stepping !####################################################################### !MP6 subroutine update_verlet_position(bergs,berg) -type(icebergs), intent(in), pointer :: bergs -type(iceberg), intent(in), pointer :: berg +type(icebergs), intent(in), pointer :: bergs +type(iceberg), intent(in), pointer :: berg type(icebergs_gridded), pointer :: grd !Local variable real :: lonn, latn @@ -4487,111 +4487,111 @@ subroutine update_verlet_position(bergs,berg) integer :: stderrunit ! Get the stderr unit number - stderrunit = stderr() + stderrunit = stderr() ! For convenience - grd=>bergs%grd + grd=>bergs%grd ! Common constants dt=bergs%dt dt_2=0.5*dt - on_tangential_plane=.false. - if ((berg%lat>89.) .and. (grd%grid_is_latlon)) on_tangential_plane=.true. - - lon1=berg%lon; lat1=berg%lat - if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1,berg%iceberg_num) - !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) - !dydl=r180_pi/Rearth - call convert_from_meters_to_grid(lat1,grd%grid_is_latlon ,dxdl1,dydl) - uvel1=berg%uvel; vvel1=berg%vvel - - ! Loading past acceleartions - Alon - axn=berg%axn; ayn=berg%ayn !Alon - bxn=berg%bxn; byn=berg%byn !Alon - - ! Velocities used to update the position - uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon - vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon - - !dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) - - if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) - u2=uvel2*dxdl1; v2=vvel2*dydl - - ! Solving for new position - if (on_tangential_plane) then - xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon - call rotpos_from_tang(xn,yn,lonn,latn) - else - lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon - endif - - ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) - uvel3=uvel1+(dt_2*axn) !Alon - vvel3=vvel1+(dt_2*ayn) !Alon - - ! Adjusting mass... - !MP3 - i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj - call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) !Alon:"unclear which velocity to use here?" - - !if (bounced) then - ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag - ! berg%axn=0.0 ; berg%ayn=0.0 - ! berg%bxn=0.0 ; berg%byn=0.0 - ! berg%uvel=0.0 ; berg%vvel=0.0 - !endif + on_tangential_plane=.false. + if ((berg%lat>89.) .and. (grd%grid_is_latlon)) on_tangential_plane=.true. + + lon1=berg%lon; lat1=berg%lat + if (on_tangential_plane) call rotpos_to_tang(lon1,lat1,x1,y1,berg%iceberg_num) + !dxdl1=r180_pi/(Rearth*cos(lat1*pi_180)) + !dydl=r180_pi/Rearth + call convert_from_meters_to_grid(lat1,grd%grid_is_latlon ,dxdl1,dydl) + uvel1=berg%uvel; vvel1=berg%vvel + + ! Loading past acceleartions - Alon + axn=berg%axn; ayn=berg%ayn !Alon + bxn=berg%bxn; byn=berg%byn !Alon + + ! Velocities used to update the position + uvel2=uvel1+(dt_2*axn)+(dt_2*bxn) !Alon + vvel2=vvel1+(dt_2*ayn)+(dt_2*byn) !Alon + + !dx=(dt*(uvel1+(dt_2*axn)+(dt_2*bxn))) + + if (on_tangential_plane) call rotvec_to_tang(lon1,uvel2,vvel2,xdot2,ydot2) + u2=uvel2*dxdl1; v2=vvel2*dydl + + ! Solving for new position + if (on_tangential_plane) then + xn=x1+(dt*xdot2) ; yn=y1+(dt*ydot2) !Alon + call rotpos_from_tang(xn,yn,lonn,latn) + else + lonn=lon1+(dt*u2) ; latn=lat1+(dt*v2) !Alon + endif + + ! Turn the velocities into u_star, v_star.(uvel3 is v_star) - Alon (not sure how this works with tangent plane) + uvel3=uvel1+(dt_2*axn) !Alon + vvel3=vvel1+(dt_2*ayn) !Alon - !Updating positions and index - berg%lon=lonn ; berg%lat=latn - berg%ine=i ; berg%jne=j - berg%xi=xi ; berg%yj=yj + ! Adjusting mass... + !MP3 + i=berg%ine; j=berg%jne; xi = berg%xi; yj = berg%yj + call adjust_index_and_ground(grd, lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag, berg%iceberg_num) !Alon:"unclear which velocity to use here?" + + !if (bounced) then + ! print *, 'you have been bounce: big time!',mpp_pe(),berg%iceberg_num,lonn, latn, uvel3, vvel3, i, j, xi, yj, bounced, error_flag + ! berg%axn=0.0 ; berg%ayn=0.0 + ! berg%bxn=0.0 ; berg%byn=0.0 + ! berg%uvel=0.0 ; berg%vvel=0.0 + !endif + + !Updating positions and index + berg%lon=lonn ; berg%lat=latn + berg%ine=i ; berg%jne=j + berg%xi=xi ; berg%yj=yj end subroutine update_verlet_position !####################################################################### - subroutine rotpos_from_tang(x, y, lon, lat) +subroutine rotpos_from_tang(x, y, lon, lat) ! Arguments real, intent(in) :: x, y real, intent(out) :: lon, lat ! Local variables real :: r - r=sqrt(x**2+y**2) - lat=90.-(r180_pi*r/Rearth) - lon=r180_pi*acos(x/r)*sign(1.,y) + r=sqrt(x**2+y**2) + lat=90.-(r180_pi*r/Rearth) + lon=r180_pi*acos(x/r)*sign(1.,y) - end subroutine rotpos_from_tang +end subroutine rotpos_from_tang - subroutine rotvec_to_tang(lon, uvel, vvel, xdot, ydot) +subroutine rotvec_to_tang(lon, uvel, vvel, xdot, ydot) ! Arguments real, intent(in) :: lon, uvel, vvel real, intent(out) :: xdot, ydot ! Local variables real :: clon,slon - clon=cos(lon*pi_180) - slon=sin(lon*pi_180) - xdot=-slon*uvel-clon*vvel - ydot=clon*uvel-slon*vvel + clon=cos(lon*pi_180) + slon=sin(lon*pi_180) + xdot=-slon*uvel-clon*vvel + ydot=clon*uvel-slon*vvel - end subroutine rotvec_to_tang +end subroutine rotvec_to_tang - subroutine rotvec_from_tang(lon, xdot, ydot, uvel, vvel) +subroutine rotvec_from_tang(lon, xdot, ydot, uvel, vvel) ! Arguments real, intent(in) :: lon, xdot, ydot real, intent(out) :: uvel, vvel ! Local variables real :: clon,slon - clon=cos(lon*pi_180) - slon=sin(lon*pi_180) - uvel=-slon*xdot+clon*ydot - vvel=-clon*xdot-slon*ydot + clon=cos(lon*pi_180) + slon=sin(lon*pi_180) + uvel=-slon*xdot+clon*ydot + vvel=-clon*xdot-slon*ydot - end subroutine rotvec_from_tang +end subroutine rotvec_from_tang ! ############################################################################## @@ -4611,7 +4611,7 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun logical :: point_in_cell_using_xi_yj ! Get the stderr unit number - stderrunit = stderr() + stderrunit = stderr() bounced=.false. error=.false. @@ -4783,9 +4783,9 @@ subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, boun if (debug) then write(stderrunit,*) 'diamonds, adjust: lon0, lat0=',lon0,lat0 write(stderrunit,*) 'diamonds, adjust: xi0, yj0=',xi0,yj0 - write(stderrunit,*) 'diamonds, adjust: i0,j0=',i0,j0 + write(stderrunit,*) 'diamonds, adjust: i0,j0=',i0,j0 write(stderrunit,*) 'diamonds, adjust: lon, lat=',lon,lat - write(stderrunit,*) 'diamonds, adjust: xi,yj=',xi,yj + write(stderrunit,*) 'diamonds, adjust: xi,yj=',xi,yj write(stderrunit,*) 'diamonds, adjust: i,j=',i,j write(stderrunit,*) 'diamonds, adjust: inm,jnm=',inm,jnm write(stderrunit,*) 'diamonds, adjust: icount=',icount @@ -4852,24 +4852,24 @@ subroutine rotpos_to_tang(lon, lat, x, y, iceberg_num_in) if (present(iceberg_num_in)) then iceberg_num=iceberg_num_in endif - + if (lat>90.) then write(stderrunit,*) 'diamonds, rotpos_to_tang: lat>90 already!',lat, lon, iceberg_num call error_mesg('diamonds, rotpos_to_tang','Something went very wrong!',FATAL) - endif - if (lat==90.) then - write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat, lon - call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) - endif + endif + if (lat==90.) then + write(stderrunit,*) 'diamonds, rotpos_to_tang: lat==90 already!',lat, lon + call error_mesg('diamonds, rotpos_to_tang','Something went wrong!',FATAL) + endif - colat=90.-lat - r=Rearth*(colat*pi_180) - clon=cos(lon*pi_180) - slon=sin(lon*pi_180) - x=r*clon - y=r*slon + colat=90.-lat + r=Rearth*(colat*pi_180) + clon=cos(lon*pi_180) + slon=sin(lon*pi_180) + x=r*clon + y=r*slon - end subroutine rotpos_to_tang +end subroutine rotpos_to_tang ! ############################################################################## @@ -4877,17 +4877,17 @@ subroutine icebergs_stock_pe(bergs, index, value) ! Modules use stock_constants_mod, only : ISTOCK_WATER, ISTOCK_HEAT ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory integer, intent(in) :: index real, intent(out) :: value ! Local variables type(icebergs_gridded), pointer :: grd real :: berg_mass, stored_mass -! For convenience -grd=>bergs%grd + ! For convenience + grd=>bergs%grd -select case (index) + select case (index) case (ISTOCK_WATER) berg_mass=sum_mass(bergs) @@ -4902,7 +4902,7 @@ subroutine icebergs_stock_pe(bergs, index, value) case default value = 0.0 -end select + end select end subroutine icebergs_stock_pe @@ -4910,7 +4910,7 @@ end subroutine icebergs_stock_pe subroutine icebergs_save_restart(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables if (.not.associated(bergs)) return @@ -4926,7 +4926,7 @@ end subroutine icebergs_save_restart subroutine icebergs_end(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(iceberg), pointer :: this, next @@ -5056,5 +5056,4 @@ end subroutine invert_tau_for_du ! ############################################################################## - end module diff --git a/icebergs_framework.F90 b/icebergs_framework.F90 index 3477dd0..1b71b9a 100644 --- a/icebergs_framework.F90 +++ b/icebergs_framework.F90 @@ -1,5 +1,8 @@ +!> Provides utilites for managing bergs in linked lists, and bonds between bergs module ice_bergs_framework +! This file is part of NOAA-GFDL/icebergs. See LICENSE.md for the license. + use constants_mod, only: radius, pi, omega, HLF use mpp_domains_mod, only: domain2D @@ -15,33 +18,33 @@ module ice_bergs_framework implicit none ; private -integer :: buffer_width=27 !Changed from 20 to 28 by Alon +integer :: buffer_width=27 !Changed from 20 to 28 by Alon integer :: buffer_width_traj=31 !Changed from 23 by Alon -!integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon +!integer, parameter :: buffer_width=26 !Changed from 20 to 26 by Alon !integer, parameter :: buffer_width_traj=29 !Changed from 23 by Alon integer, parameter :: nclasses=10 ! Number of ice bergs classes !Local Vars ! Global data (minimal for debugging) -logical :: folded_north_on_pe = .false. -logical :: verbose=.false. ! Be verbose to stderr -logical :: budget=.true. ! Calculate budgets -logical :: debug=.false. ! Turn on debugging -logical :: really_debug=.false. ! Turn on debugging -logical :: parallel_reprod=.true. ! Reproduce across different PE decompositions -logical :: use_slow_find=.true. ! Use really slow (but robust) find_cell for reading restarts -logical :: ignore_ij_restart=.false. ! Read i,j location from restart if available (needed to use restarts on different grids) -logical :: generate_test_icebergs=.false. ! Create icebergs in absence of a restart file -logical :: use_roundoff_fix=.true. ! Use a "fix" for the round-off discrepancy between is_point_in_cell() and pos_within_cell() -logical :: old_bug_rotated_weights=.false. ! Skip the rotation of off-center weights for rotated halo updates -logical :: make_calving_reproduce=.false. ! Make the calving.res.nc file reproduce across pe count changes. -logical :: old_bug_bilin=.true. ! If true, uses the inverted bilin function (use False to get correct answer) -character(len=10) :: restart_input_dir = 'INPUT/' -integer, parameter :: delta_buf=25 ! Size by which to increment buffers -real, parameter :: pi_180=pi/180. ! Converts degrees to radians -logical :: fix_restart_dates=.true. ! After a restart, check that bergs were created before the current model date -logical :: do_unit_tests=.false. ! Conduct some unit tests -logical :: force_all_pes_traj=.false. ! Force all pes write trajectory files regardless of io_layout +logical :: folded_north_on_pe = .false. !< If true, indicates the presence of the tri-polar grid +logical :: verbose=.false. !< Be verbose to stderr +logical :: budget=.true. !< Calculate budgets +logical :: debug=.false. !< Turn on debugging +logical :: really_debug=.false. !< Turn on debugging +logical :: parallel_reprod=.true. !< Reproduce across different PE decompositions +logical :: use_slow_find=.true. !< Use really slow (but robust) find_cell for reading restarts +logical :: ignore_ij_restart=.false. !< Read i,j location from restart if available (needed to use restarts on different grids) +logical :: generate_test_icebergs=.false. !< Create icebergs in absence of a restart file +logical :: use_roundoff_fix=.true. !< Use a "fix" for the round-off discrepancy between is_point_in_cell() and pos_within_cell() +logical :: old_bug_rotated_weights=.false. !< Skip the rotation of off-center weights for rotated halo updates +logical :: make_calving_reproduce=.false. !< Make the calving.res.nc file reproduce across pe count changes. +logical :: old_bug_bilin=.true. !< If true, uses the inverted bilinear function (use False to get correct answer) +character(len=10) :: restart_input_dir = 'INPUT/' !< Directory to look for restart files +integer, parameter :: delta_buf=25 !< Size by which to increment buffers +real, parameter :: pi_180=pi/180. !< Converts degrees to radians +logical :: fix_restart_dates=.true. !< After a restart, check that bergs were created before the current model date +logical :: do_unit_tests=.false. !< Conduct some unit tests +logical :: force_all_pes_traj=.false. !< Force all pes write trajectory files regardless of io_layout !Public params !Niki: write a subroutine to expose these public nclasses,buffer_width,buffer_width_traj @@ -50,7 +53,7 @@ module ice_bergs_framework public orig_read, force_all_pes_traj !Public types -public icebergs_gridded, xyt, iceberg, icebergs, buffer, bond +public icebergs_gridded, xyt, iceberg, icebergs, buffer, bond !Public subs public ice_bergs_framework_init @@ -58,7 +61,7 @@ module ice_bergs_framework public update_halo_icebergs public pack_berg_into_buffer2, unpack_berg_from_buffer2 public pack_traj_into_buffer2, unpack_traj_from_buffer2 -public increase_ibuffer +public increase_ibuffer public add_new_berg_to_list, count_out_of_order, check_for_duplicates public insert_berg_into_list, create_iceberg, delete_iceberg_from_list, destroy_iceberg public print_fld,print_berg, print_bergs,record_posn, push_posn, append_posn, check_position @@ -76,76 +79,91 @@ module ice_bergs_framework public test_check_for_duplicate_ids_in_list public check_for_duplicates_in_parallel +!> Container for gridded fields type :: icebergs_gridded - type(domain2D), pointer :: domain ! MPP domain - integer :: halo ! Nominal halo width - integer :: isc, iec, jsc, jec ! Indices of computational domain - integer :: isd, ied, jsd, jed ! Indices of data domain - integer :: isg, ieg, jsg, jeg ! Indices of global domain - integer :: my_pe, pe_N, pe_S, pe_E, pe_W ! MPI PE idenLx ! Length of domain, for periodic boundary condition (Ly to be adde later if needed) - logical :: grid_is_latlon !Flag to say whether the coordinate is in lat lon degrees, or meters - logical :: grid_is_regular !Flag to say whether point in cell can be found assuming regular cartesian grid - real :: Lx !Length of the domain in x direction - real, dimension(:,:), pointer :: lon=>null() ! Longitude of cell corners - real, dimension(:,:), pointer :: lat=>null() ! Latitude of cell corners - real, dimension(:,:), pointer :: lonc=>null() ! Longitude of cell centers - real, dimension(:,:), pointer :: latc=>null() ! Latitude of cell centers - real, dimension(:,:), pointer :: dx=>null() ! Length of cell edge (m) - real, dimension(:,:), pointer :: dy=>null() ! Length of cell edge (m) - real, dimension(:,:), pointer :: area=>null() ! Area of cell (m^2) - real, dimension(:,:), pointer :: msk=>null() ! Ocean-land mask (1=ocean) - real, dimension(:,:), pointer :: cos=>null() ! Cosine from rotation matrix to lat-lon coords - real, dimension(:,:), pointer :: sin=>null() ! Sine from rotation matrix to lat-lon coords - real, dimension(:,:), pointer :: ocean_depth=>NULL() ! Depth of ocean (m) - real, dimension(:,:), pointer :: uo=>null() ! Ocean zonal flow (m/s) - real, dimension(:,:), pointer :: vo=>null() ! Ocean meridional flow (m/s) - real, dimension(:,:), pointer :: ui=>null() ! Ice zonal flow (m/s) - real, dimension(:,:), pointer :: vi=>null() ! Ice meridional flow (m/s) - real, dimension(:,:), pointer :: ua=>null() ! Atmosphere zonal flow (m/s) - real, dimension(:,:), pointer :: va=>null() ! Atmosphere meridional flow (m/s) - real, dimension(:,:), pointer :: ssh=>null() ! Sea surface height (m) - real, dimension(:,:), pointer :: sst=>null() ! Sea surface temperature (oC) - real, dimension(:,:), pointer :: sss=>null() ! Sea surface salinity (psu) - real, dimension(:,:), pointer :: cn=>null() ! Sea-ice concentration (0 to 1) - real, dimension(:,:), pointer :: hi=>null() ! Sea-ice thickness (m) - real, dimension(:,:), pointer :: calving=>null() ! Calving mass rate [frozen runoff] (kg/s) (into stored ice) - real, dimension(:,:), pointer :: calving_hflx=>null() ! Calving heat flux [heat content of calving] (W/m2) (into stored ice) - real, dimension(:,:), pointer :: floating_melt=>null() ! Net melting rate to icebergs + bits (kg/s/m^2) - real, dimension(:,:), pointer :: berg_melt=>null() ! Melting+erosion rate of icebergs (kg/s/m^2) - real, dimension(:,:), pointer :: melt_buoy=>null() ! Buoyancy componenet of melting rate (kg/s/m^2) - real, dimension(:,:), pointer :: melt_eros=>null() ! Erosion component of melting rate (kg/s/m^2) - real, dimension(:,:), pointer :: melt_conv=>null() ! Convective component of melting rate (kg/s/m^2) - real, dimension(:,:), pointer :: bergy_src=>null() ! Mass flux from berg erosion into bergy bits (kg/s/m^2) - real, dimension(:,:), pointer :: bergy_melt=>null() ! Melting rate of bergy bits (kg/s/m^2) - real, dimension(:,:), pointer :: bergy_mass=>null() ! Mass distribution of bergy bits (kg/s/m^2) - real, dimension(:,:), pointer :: spread_mass=>null() ! Mass of icebergs after spreading (kg/m^2) - real, dimension(:,:), pointer :: spread_mass_old=>null() ! Mass of icebergs after spreading old (kg/m^2) - real, dimension(:,:), pointer :: spread_area=>null() ! Area of icebergs after spreading (m^2/m^2) - real, dimension(:,:), pointer :: u_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) - real, dimension(:,:), pointer :: v_iceberg=>null() ! Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) - real, dimension(:,:), pointer :: spread_uvel=>null() ! Average iceberg velocity in grid cell (spread area weighted) - real, dimension(:,:), pointer :: spread_vvel=>null() ! Average iceberg velocity in grid cell (spread area weighted) - real, dimension(:,:), pointer :: ustar_iceberg=>null() ! Frictional velocity below icebergs to be passed to ocean - real, dimension(:,:), pointer :: virtual_area=>null() ! Virtual surface coverage by icebergs (m^2) - real, dimension(:,:), pointer :: mass=>null() ! Mass distribution (kg/m^2) - real, dimension(:,:,:), pointer :: mass_on_ocean=>null() ! Mass distribution partitioned by neighbor (kg) - real, dimension(:,:,:), pointer :: area_on_ocean=>null() ! Area distribution partitioned by neighbor (m^2) - real, dimension(:,:,:), pointer :: Uvel_on_ocean=>null() ! zonal velocity distribution partitioned by neighbor (m^2* m/s) - real, dimension(:,:,:), pointer :: Vvel_on_ocean=>null() ! meridional momentum distribution partitioned by neighbor (m^2 m/s) - real, dimension(:,:), pointer :: tmp=>null() ! Temporary work space - real, dimension(:,:), pointer :: tmpc=>null() ! Temporary work space - real, dimension(:,:,:), pointer :: stored_ice=>null() ! Accumulated ice mass flux at calving locations (kg) - real, dimension(:,:), pointer :: rmean_calving=>null() ! Running mean for ice calving - real, dimension(:,:), pointer :: rmean_calving_hflx=>null() ! Running mean for ice calving - real, dimension(:,:), pointer :: stored_heat=>null() ! Heat content of stored ice (J) - real, dimension(:,:,:), pointer :: real_calving=>null() ! Calving rate into iceberg class at calving locations (kg/s) - real, dimension(:,:), pointer :: iceberg_heat_content=>null() ! Distributed heat content of bergs (J/m^2) - real, dimension(:,:), pointer :: parity_x=>null() ! X component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) - real, dimension(:,:), pointer :: parity_y=>null() ! Y component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) - integer, dimension(:,:), pointer :: iceberg_counter_grd=>null() ! Counts icebergs created for naming purposes - logical :: rmean_calving_initialized = .false. ! True if rmean_calving(:,:) has been filled with meaningful data - logical :: rmean_calving_hflx_initialized = .false. ! True if rmean_calving_hflx(:,:) has been filled with meaningful data - ! Diagnostics handles + type(domain2D), pointer :: domain !< MPP parallel domain + integer :: halo !< Nominal halo width + integer :: isc !< Start i-index of computational domain + integer :: iec !< End i-index of computational domain + integer :: jsc !< Start j-index of computational domain + integer :: jec !< End j-index of computational domain + integer :: isd !< Start i-index of data domain + integer :: ied !< End i-index of data domain + integer :: jsd !< Start j-index of data domain + integer :: jed !< End j-index of data domain + integer :: isg !< Start i-index of global domain + integer :: ieg !< End i-index of global domain + integer :: jsg !< Start j-index of global domain + integer :: jeg !< End j-index of global domain + integer :: my_pe !< MPI PE index + integer :: pe_N !< MPI PE index of PE to the north + integer :: pe_S !< MPI PE index of PE to the south + integer :: pe_E !< MPI PE index of PE to the east + integer :: pe_W !< MPI PE index of PE to the west + logical :: grid_is_latlon !< Flag to say whether the coordinate is in lat-lon degrees, or meters + logical :: grid_is_regular !< Flag to say whether point in cell can be found assuming regular Cartesian grid + real :: Lx !< Length of the domain in x direction + real, dimension(:,:), pointer :: lon=>null() !< Longitude of cell corners (degree E) + real, dimension(:,:), pointer :: lat=>null() !< Latitude of cell corners (degree N) + real, dimension(:,:), pointer :: lonc=>null() !< Longitude of cell centers (degree E) + real, dimension(:,:), pointer :: latc=>null() !< Latitude of cell centers (degree N) + real, dimension(:,:), pointer :: dx=>null() !< Length of cell edge (m) + real, dimension(:,:), pointer :: dy=>null() !< Length of cell edge (m) + real, dimension(:,:), pointer :: area=>null() !< Area of cell (m^2) + real, dimension(:,:), pointer :: msk=>null() !< Ocean-land mask (1=ocean) + real, dimension(:,:), pointer :: cos=>null() !< Cosine from rotation matrix to lat-lon coords + real, dimension(:,:), pointer :: sin=>null() !< Sine from rotation matrix to lat-lon coords + real, dimension(:,:), pointer :: ocean_depth=>NULL() !< Depth of ocean (m) + real, dimension(:,:), pointer :: uo=>null() !< Ocean zonal flow (m/s) + real, dimension(:,:), pointer :: vo=>null() !< Ocean meridional flow (m/s) + real, dimension(:,:), pointer :: ui=>null() !< Ice zonal flow (m/s) + real, dimension(:,:), pointer :: vi=>null() !< Ice meridional flow (m/s) + real, dimension(:,:), pointer :: ua=>null() !< Atmosphere zonal flow (m/s) + real, dimension(:,:), pointer :: va=>null() !< Atmosphere meridional flow (m/s) + real, dimension(:,:), pointer :: ssh=>null() !< Sea surface height (m) + real, dimension(:,:), pointer :: sst=>null() !< Sea surface temperature (oC) + real, dimension(:,:), pointer :: sss=>null() !< Sea surface salinity (psu) + real, dimension(:,:), pointer :: cn=>null() !< Sea-ice concentration (0 to 1) + real, dimension(:,:), pointer :: hi=>null() !< Sea-ice thickness (m) + real, dimension(:,:), pointer :: calving=>null() !< Calving mass rate [frozen runoff] (kg/s) (into stored ice) + real, dimension(:,:), pointer :: calving_hflx=>null() !< Calving heat flux [heat content of calving] (W/m2) (into stored ice) + real, dimension(:,:), pointer :: floating_melt=>null() !< Net melting rate to icebergs + bits (kg/s/m^2) + real, dimension(:,:), pointer :: berg_melt=>null() !< Melting+erosion rate of icebergs (kg/s/m^2) + real, dimension(:,:), pointer :: melt_buoy=>null() !< Buoyancy component of melting rate (kg/s/m^2) + real, dimension(:,:), pointer :: melt_eros=>null() !< Erosion component of melting rate (kg/s/m^2) + real, dimension(:,:), pointer :: melt_conv=>null() !< Convective component of melting rate (kg/s/m^2) + real, dimension(:,:), pointer :: bergy_src=>null() !< Mass flux from berg erosion into bergy bits (kg/s/m^2) + real, dimension(:,:), pointer :: bergy_melt=>null() !< Melting rate of bergy bits (kg/s/m^2) + real, dimension(:,:), pointer :: bergy_mass=>null() !< Mass distribution of bergy bits (kg/s/m^2) + real, dimension(:,:), pointer :: spread_mass=>null() !< Mass of icebergs after spreading (kg/m^2) + real, dimension(:,:), pointer :: spread_mass_old=>null() !< Mass of icebergs after spreading old (kg/m^2) + real, dimension(:,:), pointer :: spread_area=>null() !< Area of icebergs after spreading (m^2/m^2) + real, dimension(:,:), pointer :: u_iceberg=>null() !< Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) + real, dimension(:,:), pointer :: v_iceberg=>null() !< Average iceberg velocity in grid cell (mass weighted - but not spread mass weighted) + real, dimension(:,:), pointer :: spread_uvel=>null() !< Average iceberg velocity in grid cell (spread area weighted) + real, dimension(:,:), pointer :: spread_vvel=>null() !< Average iceberg velocity in grid cell (spread area weighted) + real, dimension(:,:), pointer :: ustar_iceberg=>null() !< Frictional velocity below icebergs to be passed to ocean + real, dimension(:,:), pointer :: virtual_area=>null() !< Virtual surface coverage by icebergs (m^2) + real, dimension(:,:), pointer :: mass=>null() !< Mass distribution (kg/m^2) + real, dimension(:,:,:), pointer :: mass_on_ocean=>null() !< Mass distribution partitioned by neighbor (kg) + real, dimension(:,:,:), pointer :: area_on_ocean=>null() !< Area distribution partitioned by neighbor (m^2) + real, dimension(:,:,:), pointer :: Uvel_on_ocean=>null() !< zonal velocity distribution partitioned by neighbor (m^2* m/s) + real, dimension(:,:,:), pointer :: Vvel_on_ocean=>null() !< meridional momentum distribution partitioned by neighbor (m^2 m/s) + real, dimension(:,:), pointer :: tmp=>null() !< Temporary work space + real, dimension(:,:), pointer :: tmpc=>null() !< Temporary work space + real, dimension(:,:,:), pointer :: stored_ice=>null() !< Accumulated ice mass flux at calving locations (kg) + real, dimension(:,:), pointer :: rmean_calving=>null() !< Running mean for ice calving + real, dimension(:,:), pointer :: rmean_calving_hflx=>null() !< Running mean for ice calving + real, dimension(:,:), pointer :: stored_heat=>null() !< Heat content of stored ice (J) + real, dimension(:,:,:), pointer :: real_calving=>null() !< Calving rate into iceberg class at calving locations (kg/s) + real, dimension(:,:), pointer :: iceberg_heat_content=>null() !< Distributed heat content of bergs (J/m^2) + real, dimension(:,:), pointer :: parity_x=>null() !< X component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) + real, dimension(:,:), pointer :: parity_y=>null() !< Y component of vector point from i,j to i+1,j+1 (for detecting tri-polar fold) + integer, dimension(:,:), pointer :: iceberg_counter_grd=>null() !< Counts icebergs created for naming purposes + logical :: rmean_calving_initialized = .false. !< True if rmean_calving(:,:) has been filled with meaningful data + logical :: rmean_calving_hflx_initialized = .false. !< True if rmean_calving_hflx(:,:) has been filled with meaningful data + !>@{ + !! Diagnostic handle integer :: id_uo=-1, id_vo=-1, id_calving=-1, id_stored_ice=-1, id_accum=-1, id_unused=-1, id_floating_melt=-1 integer :: id_melt_buoy=-1, id_melt_eros=-1, id_melt_conv=-1, id_virtual_area=-1, id_real_calving=-1 integer :: id_calving_hflx_in=-1, id_stored_heat=-1, id_melt_hflx=-1, id_heat_content=-1 @@ -158,134 +176,216 @@ module ice_bergs_framework integer :: id_spread_uvel=-1, id_spread_vvel=-1 integer :: id_melt_m_per_year=-1 integer :: id_ocean_depth=-1 + !>@} - real :: clipping_depth=0. ! The effective depth at which to clip the weight felt by the ocean [m]. + real :: clipping_depth=0. !< The effective depth at which to clip the weight felt by the ocean [m]. end type icebergs_gridded +!> A link in the trajectory record (diagnostic) type :: xyt - real :: lon, lat, day - real :: mass, thickness, width, length, uvel, vvel - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lat_old, lon_old !Explicit and implicit accelerations !Alon - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi, halo_berg, static_berg - real :: mass_of_bits, heat_density - integer :: year, iceberg_num - type(xyt), pointer :: next=>null() + real :: lon !< Longitude of berg (degree N or unit of grid coordinate) + real :: lat !< Latitude of berg (degree N or unit of grid coordinate) + real :: day !< Day of this record (days) + real :: mass !< Mass of berg (kg) + real :: thickness !< Thickness of berg (m) + real :: width !< Width of berg (m) + real :: length !< Length of berg (m) + real :: uvel !< Zonal velocity of berg (m/s) + real :: vvel !< Meridional velocity of berg (m/s) + real :: axn + real :: ayn + real :: bxn + real :: byn + real :: uvel_old + real :: vvel_old + real :: lat_old + real :: lon_old + real :: uo !< Zonal velocity of ocean (m/s) + real :: vo !< Meridional velocity of ocean (m/s) + real :: ui !< Zonal velocity of ice (m/s) + real :: vi !< Meridional velocity of ice (m/s) + real :: ua !< Zonal velocity of atmosphere (m/s) + real :: va !< Meridional velocity of atmosphere (m/s) + real :: ssh_x !< Zonal gradient of sea-surface height (nondim) + real :: ssh_y !< Meridional gradient of sea-surface height (nondim) + real :: sst !< Sea-surface temperature (Celsius) + real :: sss !< Sea-surface salinity (1e-3) + real :: cn !< Sea-ice concentration (nondim) + real :: hi !< Sea-ice thickness (m) + real :: halo_berg + real :: static_berg + real :: mass_of_bits !< Mass of bergy bits (kg) + real :: heat_density !< Heat density of berg (???) + integer :: year !< Year of this record (years) + integer :: iceberg_num !< Iceberg identifier + type(xyt), pointer :: next=>null() !< Next link in list end type xyt +!> An iceberg object, used as a link in a linked list type :: iceberg - type(iceberg), pointer :: prev=>null(), next=>null() + type(iceberg), pointer :: prev=>null() !< Previous link in list + type(iceberg), pointer :: next=>null() !< Next link in list ! State variables (specific to the iceberg, needed for restarts) - real :: lon, lat, uvel, vvel, mass, thickness, width, length - real :: axn, ayn, bxn, byn, uvel_old, vvel_old, lon_old, lat_old !Explicit and implicit accelerations !Alon - real :: start_lon, start_lat, start_day, start_mass, mass_scaling - real :: mass_of_bits, heat_density + real :: lon !< Longitude of berg (degree N or unit of grid coordinate) + real :: lat !< Latitude of berg (degree E or unit of grid coordinate) + real :: uvel !< Zonal velocity of berg (m/s) + real :: vvel !< Meridional velocity of berg (m/s) + real :: mass !< Mass of berg (kg) + real :: thickness !< Thickness of berg (m) + real :: width !< Width of berg (m) + real :: length !< Length of berg (m) + real :: axn + real :: ayn + real :: bxn + real :: byn + real :: uvel_old + real :: vvel_old + real :: lon_old + real :: lat_old + real :: start_lon !< Longitude where berg was created (degree N or unit of grid coordinate) + real :: start_lat !< Latitude where berg was created (degree E or unit of grid coordinate) + real :: start_day !< Day that berg was created (days) + real :: start_mass !< Mass berg had when created (kg) + real :: mass_scaling !< Multiplier to scale mass when interpreting berg as a cloud of bergs (nondim) + real :: mass_of_bits !< Mass of bergy bits following berg (kg) + real :: heat_density !< Heat density of berg (???) real :: halo_berg ! Equal to zero for bergs on computational domain, and =1 for bergs on the halo real :: static_berg ! Equal to 1 for icebergs which are static (not allowed to move). Might be extended to grounding later. - integer :: start_year - integer :: iceberg_num - integer :: ine, jne ! nearest index in NE direction (for convenience) - real :: xi, yj ! Non-dimensional coords within current cell (0..1) + integer :: start_year !< Year that berg was created (years) + integer :: iceberg_num !< Iceberg identifier + integer :: ine !< Nearest i-index in NE direction (for convenience) + integer :: jne !< Nearest j-index in NE direction (for convenience) + real :: xi !< Non-dimensional x-coordinate within current cell (0..1) + real :: yj !< Non-dimensional y-coordinate within current cell (0..1) ! Environment variables (as seen by the iceberg) - real :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi - type(xyt), pointer :: trajectory=>null() - type(bond), pointer :: first_bond=>null() !First element of bond list. + real :: uo !< Zonal velocity of ocean (m/s) + real :: vo !< Meridional velocity of ocean (m/s) + real :: ui !< Zonal velocity of ice (m/s) + real :: vi !< Meridional velocity of ice (m/s) + real :: ua !< Zonal velocity of atmosphere (m/s) + real :: va !< Meridional velocity of atmosphere (m/s) + real :: ssh_x !< Zonal gradient of sea-surface height (nondim) + real :: ssh_y !< Meridional gradient of sea-surface height (nondim) + real :: sst !< Sea-surface temperature (Celsius) + real :: sss !< Sea-surface salinity (1e-3) + real :: cn !< Sea-ice concentration (nondim) + real :: hi !< Sea-ice thickness (m) + type(xyt), pointer :: trajectory=>null() !< Trajectory for this berg + type(bond), pointer :: first_bond=>null() !< First element of bond list. end type iceberg +!> A bond object connecting two bergs, used as a link in a linked list type :: bond - type(bond), pointer :: prev_bond=>null(), next_bond=>null() + type(bond), pointer :: prev_bond=>null() !< Previous link in list + type(bond), pointer :: next_bond=>null() !< Next link in list type(iceberg), pointer :: other_berg=>null() - integer :: other_berg_num, other_berg_ine, other_berg_jne + integer :: other_berg_num + integer :: other_berg_ine + integer :: other_berg_jne end type bond +! A dynamic buffer, used for communication, that packs types into rectangular memory type :: buffer - integer :: size=0 - real, dimension(:,:), pointer :: data + integer :: size=0 !< Size of buffer + real, dimension(:,:), pointer :: data !< Buffer memory end type buffer +!> A wrapper for the iceberg linked list (since an array of pointers is not allowed) type :: linked_list - type(iceberg), pointer :: first=>null() + type(iceberg), pointer :: first=>null() !< Pointer to the beginning of a linked list of bergs end type linked_list -type :: icebergs !; private!Niki: Ask Alistair why this is private. ice_bergs_io cannot compile if this is private! - type(icebergs_gridded), pointer :: grd - type(linked_list), dimension(:,:), allocatable :: list - type(xyt), pointer :: trajectories=>null() - real :: dt ! Time-step between iceberg calls (should make adaptive?) - integer :: current_year - real :: current_yearday ! 1.00-365.99 - integer :: traj_sample_hrs, traj_write_hrs - integer :: verbose_hrs +!> Container for all types and memory +type :: icebergs !; private !Niki: Ask Alistair why this is private. ice_bergs_io cannot compile if this is private! + type(icebergs_gridded), pointer :: grd !< Container with all gridded data + type(linked_list), dimension(:,:), allocatable :: list !< Linked list of icebergs + type(xyt), pointer :: trajectories=>null() !< A linked list for detached segments of trajectories + real :: dt !< Time-step between iceberg calls + !! \todo Should make dt adaptive? + integer :: current_year !< Current year (years) + real :: current_yearday !< Current year-day, 1.00-365.99, (days) + integer :: traj_sample_hrs !< Period between sampling for trajectories (hours) + integer :: traj_write_hrs !< Period between writing of trajectories (hours) + integer :: verbose_hrs !< Period between terminal status reports (hours) integer :: max_bonds - integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia ! ids for fms timers + !>@{ + !! Handles for clocks + integer :: clock, clock_mom, clock_the, clock_int, clock_cal, clock_com, clock_ini, clock_ior, clock_iow, clock_dia integer :: clock_trw, clock_trp - real :: rho_bergs ! Density of icebergs [kg/m^3] - real :: spring_coef ! Spring contant for iceberg interactions - real :: bond_coef ! Spring contant for iceberg bonds - real :: radial_damping_coef ! Coef for relative iceberg motion damping (radial component) -Alon - real :: tangental_damping_coef ! Coef for relative iceberg motion damping (tangental component) -Alon - real :: LoW_ratio ! Initial ratio L/W for newly calved icebergs - real :: bergy_bit_erosion_fraction ! Fraction of erosion melt flux to divert to bergy bits - real :: sicn_shift ! Shift of sea-ice concentration in erosion flux modulation (0@} + real :: rho_bergs !< Density of icebergs [kg/m^3] + real :: spring_coef !< Spring constant for iceberg interactions + real :: bond_coef !< Spring constant for iceberg bonds + real :: radial_damping_coef !< Coefficient for relative iceberg motion damping (radial component) -Alon + real :: tangental_damping_coef !< Coefficient for relative iceberg motion damping (tangential component) -Alon + real :: LoW_ratio !< Initial ratio L/W for newly calved icebergs + real :: bergy_bit_erosion_fraction !< Fraction of erosion melt flux to divert to bergy bits + real :: sicn_shift !< Shift of sea-ice concentration in erosion flux modulation (0null(), ibuffer_n=>null() - type(buffer), pointer :: obuffer_s=>null(), ibuffer_s=>null() - type(buffer), pointer :: obuffer_e=>null(), ibuffer_e=>null() - type(buffer), pointer :: obuffer_w=>null(), ibuffer_w=>null() - type(buffer), pointer :: obuffer_io=>null(), ibuffer_io=>null() + logical :: restarted=.false. !< Indicate whether we read state from a restart or not + logical :: use_operator_splitting=.true. !< Use first order operator splitting for thermodynamics + logical :: add_weight_to_ocean=.true. !< Add weight of bergs to ocean + logical :: passive_mode=.false. !< Add weight of icebergs + bits to ocean + logical :: time_average_weight=.false. !< Time average the weight on the ocean + logical :: Runge_not_Verlet=.True. !< True=Runge-Kutta, False=Verlet. + logical :: use_mixed_melting=.False. !< If true, then the melt is determined partly using 3 eq model partly using iceberg parameterizations (according to iceberg bond number) + logical :: apply_thickness_cutoff_to_gridded_melt=.False. !< Prevents melt for ocean thickness below melt_cuttoff (applied to gridded melt fields) + logical :: apply_thickness_cutoff_to_bergs_melt=.False. !< Prevents melt for ocean thickness below melt_cuttoff (applied to bergs) + logical :: use_updated_rolling_scheme=.false. !< True to use the aspect ratio based rolling scheme rather than incorrect version of WM scheme (set tip_parameter=1000. for correct WM scheme) + logical :: pass_fields_to_ocean_model=.False. !< Iceberg area, mass and ustar fields are prepared to pass to ocean model + logical :: use_mixed_layer_salinity_for_thermo=.False. !< If true, then model uses ocean salinity for 3 and 2 equation melt model. + logical :: find_melt_using_spread_mass=.False. !< If true, then the model calculates ice loss by looping at the spread_mass before and after. + logical :: Use_three_equation_model=.True. !< Uses 3 equation model for melt when ice shelf type thermodynamics are used. + logical :: melt_icebergs_as_ice_shelf=.False. !< Uses iceshelf type thermodynamics + logical :: Iceberg_melt_without_decay=.False. !< Allows icebergs meltwater fluxes to enter the ocean, without the iceberg decaying or changing shape. + logical :: add_iceberg_thickness_to_SSH=.False. !< Adds the iceberg contribution to SSH. + logical :: override_iceberg_velocities=.False. !< Allows you to set a fixed iceberg velocity for all non-static icebergs. + logical :: use_f_plane=.False. !< Flag to use a f-plane for the rotation + logical :: rotate_icebergs_for_mass_spreading=.True. !< Flag allows icebergs to rotate for spreading their mass (in hexagonal spreading mode) + logical :: set_melt_rates_to_zero=.False. !< Sets all melt rates to zero, for testing purposes (thermodynamics routine is still run) + logical :: hexagonal_icebergs=.False. !< True treats icebergs as rectangles, False as hexagonal elements (for the purpose of mass spreading) + logical :: allow_bergs_to_roll=.True. !< Allows icebergs to roll over when rolling conditions are met + logical :: ignore_missing_restart_bergs=.False. !< True Allows the model to ignore icebergs missing in the restart. + logical :: Static_icebergs=.False. !< True= icebergs do no move + logical :: only_interactive_forces=.False. !< Icebergs only feel interactive forces, and not ocean, wind... + logical :: halo_debugging=.False. !< Use for debugging halos (remove when its working) + logical :: save_short_traj=.True. !< True saves only lon,lat,time,iceberg_num in iceberg_trajectory.nc + logical :: ignore_traj=.False. !< If true, then model does not write trajectory data at all + logical :: iceberg_bonds_on=.False. !< True=Allow icebergs to have bonds, False=don't allow. + logical :: manually_initialize_bonds=.False. !< True= Bonds are initialize manually. + logical :: use_new_predictive_corrective =.False. !< Flag to use Bob's predictive corrective iceberg scheme- Added by Alon + logical :: interactive_icebergs_on=.false. !< Turn on/off interactions between icebergs - Added by Alon + logical :: critical_interaction_damping_on=.true. !< Sets the damping on relative iceberg velocity to critical value - Added by Alon + logical :: use_old_spreading=.true. !< If true, spreads iceberg mass as if the berg is one grid cell wide + logical :: read_ocean_depth_from_file=.false. !< If true, ocean depth is read from a file. + integer :: debug_iceberg_with_id = -1 !< If positive, monitors a berg with this id + + real :: speed_limit=0. !< CFL speed limit for a berg [m/s] + real :: tau_calving=0. !< Time scale for smoothing out calving field (years) + real :: tip_parameter=0. !< parameter to override iceberg rolling critical ratio (use zero to get parameter directly from ice and seawater densities) + real :: grounding_fraction=0. !< Fraction of water column depth at which grounding occurs + type(buffer), pointer :: obuffer_n=>null() !< Buffer for outgoing bergs to the north + type(buffer), pointer :: ibuffer_n=>null() !< Buffer for incoming bergs from the north + type(buffer), pointer :: obuffer_s=>null() !< Buffer for outgoing bergs to the south + type(buffer), pointer :: ibuffer_s=>null() !< Buffer for incoming bergs from the south + type(buffer), pointer :: obuffer_e=>null() !< Buffer for outgoing bergs to the east + type(buffer), pointer :: ibuffer_e=>null() !< Buffer for incoming bergs from the east + type(buffer), pointer :: obuffer_w=>null() !< Buffer for outgoing bergs to the west + type(buffer), pointer :: ibuffer_w=>null() !< Buffer for incoming bergs from the west + type(buffer), pointer :: obuffer_io=>null() !< Buffer for outgoing bergs during i/o + type(buffer), pointer :: ibuffer_io=>null() !< Buffer for incoming bergs during i/o ! Budgets real :: net_calving_received=0., net_calving_returned=0. real :: net_incoming_calving=0., net_outgoing_calving=0. @@ -316,10 +416,11 @@ module ice_bergs_framework integer, dimension(:), pointer :: nbergs_calved_by_class=>null() end type icebergs -! Needs to be module global so can be public to icebergs_mod. -! Remove when backward compatibility no longer needed +!> Read original restarts. Needs to be module global so can be public to icebergs_mod. +!! \todo Remove when backward compatibility no longer needed logical :: orig_read=.false. +!> Version of file provided by CPP macro (usually set to git hash) #ifdef _FILE_VERSION character(len=128) :: version = _FILE_VERSION #else @@ -328,9 +429,7 @@ module ice_bergs_framework contains - -! ############################################################################## - +!> Initializes parallel framework subroutine ice_bergs_framework_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & @@ -353,17 +452,27 @@ subroutine ice_bergs_framework_init(bergs, & use diag_manager_mod, only: diag_axis_init ! Arguments -type(icebergs), pointer :: bergs -integer, intent(in) :: gni, gnj, layout(2), io_layout(2), axes(2) -integer, intent(in) :: dom_x_flags, dom_y_flags -real, intent(in) :: dt -type (time_type), intent(in) :: Time ! current time -real, dimension(:,:), intent(in) :: ice_lon, ice_lat, ice_wet -real, dimension(:,:), intent(in) :: ice_dx, ice_dy, ice_area -real, dimension(:,:), intent(in) :: cos_rot, sin_rot -real, dimension(:,:), intent(in),optional :: ocean_depth -logical, intent(in), optional :: maskmap(:,:) -logical, intent(in), optional :: fractional_area +type(icebergs), pointer :: bergs !< Container for all types and memory +integer, intent(in) :: gni !< Number grid cells in i-direction +integer, intent(in) :: gnj !< Number grid cells in j-direction +integer, intent(in) :: layout(2) !< Number of processing cores in i,j direction +integer, intent(in) :: io_layout(2) !< Number of i/o cores in i,j direction +integer, intent(in) :: axes(2) !< Diagnostic axes +integer, intent(in) :: dom_x_flags !< Domain flags in i-direction +integer, intent(in) :: dom_y_flags !< Domain flags in j-direction +real, intent(in) :: dt !< Time-step (s) +type (time_type), intent(in) :: Time ! Current model time +real, dimension(:,:), intent(in) :: ice_lon !< Longitude of cell corners using NE convention (degree E) +real, dimension(:,:), intent(in) :: ice_lat !< Latitude of cell corners using NE conventino (degree N) +real, dimension(:,:), intent(in) :: ice_wet !< Wet/dry mask (1 is wet, 0 is dry) of cell centers +real, dimension(:,:), intent(in) :: ice_dx !< Zonal length of cell on northern side (m) +real, dimension(:,:), intent(in) :: ice_dy !< Meridional length of cell on eastern side (m) +real, dimension(:,:), intent(in) :: ice_area !< Area of cells (m^2, or non-dim is fractional_area=True) +real, dimension(:,:), intent(in) :: cos_rot !< Cosine from rotation matrix to lat-lon coords +real, dimension(:,:), intent(in) :: sin_rot !< Sine from rotation matrix to lat-lon coords +real, dimension(:,:), intent(in),optional :: ocean_depth !< Depth of ocean bottom (m) +logical, intent(in), optional :: maskmap(:,:) !< Masks out parallel cores +logical, intent(in), optional :: fractional_area !< If true, ice_area contains cell area as fraction of entire spherical surface ! Namelist parameters (and defaults) integer :: halo=4 ! Width of halo region @@ -372,10 +481,10 @@ subroutine ice_bergs_framework_init(bergs, & integer :: verbose_hrs=24 ! Period between verbose messages integer :: max_bonds=6 ! Maximum number of iceberg bond passed between processors real :: rho_bergs=850. ! Density of icebergs -real :: spring_coef=1.e-8 ! Spring contant for iceberg interactions (this seems to be the highest stable value) -real :: bond_coef=1.e-8 ! Spring contant for iceberg bonds - not being used right now -real :: radial_damping_coef=1.e-4 ! Coef for relative iceberg motion damping (radial component) -Alon -real :: tangental_damping_coef=2.e-5 ! Coef for relative iceberg motion damping (tangental component) -Alon +real :: spring_coef=1.e-8 ! Spring constant for iceberg interactions (this seems to be the highest stable value) +real :: bond_coef=1.e-8 ! Spring constant for iceberg bonds - not being used right now +real :: radial_damping_coef=1.e-4 ! Coefficient for relative iceberg motion damping (radial component) -Alon +real :: tangental_damping_coef=2.e-5 ! Coefficient for relative iceberg motion damping (tangential component) -Alon real :: LoW_ratio=1.5 ! Initial ratio L/W for newly calved icebergs real :: bergy_bit_erosion_fraction=0. ! Fraction of erosion melt flux to divert to bergy bits real :: sicn_shift=0. ! Shift of sea-ice concentration in erosion flux modulation (0= 3 for rotating icebergs for mass spreading', WARNING) + call error_mesg('diamonds, framework', 'Setting iceberg halos =3, since halos must be >= 3 for rotating icebergs for mass spreading', WARNING) elseif ((halo .lt. 2) .and. (interactive_icebergs_on .or. iceberg_bonds_on) ) then halo=2 - call error_mesg('diamonds, framework', 'Setting iceberg halos =2, since halos must be >= 2 for interactions', WARNING) + call error_mesg('diamonds, framework', 'Setting iceberg halos =2, since halos must be >= 2 for interactions', WARNING) endif if (interactive_icebergs_on) then if (Runge_not_Verlet) then !Runge_not_Verlet=.false. ! Iceberg interactions only with Verlet - call error_mesg('diamonds, framework', 'It is unlcear whther interactive icebergs work with Runge Kutta stepping.', WARNING) + call error_mesg('diamonds, framework', 'It is unlcear whther interactive icebergs work with Runge Kutta stepping.', WARNING) endif endif if (.not.interactive_icebergs_on) then - if (iceberg_bonds_on) then - !iceberg_bonds_on=.false. - call error_mesg('diamonds, framework', 'Interactive icebergs off requires iceberg bonds off (turning bonds off).', WARNING) + if (iceberg_bonds_on) then + !iceberg_bonds_on=.false. + call error_mesg('diamonds, framework', 'Interactive icebergs off requires iceberg bonds off (turning bonds off).', WARNING) endif endif if (.not. iceberg_bonds_on) then max_bonds=0 else - buffer_width=buffer_width+(max_bonds*3) ! Increase buffer width to include bonds being passed between processors + buffer_width=buffer_width+(max_bonds*3) ! Increase buffer width to include bonds being passed between processors endif if (save_short_traj) buffer_width_traj=5 ! This is the length of the short buffer used for abrevated traj if (ignore_traj) buffer_width_traj=0 ! If this is true, then all traj files should be ignored @@ -811,8 +919,8 @@ subroutine ice_bergs_framework_init(bergs, & bergs%verbose_hrs=verbose_hrs bergs%grd%halo=halo bergs%grd%Lx=Lx - bergs%grd%grid_is_latlon=grid_is_latlon - bergs%grd%grid_is_regular=grid_is_regular + bergs%grd%grid_is_latlon=grid_is_latlon + bergs%grd%grid_is_regular=grid_is_regular bergs%max_bonds=max_bonds bergs%rho_bergs=rho_bergs bergs%spring_coef=spring_coef @@ -829,36 +937,36 @@ subroutine ice_bergs_framework_init(bergs, & bergs%tau_calving=tau_calving bergs%tip_parameter=tip_parameter bergs%use_updated_rolling_scheme=use_updated_rolling_scheme !Alon - bergs%Runge_not_Verlet=Runge_not_Verlet - bergs%use_mixed_melting=use_mixed_melting + bergs%Runge_not_Verlet=Runge_not_Verlet + bergs%use_mixed_melting=use_mixed_melting bergs%apply_thickness_cutoff_to_bergs_melt=apply_thickness_cutoff_to_bergs_melt bergs%apply_thickness_cutoff_to_gridded_melt=apply_thickness_cutoff_to_gridded_melt - bergs%melt_cutoff=melt_cutoff + bergs%melt_cutoff=melt_cutoff bergs%read_ocean_depth_from_file=read_ocean_depth_from_file - bergs%const_gamma=const_gamma + bergs%const_gamma=const_gamma bergs%Gamma_T_3EQ=Gamma_T_3EQ - bergs%pass_fields_to_ocean_model=pass_fields_to_ocean_model - bergs%ustar_icebergs_bg=ustar_icebergs_bg - bergs%utide_icebergs=utide_icebergs - bergs%cdrag_icebergs=cdrag_icebergs - bergs%use_mixed_layer_salinity_for_thermo=use_mixed_layer_salinity_for_thermo - bergs%find_melt_using_spread_mass=find_melt_using_spread_mass - bergs%Use_three_equation_model=Use_three_equation_model - bergs%melt_icebergs_as_ice_shelf=melt_icebergs_as_ice_shelf - bergs%Iceberg_melt_without_decay=Iceberg_melt_without_decay - bergs%add_iceberg_thickness_to_SSH=add_iceberg_thickness_to_SSH - bergs%override_iceberg_velocities=override_iceberg_velocities - bergs%use_f_plane=use_f_plane - bergs%rotate_icebergs_for_mass_spreading=rotate_icebergs_for_mass_spreading + bergs%pass_fields_to_ocean_model=pass_fields_to_ocean_model + bergs%ustar_icebergs_bg=ustar_icebergs_bg + bergs%utide_icebergs=utide_icebergs + bergs%cdrag_icebergs=cdrag_icebergs + bergs%use_mixed_layer_salinity_for_thermo=use_mixed_layer_salinity_for_thermo + bergs%find_melt_using_spread_mass=find_melt_using_spread_mass + bergs%Use_three_equation_model=Use_three_equation_model + bergs%melt_icebergs_as_ice_shelf=melt_icebergs_as_ice_shelf + bergs%Iceberg_melt_without_decay=Iceberg_melt_without_decay + bergs%add_iceberg_thickness_to_SSH=add_iceberg_thickness_to_SSH + bergs%override_iceberg_velocities=override_iceberg_velocities + bergs%use_f_plane=use_f_plane + bergs%rotate_icebergs_for_mass_spreading=rotate_icebergs_for_mass_spreading bergs%lat_ref=lat_ref bergs%u_override=u_override bergs%v_override=v_override bergs%initial_orientation=initial_orientation - bergs%set_melt_rates_to_zero=set_melt_rates_to_zero - bergs%allow_bergs_to_roll=allow_bergs_to_roll - bergs%hexagonal_icebergs=hexagonal_icebergs + bergs%set_melt_rates_to_zero=set_melt_rates_to_zero + bergs%allow_bergs_to_roll=allow_bergs_to_roll + bergs%hexagonal_icebergs=hexagonal_icebergs bergs%ignore_missing_restart_bergs=ignore_missing_restart_bergs - bergs%Static_icebergs=Static_icebergs + bergs%Static_icebergs=Static_icebergs bergs%only_interactive_forces=only_interactive_forces bergs%halo_debugging=halo_debugging bergs%iceberg_bonds_on=iceberg_bonds_on !Alon @@ -1008,12 +1116,12 @@ subroutine ice_bergs_framework_init(bergs, & call mpp_clock_end(bergs%clock) end subroutine ice_bergs_framework_init -! ############################################################################## +!> Adjust berg dates to allow use of restarts from later dates subroutine offset_berg_dates(bergs,Time) ! Arguments -type(icebergs), pointer :: bergs -type(time_type), intent(in) :: Time +type(icebergs), pointer :: bergs !< Container for all types and memory +type(time_type), intent(in) :: Time !< Model time ! Local variables type(iceberg), pointer :: this integer :: iyr, imon, iday, ihr, imin, isec, yr_offset @@ -1052,11 +1160,11 @@ subroutine offset_berg_dates(bergs,Time) end subroutine offset_berg_dates -! ############################################################################# - -subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists if they have moved from cell to cell. +!> Moves icebergs between lists if they have moved from cell to cell +subroutine move_berg_between_cells(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory +! Local variables type(icebergs_gridded), pointer :: grd => null() type(iceberg), pointer :: moving_berg => null(), this => null() integer :: grdi, grdj @@ -1071,7 +1179,7 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists if ((this%ine.ne.grdi) .or. (this%jne.ne.grdj)) then moving_berg=>this this=>this%next - + !Removing the iceberg from the old list if (associated(moving_berg%prev)) then moving_berg%prev%next=>moving_berg%next @@ -1080,7 +1188,7 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists endif if (associated(moving_berg%next)) moving_berg%next%prev=>moving_berg%prev - !Inserting the iceberg into the new list + !Inserting the iceberg into the new list call insert_berg_into_list(bergs%list(moving_berg%ine,moving_berg%jne)%first,moving_berg) !Clear moving_berg @@ -1094,12 +1202,10 @@ subroutine move_berg_between_cells(bergs) !Move icebergs onto the correct lists end subroutine move_berg_between_cells - -! ############################################################################# - +!> Populates the halo lists with bergs from neighbor processers subroutine update_halo_icebergs(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(iceberg), pointer :: kick_the_bucket, this integer :: nbergs_to_send_e, nbergs_to_send_w @@ -1115,31 +1221,29 @@ subroutine update_halo_icebergs(bergs) real :: current_halo_status logical :: halo_debugging -halo_width=bergs%grd%halo -halo_debugging=bergs%halo_debugging - - ! Get the stderr unit number - stderrunit = stderr() - - ! For convenience - grd=>bergs%grd + halo_width=bergs%grd%halo + halo_debugging=bergs%halo_debugging -!For debugging, MP1 -if (halo_debugging) then - do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj - this=>this%next - enddo - enddo; enddo - ! Use when debugging: - call show_all_bonds(bergs) -endif + ! Get the stderr unit number + stderrunit = stderr() + ! For convenience + grd=>bergs%grd -! Step 1: Clear the current halos + ! For debugging, MP1 + if (halo_debugging) then + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'A', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo + enddo; enddo + ! Use when debugging: + call show_all_bonds(bergs) + endif + ! Step 1: Clear the current halos call mpp_sync_self() do grdj = grd%jsd,grd%jsc-1 ; do grdi = grd%isd,grd%ied call delete_all_bergs_in_list(bergs, grdj, grdi) @@ -1158,62 +1262,57 @@ subroutine update_halo_icebergs(bergs) enddo ; enddo call mpp_sync_self() -!############################## -!For debugging -if (halo_debugging) then - do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - write(stderrunit,*) 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj - this=>this%next - enddo - enddo; enddo -endif + ! For debugging + if (halo_debugging) then + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'B', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo + enddo; enddo + endif if (debug) then nbergs_start=count_bergs(bergs) endif call mpp_sync_self() -!####################################################### - -! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes + ! Step 2: Updating the halos - This code is mostly copied from send_to_other_pes ! Find number of bergs that headed east/west nbergs_to_send_e=0 nbergs_to_send_w=0 - !Bergs on eastern side of the processor - do grdj = grd%jsc,grd%jec ; do grdi = grd%iec-halo_width+2,grd%iec + ! Bergs on eastern side of the processor + do grdj = grd%jsc,grd%jec ; do grdi = grd%iec-halo_width+2,grd%iec this=>bergs%list(grdi,grdj)%first do while (associated(this)) !write(stderrunit,*) 'sending east', this%iceberg_num, this%ine, this%jne, mpp_pe() - kick_the_bucket=>this - this=>this%next - nbergs_to_send_e=nbergs_to_send_e+1 - current_halo_status=kick_the_bucket%halo_berg - kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e, bergs%max_bonds) - kick_the_bucket%halo_berg=current_halo_status + kick_the_bucket=>this + this=>this%next + nbergs_to_send_e=nbergs_to_send_e+1 + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_e, nbergs_to_send_e, bergs%max_bonds) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo - - !Bergs on the western side of the processor - do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%isc+halo_width-1 + ! Bergs on the western side of the processor + do grdj = grd%jsc,grd%jec ; do grdi = grd%isc,grd%isc+halo_width-1 this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next nbergs_to_send_w=nbergs_to_send_w+1 - current_halo_status=kick_the_bucket%halo_berg - kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w, bergs%max_bonds) - kick_the_bucket%halo_berg=current_halo_status - enddo + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_w, nbergs_to_send_w, bergs%max_bonds) + kick_the_bucket%halo_berg=current_halo_status + enddo enddo; enddo - ! Send bergs east if (grd%pe_E.ne.NULL_PE) then call mpp_send(nbergs_to_send_e, plen=1, to_pe=grd%pe_E, tag=COMM_TAG_1) @@ -1266,13 +1365,11 @@ subroutine update_halo_icebergs(bergs) nbergs_rcvd_from_e=0 endif - - ! Find number of bergs that headed north/south + ! Find number of bergs that headed north/south nbergs_to_send_n=0 nbergs_to_send_s=0 - - !Bergs on north side of the processor + ! Bergs on north side of the processor do grdj = grd%jec-halo_width+2,grd%jec ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) @@ -1286,35 +1383,33 @@ subroutine update_halo_icebergs(bergs) enddo enddo; enddo - - !Bergs on south side of the processor + ! Bergs on south side of the processor do grdj = grd%jsc,grd%jsc+halo_width-1 ; do grdi = grd%isd,grd%ied this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next nbergs_to_send_s=nbergs_to_send_s+1 - current_halo_status=kick_the_bucket%halo_berg - kick_the_bucket%halo_berg=1. - call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s,bergs%max_bonds ) - kick_the_bucket%halo_berg=current_halo_status + current_halo_status=kick_the_bucket%halo_berg + kick_the_bucket%halo_berg=1. + call pack_berg_into_buffer2(kick_the_bucket, bergs%obuffer_s, nbergs_to_send_s,bergs%max_bonds ) + kick_the_bucket%halo_berg=current_halo_status enddo enddo; enddo - ! Send bergs north if (grd%pe_N.ne.NULL_PE) then if(folded_north_on_pe) then - call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_9) + call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_9) else - call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_5) + call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_5) endif if (nbergs_to_send_n.gt.0) then - if(folded_north_on_pe) then - call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) - else - call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_6) - endif + if(folded_north_on_pe) then + call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) + else + call mpp_send(bergs%obuffer_n%data, nbergs_to_send_n*buffer_width, grd%pe_N, tag=COMM_TAG_6) + endif endif endif @@ -1326,7 +1421,6 @@ subroutine update_halo_icebergs(bergs) endif endif - ! Receive bergs from south if (grd%pe_S.ne.NULL_PE) then nbergs_rcvd_from_s=-999 @@ -1349,9 +1443,9 @@ subroutine update_halo_icebergs(bergs) if (grd%pe_N.ne.NULL_PE) then nbergs_rcvd_from_n=-999 if(folded_north_on_pe) then - call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_9) + call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_9) else - call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_7) + call mpp_recv(nbergs_rcvd_from_n, glen=1, from_pe=grd%pe_N, tag=COMM_TAG_7) endif if (nbergs_rcvd_from_n.lt.0) then write(stderrunit,*) 'pe=',mpp_pe(),' received a bad number',nbergs_rcvd_from_n,' from',grd%pe_N,' (N) !!!!!!!!!!!!!!!!!!!!!!' @@ -1359,9 +1453,9 @@ subroutine update_halo_icebergs(bergs) if (nbergs_rcvd_from_n.gt.0) then call increase_ibuffer(bergs%ibuffer_n, nbergs_rcvd_from_n,buffer_width) if(folded_north_on_pe) then - call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) + call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_10) else - call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) + call mpp_recv(bergs%ibuffer_n%data, nbergs_rcvd_from_n*buffer_width, grd%pe_N, tag=COMM_TAG_8) endif do i=1, nbergs_rcvd_from_n call unpack_berg_from_buffer2(bergs, bergs%ibuffer_n, i, grd, max_bonds_in=bergs%max_bonds ) @@ -1371,23 +1465,20 @@ subroutine update_halo_icebergs(bergs) nbergs_rcvd_from_n=0 endif + ! For debugging + if (halo_debugging) then + call mpp_sync_self() + do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied + this=>bergs%list(grdi,grdj)%first + do while (associated(this)) + write(stderrunit,*) 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj + this=>this%next + enddo + enddo; enddo + call show_all_bonds(bergs) + endif - -!For debugging -if (halo_debugging) then - call mpp_sync_self() - do grdj = grd%jsd,grd%jed ; do grdi = grd%isd,grd%ied - this=>bergs%list(grdi,grdj)%first - do while (associated(this)) - write(stderrunit,*) 'C', this%iceberg_num, mpp_pe(), this%halo_berg, grdi, grdj - this=>this%next - enddo - enddo; enddo - call show_all_bonds(bergs) -endif - - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (debug) then nbergs_end=count_bergs(bergs) i=nbergs_rcvd_from_n+nbergs_rcvd_from_s+nbergs_rcvd_from_e+nbergs_rcvd_from_w & @@ -1427,34 +1518,32 @@ subroutine update_halo_icebergs(bergs) call error_mesg('diamonds, update_halos:', 'there are bergs still in halos!', FATAL) endif ! root_pe endif ! debug - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Debugging!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 end subroutine update_halo_icebergs - - -subroutine delete_all_bergs_in_list(bergs,grdj,grdi) - type(icebergs), pointer :: bergs +!> Destroys all bergs in a list +subroutine delete_all_bergs_in_list(bergs, grdj, grdi) + type(icebergs), pointer :: bergs !< Container for all types and memory + integer :: grdi !< i-index of list + integer :: grdj !< j-index of list ! Local variables type(iceberg), pointer :: kick_the_bucket, this - integer :: grdi, grdj this=>bergs%list(grdi,grdj)%first do while (associated(this)) kick_the_bucket=>this this=>this%next call destroy_iceberg(kick_the_bucket) -! call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) + !call delete_iceberg_from_list(bergs%list(grdi,grdj)%first,kick_the_bucket) enddo bergs%list(grdi,grdj)%first=>null() end subroutine delete_all_bergs_in_list -! ############################################################################# - +!> Send bergs in halo lists to other processors subroutine send_bergs_to_other_pes(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(iceberg), pointer :: kick_the_bucket, this integer :: nbergs_to_send_e, nbergs_to_send_w @@ -1595,7 +1684,7 @@ subroutine send_bergs_to_other_pes(bergs) if (grd%pe_N.ne.NULL_PE) then if(folded_north_on_pe) then call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_9) - else + else call mpp_send(nbergs_to_send_n, plen=1, to_pe=grd%pe_N, tag=COMM_TAG_5) endif if (nbergs_to_send_n.gt.0) then @@ -1704,379 +1793,377 @@ subroutine send_bergs_to_other_pes(bergs) end subroutine send_bergs_to_other_pes - subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) - ! Arguments - type(iceberg), pointer :: berg - type(buffer), pointer :: buff - integer, intent(in) :: n - integer, optional :: max_bonds_in - !integer, intent(in) :: max_bonds ! Change this later - ! Local variables - integer :: counter, k, max_bonds - type(bond), pointer :: current_bond - - max_bonds=0 - if (present(max_bonds_in)) max_bonds=max_bonds_in - - - if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width) - if (n>buff%size) call increase_ibuffer(buff,n,buffer_width) - - buff%data(1,n)=berg%lon - buff%data(2,n)=berg%lat - buff%data(3,n)=berg%uvel - buff%data(4,n)=berg%vvel - buff%data(5,n)=berg%xi - buff%data(6,n)=berg%yj - buff%data(7,n)=berg%start_lon - buff%data(8,n)=berg%start_lat - buff%data(9,n)=float(berg%start_year) - buff%data(10,n)=berg%start_day - buff%data(11,n)=berg%start_mass - buff%data(12,n)=berg%mass - buff%data(13,n)=berg%thickness - buff%data(14,n)=berg%width - buff%data(15,n)=berg%length - buff%data(16,n)=berg%mass_scaling - buff%data(17,n)=berg%mass_of_bits - buff%data(18,n)=berg%heat_density - buff%data(19,n)=berg%ine - buff%data(20,n)=berg%jne - buff%data(21,n)=berg%axn !Alon - buff%data(22,n)=berg%ayn !Alon - buff%data(23,n)=berg%bxn !Alon - buff%data(24,n)=berg%byn !Alon - buff%data(25,n)=float(berg%iceberg_num) - buff%data(26,n)=berg%halo_berg - buff%data(27,n)=berg%static_berg - - if (max_bonds .gt. 0) then - counter=27 !how many data points being passed so far (must match above) - current_bond=>berg%first_bond - do k = 1,max_bonds - if (associated(current_bond)) then - buff%data(counter+(3*(k-1)+1),n)=float(current_bond%other_berg_num) - buff%data(counter+(3*(k-1)+2),n)=float(current_bond%other_berg_ine) - buff%data(counter+(3*(k-1)+3),n)=float(current_bond%other_berg_jne) - current_bond=>current_bond%next_bond - else - buff%data(counter+(3*(k-1)+1),n)=0. - buff%data(counter+(3*(k-1)+2),n)=0. - buff%data(counter+(3*(k-1)+3),n)=0. - endif - enddo - endif - - ! Clearing berg pointer from partner bonds - !if (berg%halo_berg .lt. 0.5) then - ! call clear_berg_from_partners_bonds(berg) - !endif - - end subroutine pack_berg_into_buffer2 - - -!###########################################################################3 +!> Pack a berg into a buffer +subroutine pack_berg_into_buffer2(berg, buff, n, max_bonds_in) +! Arguments +type(iceberg), pointer :: berg !< Iceberg to pack into buffer +type(buffer), pointer :: buff !< Buffer to pack berg into +integer, intent(in) :: n !< Position in buffer to place berg +integer, optional :: max_bonds_in !< +!integer, intent(in) :: max_bonds ! Change this later +! Local variables +integer :: counter, k, max_bonds +type(bond), pointer :: current_bond - subroutine clear_berg_from_partners_bonds(berg) - !Arguments - type(iceberg), intent(in), pointer :: berg - type(iceberg), pointer :: other_berg - type(bond), pointer :: current_bond, matching_bond - integer :: stderrunit - ! Get the stderr unit number - stderrunit = stderr() + max_bonds=0 + if (present(max_bonds_in)) max_bonds=max_bonds_in + if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width) + if (n>buff%size) call increase_ibuffer(buff,n,buffer_width) + + buff%data(1,n)=berg%lon + buff%data(2,n)=berg%lat + buff%data(3,n)=berg%uvel + buff%data(4,n)=berg%vvel + buff%data(5,n)=berg%xi + buff%data(6,n)=berg%yj + buff%data(7,n)=berg%start_lon + buff%data(8,n)=berg%start_lat + buff%data(9,n)=float(berg%start_year) + buff%data(10,n)=berg%start_day + buff%data(11,n)=berg%start_mass + buff%data(12,n)=berg%mass + buff%data(13,n)=berg%thickness + buff%data(14,n)=berg%width + buff%data(15,n)=berg%length + buff%data(16,n)=berg%mass_scaling + buff%data(17,n)=berg%mass_of_bits + buff%data(18,n)=berg%heat_density + buff%data(19,n)=berg%ine + buff%data(20,n)=berg%jne + buff%data(21,n)=berg%axn !Alon + buff%data(22,n)=berg%ayn !Alon + buff%data(23,n)=berg%bxn !Alon + buff%data(24,n)=berg%byn !Alon + buff%data(25,n)=float(berg%iceberg_num) + buff%data(26,n)=berg%halo_berg + buff%data(27,n)=berg%static_berg + + if (max_bonds .gt. 0) then + counter=27 !how many data points being passed so far (must match above) current_bond=>berg%first_bond - do while (associated(current_bond)) !Looping over bonds - other_berg=>current_bond%other_berg - if (associated(other_berg)) then - !write(stderrunit,*) , 'Other berg', berg%iceberg_num, other_berg%iceberg_num, mpp_pe() - matching_bond=>other_berg%first_bond - do while (associated(matching_bond)) ! Looping over possible matching bonds in other_berg - if (matching_bond%other_berg_num .eq. berg%iceberg_num) then - !write(stderrunit,*) , 'Clearing', berg%iceberg_num, matching_bond%other_berg_num,other_berg%iceberg_num, mpp_pe() - matching_bond%other_berg=>null() - matching_bond=>null() - else - matching_bond=>matching_bond%next_bond - endif - enddo + do k = 1,max_bonds + if (associated(current_bond)) then + buff%data(counter+(3*(k-1)+1),n)=float(current_bond%other_berg_num) + buff%data(counter+(3*(k-1)+2),n)=float(current_bond%other_berg_ine) + buff%data(counter+(3*(k-1)+3),n)=float(current_bond%other_berg_jne) + current_bond=>current_bond%next_bond else - ! Note: This is meant to be unmatched after you have cleared the first berg - ! call error_mesg('diamonds, clear berg from partners', 'The bond you are trying to clear is unmatched!', WARNING) + buff%data(counter+(3*(k-1)+1),n)=0. + buff%data(counter+(3*(k-1)+2),n)=0. + buff%data(counter+(3*(k-1)+3),n)=0. endif - current_bond=>current_bond%next_bond - enddo !End loop over bonds + enddo + endif - end subroutine clear_berg_from_partners_bonds + ! Clearing berg pointer from partner bonds + !if (berg%halo_berg .lt. 0.5) then + ! call clear_berg_from_partners_bonds(berg) + !endif +end subroutine pack_berg_into_buffer2 - subroutine unpack_berg_from_buffer2(bergs, buff, n,grd, force_append, max_bonds_in) - ! Arguments - type(icebergs), pointer :: bergs - type(buffer), pointer :: buff - integer, intent(in) :: n - type(icebergs_gridded), pointer :: grd - logical, optional :: force_append - integer, optional :: max_bonds_in - ! Local variables - !real :: lon, lat, uvel, vvel, xi, yj - - !real :: start_lon, start_lat, start_day, start_mass - !integer :: ine, jne, start_year - logical :: lres - type(iceberg) :: localberg - type(iceberg), pointer :: this - integer :: other_berg_num, other_berg_ine, other_berg_jne - integer :: counter, k, max_bonds - integer :: stderrunit - logical :: force_app - logical :: quick +subroutine clear_berg_from_partners_bonds(berg) +! Arguments +type(iceberg), intent(in), pointer :: berg +! Local variables +type(iceberg), pointer :: other_berg +type(bond), pointer :: current_bond, matching_bond +integer :: stderrunit +! Get the stderr unit number +stderrunit = stderr() + + current_bond=>berg%first_bond + do while (associated(current_bond)) !Looping over bonds + other_berg=>current_bond%other_berg + if (associated(other_berg)) then + !write(stderrunit,*) , 'Other berg', berg%iceberg_num, other_berg%iceberg_num, mpp_pe() + matching_bond=>other_berg%first_bond + do while (associated(matching_bond)) ! Looping over possible matching bonds in other_berg + if (matching_bond%other_berg_num .eq. berg%iceberg_num) then + !write(stderrunit,*) , 'Clearing', berg%iceberg_num, matching_bond%other_berg_num,other_berg%iceberg_num, mpp_pe() + matching_bond%other_berg=>null() + matching_bond=>null() + else + matching_bond=>matching_bond%next_bond + endif + enddo + else + ! Note: This is meant to be unmatched after you have cleared the first berg + ! call error_mesg('diamonds, clear berg from partners', 'The bond you are trying to clear is unmatched!', WARNING) + endif + current_bond=>current_bond%next_bond + enddo !End loop over bonds + +end subroutine clear_berg_from_partners_bonds + +!> Unpacks a berg entry from a buffer to a new berg +subroutine unpack_berg_from_buffer2(bergs, buff, n, grd, force_append, max_bonds_in) +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +type(buffer), pointer :: buff !< Buffer from which to unpack berg +integer, intent(in) :: n !< Position in buffer to unpack +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +logical, optional :: force_append !< +integer, optional :: max_bonds_in !< +! Local variables +!real :: lon, lat, uvel, vvel, xi, yj +!real :: start_lon, start_lat, start_day, start_mass +!integer :: ine, jne, start_year +logical :: lres +type(iceberg) :: localberg +type(iceberg), pointer :: this +integer :: other_berg_num, other_berg_ine, other_berg_jne +integer :: counter, k, max_bonds +integer :: stderrunit +logical :: force_app +logical :: quick ! Get the stderr unit number stderrunit = stderr() - + quick=.false. max_bonds=0 if (present(max_bonds_in)) max_bonds=max_bonds_in force_app = .false. if(present(force_append)) force_app = force_append - - localberg%lon=buff%data(1,n) - localberg%lat=buff%data(2,n) - localberg%uvel=buff%data(3,n) - localberg%vvel=buff%data(4,n) - localberg%xi=buff%data(5,n) - localberg%yj=buff%data(6,n) - localberg%start_lon=buff%data(7,n) - localberg%start_lat=buff%data(8,n) - localberg%start_year=nint(buff%data(9,n)) - localberg%start_day=buff%data(10,n) - localberg%start_mass=buff%data(11,n) - localberg%mass=buff%data(12,n) - localberg%thickness=buff%data(13,n) - localberg%width=buff%data(14,n) - localberg%length=buff%data(15,n) - localberg%mass_scaling=buff%data(16,n) - localberg%mass_of_bits=buff%data(17,n) - localberg%heat_density=buff%data(18,n) - - localberg%axn=buff%data(21,n) - localberg%ayn=buff%data(22,n) - localberg%bxn=buff%data(23,n) - localberg%byn=buff%data(24,n) - localberg%iceberg_num=nint(buff%data(25,n)) - localberg%halo_berg=buff%data(26,n) - localberg%static_berg=buff%data(27,n) - counter=27 !how many data points being passed so far (must match largest number directly above) - - !These quantities no longer need to be passed between processors - localberg%uvel_old=localberg%uvel - localberg%vvel_old=localberg%vvel - localberg%lon_old=localberg%lon - localberg%lat_old=localberg%lat - - ! force_app=.true. - if(force_app) then !force append with origin ine,jne (for I/O) - - localberg%ine=buff%data(19,n) - localberg%jne=buff%data(20,n) - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) + + localberg%lon=buff%data(1,n) + localberg%lat=buff%data(2,n) + localberg%uvel=buff%data(3,n) + localberg%vvel=buff%data(4,n) + localberg%xi=buff%data(5,n) + localberg%yj=buff%data(6,n) + localberg%start_lon=buff%data(7,n) + localberg%start_lat=buff%data(8,n) + localberg%start_year=nint(buff%data(9,n)) + localberg%start_day=buff%data(10,n) + localberg%start_mass=buff%data(11,n) + localberg%mass=buff%data(12,n) + localberg%thickness=buff%data(13,n) + localberg%width=buff%data(14,n) + localberg%length=buff%data(15,n) + localberg%mass_scaling=buff%data(16,n) + localberg%mass_of_bits=buff%data(17,n) + localberg%heat_density=buff%data(18,n) + + localberg%axn=buff%data(21,n) + localberg%ayn=buff%data(22,n) + localberg%bxn=buff%data(23,n) + localberg%byn=buff%data(24,n) + localberg%iceberg_num=nint(buff%data(25,n)) + localberg%halo_berg=buff%data(26,n) + localberg%static_berg=buff%data(27,n) + counter=27 !how many data points being passed so far (must match largest number directly above) + + !These quantities no longer need to be passed between processors + localberg%uvel_old=localberg%uvel + localberg%vvel_old=localberg%vvel + localberg%lon_old=localberg%lon + localberg%lat_old=localberg%lat + + ! force_app=.true. + if(force_app) then !force append with origin ine,jne (for I/O) + + localberg%ine=buff%data(19,n) + localberg%jne=buff%data(20,n) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) + else + lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + if (lres) then + lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) + call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) else - lres=find_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) + lres=find_cell_wide(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) if (lres) then lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) else - lres=find_cell_wide(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne) - if (lres) then - lres=pos_within_cell(grd, localberg%lon, localberg%lat, localberg%ine, localberg%jne, localberg%xi, localberg%yj) - call add_new_berg_to_list(bergs%list(localberg%ine,localberg%jne)%first, localberg,quick,this) - else - write(stderrunit,'("diamonds, unpack_berg_from_buffer pe=(",i3,a,2i4,a,2f8.2)')& - & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat - write(stderrunit,*) localberg%lon,localberg%lat - write(stderrunit,*) localberg%uvel,localberg%vvel - write(stderrunit,*) localberg%axn,localberg%ayn !Alon - write(stderrunit,*) localberg%bxn,localberg%byn !Alon - write(stderrunit,*) localberg%uvel_old,localberg%vvel_old - write(stderrunit,*) localberg%lon_old,localberg%lat_old - write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec - write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed - write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) - write(stderrunit,*) grd%lat(grd%isc-1,grd%jsc-1),grd%lat(grd%iec,grd%jec) - write(stderrunit,*) grd%lon(grd%isd,grd%jsd),grd%lon(grd%ied,grd%jsd) - write(stderrunit,*) grd%lat(grd%isd,grd%jsd),grd%lat(grd%ied,grd%jed) - write(stderrunit,*) lres - call error_mesg('diamonds, unpack_berg_from_buffer', 'can not find a cell to place berg in!', FATAL) - endif + write(stderrunit,'("diamonds, unpack_berg_from_buffer pe=(",i3,a,2i4,a,2f8.2)')& + & mpp_pe(),') Failed to find i,j=',localberg%ine,localberg%jne,' for lon,lat=',localberg%lon,localberg%lat + write(stderrunit,*) localberg%lon,localberg%lat + write(stderrunit,*) localberg%uvel,localberg%vvel + write(stderrunit,*) localberg%axn,localberg%ayn !Alon + write(stderrunit,*) localberg%bxn,localberg%byn !Alon + write(stderrunit,*) localberg%uvel_old,localberg%vvel_old + write(stderrunit,*) localberg%lon_old,localberg%lat_old + write(stderrunit,*) grd%isc,grd%iec,grd%jsc,grd%jec + write(stderrunit,*) grd%isd,grd%ied,grd%jsd,grd%jed + write(stderrunit,*) grd%lon(grd%isc-1,grd%jsc-1),grd%lon(grd%iec,grd%jsc) + write(stderrunit,*) grd%lat(grd%isc-1,grd%jsc-1),grd%lat(grd%iec,grd%jec) + write(stderrunit,*) grd%lon(grd%isd,grd%jsd),grd%lon(grd%ied,grd%jsd) + write(stderrunit,*) grd%lat(grd%isd,grd%jsd),grd%lat(grd%ied,grd%jed) + write(stderrunit,*) lres + call error_mesg('diamonds, unpack_berg_from_buffer', 'can not find a cell to place berg in!', FATAL) endif endif + endif - !# Do stuff to do with bonds here MP1 - - this%first_bond=>null() - if (max_bonds .gt. 0) then - do k = 1,max_bonds - other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) - other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) - other_berg_jne=nint(buff%data(counter+(3*(k-1)+3),n)) - if (other_berg_num .gt. 0.5) then - call form_a_bond(this, other_berg_num, other_berg_ine, other_berg_jne) - endif - enddo - endif - this=>null() - - !############################## + !# Do stuff to do with bonds here MP1 + this%first_bond=>null() + if (max_bonds .gt. 0) then + do k = 1,max_bonds + other_berg_num=nint(buff%data(counter+(3*(k-1)+1),n)) + other_berg_ine=nint(buff%data(counter+(3*(k-1)+2),n)) + other_berg_jne=nint(buff%data(counter+(3*(k-1)+3),n)) + if (other_berg_num .gt. 0.5) then + call form_a_bond(this, other_berg_num, other_berg_ine, other_berg_jne) + endif + enddo + endif + this=>null() - end subroutine unpack_berg_from_buffer2 +end subroutine unpack_berg_from_buffer2 - subroutine increase_ibuffer(old,num_bergs,width) - ! Arguments - type(buffer), pointer :: old - integer, intent(in) :: num_bergs,width - ! Local variables - type(buffer), pointer :: new - integer :: new_size, old_size - !This routine checks if the buffer size is smaller than nbergs - !If it is, the buffer size is increased by delta_buf - !The buffer increases by more than 1 so that the buffer does not have to increase every time +!> Increase size of buffer +!! +!! This routine checks if the buffer size is smaller than nbergs +!! If it is, the buffer size is increased by delta_buf. +!! The buffer increases by more than 1 so that the buffer does not have to increase every time. +subroutine increase_ibuffer(old, num_bergs, width) +! Arguments +type(buffer), pointer :: old !< Buffer to expand +integer, intent(in) :: num_bergs !< Number of bergs +integer, intent(in) :: width !< Width of buffer (first dimension) +! Local variables +type(buffer), pointer :: new +integer :: new_size, old_size - if (.not.associated(old)) then - new_size=num_bergs+delta_buf - old_size=0 + if (.not.associated(old)) then + new_size=num_bergs+delta_buf + old_size=0 + else + old_size=old%size + if (num_bergsnew - !write(stderr(),*) 'diamonds, increase_ibuffer',mpp_pe(),' increased to',new_size + new_size=num_bergs+delta_buf endif + endif - end subroutine increase_ibuffer - - subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) - ! Arguments - type(xyt), pointer :: traj - type(buffer), pointer :: buff - integer, intent(in) :: n - logical, intent(in) :: save_short_traj - ! Local variables - - if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width_traj) - if (n>buff%size) call increase_ibuffer(buff,n,buffer_width_traj) - - buff%data(1,n)=traj%lon - buff%data(2,n)=traj%lat - buff%data(3,n)=float(traj%year) - buff%data(4,n)=traj%day - buff%data(5,n)=float(traj%iceberg_num) - if (.not. save_short_traj) then - buff%data(6,n)=traj%uvel - buff%data(7,n)=traj%vvel - buff%data(8,n)=traj%mass - buff%data(9,n)=traj%mass_of_bits - buff%data(10,n)=traj%heat_density - buff%data(11,n)=traj%thickness - buff%data(12,n)=traj%width - buff%data(13,n)=traj%length - buff%data(14,n)=traj%uo - buff%data(15,n)=traj%vo - buff%data(16,n)=traj%ui - buff%data(17,n)=traj%vi - buff%data(18,n)=traj%ua - buff%data(19,n)=traj%va - buff%data(20,n)=traj%ssh_x - buff%data(21,n)=traj%ssh_y - buff%data(22,n)=traj%sst - buff%data(23,n)=traj%cn - buff%data(24,n)=traj%hi - buff%data(25,n)=traj%axn !Alon - buff%data(26,n)=traj%ayn !Alon - buff%data(27,n)=traj%bxn !Alon - buff%data(28,n)=traj%byn !Alon - buff%data(29,n)=traj%halo_berg !Alon - buff%data(30,n)=traj%static_berg !Alon - buff%data(31,n)=traj%sss + if (old_size.ne.new_size) then + allocate(new) + !allocate(new%data(buffer_width,new_size)) + allocate(new%data(width,new_size)) + new%size=new_size + if (associated(old)) then + new%data(:,1:old%size)=old%data(:,1:old%size) + deallocate(old%data) + deallocate(old) endif + old=>new + !write(stderr(),*) 'diamonds, increase_ibuffer',mpp_pe(),' increased to',new_size + endif - end subroutine pack_traj_into_buffer2 - - subroutine unpack_traj_from_buffer2(first, buff, n, save_short_traj) - ! Arguments - type(xyt), pointer :: first - type(buffer), pointer :: buff - integer, intent(in) :: n - ! Local variables - type(xyt) :: traj - integer :: stderrunit - logical, intent(in) :: save_short_traj - ! Get the stderr unit number - stderrunit = stderr() +end subroutine increase_ibuffer - traj%lon=buff%data(1,n) - traj%lat=buff%data(2,n) - traj%year=nint(buff%data(3,n)) - traj%day=buff%data(4,n) - traj%iceberg_num=nint(buff%data(5,n)) - if (.not. save_short_traj) then - traj%uvel=buff%data(6,n) - traj%vvel=buff%data(7,n) - traj%mass=buff%data(8,n) - traj%mass_of_bits=buff%data(9,n) - traj%heat_density=buff%data(10,n) - traj%thickness=buff%data(11,n) - traj%width=buff%data(12,n) - traj%length=buff%data(13,n) - traj%uo=buff%data(14,n) - traj%vo=buff%data(15,n) - traj%ui=buff%data(16,n) - traj%vi=buff%data(17,n) - traj%ua=buff%data(18,n) - traj%va=buff%data(19,n) - traj%ssh_x=buff%data(20,n) - traj%ssh_y=buff%data(21,n) - traj%sst=buff%data(22,n) - traj%cn=buff%data(23,n) - traj%hi=buff%data(24,n) - traj%axn=buff%data(25,n) !Alon - traj%ayn=buff%data(26,n) !Alon - traj%bxn=buff%data(27,n) !Alon - traj%byn=buff%data(28,n) !Alon - traj%halo_berg=buff%data(29,n) !Alon - traj%static_berg=buff%data(30,n) !Alon - traj%sss=buff%data(31,n) - endif - call append_posn(first, traj) +!> Packs a trajectory entry into a buffer +subroutine pack_traj_into_buffer2(traj, buff, n, save_short_traj) +! Arguments +type(xyt), pointer :: traj !< Trajectory entry to pack +type(buffer), pointer :: buff !< Buffer to pack entry into +integer, intent(in) :: n !< Position in buffer to place entry +logical, intent(in) :: save_short_traj !< If true, only use a subset of trajectory data + + if (.not.associated(buff)) call increase_ibuffer(buff,n,buffer_width_traj) + if (n>buff%size) call increase_ibuffer(buff,n,buffer_width_traj) + + buff%data(1,n)=traj%lon + buff%data(2,n)=traj%lat + buff%data(3,n)=float(traj%year) + buff%data(4,n)=traj%day + buff%data(5,n)=float(traj%iceberg_num) + if (.not. save_short_traj) then + buff%data(6,n)=traj%uvel + buff%data(7,n)=traj%vvel + buff%data(8,n)=traj%mass + buff%data(9,n)=traj%mass_of_bits + buff%data(10,n)=traj%heat_density + buff%data(11,n)=traj%thickness + buff%data(12,n)=traj%width + buff%data(13,n)=traj%length + buff%data(14,n)=traj%uo + buff%data(15,n)=traj%vo + buff%data(16,n)=traj%ui + buff%data(17,n)=traj%vi + buff%data(18,n)=traj%ua + buff%data(19,n)=traj%va + buff%data(20,n)=traj%ssh_x + buff%data(21,n)=traj%ssh_y + buff%data(22,n)=traj%sst + buff%data(23,n)=traj%cn + buff%data(24,n)=traj%hi + buff%data(25,n)=traj%axn !Alon + buff%data(26,n)=traj%ayn !Alon + buff%data(27,n)=traj%bxn !Alon + buff%data(28,n)=traj%byn !Alon + buff%data(29,n)=traj%halo_berg !Alon + buff%data(30,n)=traj%static_berg !Alon + buff%data(31,n)=traj%sss + endif - end subroutine unpack_traj_from_buffer2 +end subroutine pack_traj_into_buffer2 +!> Unpacks a trajectory entry from a buffer +subroutine unpack_traj_from_buffer2(first, buff, n, save_short_traj) +! Arguments +type(xyt), pointer :: first !< Trajectory list +type(buffer), pointer :: buff !< Buffer from which to unpack +integer, intent(in) :: n !< Position in buffer to unpack +logical, intent(in) :: save_short_traj !< If true, only use a subset of trajectory data +! Local variables +type(xyt) :: traj + + traj%lon=buff%data(1,n) + traj%lat=buff%data(2,n) + traj%year=nint(buff%data(3,n)) + traj%day=buff%data(4,n) + traj%iceberg_num=nint(buff%data(5,n)) + if (.not. save_short_traj) then + traj%uvel=buff%data(6,n) + traj%vvel=buff%data(7,n) + traj%mass=buff%data(8,n) + traj%mass_of_bits=buff%data(9,n) + traj%heat_density=buff%data(10,n) + traj%thickness=buff%data(11,n) + traj%width=buff%data(12,n) + traj%length=buff%data(13,n) + traj%uo=buff%data(14,n) + traj%vo=buff%data(15,n) + traj%ui=buff%data(16,n) + traj%vi=buff%data(17,n) + traj%ua=buff%data(18,n) + traj%va=buff%data(19,n) + traj%ssh_x=buff%data(20,n) + traj%ssh_y=buff%data(21,n) + traj%sst=buff%data(22,n) + traj%cn=buff%data(23,n) + traj%hi=buff%data(24,n) + traj%axn=buff%data(25,n) !Alon + traj%ayn=buff%data(26,n) !Alon + traj%bxn=buff%data(27,n) !Alon + traj%byn=buff%data(28,n) !Alon + traj%halo_berg=buff%data(29,n) !Alon + traj%static_berg=buff%data(30,n) !Alon + traj%sss=buff%data(31,n) + endif + call append_posn(first, traj) -! ############################################################################## +end subroutine unpack_traj_from_buffer2 +!> Add a new berg to a list by copying values +!! +!! The input berg are a berg with set values whose memory is assumed to be +!! temporary. This routine allocates memory for a new berg and copies the +!! the input values into it. The memory for the new berg is pointed to +!! by newberg_return (if present). subroutine add_new_berg_to_list(first, bergvals, quick, newberg_return) ! Arguments -type(iceberg), pointer :: first -type(iceberg), intent(in) :: bergvals -type(iceberg), intent(out), pointer, optional :: newberg_return -logical, intent(in), optional :: quick +type(iceberg), pointer :: first !< List of icebergs +type(iceberg), intent(in) :: bergvals !< Berg values to copy +type(iceberg), intent(out), pointer, optional :: newberg_return !< New berg +logical, intent(in), optional :: quick !< If true, use the quick insertion algorithm ! Local variables type(iceberg), pointer :: new=>null() @@ -2103,12 +2190,12 @@ subroutine add_new_berg_to_list(first, bergvals, quick, newberg_return) end subroutine add_new_berg_to_list -! ############################################################################## +!> Scans all lists and checks that bergs are in a sorted order in each list subroutine count_out_of_order(bergs,label) ! Arguments -type(icebergs), pointer :: bergs -character(len=*) :: label +type(icebergs), pointer :: bergs !< Container for all types and memory +character(len=*) :: label !< Label to add to messages ! Local variables type(iceberg), pointer :: this, next integer :: i, icnt1, icnt2, icnt3 @@ -2157,12 +2244,11 @@ subroutine count_out_of_order(bergs,label) end subroutine count_out_of_order -! ############################################################################## - +!> Scans all lists and checks for duplicate identifiers between lists subroutine check_for_duplicates(bergs,label) ! Arguments -type(icebergs), pointer :: bergs -character(len=*) :: label +type(icebergs), pointer :: bergs !< Container for all types and memory +character(len=*) :: label !< Label to add to message ! Local variables type(iceberg), pointer :: this1, next1, this2, next2 integer :: icnt_id, icnt_same @@ -2201,12 +2287,14 @@ subroutine check_for_duplicates(bergs,label) end subroutine check_for_duplicates -! ############################################################################## - +!> Prints a particular berg's vitals +!! +!! All lists are scanned and if a berg has the identifier equal to +!! debug_iceberg_with_id then the state of that berg is printed. subroutine monitor_a_berg(bergs, label) ! Arguments -type(icebergs), pointer :: bergs -character(len=*) :: label +type(icebergs), pointer :: bergs !< Container for all types and memory +character(len=*) :: label !< Label to add to message ! Local variables type(iceberg), pointer :: this integer :: grdi, grdj @@ -2227,12 +2315,13 @@ subroutine monitor_a_berg(bergs, label) end subroutine monitor_a_berg -! ############################################################################## - +!> Inserts a berg into a list subroutine insert_berg_into_list(first, newberg, quick) ! Arguments -type(iceberg), pointer :: first, newberg -logical, intent(in), optional :: quick +type(iceberg), pointer :: first !< List of bergs +type(iceberg), pointer :: newberg !< New berg to insert +logical, intent(in), optional :: quick !< If true, use the quick insertion algorithm + !! \todo Delete arguments since the code does not appear to use it. ! Local variables type(iceberg), pointer :: this, prev logical :: quickly @@ -2277,11 +2366,13 @@ subroutine insert_berg_into_list(first, newberg, quick) end subroutine insert_berg_into_list -! ############################################################################## - +!> Returns True when berg1 and berg2 are in sorted order +!! \todo inorder() should use the iceberg identifier for efficiency and simplicity +!! instead of dates and properties logical function inorder(berg1, berg2) !MP Alon - Change to include iceberg_num ! Arguments -type(iceberg), pointer :: berg1, berg2 +type(iceberg), pointer :: berg1 !< An iceberg +type(iceberg), pointer :: berg2 !< An iceberg ! Local variables if (berg1%start_year Returns a hash of a berg's start year and day +!! \todo Should be able to remove this function if using identifiers properly +real function time_hash(berg)! Alon: Think about removing this. +! Arguments +type(iceberg), pointer :: berg + time_hash=berg%start_day+366.*float(berg%start_year) +end function time_hash -! ############################################################################## +!> Returns a hash of a berg's start position +!! \todo Should be able to remove this function if using identifiers properly +real function pos_hash(berg) +! Arguments +type(iceberg), pointer :: berg !< An iceberg + pos_hash=berg%start_lon+360.*(berg%start_lat+90.) +end function pos_hash +!> Returns True if berg1 and berg2 have the identifying properties +!! +!! This function compares the start year, day, mass and position of the bergs. logical function sameid(berg1, berg2) ! Alon: MP updat this. ! Arguments -type(iceberg), pointer :: berg1, berg2 +type(iceberg), pointer :: berg1 !< An iceberg +type(iceberg), pointer :: berg2 !< An iceberg ! Local variables sameid=.false. if (berg1%start_year.ne.berg2%start_year) return @@ -2352,11 +2446,12 @@ logical function sameid(berg1, berg2) ! Alon: MP updat this. sameid=.true. ! passing the above tests means that bergs 1 and 2 have the same id end function sameid -! ############################################################################## - +!> Returns True if berg1 and berg2 are identical in both identifying properties +!! and dynamic properties logical function sameberg(berg1, berg2) ! Arguments -type(iceberg), pointer :: berg1, berg2 +type(iceberg), pointer :: berg1 !< An iceberg +type(iceberg), pointer :: berg2 !< An iceberg ! Local variables sameberg=.false. if (.not. sameid(berg1, berg2)) return @@ -2379,22 +2474,24 @@ logical function sameberg(berg1, berg2) sameberg=.true. ! passing the above tests mean that bergs 1 and 2 are identical end function sameberg -! ############################################################################## - +!> Returns the year day (a single float for the day of the year, range 0-365.999...) real function yearday(imon, iday, ihr, imin, isec) ! Arguments -integer, intent(in) :: imon, iday, ihr, imin, isec +integer, intent(in) :: imon !< Month of year (1-12) +integer, intent(in) :: iday !< Day of month (1-31) +integer, intent(in) :: ihr !< Hour of day (0-23) +integer, intent(in) :: imin !< Minute of hour (0-59) +integer, intent(in) :: isec !< Second of minute (0-59) yearday=float(imon-1)*31.+float(iday-1)+(float(ihr)+(float(imin)+float(isec)/60.)/60.)/24. end function yearday -! ############################################################################## - +!> Create a new berg with given values subroutine create_iceberg(berg, bergvals) ! Arguments -type(iceberg), pointer :: berg -type(iceberg), intent(in) :: bergvals +type(iceberg), pointer :: berg !< Berg to be created +type(iceberg), intent(in) :: bergvals !< Values to assign ! Local variables integer :: stderrunit @@ -2413,11 +2510,13 @@ subroutine create_iceberg(berg, bergvals) end subroutine create_iceberg -! ############################################################################## - +!> Delete a berg from a list and destroy the memory for the berg +!! +!! first is needed when berg is the first in the list subroutine delete_iceberg_from_list(first, berg) ! Arguments -type(iceberg), pointer :: first, berg +type(iceberg), pointer :: first !< List of bergs +type(iceberg), pointer :: berg !< Berg to be deleted ! Local variables ! Connect neighbors to each other @@ -2433,14 +2532,15 @@ subroutine delete_iceberg_from_list(first, berg) end subroutine delete_iceberg_from_list -! ############################################################################## - +!> Destroy a berg +!! +!! Deallocates memory for a berg after deleting links to the berg recorded in bonds subroutine destroy_iceberg(berg) ! Arguments type(iceberg), pointer :: berg ! Local variables - ! Clears all matching bonds before deallocint memory + ! Clears all matching bonds before deallocating memory call clear_berg_from_partners_bonds(berg) ! Bye-bye berg @@ -2448,14 +2548,14 @@ subroutine destroy_iceberg(berg) end subroutine destroy_iceberg -! ############################################################################## - +!> Print the state of a particular berg subroutine print_berg(iochan, berg, label, il, jl) ! Arguments -integer, intent(in) :: iochan -type(iceberg), pointer :: berg -character(len=*) :: label -integer, optional, intent(in) :: il, jl !< Indices of cell berg should be in +integer, intent(in) :: iochan !< Standard channel to use (usually stdout or stderr) +type(iceberg), pointer :: berg !< Berg to print +character(len=*) :: label !< Label to use in messages +integer, optional, intent(in) :: il !< i-index of cell berg should be in +integer, optional, intent(in) :: jl !< j-index of cell berg should be in ! Local variables write(iochan,'("diamonds, print_berg: ",2a,i5,a,i12,a,2f10.4,i5,f7.2,es12.4,f5.1)') & @@ -2489,13 +2589,12 @@ subroutine print_berg(iochan, berg, label, il, jl) ' ui,vi=', berg%ui, berg%vi end subroutine print_berg -! ############################################################################## - +!> Print the state of all bergs subroutine print_bergs(iochan, bergs, label) ! Arguments -integer, intent(in) :: iochan -type(icebergs), pointer :: bergs -character(len=*) :: label +integer, intent(in) :: iochan !< Standard channel to use (usually stdout or stderr) +type(icebergs), pointer :: bergs !< Container for all types and memory +character(len=*) :: label !< Label to use in messages ! Local variables integer :: nbergs, nnbergs type(iceberg), pointer :: this @@ -2515,11 +2614,8 @@ subroutine print_bergs(iochan, bergs, label) end subroutine print_bergs - -! ############################################################################## - subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, other_berg) - +! Arguments type(iceberg), pointer :: berg type(iceberg), optional, pointer :: other_berg type(bond) , pointer :: new_bond, first_bond @@ -2528,9 +2624,9 @@ subroutine form_a_bond(berg, other_berg_num, other_berg_ine, other_berg_jne, oth integer :: stderrunit stderrunit = stderr() - + if (berg%iceberg_num .ne. other_berg_num) then - + !write (stderrunit,*) , 'Forming a bond!!!', mpp_pe(), berg%iceberg_num, other_berg_num, berg%halo_berg, berg%ine, berg%jne ! Step 1: Create a new bond @@ -2570,7 +2666,8 @@ end subroutine form_a_bond ! ############################################################################# subroutine bond_address_update(bergs) -type(icebergs), pointer :: bergs +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: other_berg, berg type(icebergs_gridded), pointer :: grd integer :: grdi, grdj, nbonds @@ -2589,7 +2686,7 @@ subroutine bond_address_update(bergs) current_bond%other_berg_ine=current_bond%other_berg%ine current_bond%other_berg_jne=current_bond%other_berg%jne else - if (berg%halo_berg .lt. 0.5) then + if (berg%halo_berg .lt. 0.5) then call error_mesg('diamonds, bond address update', 'other berg in bond not assosiated!', FATAL) endif endif @@ -2603,10 +2700,8 @@ subroutine bond_address_update(bergs) end subroutine bond_address_update -!################################################################################################### - subroutine show_all_bonds(bergs) -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: other_berg, berg type(icebergs_gridded), pointer :: grd integer :: grdi, grdj, nbonds @@ -2640,9 +2735,8 @@ subroutine show_all_bonds(bergs) end subroutine show_all_bonds - subroutine connect_all_bonds(bergs) -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: other_berg, berg type(icebergs_gridded), pointer :: grd integer :: i, j @@ -2674,10 +2768,10 @@ subroutine connect_all_bonds(bergs) if (other_berg%iceberg_num .eq. current_bond%other_berg_num) then current_bond%other_berg=>other_berg other_berg=>null() - bond_matched=.true. + bond_matched=.true. else other_berg=>other_berg%next - endif + endif enddo endif if (.not.bond_matched) then @@ -2692,24 +2786,24 @@ subroutine connect_all_bonds(bergs) if (other_berg%iceberg_num .eq. current_bond%other_berg_num) then current_bond%other_berg=>other_berg other_berg=>null() - bond_matched=.true. + bond_matched=.true. else other_berg=>other_berg%next - endif + endif enddo endif endif enddo;enddo endif - if (.not.bond_matched) then + if (.not.bond_matched) then if (berg%halo_berg .lt. 0.5) then - missing_bond=.true. - print * ,'non-halo berg unmatched: ', berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine + missing_bond=.true. + print * ,'non-halo berg unmatched: ', berg%iceberg_num, mpp_pe(), current_bond%other_berg_num, current_bond%other_berg_ine call error_mesg('diamonds, connect_all_bonds', 'A non-halo bond is missing!!!', FATAL) else ! This is not a problem if the partner berg is not yet in the halo !if ( (current_bond%other_berg_ine .gt.grd%isd-1) .and. (current_bond%other_berg_ine .lt.grd%ied+1) & - !.and. (current_bond%other_berg_jne .gt.grd%jsd-1) .and. (current_bond%other_berg_jne .lt.grd%jed+1) ) then - !print * ,'halo berg unmatched: ',mpp_pe(), berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine,current_bond%other_berg_jne + !.and. (current_bond%other_berg_jne .gt.grd%jsd-1) .and. (current_bond%other_berg_jne .lt.grd%jed+1) ) then + !print * ,'halo berg unmatched: ',mpp_pe(), berg%iceberg_num, current_bond%other_berg_num, current_bond%other_berg_ine,current_bond%other_berg_jne !call error_mesg('diamonds, connect_all_bonds', 'A halo bond is missing!!!', WARNING) !endif endif @@ -2728,11 +2822,9 @@ subroutine connect_all_bonds(bergs) endif end subroutine connect_all_bonds - -! ############################################################################# subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg type(iceberg), pointer :: other_berg type(icebergs_gridded), pointer :: grd @@ -2744,7 +2836,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) logical, intent(inout), optional :: check_bond_quality logical :: quality_check integer :: num_unmatched_bonds,num_unmatched_bonds_all_pe -integer :: num_unassosiated_bond_pairs, num_unassosiated_bond_pairs_all_pe +integer :: num_unassosiated_bond_pairs, num_unassosiated_bond_pairs_all_pe integer :: stderrunit ! print *, "starting bond_check" @@ -2776,12 +2868,12 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) other_berg=>current_bond%other_berg if (associated(other_berg)) then other_berg_bond=>other_berg%first_bond - do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list + do while (associated(other_berg_bond)) !loops over the icebergs in the other icebergs bond list if (associated(other_berg_bond%other_berg)) then if (other_berg_bond%other_berg%iceberg_num .eq.berg%iceberg_num) then bond_is_good=.True. !Bond_is_good becomes true when the corresponding bond is found endif - endif + endif if (bond_is_good) then other_berg_bond=>null() else @@ -2791,12 +2883,12 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) if (bond_is_good) then if (debug) write(stderrunit,*) 'Perfect quality Bond:', berg%iceberg_num, current_bond%other_berg_num - else + else if (debug) write(stderrunit,*) 'Non-matching bond...:', berg%iceberg_num, current_bond%other_berg_num num_unmatched_bonds=num_unmatched_bonds+1 endif else - if (debug) write(stderrunit,*) 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%other_berg%iceberg_num + if (debug) write(stderrunit,*) 'Opposite berg is not assosiated:', berg%iceberg_num, current_bond%other_berg%iceberg_num num_unassosiated_bond_pairs=0 endif endif @@ -2811,7 +2903,7 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) call mpp_sum(number_of_bonds_all_pe) bergs%nbonds=number_of_bonds_all_pe !Total number of bonds across all pe's - if (debug) then + if (debug) then if (number_of_bonds .gt. 0) then write(stderrunit,*) "Bonds on PE:",number_of_bonds, "Total bonds", number_of_bonds_all_PE, "on PE number:", mpp_pe() endif @@ -2844,14 +2936,11 @@ subroutine count_bonds(bergs, number_of_bonds, check_bond_quality) end subroutine count_bonds - - -! ############################################################################## - +!> Returns number of bergs across all lists integer function count_bergs(bergs, with_halos) ! Arguments -type(icebergs), pointer :: bergs -logical, optional :: with_halos +type(icebergs), pointer :: bergs !< Container for all types and memory +logical, optional :: with_halos !< If true, include halo lists ! Local variables integer :: grdi, grdj, is, ie, js, je logical :: include_halos @@ -2871,11 +2960,10 @@ integer function count_bergs(bergs, with_halos) end function count_bergs -! ############################################################################## - +!> Returns number of bergs in a list integer function count_bergs_in_list(first) ! Arguments -type(iceberg), pointer :: first +type(iceberg), pointer :: first !< List of bergs ! Local variables type(iceberg), pointer :: this @@ -2888,11 +2976,10 @@ integer function count_bergs_in_list(first) end function count_bergs_in_list -! ############################################################################## - +!> Add a record to the trajectory of each berg subroutine record_posn(bergs) ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(xyt) :: posn type(iceberg), pointer :: this @@ -2938,21 +3025,20 @@ subroutine record_posn(bergs) posn%halo_berg=this%halo_berg posn%static_berg=this%static_berg endif - + call push_posn(this%trajectory, posn) - + this=>this%next enddo enddo ; enddo end subroutine record_posn -! ############################################################################## - +!> Add trajectory values as a new record in a trajectory subroutine push_posn(trajectory, posn_vals) ! Arguments -type(xyt), pointer :: trajectory -type(xyt) :: posn_vals +type(xyt), pointer :: trajectory !< Trajectory list +type(xyt) :: posn_vals !< Values to add ! Local variables type(xyt), pointer :: new_posn @@ -2963,11 +3049,12 @@ subroutine push_posn(trajectory, posn_vals) end subroutine push_posn +!> Appends trajectory values to the end of the trajectory list (slow) +!! \todo append_posn() is very slow and should be removed a.s.a.p. subroutine append_posn(trajectory, posn_vals) -! This routine appends a new position leaf to the end of the given trajectory ! Arguments -type(xyt), pointer :: trajectory -type(xyt) :: posn_vals +type(xyt), pointer :: trajectory !< Trajectory list +type(xyt) :: posn_vals !< Values to add ! Local variables type(xyt), pointer :: new_posn,next,last @@ -2987,12 +3074,11 @@ subroutine append_posn(trajectory, posn_vals) endif end subroutine append_posn -! ############################################################################## - +!> Disconnect a trajectory from a berg and add it to a list of trajectory segments subroutine move_trajectory(bergs, berg) ! Arguments -type(icebergs), pointer :: bergs -type(iceberg), pointer :: berg +type(icebergs), pointer :: bergs !< Container for all types and memory +type(iceberg), pointer :: berg !< Berg containing trajectory ! Local variables type(xyt), pointer :: next, last type(xyt) :: vals @@ -3030,17 +3116,17 @@ subroutine move_trajectory(bergs, berg) end subroutine move_trajectory -! ############################################################################## - +!> Scan all bergs in a list and disconnect trajectories and more to the list of trajectory segments +!! \todo The argument delete_bergs should be removed. subroutine move_all_trajectories(bergs, delete_bergs) ! Arguments -type(icebergs), pointer :: bergs -logical, optional, intent(in) :: delete_bergs +type(icebergs), pointer :: bergs !< Container for all types and memory +logical, optional, intent(in) :: delete_bergs !< If true, delete bergs after disconnecting its trajectory ! Local variables type(iceberg), pointer :: this, next logical :: delete_bergs_after_moving_traj integer :: grdi, grdj - + if (bergs%ignore_traj) return delete_bergs_after_moving_traj = .false. @@ -3057,22 +3143,23 @@ subroutine move_all_trajectories(bergs, delete_bergs) end subroutine move_all_trajectories -! ############################################################################## - +!> Search the grid for a cell containing position x,y logical function find_cell_by_search(grd, x, y, i, j) ! Arguments -type(icebergs_gridded), pointer :: grd -real, intent(in) :: x, y -integer, intent(inout) :: i, j +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +real, intent(in) :: x !< Longitude of position +real, intent(in) :: y !< Latitude of position +integer, intent(inout) :: i !< i-index of cell containing x,y +integer, intent(inout) :: j !< j-index of cell containing x,y ! Local variables integer :: is,ie,js,je,di,dj,io,jo,icnt real :: d0,d1,d2,d3,d4,d5,d6,d7,d8,dmin logical :: explain=.false. real :: Lx - + 911 continue - Lx=grd%Lx + Lx=grd%Lx find_cell_by_search=.false. is=grd%isc; ie=grd%iec; js=grd%jsc; je=grd%jec @@ -3100,7 +3187,7 @@ logical function find_cell_by_search(grd, x, y, i, j) find_cell_by_search=.true. return endif - + do icnt=1, 1*(ie-is+je-js) io=i; jo=j @@ -3143,7 +3230,7 @@ logical function find_cell_by_search(grd, x, y, i, j) find_cell_by_search=.true. return endif - + if ((i==io.and.j==jo) & .and. .not.find_better_min(grd, x, y, 3, i, j) & ) then @@ -3191,7 +3278,7 @@ logical function find_cell_by_search(grd, x, y, i, j) contains -! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # real function dcost(x1, y1, x2, y2,Lx) ! Arguments @@ -3204,11 +3291,11 @@ real function dcost(x1, y1, x2, y2,Lx) dcost=(x2-x1m)**2+(y2-y1)**2 end function dcost -! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # logical function find_better_min(grd, x, y, w, oi, oj) ! Arguments - type(icebergs_gridded), intent(in) :: grd + type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields real, intent(in) :: x, y integer, intent(in) :: w integer, intent(inout) :: oi, oj @@ -3237,11 +3324,11 @@ logical function find_better_min(grd, x, y, w, oi, oj) end function find_better_min -! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +! # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # logical function find_cell_loc(grd, x, y, is, ie, js, je, w, oi, oj) ! Arguments - type(icebergs_gridded), intent(in) :: grd + type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields real, intent(in) :: x, y integer, intent(in) :: is, ie, js, je, w integer, intent(inout) :: oi, oj @@ -3265,18 +3352,19 @@ end function find_cell_loc end function find_cell_by_search - -! ############################################################################## - -subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found, search_data_domain) -type(icebergs), pointer :: bergs +!> Returns the i,j of cell containing an iceberg with the given identifier +subroutine find_individual_iceberg(bergs, iceberg_num, ine, jne, berg_found, search_data_domain) +! Arguments +type(icebergs), pointer :: bergs !< Container for all types and memory +integer, intent(in) :: iceberg_num !< Berg identifier +integer, intent(out) :: ine !< i-index of cell containing berg +integer, intent(out) :: jne !< j-index of cell containing berg +logical, intent(in) :: search_data_domain !< If true, search halos too +real, intent(out) :: berg_found !< Returns 1.0 if berg is found, 0. otherwise +! Local variables type(iceberg), pointer :: this type(icebergs_gridded), pointer :: grd integer :: grdi, grdj -integer, intent(in) :: iceberg_num -logical, intent(in) :: search_data_domain -integer, intent(out) :: ine, jne -real, intent(out) :: berg_found integer :: ilim1, ilim2, jlim1, jlim2 berg_found=0.0 @@ -3284,7 +3372,7 @@ subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found, sear jne=999 ! For convenience grd=>bergs%grd - + if (search_data_domain) then ilim1 = grd%isd ; ilim2=grd%ied ; jlim1 = grd%jsd ; jlim2=grd%jed else @@ -3306,17 +3394,17 @@ subroutine find_individual_iceberg(bergs,iceberg_num, ine, jne, berg_found, sear endif this=>this%next enddo - enddo ; enddo -end subroutine find_individual_iceberg - - -! ############################################################################## + enddo ; enddo +end subroutine find_individual_iceberg -logical function find_cell(grd, x, y, oi, oj) +!> Scans each computational grid cell until is_point_in_cell() is true +logical function find_cell(grd, x, y, oi, oj) ! Arguments -type(icebergs_gridded), intent(in) :: grd -real, intent(in) :: x, y -integer, intent(out) :: oi, oj +type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields +real, intent(in) :: x !< Longitude of position +real, intent(in) :: y !< Latitude of position +integer, intent(out) :: oi !< i-index of cell containing position or -999 +integer, intent(out) :: oj !< j-index of cell containing position or -999 ! Local variables integer :: i,j @@ -3331,13 +3419,14 @@ logical function find_cell(grd, x, y, oi, oj) end function find_cell -! ############################################################################## - +!> Scans each all grid cells until is_point_in_cell() is true (includes halos) logical function find_cell_wide(grd, x, y, oi, oj) ! Arguments -type(icebergs_gridded), intent(in) :: grd -real, intent(in) :: x, y -integer, intent(out) :: oi, oj +type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields +real, intent(in) :: x !< Longitude of position +real, intent(in) :: y !< Latitude of position +integer, intent(out) :: oi !< i-index of cell containing position or -999 +integer, intent(out) :: oj !< j-index of cell containing position or -999 ! Local variables integer :: i,j @@ -3352,14 +3441,15 @@ logical function find_cell_wide(grd, x, y, oi, oj) end function find_cell_wide -! ############################################################################## - +!> Returns True if x,y is in cell i,j logical function is_point_in_cell(grd, x, y, i, j, explain) ! Arguments -type(icebergs_gridded), intent(in) :: grd -real, intent(in) :: x, y -integer, intent(in) :: i, j -logical, intent(in), optional :: explain +type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields +real, intent(in) :: x !< Longitude of position +real, intent(in) :: y !< Latitude of position +integer, intent(in) :: i !< i-index of cell +integer, intent(in) :: j !< j-index of cell +logical, intent(in), optional :: explain !< If true, print debugging ! Local variables real :: xlo, xhi, ylo, yhi integer :: stderrunit @@ -3381,11 +3471,11 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) is_point_in_cell=.false. ! Test crude bounds - xlo=min( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & + xlo=min( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & apply_modulo_around_point(grd%lon(i ,j-1) ,x, Lx), & apply_modulo_around_point(grd%lon(i-1,j ) ,x, Lx), & apply_modulo_around_point(grd%lon(i ,j ) ,x, Lx) ) - xhi=max( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & + xhi=max( apply_modulo_around_point(grd%lon(i-1,j-1) ,x, Lx), & apply_modulo_around_point(grd%lon(i ,j-1) ,x, Lx), & apply_modulo_around_point(grd%lon(i-1,j ) ,x, Lx), & apply_modulo_around_point(grd%lon(i ,j ) ,x, Lx) ) @@ -3393,57 +3483,66 @@ logical function is_point_in_cell(grd, x, y, i, j, explain) ! The modolo function inside sum_sign_dot_prod leads to a roundoff. !Adding adding a tolorance to the crude bounds avoids excluding the cell which !would be correct after roundoff. This is a bit of a hack. - tol=0.1 + tol=0.1 if (x.lt.(xlo-tol) .or. x.gt.(xhi+tol)) return ylo=min( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) yhi=max( grd%lat(i-1,j-1), grd%lat(i,j-1), grd%lat(i-1,j), grd%lat(i,j) ) if (y.lt.ylo .or. y.gt.yhi) return - + if ((grd%lat(i,j).gt.89.999).and. (grd%grid_is_latlon)) then is_point_in_cell=sum_sign_dot_prod5(grd%lon(i-1,j-1),grd%lat(i-1,j-1), & grd%lon(i ,j-1),grd%lat(i ,j-1), & grd%lon(i ,j-1),grd%lat(i ,j ), & grd%lon(i-1,j ),grd%lat(i ,j ), & grd%lon(i-1,j ),grd%lat(i-1,j ), & - x, y, Lx,explain=explain) + x, y, Lx,explain=explain) elseif ((grd%lat(i-1,j).gt.89.999) .and. (grd%grid_is_latlon)) then is_point_in_cell=sum_sign_dot_prod5(grd%lon(i-1,j-1),grd%lat(i-1,j-1), & grd%lon(i ,j-1),grd%lat(i ,j-1), & grd%lon(i ,j ),grd%lat(i ,j ), & grd%lon(i ,j ),grd%lat(i-1,j ), & grd%lon(i-1,j-1),grd%lat(i-1,j ), & - x, y,Lx, explain=explain) + x, y,Lx, explain=explain) elseif ((grd%lat(i-1,j-1).gt.89.999) .and. (grd%grid_is_latlon)) then is_point_in_cell=sum_sign_dot_prod5(grd%lon(i-1,j ),grd%lat(i-1,j-1), & grd%lon(i ,j-1),grd%lat(i-1,j-1), & grd%lon(i ,j-1),grd%lat(i ,j-1), & grd%lon(i ,j ),grd%lat(i ,j ), & grd%lon(i-1,j ),grd%lat(i-1,j ), & - x, y,Lx, explain=explain) + x, y,Lx, explain=explain) elseif ((grd%lat(i,j-1).gt.89.999) .and. (grd%grid_is_latlon)) then is_point_in_cell=sum_sign_dot_prod5(grd%lon(i-1,j-1),grd%lat(i-1,j-1), & grd%lon(i-1,j-1),grd%lat(i ,j-1), & grd%lon(i ,j ),grd%lat(i ,j-1), & grd%lon(i ,j ),grd%lat(i ,j ), & grd%lon(i-1,j ),grd%lat(i-1,j ), & - x, y, Lx,explain=explain) + x, y, Lx,explain=explain) else is_point_in_cell=sum_sign_dot_prod4(grd%lon(i-1,j-1),grd%lat(i-1,j-1), & grd%lon(i ,j-1),grd%lat(i ,j-1), & grd%lon(i ,j ),grd%lat(i ,j ), & grd%lon(i-1,j ),grd%lat(i-1,j ), & - x, y,Lx, explain=explain) + x, y,Lx, explain=explain) endif end function is_point_in_cell -! ############################################################################## - -logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, explain) +!> Returns true if point x,y is inside polygon with four corners +logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y, Lx, explain) ! Arguments -real, intent(in) :: x0, y0, x1, y1, x2, y2, x3, y3, x, y, Lx -logical, intent(in), optional :: explain +real, intent(in) :: x0 !< Longitude of first corner +real, intent(in) :: y0 !< Latitude of first corner +real, intent(in) :: x1 !< Longitude of second corner +real, intent(in) :: y1 !< Latitude of second corner +real, intent(in) :: x2 !< Longitude of third corner +real, intent(in) :: y2 !< Latitude of third corner +real, intent(in) :: x3 !< Longitude of fourth corner +real, intent(in) :: y3 !< Latitude of fourth corner +real, intent(in) :: x !< Longitude of point +real, intent(in) :: y !< Latitude of point +real, intent(in) :: Lx !< Length of domain in zonal direction +logical, intent(in), optional :: explain !< If true, print debugging ! Local variables real :: p0,p1,p2,p3,xx real :: l0,l1,l2,l3 @@ -3466,7 +3565,7 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp l2=(xx-xx2)*(y3-y2)-(y-y2)*(xx3-xx2) l3=(xx-xx3)*(y0-y3)-(y-y3)*(xx0-xx3) - !We use an assymerty between South and East line boundaries and North and East + !We use an asymmetry between South and East line boundaries and North and East !to avoid icebergs appearing to two cells (half values used for debugging) !This is intended to make the South and East boundaries be part of the !cell, while the North and West are not part of the cell. @@ -3497,12 +3596,23 @@ logical function sum_sign_dot_prod4(x0, y0, x1, y1, x2, y2, x3, y3, x, y,Lx, exp end function sum_sign_dot_prod4 -! ############################################################################## - +!> Returns true if point x,y is inside polygon with five corners logical function sum_sign_dot_prod5(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x, y, Lx, explain) ! Arguments -real, intent(in) :: x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x, y, Lx -logical, intent(in), optional :: explain +real, intent(in) :: x0 !< Longitude of first corner +real, intent(in) :: y0 !< Latitude of first corner +real, intent(in) :: x1 !< Longitude of second corner +real, intent(in) :: y1 !< Latitude of second corner +real, intent(in) :: x2 !< Longitude of third corner +real, intent(in) :: y2 !< Latitude of third corner +real, intent(in) :: x3 !< Longitude of fourth corner +real, intent(in) :: y3 !< Latitude of fourth corner +real, intent(in) :: x4 !< Longitude of fifth corner +real, intent(in) :: y4 !< Latitude of fifth corner +real, intent(in) :: x !< Longitude of point +real, intent(in) :: y !< Latitude of point +real, intent(in) :: Lx !< Length of domain in zonal direction +logical, intent(in), optional :: explain !< If true, print debugging ! Local variables real :: p0,p1,p2,p3,p4,xx real :: l0,l1,l2,l3,l4 @@ -3554,15 +3664,17 @@ logical function sum_sign_dot_prod5(x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x, y end function sum_sign_dot_prod5 -! ############################################################################## - +!> Calculates non-dimensional position with cell i,j and returns true if point is in cell logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) ! Arguments -type(icebergs_gridded), intent(in) :: grd -real, intent(in) :: x, y -integer, intent(in) :: i, j -real, intent(out) :: xi, yj -logical, intent(in), optional :: explain +type(icebergs_gridded), intent(in) :: grd !< Container for gridded fields +real, intent(in) :: x !< Longitude of position +real, intent(in) :: y !< Latitude of position +integer, intent(in) :: i !< i-index of cell +integer, intent(in) :: j !< j-index of cell +real, intent(out) :: xi !< Non-dimensional x-position within cell +real, intent(out) :: yj !< Non-dimensional y-position within cell +logical, intent(in), optional :: explain !< If true, print debugging ! Local variables real :: x1,y1,x2,y2,x3,y3,x4,y4,xx,yy,fac integer :: stderrunit @@ -3692,11 +3804,23 @@ logical function pos_within_cell(grd, x, y, i, j, xi, yj, explain) contains - subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj,Lx, explain) + !> Calculates non-dimension position of x,y within a polygon with four corners + subroutine calc_xiyj(x1, x2, x3, x4, y1, y2, y3, y4, x, y, xi, yj, Lx, explain) ! Arguments - real, intent(in) :: x1, x2, x3, x4, y1, y2, y3, y4, x, y, Lx - real, intent(out) :: xi, yj - logical, intent(in), optional :: explain + real, intent(in) :: x1 !< Longitude of first corner + real, intent(in) :: y1 !< Latitude of first corner + real, intent(in) :: x2 !< Longitude of second corner + real, intent(in) :: y2 !< Latitude of second corner + real, intent(in) :: x3 !< Longitude of third corner + real, intent(in) :: y3 !< Latitude of third corner + real, intent(in) :: x4 !< Longitude of fourth corner + real, intent(in) :: y4 !< Latitude of fourth corner + real, intent(in) :: x !< Longitude of point + real, intent(in) :: y !< Latitude of point + real, intent(out) :: xi !< Non-dimensional x-position within cell + real, intent(out) :: yj !< Non-dimensional y-position within cell + real, intent(in) :: Lx !< Length of domain in zonal direction + logical, intent(in), optional :: explain !< If true, print debugging ! Local variables real :: alpha, beta, gamma, delta, epsilon, kappa, a, b, c, d, dx, dy, yy1, yy2 logical :: expl=.false. @@ -3780,11 +3904,14 @@ end subroutine calc_xiyj end function pos_within_cell -! ############################################################################## - +!> Returns true if non-dimensional position xi,yj is in unit interval +!! +!! Includes South and East boundaries, and excludes North and West. +!! \todo Double check definition of is_point_within_xi_yj_bounds() logical function is_point_within_xi_yj_bounds(xi,yj) ! Arguments -real, intent(in) :: xi, yj +real, intent(in) :: xi !< Non-dimensional x-position +real, intent(in) :: yj !< Non-dimensional y-position ! Local variables !Includes South and East boundaries, and excludes North and West (double check this is the way that is needed) is_point_within_xi_yj_bounds=.False. @@ -3795,13 +3922,17 @@ logical function is_point_within_xi_yj_bounds(xi,yj) endif end function is_point_within_xi_yj_bounds -real function apply_modulo_around_point(x,y,Lx) +!> Modulo value of x in an interval [y-(Lx/2) y+(Lx/2)] +!! +!! Gives the modulo value of x in an interval [y-(Lx/2) y+(Lx/2)] , modulo Lx +!! If Lx<=0, then it returns x without applying modulo arithmetic. +real function apply_modulo_around_point(x, y, Lx) ! Arguments -real, intent(in) :: x ,y ,Lx +real, intent(in) :: x !< Value to apply modulo arithmetic to +real, intent(in) :: y !< Center of modulo range +real, intent(in) :: Lx !< Modulo width !Local_variables real ::Lx_2 -!Gives the modula value of x in an interval [y-(Lx/2) y+(Lx/2)] , modulo Lx -!If Lx<=0, then it returns x without applying modulo arithmetic. if (Lx>0.) then Lx_2=Lx/2. @@ -3812,12 +3943,14 @@ real function apply_modulo_around_point(x,y,Lx) end function apply_modulo_around_point +!> Checks that a berg's position metrics are consistent subroutine check_position(grd, berg, label, il, jl) ! Arguments -type(icebergs_gridded), pointer :: grd -type(iceberg), pointer :: berg -character(len=*) :: label -integer, optional, intent(in) :: il, jl !< Indices of cell berg should be in +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +type(iceberg), pointer :: berg !< Berg to check +character(len=*) :: label !< Label to add to messages +integer, optional, intent(in) :: il !< i-index of cell berg should be in +integer, optional, intent(in) :: jl !< j-index of cell berg should be in ! Local variables real :: xi, yj logical :: lret @@ -3840,12 +3973,12 @@ subroutine check_position(grd, berg, label, il, jl) end subroutine check_position -! ############################################################################## - -real function sum_mass(bergs,justbits,justbergs) +!> Add up the mass of bergs and/or bergy bits +real function sum_mass(bergs, justbits, justbergs) ! Arguments -type(icebergs), pointer :: bergs -logical, intent(in), optional :: justbits, justbergs +type(icebergs), pointer :: bergs !< Container for all types and memory +logical, intent(in), optional :: justbits !< If present, add up mass of just bergy bits +logical, intent(in), optional :: justbergs !< If present, add up mass of just bergs ! Local variables type(iceberg), pointer :: this integer :: grdi, grdj @@ -3867,12 +4000,12 @@ real function sum_mass(bergs,justbits,justbergs) end function sum_mass -! ############################################################################## - +!> Add up the heat content of bergs and/or bergy bits real function sum_heat(bergs,justbits,justbergs) ! Arguments -type(icebergs), pointer :: bergs -logical, intent(in), optional :: justbits, justbergs +type(icebergs), pointer :: bergs !< Container for all types and memory +logical, intent(in), optional :: justbits !< If present, add up heat content of just bergy bits +logical, intent(in), optional :: justbergs !< If present, add up heat content of just bergs ! Local variables type(iceberg), pointer :: this real :: dm @@ -3897,11 +4030,11 @@ real function sum_heat(bergs,justbits,justbergs) end function sum_heat - -subroutine sanitize_field(arr,val) +!> Set elements of an array to 0. if the absolute value is larger than a given value +subroutine sanitize_field(arr, val) ! Arguments -real, dimension(:,:),intent(inout) :: arr -real, intent(in) :: val +real, dimension(:,:),intent(inout) :: arr !< Array to sanitize +real, intent(in) :: val !< Threshold value to use for sanitizing ! Local variables integer :: i, j @@ -3913,17 +4046,11 @@ subroutine sanitize_field(arr,val) end subroutine sanitize_field -! ############################################################################## - - - - -! ############################################################################## - +!> Calculates checksums for all gridded fields subroutine checksum_gridded(grd, label) ! Arguments -type(icebergs_gridded), pointer :: grd -character(len=*) :: label +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +character(len=*) :: label !< Label to use in messages ! Local variables if (mpp_pe().eq.mpp_root_pe()) write(*,'(2a)') 'diamonds: checksumming gridded data @ ',trim(label) @@ -3985,13 +4112,12 @@ subroutine checksum_gridded(grd, label) end subroutine checksum_gridded -! ############################################################################## - +!> Calculates checksum for a 3d field subroutine grd_chksum3(grd, fld, txt) ! Arguments -type(icebergs_gridded), pointer :: grd -real, dimension(:,:,:), intent(in) :: fld -character(len=*), intent(in) :: txt +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +real, dimension(:,:,:), intent(in) :: fld !< Field to checksum +character(len=*), intent(in) :: txt !< Label to use in message ! Local variables integer :: i, j, k, halo, icount, io, jo real :: mean, rms, SD, minv, maxv @@ -4057,13 +4183,12 @@ subroutine grd_chksum3(grd, fld, txt) end subroutine grd_chksum3 -! ############################################################################## - +!> Calculates checksum for a 2d field subroutine grd_chksum2(grd, fld, txt) ! Arguments -type(icebergs_gridded), pointer :: grd -real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: fld -character(len=*), intent(in) :: txt +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: fld !< Field to checksum +character(len=*), intent(in) :: txt !< Label to use in message ! Local variables integer :: i, j, icount real :: mean, rms, SD, minv, maxv @@ -4115,12 +4240,11 @@ subroutine grd_chksum2(grd, fld, txt) end subroutine grd_chksum2 -! ############################################################################## - +!> Calculates checksums for all bergs subroutine bergs_chksum(bergs, txt, ignore_halo_violation) ! Arguments -type(icebergs), pointer :: bergs -character(len=*), intent(in) :: txt +type(icebergs), pointer :: bergs !< Container for all types and memory +character(len=*), intent(in) :: txt !< Label to use in messages logical, optional :: ignore_halo_violation ! Local variables integer :: i, nbergs, ichk1, ichk2, ichk3, ichk4, ichk5, iberg @@ -4217,11 +4341,10 @@ subroutine bergs_chksum(bergs, txt, ignore_halo_violation) end subroutine bergs_chksum -! ############################################################################## - +!> Checksum a list of bergs integer function list_chksum(first) ! Arguments -type(iceberg), pointer :: first +type(iceberg), pointer :: first !< List of bergs ! Local variables integer :: i type(iceberg), pointer :: this @@ -4236,11 +4359,10 @@ integer function list_chksum(first) end function list_chksum -! ############################################################################## - +!> Checksum a berg integer function berg_chksum(berg) ! Arguments -type(iceberg), pointer :: berg +type(iceberg), pointer :: berg !< An iceberg ! Local variables real :: rtmp(38) !Changed from 28 to 34 by Alon integer :: itmp(38+4), i8=0, ichk1, ichk2, ichk3 !Changed from 28 to 34 by Alon @@ -4274,24 +4396,24 @@ integer function berg_chksum(berg) rtmp(26)=berg%ssh_y rtmp(27)=berg%cn rtmp(28)=berg%hi - rtmp(29)=berg%axn - rtmp(30)=berg%ayn - rtmp(31)=berg%bxn - rtmp(32)=berg%byn - rtmp(33)=berg%uvel_old - rtmp(34)=berg%vvel_old - rtmp(35)=berg%lat_old - rtmp(36)=berg%lon_old - itmp(37)=berg%halo_berg - itmp(38)=berg%static_berg - itmp(1:38)=transfer(rtmp,i8) - itmp(39)=berg%start_year - itmp(40)=berg%ine - itmp(41)=berg%jne - itmp(42)=berg%iceberg_num + rtmp(29)=berg%axn + rtmp(30)=berg%ayn + rtmp(31)=berg%bxn + rtmp(32)=berg%byn + rtmp(33)=berg%uvel_old + rtmp(34)=berg%vvel_old + rtmp(35)=berg%lat_old + rtmp(36)=berg%lon_old + itmp(37)=berg%halo_berg + itmp(38)=berg%static_berg + itmp(1:38)=transfer(rtmp,i8) + itmp(39)=berg%start_year + itmp(40)=berg%ine + itmp(41)=berg%jne + itmp(42)=berg%iceberg_num ichk1=0; ichk2=0; ichk3=0 - do i=1,38+4 + do i=1,38+4 ichk1=ichk1+itmp(i) ichk2=ichk2+itmp(i)*i ichk3=ichk3+itmp(i)*i*i @@ -4300,13 +4422,15 @@ integer function berg_chksum(berg) end function berg_chksum -! ############################################################################## - +!> Bi-linear interpolate a field at corners in cell i,j to non-dimensional position xi,yj real function bilin(grd, fld, i, j, xi, yj) ! Arguments -type(icebergs_gridded), pointer :: grd -real, intent(in) :: fld(grd%isd:grd%ied,grd%jsd:grd%jed), xi, yj -integer, intent(in) :: i, j +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +real, intent(in) :: fld(grd%isd:grd%ied,grd%jsd:grd%jed) !< Field to interpolate +real, intent(in) :: xi !< Non-dimensional x-position within cell +real, intent(in) :: yj !< Non-dimensional y-position within cell +integer, intent(in) :: i !< i-index of cell +integer, intent(in) :: j !< j-index of cell ! Local variables if (old_bug_bilin) then @@ -4318,13 +4442,12 @@ real function bilin(grd, fld, i, j, xi, yj) endif end function bilin -! ############################################################################## - +!> Prints a field subroutine print_fld(grd, fld, label) ! Arguments -type(icebergs_gridded), pointer :: grd -real, intent(in) :: fld(grd%isd:grd%ied,grd%jsd:grd%jed) -character(len=*) :: label +type(icebergs_gridded), pointer :: grd !< Container for gridded fields +real, intent(in) :: fld(grd%isd:grd%ied,grd%jsd:grd%jed) !< Field to print +character(len=*) :: label !< Label to use in title ! Local variables integer :: i, j integer :: stderrunit @@ -4339,12 +4462,11 @@ subroutine print_fld(grd, fld, label) end subroutine print_fld -! ############################################################################## - +!> Invoke some unit tests logical function unitTests(bergs) - type(icebergs), pointer :: bergs - type(icebergs_gridded), pointer :: grd + type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables + type(icebergs_gridded), pointer :: grd integer :: stderrunit,i,j ! This function returns True is a unit test fails @@ -4352,7 +4474,7 @@ logical function unitTests(bergs) ! For convenience grd=>bergs%grd stderrunit=stderr() - + i=grd%isc; j=grd%jsc call localTest( bilin(grd, grd%lon, i, j, 0., 1.), grd%lon(i-1,j) ) call localTest( bilin(grd, grd%lon, i, j, 1., 1.), grd%lon(i,j) ) @@ -4360,6 +4482,8 @@ logical function unitTests(bergs) call localTest( bilin(grd, grd%lat, i, j, 1., 1.), grd%lat(i,j) ) contains + + !> Checks answer to right answer and prints results if different subroutine localTest(answer, rightAnswer) real, intent(in) :: answer, rightAnswer if (answer==rightAnswer) return @@ -4368,12 +4492,11 @@ subroutine localTest(answer, rightAnswer) end subroutine localTest end function unitTests -! ############################################################################## - !> Check for duplicates of icebergs on and across processors and issue an error !! if any are detected subroutine check_for_duplicates_in_parallel(bergs) - type(icebergs), pointer :: bergs !< Icebergs + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory ! Local variables type(icebergs_gridded), pointer :: grd type(iceberg), pointer :: this @@ -4410,9 +4533,11 @@ end subroutine check_for_duplicates_in_parallel !> Returns error count of duplicates of integer values in a distributed list integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) + ! Arguments integer, intent(in) :: nbergs !< Length of ids integer, dimension(:), intent(inout) :: ids !< List of ids logical, intent(in) :: verbose !< True if messages should be written + ! Local variables integer :: stderrunit, i, j, k, l, nbergs_total, ii, lowest_id, nonexistent_id logical :: have_berg @@ -4478,7 +4603,9 @@ integer function check_for_duplicate_ids_in_list(nbergs, ids, verbose) end function check_for_duplicate_ids_in_list +!> Unit test for check_for_duplicate_ids_in_list() subroutine test_check_for_duplicate_ids_in_list() + ! Local variables integer :: k integer, dimension(:), allocatable :: ids integer :: error_count diff --git a/icebergs_io.F90 b/icebergs_io.F90 index b8bee75..b55b229 100644 --- a/icebergs_io.F90 +++ b/icebergs_io.F90 @@ -1,5 +1,8 @@ +!> Handles reading/writing of restart files and trajectory-based diagnostic files module ice_bergs_io +! This file is part of NOAA-GFDL/icebergs. See LICENSE.md for the license. + use mpp_domains_mod, only: domain2D use mpp_domains_mod, only: mpp_domain_is_tile_root_pe,mpp_get_domain_tile_root_pe use mpp_domains_mod, only: mpp_get_tile_pelist,mpp_get_tile_npes,mpp_get_io_domain,mpp_get_tile_id @@ -66,9 +69,10 @@ module ice_bergs_io contains +!> Initialize parallel i/o subroutine ice_bergs_io_init(bergs, io_layout) -type(icebergs), pointer :: bergs -integer, intent(in) :: io_layout(2) +type(icebergs), pointer :: bergs !< Icebergs container +integer, intent(in) :: io_layout(2) !< Decomposition of i/o processors integer :: np integer :: stdlogunit, stderrunit @@ -78,7 +82,7 @@ subroutine ice_bergs_io_init(bergs, io_layout) stdlogunit=stdlog() write(stdlogunit,*) "ice_bergs_framework: "//trim(version) - !I/O layout init + !I/O layout init io_tile_id=-1 io_domain => mpp_get_io_domain(bergs%grd%domain) if(associated(io_domain)) then @@ -96,13 +100,12 @@ subroutine ice_bergs_io_init(bergs, io_layout) end subroutine ice_bergs_io_init -! ############################################################################## - +!> Write an iceberg restart file subroutine write_restart(bergs) ! Arguments -type(icebergs), pointer :: bergs -type(bond), pointer :: current_bond +type(icebergs), pointer :: bergs !< Icebergs container ! Local variables +type(bond), pointer :: current_bond integer :: i,j,id character(len=35) :: filename character(len=35) :: filename_bonds @@ -113,7 +116,7 @@ subroutine write_restart(bergs) type(restart_file_type) :: bergs_bond_restart integer :: nbergs, nbonds integer :: n_static_bergs -logical :: check_bond_quality +logical :: check_bond_quality type(icebergs_gridded), pointer :: grd real, allocatable, dimension(:) :: lon, & lat, & @@ -149,14 +152,14 @@ subroutine write_restart(bergs) integer :: grdi, grdj - + ! Get the stderr unit number stderrunit=stderr() ! For convenience grd=>bergs%grd - + !First add the bergs on the io_tile_root_pe (if any) to the I/O list nbergs = 0 do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec @@ -248,13 +251,13 @@ subroutine write_restart(bergs) this=>this%next enddo enddo ; enddo - call mpp_sum(n_static_bergs) + call mpp_sum(n_static_bergs) if (n_static_bergs .gt. 0) & id = register_restart_field(bergs_restart,filename,'static_berg',static_berg, & longname='static_berg',units='dimensionless') ! Write variables - + i = 0 do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec this=>bergs%list(grdi,grdj)%first @@ -270,8 +273,8 @@ subroutine write_restart(bergs) start_lon(i) = this%start_lon; start_lat(i) = this%start_lat start_year(i) = this%start_year; start_day(i) = this%start_day start_mass(i) = this%start_mass; mass_scaling(i) = this%mass_scaling - static_berg(i) = this%static_berg - iceberg_num(i) = this%iceberg_num; + static_berg(i) = this%static_berg + iceberg_num(i) = this%iceberg_num mass_of_bits(i) = this%mass_of_bits; heat_density(i) = this%heat_density this=>this%next enddo @@ -313,18 +316,18 @@ subroutine write_restart(bergs) !########## Creating bond restart file ###################### - !Allocating restart memory for bond related variables. - nbonds=0 - if (bergs%iceberg_bonds_on) then - check_bond_quality=.true. - call count_bonds(bergs, nbonds,check_bond_quality) + !Allocating restart memory for bond related variables. + nbonds=0 + if (bergs%iceberg_bonds_on) then + check_bond_quality=.true. + call count_bonds(bergs, nbonds,check_bond_quality) - allocate(first_berg_num(nbonds)) - allocate(other_berg_num(nbonds)) - allocate(first_berg_ine(nbonds)) - allocate(first_berg_jne(nbonds)) - allocate(other_berg_ine(nbonds)) - allocate(other_berg_jne(nbonds)) + allocate(first_berg_num(nbonds)) + allocate(other_berg_num(nbonds)) + allocate(first_berg_ine(nbonds)) + allocate(first_berg_jne(nbonds)) + allocate(other_berg_ine(nbonds)) + allocate(other_berg_jne(nbonds)) call get_instance_filename("bonds_iceberg.res.nc", filename_bonds) call set_domain(bergs%grd%domain) @@ -341,10 +344,10 @@ subroutine write_restart(bergs) id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_ine',other_berg_ine,longname='iceberg ine of second berg in bond',units='dimensionless') id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_jne',other_berg_jne,longname='iceberg jne of second berg in bond',units='dimensionless') id = register_restart_field(bergs_bond_restart,filename_bonds,'other_berg_num',other_berg_num,longname='iceberg id second berg in bond',units='dimensionless') - - + + ! Write variables - + i = 0 do grdj = bergs%grd%jsc,bergs%grd%jec ; do grdi = bergs%grd%isc,bergs%grd%iec this=>bergs%list(grdi,grdj)%first @@ -379,8 +382,7 @@ subroutine write_restart(bergs) call nullify_domain() - endif -!############################################################################################# + endif ! Write stored ice filename='RESTART/calving.res.nc' @@ -400,9 +402,11 @@ subroutine write_restart(bergs) endif contains + !> Find the last berg in a linked list. function last_berg(berg) ! Arguments - type(iceberg), pointer :: last_berg, berg + type(iceberg), pointer :: berg !< Pointer to an iceberg + type(iceberg), pointer :: last_berg ! Local variables last_berg=>berg @@ -414,12 +418,11 @@ end function last_berg end subroutine write_restart -! ############################################################################## - +!> Read an iceberg restart file (original implementation) subroutine read_restart_bergs_orig(bergs,Time) ! Arguments -type(icebergs), pointer :: bergs -type(time_type), intent(in) :: Time +type(icebergs), pointer :: bergs !< Icebergs container +type(time_type), intent(in) :: Time !< Model time ! Local variables integer, dimension(:), allocatable :: found_restart_int integer :: k, ierr, ncid, dimid, nbergs_in_file @@ -471,7 +474,7 @@ subroutine read_restart_bergs_orig(bergs,Time) elseif (found_restart) then ! if (.not.found_restart) ! only do the following if a file was found - + if (verbose.and.mpp_pe()==mpp_root_pe()) write(*,'(2a)') 'diamonds, read_restart_bergs: found restart file = ',filename ierr=nf_open(filename, NF_NOWRITE, ncid) @@ -580,7 +583,7 @@ subroutine read_restart_bergs_orig(bergs,Time) else ! if no restart file was read on this PE nbergs_in_file=0 endif ! if (.not.found_restart) - + ! Sanity check k=count_bergs(bergs) if (verbose) write(*,'(2(a,i8))') 'diamonds, read_restart_bergs: # bergs =',k,' on PE',mpp_pe() @@ -595,7 +598,7 @@ subroutine read_restart_bergs_orig(bergs,Time) k,' bergs have been read' endif - if (k.ne.nbergs_in_file) call error_mesg('diamonds, read_restart_bergs', 'wrong number of bergs read!', FATAL) + if (k.ne.nbergs_in_file) call error_mesg('diamonds, read_restart_bergs', 'wrong number of bergs read!', FATAL) if (.not. found_restart .and. bergs%nbergs_start==0 .and. generate_test_icebergs) call generate_bergs(bergs,Time) @@ -609,6 +612,7 @@ subroutine read_restart_bergs_orig(bergs,Time) contains + !> Read a real value from a file and optionally return a default value if variable is missing real function get_real_from_file(ncid, varid, k, value_if_not_in_file) integer, intent(in) :: ncid, varid, k real, optional :: value_if_not_in_file @@ -619,11 +623,12 @@ real function get_real_from_file(ncid, varid, k, value_if_not_in_file) get_real_from_file=get_double(ncid, ncid, k) endif end function get_real_from_file - + + !> Generate bergs for the purpose of debugging subroutine generate_bergs(bergs,Time) ! Arguments - type(icebergs), pointer :: bergs - type(time_type), intent(in) :: Time + type(icebergs), pointer :: bergs !< Icebergs container + type(time_type), intent(in) :: Time !< Model time ! Local variables integer :: i,j integer :: iNg, jNg !Total number of points gloablly in i and j direction @@ -667,7 +672,7 @@ subroutine generate_bergs(bergs,Time) localberg%vvel_old=0. !Alon localberg%bxn=0. !Alon localberg%byn=0. !Alon - + !Berg A localberg%uvel=1. localberg%vvel=0. @@ -701,15 +706,14 @@ subroutine generate_bergs(bergs,Time) write(*,'(a,i8,a)') 'diamonds, generate_bergs: ',bergs%nbergs_start,' were generated' end subroutine generate_bergs - -end subroutine read_restart_bergs_orig -! ############################################################################## +end subroutine read_restart_bergs_orig +!> Read an iceberg restart file subroutine read_restart_bergs(bergs,Time) ! Arguments -type(icebergs), pointer :: bergs -type(time_type), intent(in) :: Time +type(icebergs), pointer :: bergs !< Icebergs container +type(time_type), intent(in) :: Time !< Model time ! Local variables integer :: k, siz(4), nbergs_in_file, nbergs_read logical :: lres, found_restart, found @@ -830,7 +834,7 @@ subroutine read_restart_bergs(bergs,Time) lon1=maxval( grd%lon(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) lat0=minval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) lat1=maxval( grd%lat(grd%isc-1:grd%iec,grd%jsc-1:grd%jec) ) - + do k=1, nbergs_in_file localberg%lon=lon(k) localberg%lat=lat(k) @@ -905,7 +909,7 @@ subroutine read_restart_bergs(bergs,Time) call error_mesg('diamonds, read_restart_bergs', 'berg in PE file was not on PE!', FATAL) endif enddo - + if(nbergs_in_file > 0) then deallocate( & lon, & @@ -971,12 +975,13 @@ subroutine read_restart_bergs(bergs,Time) contains + !> Read a vector of reals from file and use a default value if variable is missing subroutine read_real_vector(filename, varname, values, domain, value_if_not_in_file) - character(len=*), intent(in) :: filename - character(len=*), intent(in) :: varname - real, intent(out) :: values(:) - type(domain2D), intent(in) :: domain - real, optional, intent(in) :: value_if_not_in_file + character(len=*), intent(in) :: filename !< Name of file to read from + character(len=*), intent(in) :: varname !< Name of variable to read + real, intent(out) :: values(:) !< Returned vector of reals + type(domain2D), intent(in) :: domain !< Parallel decomposition + real, optional, intent(in) :: value_if_not_in_file !< Value to use if variable is not in file if (present(value_if_not_in_file).and..not.field_exist(filename, varname)) then values(:)=value_if_not_in_file @@ -985,12 +990,13 @@ subroutine read_real_vector(filename, varname, values, domain, value_if_not_in_f endif end subroutine read_real_vector + !> Read a vector of integers from file and use a default value if variable is missing subroutine read_int_vector(filename, varname, values, domain, value_if_not_in_file) - character(len=*), intent(in) :: filename - character(len=*), intent(in) :: varname - integer, intent(out) :: values(:) - type(domain2D), intent(in) :: domain - integer, optional, intent(in) :: value_if_not_in_file + character(len=*), intent(in) :: filename !< Name of file to read from + character(len=*), intent(in) :: varname !< Name of variable to read + integer, intent(out) :: values(:) !< Returned vector of integers + type(domain2D), intent(in) :: domain !< Parallel decomposition + integer, optional, intent(in) :: value_if_not_in_file !< Value to use if variable is not in file if (present(value_if_not_in_file).and..not.field_exist(filename, varname)) then values(:)=value_if_not_in_file @@ -998,11 +1004,12 @@ subroutine read_int_vector(filename, varname, values, domain, value_if_not_in_fi call read_unlimited_axis(filename,varname,values,domain=domain) endif end subroutine read_int_vector - + + !> Generate bergs for the purpose of debugging subroutine generate_bergs(bergs,Time) ! Arguments - type(icebergs), pointer :: bergs - type(time_type), intent(in) :: Time + type(icebergs), pointer :: bergs !< Icebergs container + type(time_type), intent(in) :: Time !< Model time ! Local variables integer :: i,j integer :: iNg, jNg !Total number of points gloablly in i and j direction @@ -1080,9 +1087,12 @@ subroutine generate_bergs(bergs,Time) end subroutine generate_bergs subroutine loc_set_berg_pos(grd, xi, yj, uvel, vvel, berg) - type(icebergs_gridded), pointer :: grd - real, intent(in) :: xi, yj, uvel, vvel - type(iceberg), intent(inout) :: berg + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + real, intent(in) :: xi !< Non-dimensional x-position within cell to give berg + real, intent(in) :: yj !< Non-dimensional y-position within cell to give berg + real, intent(in) :: uvel !< Zonal velocity to give berg + real, intent(in) :: vvel !< Meridional velocity to give berg + type(iceberg), intent(inout) :: berg !< An iceberg integer :: i, j logical :: lres i = berg%ine ; j = berg%jne @@ -1108,15 +1118,15 @@ subroutine loc_set_berg_pos(grd, xi, yj, uvel, vvel, berg) stop 'generate_bergs, loc_set_berg_pos(): VERY FATAL!' endif end subroutine loc_set_berg_pos - + end subroutine read_restart_bergs -! ############################################################################## +!> Read bond restart file subroutine read_restart_bonds(bergs,Time) ! Arguments -type(icebergs), pointer :: bergs -type(time_type), intent(in) :: Time +type(icebergs), pointer :: bergs !< Icebergs container +type(time_type), intent(in) :: Time !< Model time ! Local variables integer :: k, siz(4), nbonds_in_file logical :: lres, found_restart, found @@ -1166,7 +1176,7 @@ subroutine read_restart_bonds(bergs,Time) filename = filename_base call get_field_size(filename,'i',siz, field_found=found, domain=bergs%grd%domain) nbonds_in_file = siz(1) - + if (mpp_pe() .eq. mpp_root_pe()) then write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds in file', nbonds_in_file endif @@ -1195,10 +1205,9 @@ subroutine read_restart_bonds(bergs,Time) number_perfect_bonds_with_first_on_pe=0 do k=1, nbonds_in_file - ! If i,j in restart files are not good, then we find the berg position of the bond addresses manually: - if (ignore_ij_restart) then + if (ignore_ij_restart) then !Finding first iceberg in bond ine=999 ; jne=999 ; berg_found=0.0 ; search_data_domain=.true. call find_individual_iceberg(bergs,first_berg_num(k), ine, jne,berg_found,search_data_domain) @@ -1238,7 +1247,7 @@ subroutine read_restart_bonds(bergs,Time) if ( (first_berg_ine(k)>=grd%isd) .and. (first_berg_ine(k)<=grd%ied) .and. & (first_berg_jne(k)>=grd%jsd) .and. (first_berg_jne(k)<=grd%jed) ) then number_first_bonds_matched=number_first_bonds_matched+1 - + ! Search for the first berg, which the bond belongs to first_berg_found=.false. first_berg=>null() @@ -1249,11 +1258,10 @@ subroutine read_restart_bonds(bergs,Time) first_berg=>this !if (first_berg%halo_berg.gt.0.5) print *, 'bonding halo berg:', first_berg_num(k), first_berg_ine(k),first_berg_jne(k) ,grd%isc, grd%iec, mpp_pe() this=>null() - else + else this=>this%next endif enddo - ! Decide whether the second iceberg is on the processeor (data domain) second_berg_found=.false. @@ -1271,24 +1279,24 @@ subroutine read_restart_bonds(bergs,Time) second_berg_found=.true. second_berg=>this this=>null() - else + else this=>this%next endif enddo endif - + if (first_berg_found) then number_partial_bonds=number_partial_bonds+1 if (second_berg_found) then call form_a_bond(first_berg, other_berg_num(k), other_berg_ine(k), other_berg_jne(k), second_berg) number_perfect_bonds=number_perfect_bonds+1 - + !Counting number of bonds where the first bond is in the computational domain if ( (first_berg_ine(k)>=grd%isc) .and. (first_berg_ine(k)<=grd%iec) .and. & (first_berg_jne(k)>=grd%jsc) .and. (first_berg_jne(k)<=grd%jec) ) then number_perfect_bonds_with_first_on_pe=number_perfect_bonds_with_first_on_pe+1 - endif - + endif + else !print *, 'Forming a bond of the second type', mpp_pe(), first_berg_num(k), other_berg_num(k) !call form_a_bond(first_berg, other_berg_num(k),other_berg_ine(k),other_berg_jne(k)) @@ -1314,7 +1322,7 @@ subroutine read_restart_bonds(bergs,Time) write(stderrunit,*) 'diamonds, bond read restart : ','Not enough partial bonds formed', all_pe_number_partial_bonds , nbonds_in_file call error_mesg('read_restart_bonds_bergs_new', 'Not enough partial bonds formed', FATAL) endif - + if (all_pe_number_perfect_bonds .lt. nbonds_in_file) then call mpp_sum(all_pe_number_first_bonds_matched) call mpp_sum(all_pe_number_second_bonds_matched) @@ -1339,7 +1347,7 @@ subroutine read_restart_bonds(bergs,Time) other_berg_ine, & other_berg_jne ) endif - + if (mpp_pe() .eq. mpp_root_pe()) then write(stderrunit,*) 'diamonds, bond read restart : ','Number of bonds (including halos)', all_pe_number_perfect_bonds write(stderrunit,*) 'diamonds, bond read restart : ','Number of true bonds created', all_pe_number_perfect_bonds_with_first_on_pe @@ -1347,12 +1355,11 @@ subroutine read_restart_bonds(bergs,Time) end subroutine read_restart_bonds -! ############################################################################## - +!> Reading calving and gridded restart data subroutine read_restart_calving(bergs) use random_numbers_mod, only: initializeRandomNumberStream, getRandomNumbers, randomNumberStream ! Arguments -type(icebergs), pointer :: bergs +type(icebergs), pointer :: bergs !< Icebergs container ! Local variables integer :: k,i,j character(len=37) :: filename, actual_filename @@ -1399,7 +1406,7 @@ subroutine read_restart_calving(bergs) if (field_exist(filename, 'iceberg_counter_grd')) then if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: reading iceberg_counter_grd from restart file.' - call read_data(filename, 'iceberg_counter_grd', grd%iceberg_counter_grd, grd%domain) + call read_data(filename, 'iceberg_counter_grd', grd%iceberg_counter_grd, grd%domain) else if (verbose.and.mpp_pe().eq.mpp_root_pe()) write(*,'(a)') & 'diamonds, read_restart_calving: iceberg_counter_grd WAS NOT FOUND in the file. Setting to 0.' @@ -1450,13 +1457,12 @@ subroutine read_restart_calving(bergs) end subroutine read_restart_calving -! ############################################################################## - +!> Read ocean depth from file subroutine read_ocean_depth(grd) ! Arguments +type(icebergs_gridded), pointer :: grd !< Container for gridded fields ! Local variables -character(len=37) :: filename -type(icebergs_gridded), pointer :: grd +character(len=37) :: filename ! Read stored ice filename=trim(restart_input_dir)//'topog.nc' @@ -1480,11 +1486,11 @@ subroutine read_ocean_depth(grd) !call grd_chksum2(bergs%grd, bergs%grd%ocean_depth, 'read_ocean_depth, ocean_depth') end subroutine read_ocean_depth -! ############################################################################## - +!> Write a trajectory-based diagnostics file subroutine write_trajectory(trajectory, save_short_traj) ! Arguments -type(xyt), pointer :: trajectory +type(xyt), pointer :: trajectory !< An iceberg trajectory +logical, intent(in) :: save_short_traj !< If true, record less data ! Local variables integer :: iret, ncid, i_dim, i integer :: lonid, latid, yearid, dayid, uvelid, vvelid, iceberg_numid @@ -1495,7 +1501,6 @@ subroutine write_trajectory(trajectory, save_short_traj) character(len=7) :: pe_name type(xyt), pointer :: this, next integer :: stderrunit -logical, intent(in) :: save_short_traj !I/O vars type(xyt), pointer :: traj4io=>null() integer :: ntrajs_sent_io,ntrajs_rcvd_io @@ -1528,7 +1533,7 @@ subroutine write_trajectory(trajectory, save_short_traj) !Now gather and append the bergs from all pes in the io_tile to the list on corresponding io_tile_root_pe ntrajs_sent_io =0 - ntrajs_rcvd_io =0 + ntrajs_rcvd_io =0 if(is_io_tile_root_pe) then !Receive trajs from all pes in this I/O tile !FRAGILE!SCARY! @@ -1552,7 +1557,7 @@ subroutine write_trajectory(trajectory, save_short_traj) trajectory => trajectory%next ! This will eventually result in trajectory => null() deallocate(this) ! Delete the link from memory enddo - + call mpp_send(ntrajs_sent_io, plen=1, to_pe=io_tile_root_pe, tag=COMM_TAG_11) if (ntrajs_sent_io .gt. 0) then call mpp_send(obuffer_io%data, ntrajs_sent_io*buffer_width_traj, to_pe=io_tile_root_pe, tag=COMM_TAG_12) @@ -1567,21 +1572,21 @@ subroutine write_trajectory(trajectory, save_short_traj) call mpp_clock_begin(clock_trw) if((force_all_pes_traj .OR. is_io_tile_root_pe) .AND. associated(traj4io)) then - + call get_instance_filename("iceberg_trajectories.nc", filename) if(io_tile_id(1) .ge. 0 .AND. .NOT. force_all_pes_traj) then !io_tile_root_pes write if(io_npes .gt. 1) then !attach tile_id to filename only if there is more than one I/O pe if (io_tile_id(1)<10000) then - write(filename,'(A,".",I4.4)') trim(filename), io_tile_id(1) + write(filename,'(A,".",I4.4)') trim(filename), io_tile_id(1) else - write(filename,'(A,".",I6.6)') trim(filename), io_tile_id(1) + write(filename,'(A,".",I6.6)') trim(filename), io_tile_id(1) endif endif else !All pes write, attach pe# to filename if (mpp_npes()<10000) then - write(filename,'(A,".",I4.4)') trim(filename), mpp_pe() + write(filename,'(A,".",I4.4)') trim(filename), mpp_pe() else - write(filename,'(A,".",I6.6)') trim(filename), mpp_pe() + write(filename,'(A,".",I6.6)') trim(filename), mpp_pe() endif endif @@ -1677,7 +1682,7 @@ subroutine write_trajectory(trajectory, save_short_traj) call put_att(ncid, dayid, 'units', 'days') call put_att(ncid, iceberg_numid, 'long_name', 'iceberg id number') call put_att(ncid, iceberg_numid, 'units', 'dimensionless') - + if (.not. save_short_traj) then call put_att(ncid, uvelid, 'long_name', 'zonal spped') call put_att(ncid, uvelid, 'units', 'm/s') @@ -1724,7 +1729,7 @@ subroutine write_trajectory(trajectory, save_short_traj) ! End define mode iret = nf_enddef(ncid) - + ! Write variables this=>traj4io if (io_is_in_append_mode) then @@ -1775,20 +1780,18 @@ subroutine write_trajectory(trajectory, save_short_traj) end subroutine write_trajectory - -! ############################################################################## - +!> Returns netcdf id of variable integer function inq_var(ncid, var, unsafe) ! Arguments -integer, intent(in) :: ncid -character(len=*), intent(in) :: var -logical, optional, intent(in) :: unsafe +integer, intent(in) :: ncid !< Handle to netcdf file +character(len=*), intent(in) :: var !< Name of variable +logical, optional, intent(in) :: unsafe !< If present and true, do not fail if variable is not in file ! Local variables integer :: iret integer :: stderrunit logical :: unsafely=.false. -if(present(unsafe)) unsafely=unsafe + if(present(unsafe)) unsafely=unsafe ! Get the stderr unit number stderrunit=stderr() @@ -1804,12 +1807,13 @@ integer function inq_var(ncid, var, unsafe) end function inq_var -! ############################################################################## - +!> Define a netcdf variable integer function def_var(ncid, var, ntype, idim) ! Arguments -integer, intent(in) :: ncid, ntype, idim -character(len=*), intent(in) :: var +integer, intent(in) :: ncid !< Handle to netcdf file +character(len=*), intent(in) :: var !< Name of variable +integer, intent(in) :: ntype !< Netcdf type of variable +integer, intent(in) :: idim !< Length of vector ! Local variables integer :: iret integer :: stderrunit @@ -1825,12 +1829,11 @@ integer function def_var(ncid, var, ntype, idim) end function def_var -! ############################################################################## - +!> Returns id of variable integer function inq_varid(ncid, var) ! Arguments -integer, intent(in) :: ncid -character(len=*), intent(in) :: var +integer, intent(in) :: ncid !< Handle to netcdf file +character(len=*), intent(in) :: var !< Name of variable ! Local variables integer :: iret integer :: stderrunit @@ -1846,12 +1849,13 @@ integer function inq_varid(ncid, var) end function inq_varid -! ############################################################################## - +!> Add a string attribute to a netcdf variable subroutine put_att(ncid, id, att, attval) ! Arguments -integer, intent(in) :: ncid, id -character(len=*), intent(in) :: att, attval +integer, intent(in) :: ncid !< Handle to netcdf file +integer, intent(in) :: id !< Netcdf id of variable +character(len=*), intent(in) :: att !< Name of attribute +character(len=*), intent(in) :: attval !< Value of attribute ! Local variables integer :: vallen, iret integer :: stderrunit @@ -1869,11 +1873,12 @@ subroutine put_att(ncid, id, att, attval) end subroutine put_att -! ############################################################################## - +!> Read a real from a netcdf file real function get_double(ncid, id, i) ! Arguments -integer, intent(in) :: ncid, id, i +integer, intent(in) :: ncid !< Handle to netcdf file +integer, intent(in) :: id !< Netcdf id of variable +integer, intent(in) :: i !< Index to read ! Local variables integer :: iret integer :: stderrunit @@ -1889,11 +1894,12 @@ real function get_double(ncid, id, i) end function get_double -! ############################################################################## - +!> Read an integer from a netcdf file integer function get_int(ncid, id, i) ! Arguments -integer, intent(in) :: ncid, id, i +integer, intent(in) :: ncid !< Handle to netcdf file +integer, intent(in) :: id !< Netcdf id of variable +integer, intent(in) :: i !< Index to read ! Local variables integer :: iret integer :: stderrunit @@ -1909,12 +1915,13 @@ integer function get_int(ncid, id, i) end function get_int -! ############################################################################## - +!> Write a real to a netcdf file subroutine put_double(ncid, id, i, val) ! Arguments -integer, intent(in) :: ncid, id, i -real, intent(in) :: val +integer, intent(in) :: ncid !< Handle to netcdf file +integer, intent(in) :: id !< Netcdf id of variable +integer, intent(in) :: i !< Index of position to write +real, intent(in) :: val !< Value to write ! Local variables integer :: iret integer :: stderrunit @@ -1930,11 +1937,13 @@ subroutine put_double(ncid, id, i, val) end subroutine put_double -! ############################################################################## - +!> Write an integer to a netcdf file subroutine put_int(ncid, id, i, val) ! Arguments -integer, intent(in) :: ncid, id, i, val +integer, intent(in) :: ncid !< Handle to netcdf file +integer, intent(in) :: id !< Netcdf id of variable +integer, intent(in) :: i !< Index of position to write +integer, intent(in) :: val !< Value to write ! Local variables integer :: iret integer :: stderrunit @@ -1950,14 +1959,12 @@ subroutine put_int(ncid, id, i, val) end subroutine put_int - -! ############################################################################## - +!> True is a restart file can be found logical function find_restart_file(filename, actual_file, multiPErestart, tile_id) - character(len=*), intent(in) :: filename - character(len=*), intent(out) :: actual_file - logical, intent(out) :: multiPErestart - integer, intent(in) :: tile_id + character(len=*), intent(in) :: filename !< Base-name of restart file + character(len=*), intent(out) :: actual_file !< Actual name of file, if found + logical, intent(out) :: multiPErestart !< True if found, false otherwise + integer, intent(in) :: tile_id !< Parallel tile number of file character(len=6) :: pe_name @@ -1965,19 +1972,19 @@ logical function find_restart_file(filename, actual_file, multiPErestart, tile_i ! If running as ensemble, add the ensemble id string to the filename call get_instance_filename(filename, actual_file) - + ! Prefer combined restart files. inquire(file=actual_file,exist=find_restart_file) if (find_restart_file) return - + ! Uncombined restart if(tile_id .ge. 0) then write(actual_file,'(A,".",I4.4)') trim(actual_file), tile_id else if (mpp_npes()>10000) then - write(pe_name,'(a,i6.6)' )'.', mpp_pe() + write(pe_name,'(a,i6.6)' )'.', mpp_pe() else - write(pe_name,'(a,i4.4)' )'.', mpp_pe() + write(pe_name,'(a,i4.4)' )'.', mpp_pe() endif actual_file=trim(actual_file)//trim(pe_name) endif @@ -1994,5 +2001,4 @@ logical function find_restart_file(filename, actual_file, multiPErestart, tile_i end function find_restart_file - end module From b3e877492d639bba68bcc9f1f4d87c270bd40a61 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 27 Mar 2017 16:41:14 -0400 Subject: [PATCH 212/361] More doxygenization of icebergs.F90 - More indenting and API documentation - Still far from complete --- icebergs.F90 | 622 +++++++++++++++++++++++++-------------------------- 1 file changed, 310 insertions(+), 312 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 693b55d..8853f00 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -82,33 +82,33 @@ subroutine icebergs_init(bergs, & gni, gnj, layout, io_layout, axes, dom_x_flags, dom_y_flags, & dt, Time, ice_lon, ice_lat, ice_wet, ice_dx, ice_dy, ice_area, & cos_rot, sin_rot, ocean_depth, maskmap, fractional_area) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -integer, intent(in) :: gni !< Number of global points in i-direction -integer, intent(in) :: gnj !< Number of global points in j-direction -integer, intent(in) :: layout(2) !< Parallel decomposition of computational processors in i/j direction -integer, intent(in) :: io_layout(2) !< Parallel decomposition of i/o processors in i/j direction -integer, intent(in) :: axes(2) !< Diagnostic axes -integer, intent(in) :: dom_x_flags !< Decomposition flags for i-direction -integer, intent(in) :: dom_y_flags !< Decomposition flags for j-direction -real, intent(in) :: dt !< Time step (s) -type (time_type), intent(in) :: Time !< Model time -real, dimension(:,:), intent(in) :: ice_lon !< Longitude of cell corners using NE convention (degree E) -real, dimension(:,:), intent(in) :: ice_lat !< Latitude of cell corners using NE conventino (degree N) -real, dimension(:,:), intent(in) :: ice_wet !< Wet/dry mask (1 is wet, 0 is dry) of cell centers -real, dimension(:,:), intent(in) :: ice_dx !< Zonal length of cell on northern side (m) -real, dimension(:,:), intent(in) :: ice_dy !< Meridional length of cell on eastern side (m) -real, dimension(:,:), intent(in) :: ice_area !< Area of cells (m^2, or non-dim is fractional_area=True) -real, dimension(:,:), intent(in) :: cos_rot !< Cosine from rotation matrix to lat-lon coords -real, dimension(:,:), intent(in) :: sin_rot !< Sine from rotation matrix to lat-lon coords -real, dimension(:,:), intent(in),optional :: ocean_depth !< Depth of ocean bottom (m) -logical, intent(in), optional :: maskmap(:,:) !< Masks out parallel cores -logical, intent(in), optional :: fractional_area !< If true, ice_area contains cell area as fraction of entire spherical surface -! Local variables -type(icebergs_gridded), pointer :: grd => null() -integer :: nbonds -logical :: check_bond_quality -integer :: stdlogunit, stderrunit + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + integer, intent(in) :: gni !< Number of global points in i-direction + integer, intent(in) :: gnj !< Number of global points in j-direction + integer, intent(in) :: layout(2) !< Parallel decomposition of computational processors in i/j direction + integer, intent(in) :: io_layout(2) !< Parallel decomposition of i/o processors in i/j direction + integer, intent(in) :: axes(2) !< Diagnostic axes + integer, intent(in) :: dom_x_flags !< Decomposition flags for i-direction + integer, intent(in) :: dom_y_flags !< Decomposition flags for j-direction + real, intent(in) :: dt !< Time step (s) + type (time_type), intent(in) :: Time !< Model time + real, dimension(:,:), intent(in) :: ice_lon !< Longitude of cell corners using NE convention (degree E) + real, dimension(:,:), intent(in) :: ice_lat !< Latitude of cell corners using NE conventino (degree N) + real, dimension(:,:), intent(in) :: ice_wet !< Wet/dry mask (1 is wet, 0 is dry) of cell centers + real, dimension(:,:), intent(in) :: ice_dx !< Zonal length of cell on northern side (m) + real, dimension(:,:), intent(in) :: ice_dy !< Meridional length of cell on eastern side (m) + real, dimension(:,:), intent(in) :: ice_area !< Area of cells (m^2, or non-dim is fractional_area=True) + real, dimension(:,:), intent(in) :: cos_rot !< Cosine from rotation matrix to lat-lon coords + real, dimension(:,:), intent(in) :: sin_rot !< Sine from rotation matrix to lat-lon coords + real, dimension(:,:), intent(in),optional :: ocean_depth !< Depth of ocean bottom (m) + logical, intent(in), optional :: maskmap(:,:) !< Masks out parallel cores + logical, intent(in), optional :: fractional_area !< If true, ice_area contains cell area as fraction of entire spherical surface + ! Local variables + type(icebergs_gridded), pointer :: grd => null() + integer :: nbonds + logical :: check_bond_quality + integer :: stdlogunit, stderrunit ! Get the stderr and stdlog unit numbers stderrunit=stderr() @@ -158,24 +158,24 @@ end subroutine icebergs_init !> Invoke some unit testing subroutine unit_testing(bergs) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory -call hexagon_test() -call point_in_triangle_test() -call basal_melt_test(bergs) -call test_check_for_duplicate_ids_in_list() + call hexagon_test() + call point_in_triangle_test() + call basal_melt_test(bergs) + call test_check_for_duplicate_ids_in_list() end subroutine unit_testing !> Test find_basal_melt() subroutine basal_melt_test(bergs) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -! Local variables -real :: dvo,lat,salt,temp, basal_melt, thickness -integer :: iceberg_num -logical :: Use_three_equation_model + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + ! Local variables + real :: dvo,lat,salt,temp, basal_melt, thickness + integer :: iceberg_num + logical :: Use_three_equation_model if (mpp_pe() .eq. mpp_root_pe() ) print *, 'Begining Basal Melting Unit Test' dvo=0.2 ;lat=0.0 ; salt=35.0 ; temp=2.0 ;thickness=100.; iceberg_num=0 @@ -191,10 +191,10 @@ end subroutine basal_melt_test !> Test point_in_triangle() subroutine point_in_triangle_test() -! Arguments -real :: Ax,Ay,Bx,By,Cx,Cy !Position of icebergs -logical :: fail_unit_test -integer :: stderrunit + ! Local variables + real :: Ax,Ay,Bx,By,Cx,Cy !Position of icebergs + logical :: fail_unit_test + integer :: stderrunit ! Get the stderr unit number. stderrunit = stderr() @@ -212,13 +212,13 @@ end subroutine point_in_triangle_test !> Test Hexagon_into_quadrants_using_triangles() subroutine hexagon_test() -! Arguments -real :: x0,y0 !Position of icebergs -real :: H,theta,S !Apothen of iceberg and angle. -real :: Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 ! Areas of icebergs -real :: tol -logical :: fail_unit_test -integer :: stderrunit + ! Local variables + real :: x0,y0 !Position of icebergs + real :: H,theta,S !Apothen of iceberg and angle. + real :: Area_hex, Area_Q1, Area_Q2, Area_Q3, Area_Q4 ! Areas of icebergs + real :: tol + logical :: fail_unit_test + integer :: stderrunit ! Get the stderr unit number. stderrunit = stderr() @@ -317,24 +317,23 @@ subroutine hexagon_test() if (fail_unit_test) call error_mesg('diamonds, hexagon unit testing:', 'Hexagon unit testing does not pass!', FATAL) - end subroutine hexagon_test !> Initializes bonds subroutine initialize_iceberg_bonds(bergs) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -! Local variables -type(iceberg), pointer :: berg -type(iceberg), pointer :: other_berg -type(icebergs_gridded), pointer :: grd -real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg -real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg -real :: dlon,dlat -real :: dx_dlon,dy_dlat, lat_ref -real :: r_dist_x, r_dist_y, r_dist -integer :: grdi_outer, grdj_outer -integer :: grdi_inner, grdj_inner + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + ! Local variables + type(iceberg), pointer :: berg + type(iceberg), pointer :: other_berg + type(icebergs_gridded), pointer :: grd + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg + real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg + real :: dlon,dlat + real :: dx_dlon,dy_dlat, lat_ref + real :: r_dist_x, r_dist_y, r_dist + integer :: grdi_outer, grdj_outer + integer :: grdi_inner, grdj_inner ! For convenience grd=>bergs%grd @@ -380,11 +379,11 @@ end subroutine initialize_iceberg_bonds ! Returns metric converting grid distances to meters subroutine convert_from_grid_to_meters(lat_ref, grid_is_latlon, dx_dlon, dy_dlat) -! Arguments -real, intent(in) :: lat_ref -logical, intent(in) :: grid_is_latlon -real, intent(out) :: dx_dlon -real, intent(out) :: dy_dlat + ! Arguments + real, intent(in) :: lat_ref !< Latitude at which to make metric conversion (degree N) + logical, intent(in) :: grid_is_latlon !< True if grid model grid is in lat-lon coordinates + real, intent(out) :: dx_dlon !< Metric dx/dlon + real, intent(out) :: dy_dlat !< Metric dy/dlat if (grid_is_latlon) then dx_dlon=(pi/180.)*Rearth*cos((lat_ref)*(pi/180.)) @@ -394,15 +393,15 @@ subroutine convert_from_grid_to_meters(lat_ref, grid_is_latlon, dx_dlon, dy_dlat dy_dlat=1. endif -end subroutine convert_from_grid_to_meters +end subroutine convert_from_grid_to_meters ! Returns metric converting distance in meters to grid distance subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) -! Arguments -real, intent(in) :: lat_ref -logical, intent(in) :: grid_is_latlon -real, intent(out) :: dlon_dx -real, intent(out) :: dlat_dy + ! Arguments + real, intent(in) :: lat_ref !< Latitude at which to make metric conversion (degree N) + logical, intent(in) :: grid_is_latlon !< True if grid model grid is in lat-lon coordinates + real, intent(out) :: dlon_dx !< Metric dlon/dx + real, intent(out) :: dlat_dy !< Metric dlat/dy if (grid_is_latlon) then dlon_dx=(180./pi)/(Rearth*cos((lat_ref)*(pi/180.))) @@ -412,34 +411,34 @@ subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) dlat_dy=1. endif -end subroutine convert_from_meters_to_grid +end subroutine convert_from_meters_to_grid +!> Calculates interactive forcs between two bergs. subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) -!Calculating interactive force between icebergs. Alon, Markpoint_4 -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(iceberg), pointer :: berg -type(iceberg), pointer :: other_berg -type(bond), pointer :: current_bond -real, intent(in) :: u0 -real, intent(in) :: v0 -real, intent(in) :: u1 -real, intent(in) :: v1 -real, intent(out) :: IA_x -real, intent(out) :: IA_y -real, intent(out) :: P_ia_11 -real, intent(out) :: P_ia_12 -real, intent(out) :: P_ia_22 -real, intent(out) :: P_ia_21 -real, intent(out) :: P_ia_times_u_x -real, intent(out) :: P_ia_times_u_y -! Local variables -real :: u2, v2 -logical :: critical_interaction_damping_on -integer :: grdi, grdj -logical :: iceberg_bonds_on -logical :: bonded + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(iceberg), pointer :: berg !< Primary iceberg + type(iceberg), pointer :: other_berg !< Berg that primary is interacting with + real, intent(in) :: u0 + real, intent(in) :: v0 + real, intent(in) :: u1 + real, intent(in) :: v1 + real, intent(out) :: IA_x + real, intent(out) :: IA_y + real, intent(out) :: P_ia_11 + real, intent(out) :: P_ia_12 + real, intent(out) :: P_ia_22 + real, intent(out) :: P_ia_21 + real, intent(out) :: P_ia_times_u_x + real, intent(out) :: P_ia_times_u_y + ! Local variables + type(bond), pointer :: current_bond + real :: u2, v2 + logical :: critical_interaction_damping_on + integer :: grdi, grdj + logical :: iceberg_bonds_on + logical :: bonded iceberg_bonds_on=bergs%iceberg_bonds_on @@ -480,25 +479,26 @@ subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& contains subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, & - P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) - !Arguments - type(icebergs), pointer :: bergs !< Container for all types and memory - type(iceberg), pointer :: berg - type(iceberg), pointer :: other_berg - real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg - real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg - real :: dlon, dlat - real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min - real, intent(in) :: u0,v0, u1, v1 - real :: P_11, P_12, P_21, P_22 - real :: M1, M2, M_min - real :: u2, v2 - real :: lat_ref, dx_dlon, dy_dlat - logical :: critical_interaction_damping_on - real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef - real, intent(inout) :: IA_x, IA_y - real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y - logical ,intent(in) :: bonded + P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(iceberg), pointer :: berg !< Primary berg + type(iceberg), pointer :: other_berg !< Berg that primary is interacting with + real, intent(inout) :: IA_x, IA_y + real, intent(in) :: u0, v0, u1, v1 + real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y + logical ,intent(in) :: bonded + ! Local variables + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg + real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg + real :: dlon, dlat + real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min + real :: P_11, P_12, P_21, P_22 + real :: M1, M2, M_min + real :: u2, v2 + real :: lat_ref, dx_dlon, dy_dlat + logical :: critical_interaction_damping_on + real :: spring_coef, accel_spring, radial_damping_coef, p_ia_coef, tangental_damping_coef, bond_coef spring_coef=bergs%spring_coef !bond_coef=bergs%bond_coef @@ -631,14 +631,14 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, end subroutine calculate_force subroutine overlap_area(R1, R2, d, A, trapped) - ! Arguments - real, intent(in) :: R1 - real, intent(in) :: R2 - real, intent(in) :: d - real, intent(out) :: A - real, intent(out) :: Trapped - ! Local variables - real :: R1_sq, R2_sq, d_sq + ! Arguments + real, intent(in) :: R1 + real, intent(in) :: R2 + real, intent(in) :: d + real, intent(out) :: A + real, intent(out) :: Trapped + ! Local variables + real :: R1_sq, R2_sq, d_sq R1_sq=R1**2 R2_sq=R2**2 @@ -665,48 +665,47 @@ end subroutine overlap_area end subroutine interactive_force !> Calculates the instantaneous acceleration of an iceberg -subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) !Saving acceleration for Verlet, Adding Verlet flag - Alon MP1 -!subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, debug_flag) !old version commmented out by Alon -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(iceberg), pointer :: berg !< An iceberg -integer, intent(in) :: i !< i-index of cell berg is in -integer, intent(in) :: j !< j-index of cell berg is in -real, intent(in) :: xi !< Non-dimensional x-position within cell of berg -real, intent(in) :: yj !< Non-dimensional y-position within cell of berg -real, intent(in) :: lat !< Latitude of berg (degree N) -real, intent(in) :: uvel !< Zonal velocity of berg (m/s) -real, intent(in) :: vvel !< Meridional velocity of berg (m/s) -real, intent(in) :: uvel0 -real, intent(in) :: vvel0 -real, intent(in) :: dt !< Time step (s) -real, intent(out) :: ax !< Zonal acceleration (m/s2) -real, intent(out) :: ay !< Meridional acceleration (m/s2) -real, intent(inout) :: axn -real, intent(inout) :: ayn -real, intent(inout) :: bxn -real, intent(inout) :: byn ! Added implicit and explicit accelerations to output -Alon -logical, optional :: debug_flag !< If true, print debugging -! Local variables -type(icebergs_gridded), pointer :: grd -real :: uo, vo, ui, vi, ua, va, uwave, vwave, ssh_x, ssh_y, sst, sss, cn, hi -real :: f_cori, T, D, W, L, M, F -real :: drag_ocn, drag_atm, drag_ice, wave_rad -real :: c_ocn, c_atm, c_ice -real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop -real, parameter :: accel_lim=1.e-2, Cr0=0.06, vel_lim=15. -real :: alpha, beta, C_N -real :: lambda, detA, A11, A12, A21, A22, RHS_x, RHS_y, D_hi -real :: uveln, vveln, us, vs, speed, loc_dx, new_speed -real :: u_star, v_star !Added by Alon -real :: IA_x, IA_y !Added by Alon -real :: P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y !Added by Alon -logical :: dumpit -logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. -logical :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet -logical :: use_new_predictive_corrective !Flad to use Bob's predictive corrective scheme. (default off) -integer :: itloop -integer :: stderrunit +subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, ax, ay, axn, ayn, bxn, byn, debug_flag) + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(iceberg), pointer :: berg !< An iceberg + integer, intent(in) :: i !< i-index of cell berg is in + integer, intent(in) :: j !< j-index of cell berg is in + real, intent(in) :: xi !< Non-dimensional x-position within cell of berg + real, intent(in) :: yj !< Non-dimensional y-position within cell of berg + real, intent(in) :: lat !< Latitude of berg (degree N) + real, intent(in) :: uvel !< Zonal velocity of berg (m/s) + real, intent(in) :: vvel !< Meridional velocity of berg (m/s) + real, intent(in) :: uvel0 !< Zonal velocity of berg at beginning of time-step (m/s) + real, intent(in) :: vvel0 !< Meridional velocity of berg at beginning of time-step (m/s) + real, intent(in) :: dt !< Time step (s) + real, intent(out) :: ax !< Zonal acceleration (m/s2) + real, intent(out) :: ay !< Meridional acceleration (m/s2) + real, intent(inout) :: axn !< Explicit estimate of zonal acceleration (m/s2) + real, intent(inout) :: ayn !< Explicit estimate of meridional acceleration (m/s2) + real, intent(inout) :: bxn !< Implicit component of zonal acceleration (m/s2) + real, intent(inout) :: byn !< Implicit component of meridional acceleration (m/s2) + logical, optional :: debug_flag !< If true, print debugging + ! Local variables + type(icebergs_gridded), pointer :: grd + real :: uo, vo, ui, vi, ua, va, uwave, vwave, ssh_x, ssh_y, sst, sss, cn, hi + real :: f_cori, T, D, W, L, M, F + real :: drag_ocn, drag_atm, drag_ice, wave_rad + real :: c_ocn, c_atm, c_ice + real :: ampl, wmod, Cr, Lwavelength, Lcutoff, Ltop + real, parameter :: accel_lim=1.e-2, Cr0=0.06, vel_lim=15. + real :: alpha, beta, C_N + real :: lambda, detA, A11, A12, A21, A22, RHS_x, RHS_y, D_hi + real :: uveln, vveln, us, vs, speed, loc_dx, new_speed + real :: u_star, v_star !Added by Alon + real :: IA_x, IA_y !Added by Alon + real :: P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y !Added by Alon + logical :: dumpit + logical :: interactive_icebergs_on ! Flag to decide whether to use forces between icebergs. + logical :: Runge_not_Verlet ! Flag to specify whether it is Runge-Kutta or Verlet + logical :: use_new_predictive_corrective !Flad to use Bob's predictive corrective scheme. (default off) + integer :: itloop + integer :: stderrunit Runge_not_Verlet=bergs%Runge_not_Verlet ! Loading directly from namelist/default , Alon interactive_icebergs_on=bergs%interactive_icebergs_on ! Loading directly from namelist/default , Alon @@ -881,7 +880,6 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !print *,'Before calculation:', berg%iceberg_num, IA_x, IA_y, P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y endif - ! Solve for implicit accelerations if (alpha+beta.gt.0.) then lambda=drag_ocn+drag_atm+drag_ice @@ -1097,75 +1095,74 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a contains subroutine dump_locfld(grd,i0,j0,A,lbl) - ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i0, j0 - real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A - character(len=*) :: lbl -! Local variables - integer :: i, j, ii, jj - real :: B(-1:1,-1:1), fac - - do jj=-1,1 - j=max(grd%jsd,min(grd%jed,jj+j0)) - do ii=-1,1 - i=max(grd%isd,min(grd%ied,ii+i0)) - B(ii,jj)=A(i,j) - if ((i.ne.ii+i0).or.(j.ne.jj+j0)) B(ii,jj)=-9.999999e-99 + ! Arguments + type(icebergs_gridded), pointer :: grd + integer, intent(in) :: i0, j0 + real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A + character(len=*) :: lbl + ! Local variables + integer :: i, j, ii, jj + real :: B(-1:1,-1:1), fac + + do jj=-1,1 + j=max(grd%jsd,min(grd%jed,jj+j0)) + do ii=-1,1 + i=max(grd%isd,min(grd%ied,ii+i0)) + B(ii,jj)=A(i,j) + if ((i.ne.ii+i0).or.(j.ne.jj+j0)) B(ii,jj)=-9.999999e-99 + enddo + enddo + write(stderrunit,'("pe=",i3,x,a8,3i12)') mpp_pe(),lbl,(i0+ii,ii=-1,1) + do jj=1,-1,-1 + write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,1) enddo - enddo - write(stderrunit,'("pe=",i3,x,a8,3i12)') mpp_pe(),lbl,(i0+ii,ii=-1,1) - do jj=1,-1,-1 - write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,1) - enddo end subroutine dump_locfld subroutine dump_locvel(grd,i0,j0,A,lbl) - ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i0, j0 - real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A - character(len=*) :: lbl -! Local variables - integer :: i, j, ii, jj - real :: B(-1:0,-1:0), fac - - do jj=-1,0 - j=max(grd%jsd,min(grd%jed,jj+j0)) - do ii=-1,0 - i=max(grd%isd,min(grd%ied,ii+i0)) - B(ii,jj)=A(i,j) - if ((i.ne.ii+i0).or.(j.ne.jj+j0)) B(ii,jj)=-9.999999e-99 + ! Arguments + type(icebergs_gridded), pointer :: grd + integer, intent(in) :: i0, j0 + real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A + character(len=*) :: lbl + ! Local variables + integer :: i, j, ii, jj + real :: B(-1:0,-1:0), fac + + do jj=-1,0 + j=max(grd%jsd,min(grd%jed,jj+j0)) + do ii=-1,0 + i=max(grd%isd,min(grd%ied,ii+i0)) + B(ii,jj)=A(i,j) + if ((i.ne.ii+i0).or.(j.ne.jj+j0)) B(ii,jj)=-9.999999e-99 + enddo + enddo + write(stderrunit,'("pe=",i3,x,a8,3i12)') mpp_pe(),lbl,(i0+ii,ii=-1,0) + do jj=0,-1,-1 + write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,0) enddo - enddo - write(stderrunit,'("pe=",i3,x,a8,3i12)') mpp_pe(),lbl,(i0+ii,ii=-1,0) - do jj=0,-1,-1 - write(stderrunit,'("pe=",i3,x,i8,3es12.4)') mpp_pe(),j0+jj,(B(ii,jj),ii=-1,0) - enddo end subroutine dump_locvel end subroutine accel -! ############################################################################## - +!> Steps forward thermodynamic state of all bergs subroutine thermodynamics(bergs) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -! Local variables -type(icebergs_gridded), pointer :: grd -type(bond), pointer :: current_bond -real :: M, T, W, L, SST, Vol, Ln, Wn, Tn, nVol, IC, Dn -real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv -real :: Mnew, Mnew1, Mnew2, Hocean -real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb -real :: tip_parameter -real :: Ms, N_bonds, N_max !Ice shelf melt, Number of bonds, Max_number of bonds -real :: Delta, q -integer :: i,j, stderrunit -type(iceberg), pointer :: this, next -real, parameter :: perday=1./86400. -integer :: grdi, grdj -real :: SSS !Temporarily here + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + ! Local variables + type(icebergs_gridded), pointer :: grd + type(bond), pointer :: current_bond + real :: M, T, W, L, SST, Vol, Ln, Wn, Tn, nVol, IC, Dn + real :: Mv, Me, Mb, melt, dvo, dva, dM, Ss, dMe, dMb, dMv + real :: Mnew, Mnew1, Mnew2, Hocean + real :: Mbits, nMbits, dMbitsE, dMbitsM, Lbits, Abits, Mbb + real :: tip_parameter + real :: Ms, N_bonds, N_max !Ice shelf melt, Number of bonds, Max_number of bonds + real :: Delta, q + integer :: i,j, stderrunit + type(iceberg), pointer :: this, next + real, parameter :: perday=1./86400. + integer :: grdi, grdj + real :: SSS !Temporarily here ! For convenience grd=>bergs%grd @@ -1425,9 +1422,9 @@ subroutine thermodynamics(bergs) contains subroutine swap_variables(x,y) - ! Arguments - real, intent(inout) :: x, y - real :: temp + ! Arguments + real, intent(inout) :: x, y + real :: temp temp=x x=y y=temp @@ -1536,87 +1533,88 @@ subroutine create_gridded_icebergs_fields(bergs) endif end subroutine create_gridded_icebergs_fields +!> Calculates basl melt for given thermodynamic properties subroutine find_basal_melt(bergs, dvo, lat, salt, temp, Use_three_equation_model, thickness, basal_melt, iceberg_num) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -real, intent(in) :: dvo !< Speed of iceberg relative to ocean mixed layer -real, intent(in) :: lat !< Latitude (for boundary layer calculation) -real, intent(in) :: salt !< Salinity of mixed layer -real, intent(in) :: temp !< Temperature of mixed layer -logical, intent(in) :: Use_three_equation_model !< True uses the 3 equation model, False uses the 2 equation model. -real, intent(in) :: thickness !< Ice thickness - needed to work out the pressure below the ice -real, intent(out) :: basal_melt !< Melt rate underneath the icebergs -integer, intent(in) :: iceberg_num !< Iceberg number, used for debugging (error messages) -! Local variables -real :: ustar, f_cori, absf,tfreeze -real :: Hml !Mixed layer depth - -!These could also be useful output variables if needed. -real :: t_flux, exch_vel_t, exch_vel_s,tflux_shelf,lprec - -real :: Rhoml ! Ocean mixed layer density in kg m-3. -real :: p_int ! The pressure at the ice-ocean interface, in Pa. - -real, parameter :: VK = 0.40 ! Von Karman's constant - dimensionless -real :: ZETA_N = 0.052 ! The fraction of the boundary layer over which the - ! viscosity is linearly increasing. (Was 1/8. Why?) -real, parameter :: RC = 0.20 ! critical flux Richardson number. -real :: I_ZETA_N ! The inverse of ZETA_N. -real :: I_LF ! Inverse of Latent Heat of fusion (J kg-1) -real :: I_VK ! The inverse of VK. -real :: PR, SC ! The Prandtl number and Schmidt number, nondim. - -! 3 equation formulation variables -real :: Sbdry ! Salinities in the ocean at the interface with the -real :: Sbdry_it ! the ice shelf, in PSU. -real :: dS_it ! The interface salinity change during an iteration, in PSU. -real :: hBL_neut ! The neutral boundary layer thickness, in m. -real :: hBL_neut_h_molec ! The ratio of the neutral boundary layer thickness - ! to the molecular boundary layer thickness, ND. -real :: wT_flux ! The vertical fluxes of heat and buoyancy just inside the -real :: wB_flux ! ocean, in C m s-1 and m2 s-3, ###CURRENTLY POSITIVE UPWARD. -real :: dB_dS ! The derivative of buoyancy with salinity, in m s-2 PSU-1. -real :: dB_dT ! The derivative of buoyancy with temperature, in m s-2 C-1. -real :: I_n_star, n_star_term -real :: dIns_dwB ! The partial derivative of I_n_star with wB_flux, in ???. -real :: dT_ustar, dS_ustar -real :: ustar_h -real :: Gam_turb -real :: Gam_mol_t, Gam_mol_s -real :: RhoCp -real :: I_RhoLF -real :: Rho0 -real :: ln_neut -real :: mass_exch -real :: Sb_min, Sb_max -real :: dS_min, dS_max -real :: density_ice - -! Variables used in iterating for wB_flux. -real :: wB_flux_new, DwB, dDwB_dwB_in -real :: I_Gam_T, I_Gam_S -real :: dG_dwB, iDens -logical :: Sb_min_set, Sb_max_set -logical :: out_of_bounds - -real, parameter :: c2_3 = 2.0/3.0 -integer :: it1, it3 - -!Parameters copied ice shelf module defaults (could be entered in the namelist later) -real, parameter :: dR0_dT = -0.038357 ! Partial derivative of the mixed layer density with temperature, in units of kg m-3 K-1. -real, parameter :: dR0_dS = 0.805876 ! Partial derivative of the mixed layer density with salinity, in units of kg m-3 psu-1. -real, parameter :: RHO_T0_S0 = 999.910681 ! Density of water with T=0, S=0 for linear EOS -real, parameter :: Salin_Ice =0.0 !Salinity of ice -real, parameter :: Temp_Ice = -15.0 !Salinity of ice -real, parameter :: kd_molec_salt= 8.02e-10 !The molecular diffusivity of salt in sea water at the freezing point -real, parameter :: kd_molec_temp= 1.41e-7 !The molecular diffusivity of heat in sea water at the freezing point -real, parameter :: kv_molec= 1.95e-6 !The molecular molecular kinematic viscosity of sea water at the freezing point -real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) -real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) -real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) -real, parameter :: gamma_t = 0.0 ! Exchange velocity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independent of u_star. - ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. -real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + real, intent(in) :: dvo !< Speed of iceberg relative to ocean mixed layer + real, intent(in) :: lat !< Latitude (for boundary layer calculation) + real, intent(in) :: salt !< Salinity of mixed layer + real, intent(in) :: temp !< Temperature of mixed layer + logical, intent(in) :: Use_three_equation_model !< True uses the 3 equation model, False uses the 2 equation model. + real, intent(in) :: thickness !< Ice thickness - needed to work out the pressure below the ice + real, intent(out) :: basal_melt !< Melt rate underneath the icebergs + integer, intent(in) :: iceberg_num !< Iceberg number, used for debugging (error messages) + ! Local variables + real :: ustar, f_cori, absf,tfreeze + real :: Hml !Mixed layer depth + + !These could also be useful output variables if needed. + real :: t_flux, exch_vel_t, exch_vel_s,tflux_shelf,lprec + + real :: Rhoml ! Ocean mixed layer density in kg m-3. + real :: p_int ! The pressure at the ice-ocean interface, in Pa. + + real, parameter :: VK = 0.40 ! Von Karman's constant - dimensionless + real :: ZETA_N = 0.052 ! The fraction of the boundary layer over which the + ! viscosity is linearly increasing. (Was 1/8. Why?) + real, parameter :: RC = 0.20 ! critical flux Richardson number. + real :: I_ZETA_N ! The inverse of ZETA_N. + real :: I_LF ! Inverse of Latent Heat of fusion (J kg-1) + real :: I_VK ! The inverse of VK. + real :: PR, SC ! The Prandtl number and Schmidt number, nondim. + + ! 3 equation formulation variables + real :: Sbdry ! Salinities in the ocean at the interface with the + real :: Sbdry_it ! the ice shelf, in PSU. + real :: dS_it ! The interface salinity change during an iteration, in PSU. + real :: hBL_neut ! The neutral boundary layer thickness, in m. + real :: hBL_neut_h_molec ! The ratio of the neutral boundary layer thickness + ! to the molecular boundary layer thickness, ND. + real :: wT_flux ! The vertical fluxes of heat and buoyancy just inside the + real :: wB_flux ! ocean, in C m s-1 and m2 s-3, ###CURRENTLY POSITIVE UPWARD. + real :: dB_dS ! The derivative of buoyancy with salinity, in m s-2 PSU-1. + real :: dB_dT ! The derivative of buoyancy with temperature, in m s-2 C-1. + real :: I_n_star, n_star_term + real :: dIns_dwB ! The partial derivative of I_n_star with wB_flux, in ???. + real :: dT_ustar, dS_ustar + real :: ustar_h + real :: Gam_turb + real :: Gam_mol_t, Gam_mol_s + real :: RhoCp + real :: I_RhoLF + real :: Rho0 + real :: ln_neut + real :: mass_exch + real :: Sb_min, Sb_max + real :: dS_min, dS_max + real :: density_ice + + ! Variables used in iterating for wB_flux. + real :: wB_flux_new, DwB, dDwB_dwB_in + real :: I_Gam_T, I_Gam_S + real :: dG_dwB, iDens + logical :: Sb_min_set, Sb_max_set + logical :: out_of_bounds + + real, parameter :: c2_3 = 2.0/3.0 + integer :: it1, it3 + + !Parameters copied ice shelf module defaults (could be entered in the namelist later) + real, parameter :: dR0_dT = -0.038357 ! Partial derivative of the mixed layer density with temperature, in units of kg m-3 K-1. + real, parameter :: dR0_dS = 0.805876 ! Partial derivative of the mixed layer density with salinity, in units of kg m-3 psu-1. + real, parameter :: RHO_T0_S0 = 999.910681 ! Density of water with T=0, S=0 for linear EOS + real, parameter :: Salin_Ice =0.0 !Salinity of ice + real, parameter :: Temp_Ice = -15.0 !Salinity of ice + real, parameter :: kd_molec_salt= 8.02e-10 !The molecular diffusivity of salt in sea water at the freezing point + real, parameter :: kd_molec_temp= 1.41e-7 !The molecular diffusivity of heat in sea water at the freezing point + real, parameter :: kv_molec= 1.95e-6 !The molecular molecular kinematic viscosity of sea water at the freezing point + real, parameter :: Cp_Ice = 2009.0 !Specific heat capacity of ice, taking from HJ99 (Holland and Jenkins 1999) + real, parameter :: Cp_ml = 3974.0 !Specific heat capacity of mixed layer, taking from HJ99 (Holland and Jenkins 1999) + real, parameter :: LF = 3.335e5 !Latent heat of fusion, taken from HJ99 (Holland and Jenkins 1999) + real, parameter :: gamma_t = 0.0 ! Exchange velocity used in 2 equation model. Whn gamma_t is >0, the exchange velocity is independent of u_star. + ! When gamma_t=0.0, then gamma_t is not used, and the exchange velocity is found using u_star. + real, parameter :: p_atm = 101325 ! Average atmospheric pressure (Pa) - from Google. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! density_ice = bergs%rho_bergs From 0dca7ae756b870054e34e1d6893bf7df90c6ae00 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Mon, 27 Mar 2017 23:58:31 -0400 Subject: [PATCH 213/361] More doxygenization of icebergs.F90 - More API documentation. - More indenting fixes. - This is hard work - vim says I'm only 73% of the way through the file and this is my second commit after hours of editing for each! --- icebergs.F90 | 1216 +++++++++++++++++++++++++++++--------------------- 1 file changed, 700 insertions(+), 516 deletions(-) diff --git a/icebergs.F90 b/icebergs.F90 index 8853f00..deba85a 100644 --- a/icebergs.F90 +++ b/icebergs.F90 @@ -377,7 +377,7 @@ subroutine initialize_iceberg_bonds(bergs) end subroutine initialize_iceberg_bonds -! Returns metric converting grid distances to meters +!> Returns metric converting grid distances to meters subroutine convert_from_grid_to_meters(lat_ref, grid_is_latlon, dx_dlon, dy_dlat) ! Arguments real, intent(in) :: lat_ref !< Latitude at which to make metric conversion (degree N) @@ -395,7 +395,7 @@ subroutine convert_from_grid_to_meters(lat_ref, grid_is_latlon, dx_dlon, dy_dlat end subroutine convert_from_grid_to_meters -! Returns metric converting distance in meters to grid distance +!> Returns metric converting distance in meters to grid distance subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) ! Arguments real, intent(in) :: lat_ref !< Latitude at which to make metric conversion (degree N) @@ -413,19 +413,19 @@ subroutine convert_from_meters_to_grid(lat_ref,grid_is_latlon ,dlon_dx,dlat_dy) end subroutine convert_from_meters_to_grid -!> Calculates interactive forcs between two bergs. +!> Calculates interactions between a berg and all bergs in range subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y) ! Arguments type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg !< Primary iceberg type(iceberg), pointer :: other_berg !< Berg that primary is interacting with - real, intent(in) :: u0 - real, intent(in) :: v0 - real, intent(in) :: u1 - real, intent(in) :: v1 - real, intent(out) :: IA_x - real, intent(out) :: IA_y + real, intent(in) :: u0 !< Zonal velocity of primary berg (m/s) + real, intent(in) :: v0 !< Meridional velocity of primary berg (m/s) + real, intent(in) :: u1 !< Zonal velocity of other berg (m/s) + real, intent(in) :: v1 !< Meridional velocity of other berg (m/s) + real, intent(out) :: IA_x !< Net zonal acceleration of berg due to interactions (m/s2) + real, intent(out) :: IA_y !< Net meridional acceleration of berg due to interactions (m/s2) real, intent(out) :: P_ia_11 real, intent(out) :: P_ia_12 real, intent(out) :: P_ia_22 @@ -447,17 +447,17 @@ subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& P_ia_11=0. ; P_ia_12=0. ; P_ia_21=0.; P_ia_22=0. P_ia_times_u_x=0. ; P_ia_times_u_y=0. - bonded=.false. !Unbonded iceberg interactions - do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 !Note: need to make sure this is wide enough, but less than the halo width + bonded=.false. ! Unbonded iceberg interactions + do grdj = berg%jne-1,berg%jne+1 ; do grdi = berg%ine-1,berg%ine+1 ! Note: need to make sure this is wide enough, but less than the halo width other_berg=>bergs%list(grdi,grdj)%first do while (associated(other_berg)) ! loop over all other bergs - call calculate_force(bergs,berg,other_berg, IA_x, IA_y, u0, v0, u1, v1, & + call calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, & P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) other_berg=>other_berg%next enddo ! loop over all bergs enddo ; enddo - bonded=.true. !Interactions due to iceberg bonds + bonded=.true. ! Interactions due to iceberg bonds if (iceberg_bonds_on) then ! MP1 current_bond=>berg%first_bond do while (associated(current_bond)) ! loop over all bonds @@ -465,7 +465,7 @@ subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& if (.not. associated(other_berg)) then call error_mesg('diamonds,bond interactions', 'Trying to do Bond interactions with unassosiated berg!' ,FATAL) else - call calculate_force(bergs,berg,other_berg, IA_x, IA_y, u0, v0, u1, v1, & + call calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, & P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y,bonded) endif current_bond=>current_bond%next_bond @@ -478,19 +478,29 @@ subroutine interactive_force(bergs, berg, IA_x, IA_y, u0, v0, u1, v1,& contains + !> Calculate interactive forces between two bergs subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, & P_ia_11, P_ia_12, P_ia_21, P_ia_22, P_ia_times_u_x, P_ia_times_u_y, bonded) ! Arguments type(icebergs), pointer :: bergs !< Container for all types and memory type(iceberg), pointer :: berg !< Primary berg type(iceberg), pointer :: other_berg !< Berg that primary is interacting with - real, intent(inout) :: IA_x, IA_y - real, intent(in) :: u0, v0, u1, v1 - real, intent(inout) :: P_ia_11, P_ia_12, P_ia_22, P_ia_21, P_ia_times_u_x, P_ia_times_u_y + real, intent(inout) :: IA_x !< Net zonal acceleration of berg due to interactions (m/s2) + real, intent(inout) :: IA_y !< Net meridional acceleration of berg due to interactions (m/s2) + real, intent(in) :: u0 !< Zonal velocity of primary berg (m/s) + real, intent(in) :: v0 !< Meridional velocity of primary berg (m/s) + real, intent(in) :: u1 !< Zonal velocity of other berg (m/s) + real, intent(in) :: v1 !< Meridional velocity of other berg (m/s) + real, intent(inout) :: P_ia_11 + real, intent(inout) :: P_ia_12 + real, intent(inout) :: P_ia_22 + real, intent(inout) :: P_ia_21 + real, intent(inout) :: P_ia_times_u_x + real, intent(inout) :: P_ia_times_u_y logical ,intent(in) :: bonded ! Local variables - real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 !Current iceberg - real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 !Other iceberg + real :: T1, L1, W1, lon1, lat1, x1, y1, R1, A1 ! Current iceberg + real :: T2, L2, W2, lon2, lat2, x2, y2, R2, A2 ! Other iceberg real :: dlon, dlat real :: r_dist_x, r_dist_y, r_dist, A_o, A_min, trapped, T_min real :: P_11, P_12, P_21, P_22 @@ -506,14 +516,14 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, tangental_damping_coef=bergs%tangental_damping_coef critical_interaction_damping_on=bergs%critical_interaction_damping_on - !Using critical values for damping rather than manually setting the damping. + ! Using critical values for damping rather than manually setting the damping. if (critical_interaction_damping_on) then - radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping - tangental_damping_coef=(2.*sqrt(spring_coef))/4 ! Critical damping (just a guess) + radial_damping_coef=2.*sqrt(spring_coef) ! Critical damping + tangental_damping_coef=(2.*sqrt(spring_coef))/4 ! Critical damping (just a guess) endif if (berg%iceberg_num .ne. other_berg%iceberg_num) then - !From Berg 1 + ! From Berg 1 L1=berg%length W1=berg%width T1=berg%thickness @@ -522,7 +532,7 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, lon1=berg%lon_old; lat1=berg%lat_old !call rotpos_to_tang(lon1,lat1,x1,y1) - !From Berg 1 + ! From Berg 1 L2=other_berg%length W2=other_berg%width T2=other_berg%thickness @@ -537,8 +547,8 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, dlon=lon1-lon2 dlat=lat1-lat2 - !Note that this is not the exact distance along a great circle. - !Approximation for small distances. Should be fine. + ! Note that this is not the exact distance along a great circle. + ! Approximation for small distances. Should be fine. !r_dist_x=x1-x2 ; r_dist_y=y1-y2 !r_dist=sqrt( ((x1-x2)**2) + ((y1-y2)**2) ) lat_ref=0.5*(lat1+lat2) @@ -572,7 +582,7 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, M_min=min(M1,M2) !Calculating spring force (later this should only be done on the first time around) if ((r_dist>0.) .AND. ((r_dist< (R1+R2).AND. (.not. bonded)) .OR. ( (r_dist> (R1+R2)) .AND. (bonded) ) )) then - !Spring force + ! Spring force !accel_spring=spring_coef*(T_min/T1)*(A_o/A1) ! Old version dependent on area accel_spring=spring_coef*(M_min/M1)*(R1+R2-r_dist) IA_x=IA_x+(accel_spring*(r_dist_x/r_dist)) @@ -588,8 +598,8 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, !endif !print *, 'in the loop1', spring_coef, (M_min/M1), accel_spring,(R1+R2-r_dist) !print *, 'in the loop2', IA_x, IA_y, R1, R2,r_dist, berg%iceberg_num,other_berg%iceberg_num - !Damping force: - !Paralel velocity + ! Damping force: + ! Paralel velocity P_11=(r_dist_x*r_dist_x)/(r_dist**2) P_12=(r_dist_x*r_dist_y)/(r_dist**2) P_21=(r_dist_x*r_dist_y)/(r_dist**2) @@ -607,7 +617,7 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, P_ia_times_u_y=P_ia_times_u_y+ (p_ia_coef* ((P_12*u2) +(P_22*v2))) !print *, 'Paralel: ',berg%iceberg_num, p_ia_coef, IA_x, P_ia_11, P_ia_21,P_ia_12, P_ia_22 - !Normal velocities + ! Normal velocities P_11=1-P_11 ; P_12=-P_12 ; P_21= -P_21 ; P_22=1-P_22 !p_ia_coef=tangental_damping_coef*(T_min/T1)*(A_min/A1) p_ia_coef=tangental_damping_coef*(M_min/M1) @@ -630,13 +640,14 @@ subroutine calculate_force(bergs, berg, other_berg, IA_x, IA_y, u0, v0, u1, v1, end subroutine calculate_force + !> Calculates area of overlap between two circular bergs subroutine overlap_area(R1, R2, d, A, trapped) ! Arguments - real, intent(in) :: R1 - real, intent(in) :: R2 - real, intent(in) :: d - real, intent(out) :: A - real, intent(out) :: Trapped + real, intent(in) :: R1 !< Radius of berg 1 (m) + real, intent(in) :: R2 !< Radius of berg 2 (m) + real, intent(in) :: d !< Separation of berg centers (m) + real, intent(out) :: A !< Overlap area (m2) + real, intent(out) :: Trapped !< =1. if one berg is completely inside the other, =0. otherwise ! Local variables real :: R1_sq, R2_sq, d_sq @@ -648,7 +659,7 @@ subroutine overlap_area(R1, R2, d, A, trapped) if (d>0.) then if (d<(R1+R2)) then if (d>abs(R1-R2)) then - A= (R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) + A=(R1_sq*acos((d_sq+R1_sq-R2_sq)/(2.*d*R1))) + (R2_sq*acos((d_sq+R2_sq-R1_sq)/(2.*d*R2))) - (0.5*sqrt((-d+R1+R2)*(d+R1-R2)*(d-R1+R2)*(d+R1+R2))) else A=min(pi*R1_sq,pi*R2_sq) Trapped=1. @@ -657,7 +668,7 @@ subroutine overlap_area(R1, R2, d, A, trapped) A=0. endif else - A=0. ! No area of perfectly overlapping bergs (ie: a berg interacting with itself) + A=0. ! No area of perfectly overlapping bergs (ie: a berg interacting with itself) endif end subroutine overlap_area @@ -763,7 +774,7 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a ! Wave radiation uwave=ua-uo; vwave=va-vo ! Use wind speed rel. to ocean for wave model (aja)? - wmod=uwave*uwave+vwave*vwave ! The wave amplitude and length depend on the wind speed relative to the ocean current; + wmod=uwave*uwave+vwave*vwave ! The wave amplitude and length depend on the wind speed relative to the ocean current ! actually wmod is wmod**2 here. ampl=0.5*0.02025*wmod ! This is "a", the wave amplitude Lwavelength=0.32*wmod ! Surface wave length fitted to data in table at @@ -1087,19 +1098,21 @@ subroutine accel(bergs, berg, i, j, xi, yj, lat, uvel, vvel, uvel0, vvel0, dt, a !Used for testing the ocean response to fixed iceberg motion. if (bergs%override_iceberg_velocities) then - ax = 0.0; ay = 0.0; - axn = 0.0; ayn = 0.0; - bxn = 0.0; byn = 0.0; + ax = 0.0; ay = 0.0 + axn = 0.0; ayn = 0.0 + bxn = 0.0; byn = 0.0 endif contains - subroutine dump_locfld(grd,i0,j0,A,lbl) + !> Print 3x3 cells from 2d array A + subroutine dump_locfld(grd, i0, j0, A, lbl) ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i0, j0 - real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A - character(len=*) :: lbl + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + integer, intent(in) :: i0 !< i-index of center of 3x3 patch to print + integer, intent(in) :: j0 !< j-index of center of 3x3 patch to print + real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A !< Field to print + character(len=*) :: lbl !< Label to add to messages ! Local variables integer :: i, j, ii, jj real :: B(-1:1,-1:1), fac @@ -1118,12 +1131,14 @@ subroutine dump_locfld(grd,i0,j0,A,lbl) enddo end subroutine dump_locfld - subroutine dump_locvel(grd,i0,j0,A,lbl) + !> Print 2x2 cells from 2d array A + subroutine dump_locvel(grd, i0, j0, A, lbl) ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i0, j0 - real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A - character(len=*) :: lbl + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + integer, intent(in) :: i0 !< i-index of NE-cell of 2x2 patch to print + integer, intent(in) :: j0 !< j-index of NE-cell of 2x2 patch to print + real, dimension(grd%isd:grd%ied,grd%jsd:grd%jed), intent(in) :: A !< Field to print + character(len=*) :: lbl !< Label to add to messages ! Local variables integer :: i, j, ii, jj real :: B(-1:0,-1:0), fac @@ -1533,7 +1548,7 @@ subroutine create_gridded_icebergs_fields(bergs) endif end subroutine create_gridded_icebergs_fields -!> Calculates basl melt for given thermodynamic properties +!> Calculates basal melt for given thermodynamic properties subroutine find_basal_melt(bergs, dvo, lat, salt, temp, Use_three_equation_model, thickness, basal_melt, iceberg_num) ! Arguments type(icebergs), pointer :: bergs !< Container for all types and memory @@ -1829,65 +1844,62 @@ subroutine find_basal_melt(bergs, dvo, lat, salt, temp, Use_three_equation_model contains + !> Calculates freezing point potential temperature of seawater using a linear relation + !! + !! This subroutine computes the freezing point potential temperature + !! (in deg C) from salinity (in psu), and pressure (in Pa) using a simple + !! linear expression, with coefficients passed in as arguments. + !! + !! Copied from subroutine calculate_TFreeze_linear_scalar (in MOM/equation_of_state) subroutine calculate_TFreeze(S, pres, T_Fr) - !Arguments - real, intent(in) :: S, pres - real, intent(out) :: T_Fr + ! Arguments + real, intent(in) :: S !< Salinity (1e-3) + real, intent(in) :: pres !< Presure (Pa) + real, intent(out) :: T_Fr !< Freezing point (C) + ! Local variables real, parameter :: dTFr_dp = -7.53E-08 !DTFREEZE_DP in MOM_input real, parameter :: dTFr_dS = -0.0573 !DTFREEZE_DS in MOM_input real, parameter :: TFr_S0_P0 =0.0832 !TFREEZE_S0_P0 in MOM_input - ! This subroutine computes the freezing point potential temparature - ! (in deg C) from salinity (in psu), and pressure (in Pa) using a simple - ! linear expression, with coefficients passed in as arguments. - ! Copied from subroutine calculate_TFreeze_linear_scalar (in MOM/equation_of_state) - ! - ! Arguments: S - salinity in PSU. - ! (in) pres - pressure in Pa. - ! (out) T_Fr - Freezing point potential temperature in deg C. - ! (in) TFr_S0_P0 - The freezing point at S=0, p=0, in deg C. - ! (in) dTFr_dS - The derivatives of freezing point with salinity, in - ! deg C PSU-1. - ! (in) dTFr_dp - The derivatives of freezing point with pressure, in - ! deg C Pa-1. + ! TFr_S0_P0 - The freezing point at S=0, p=0, in deg C. + ! dTFr_dS - The derivatives of freezing point with salinity, in deg C PSU-1. + ! dTFr_dp - The derivatives of freezing point with pressure, in deg C Pa-1. T_Fr = (TFr_S0_P0 + dTFr_dS*S) + dTFr_dp*pres end subroutine calculate_TFreeze + !> Calculates density of seawater using a linear equation of state + !! + !! This subroutine computes the density of sea water with a trivial + !! linear equation of state (in kg/m^3) from salinity (sal in psu), + !! potential temperature (T in deg C), and pressure in Pa. + !! + !! Copied from subroutine calculate_density_scalar_linear (in MOM/equation_of_state) subroutine calculate_density(T, S, pressure, rho, Rho_T0_S0, dRho_dT, dRho_dS) !Arguments - real, intent(in) :: T, S, pressure - real, intent(out) :: rho - real, intent(in) :: Rho_T0_S0, dRho_dT, dRho_dS - ! * This subroutine computes the density of sea water with a trivial * - ! * linear equation of state (in kg/m^3) from salinity (sal in psu), * - ! * potential temperature (T in deg C), and pressure in Pa. * - ! Copied from subroutine calculate_density_scalar_linear (in MOM/equation_of_state) - ! * * - ! * Arguments: T - potential temperature relative to the surface in C. * - ! * (in) S - salinity in PSU. * - ! * (in) pressure - pressure in Pa. * - ! * (out) rho - in situ density in kg m-3. * - ! * (in) start - the starting point in the arrays. * - ! * (in) npts - the number of values to calculate. * - ! * (in) Rho_T0_S0 - The density at T=0, S=0, in kg m-3. * - ! * (in) dRho_dT - The derivatives of density with temperature * - ! * (in) dRho_dS - and salinity, in kg m-3 C-1 and kg m-3 psu-1. * + real, intent(in) :: T !< Potential temperature (C) + real, intent(in) :: S !< Salinity (1e-3) + real, intent(in) :: pressure !< Pressure (Pa) + real, intent(out) :: rho !< In situ density (kg/3) + real, intent(in) :: Rho_T0_S0 !< Density at T=0, S=0 (kg/m3) + real, intent(in) :: dRho_dT !< Derivative of density w.r.t. potential temperature (kg/m3/C) + real, intent(in) :: dRho_dS !< Derivative of density w.r.t. salinity (1e3 kg/m3) rho = Rho_T0_S0 + dRho_dT*T + dRho_dS*S end subroutine calculate_density end subroutine find_basal_melt +!> Returns orientation of a berg determined by its bonds subroutine find_orientation_using_iceberg_bonds(grd, berg, orientation) -! Arguments -type(icebergs_gridded), pointer :: grd -type(iceberg), pointer :: berg -real, intent(inout) :: orientation -! Local variables -type(iceberg), pointer :: other_berg -type(bond), pointer :: current_bond -real :: angle, lat1,lat2,lon1,lon2,dlat,dlon -real :: r_dist_x, r_dist_y -real :: lat_ref, dx_dlon, dy_dlat -real :: theta, bond_count, Average_angle + ! Arguments + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + type(iceberg), pointer :: berg !< Berg for which orientation is needed + real, intent(inout) :: orientation !< Angle of orientation (radians) + ! Local variables + type(iceberg), pointer :: other_berg + type(bond), pointer :: current_bond + real :: angle, lat1,lat2,lon1,lon2,dlat,dlon + real :: r_dist_x, r_dist_y + real :: lat_ref, dx_dlon, dy_dlat + real :: theta, bond_count, Average_angle bond_count=0. Average_angle=0. @@ -1941,27 +1953,34 @@ subroutine find_orientation_using_iceberg_bonds(grd, berg, orientation) end subroutine find_orientation_using_iceberg_bonds +!> Spread mass of a berg around cells centered on i,j subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, scaling, Area, Tn) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(icebergs_gridded), pointer :: grd -type(iceberg), pointer :: berg -integer, intent(in) :: i, j -real, intent(in) :: x, y, Mberg, Mbits, scaling, Area -real, intent(in) :: Tn -! Local variables -real :: xL, xC, xR, yD, yC, yU, Mass, L -real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR -real :: S, H, origin_x, origin_y, x0, y0 -real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex -real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) -real :: I_fraction_used !Inverse of fraction used -real :: tol -real :: Dn, Hocean -real, parameter :: rho_seawater=1035. -integer :: stderrunit -logical :: debug -real :: orientation, Mass_berg + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(iceberg), pointer :: berg !< Berg whose mass is being considered + integer, intent(in) :: i !< i-index of cell contained center of berg + integer, intent(in) :: j !< j-index of cell contained center of berg + real, intent(in) :: x !< Longitude of berg (degree E) + real, intent(in) :: y !< Latitude of berg (degree N) + real, intent(in) :: Mberg !< Mass of berg (kg) + real, intent(in) :: Mbits !< Mass of bergy bits (kg) + real, intent(in) :: scaling !< Multiplier to scale mass (nondim) + real, intent(in) :: Area !< Area of berg (m2) + real, intent(in) :: Tn !< Thickness of berg (m) + ! Local variables + type(icebergs_gridded), pointer :: grd + real :: xL, xC, xR, yD, yC, yU, Mass, L + real :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR + real :: S, H, origin_x, origin_y, x0, y0 + real :: Area_Q1,Area_Q2 , Area_Q3,Area_Q4, Area_hex + real :: fraction_used !fraction of iceberg mass included (part of the mass near the boundary is discarded sometimes) + real :: I_fraction_used !Inverse of fraction used + real :: tol + real :: Dn, Hocean + real, parameter :: rho_seawater=1035. + integer :: stderrunit + logical :: debug + real :: orientation, Mass_berg ! Get the stderr unit number stderrunit = stderr() @@ -1970,7 +1989,7 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, grd=>bergs%grd Mass_berg=Mberg - !Trimming icebergs to account for grounded fraction. + ! Trimming icebergs to account for grounded fraction. if (bergs%grounding_fraction>0.) then Hocean=bergs%grounding_fraction*(grd%ocean_depth(i,j)+grd%ssh(i,j)) Dn=(bergs%rho_bergs/rho_seawater)*Tn ! re-calculate draught (keel depth) @@ -1986,9 +2005,9 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, yDxL=0. ; yDxC=0. ; yDxR=0. ; yCxL=0. ; yCxR=0. yUxL=0. ; yUxC=0. ; yUxR=0. ; yCxC=1. - if (.not. bergs%hexagonal_icebergs) then !Treat icebergs as rectangles of size L: (this is the default) + if (.not. bergs%hexagonal_icebergs) then ! Treat icebergs as rectangles of size L: (this is the default) - !L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. + ! L is the non dimensional length of the iceberg [ L=(Area of berg/ Area of grid cell)^0.5 ] or something like that. if (grd%area(i,j)>0) then L=min( sqrt(Area / grd%area(i,j)),1.0) else @@ -1996,7 +2015,7 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, endif if (bergs%use_old_spreading) then - !Old version before icebergs were given size L + ! Old version before icebergs were given size L xL=min(0.5, max(0., 0.5-x)) xR=min(0.5, max(0., x-0.5)) xC=max(0., 1.-(xL+xR)) @@ -2022,23 +2041,23 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, yUxR=yU*xR*grd%msk(i+1,j+1) yCxC=1.-( ((yDxL+yUxR)+(yDxR+yUxL)) + ((yCxL+yCxR)+(yDxC+yUxC)) ) - fraction_used=1. !rectangular bergs do share mass with boundaries (all mass is included in cells) + fraction_used=1. ! rectangular bergs do share mass with boundaries (all mass is included in cells) - else !Spread mass as if elements area hexagonal + else ! Spread mass as if elements area hexagonal orientation=bergs%initial_orientation if ((bergs%iceberg_bonds_on) .and. (bergs%rotate_icebergs_for_mass_spreading)) call find_orientation_using_iceberg_bonds(grd,berg,orientation) if (grd%area(i,j)>0) then - H = min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ; !Non dimensionalize element length by grid area. (This gives the non-dim Apothen of the hexagon) + H=min(( (sqrt(Area/(2.*sqrt(3.))) / sqrt(grd%area(i,j)))),1.) ! Non-dimensionalize element length by grid area. (This gives the non-dim Apothem of the hexagon) else - H= (sqrt(3.)/2)*(0.49) !Largest allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) + H=(sqrt(3.)/2)*(0.49) ! Largest allowable H, since this makes S=0.49, and S has to be less than 0.5 (Not sure what the implications of this are) endif S=(2/sqrt(3.))*H !Side of the hexagon if (S>0.5) then - !The width of an iceberg should not be greater than half the gridcell, or else it can spread over 3 cells (i.e. S must be less than 0.5 nondimensionally) - !print 'Elements must be smaller than a whole gridcell', 'i.e.: S= ' , S , '>=0.5' + ! The width of an iceberg should not be greater than half the grid cell, or else it can spread over 3 cells (i.e. S must be less than 0.5 non-dimensionally) + !print 'Elements must be smaller than a whole grid cell', 'i.e.: S= ' , S , '>=0.5' call error_mesg('diamonds, hexagonal spreading', 'Diameter of the iceberg is larger than a grid cell. Use smaller icebergs', WARNING) endif @@ -2125,15 +2144,25 @@ subroutine spread_mass_across_ocean_cells(bergs, berg, i, j, x, y, Mberg, Mbits, end subroutine spread_mass_across_ocean_cells -subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & - yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR,I_fraction_used) +!> Distribute a quantity among nine cells on a grid centered at cell i,j +subroutine spread_variable_across_cells(grd, variable_on_ocean, Var, i, j, & + yDxL, yDxC,yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR, I_fraction_used) ! Arguments - type(icebergs_gridded), pointer, intent(in) :: grd - real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean - real, intent(in) :: Var !Variable to be spread accross cell - real, intent(in) :: yDxL, yDxC, yDxR, yCxL, yCxC, yCxR, yUxL, yUxC, yUxR !Weights - real, intent(in) :: I_fraction_used !Amount of iceberg used (inverse) - integer, intent(in) :: i, j + type(icebergs_gridded), pointer, intent(in) :: grd !< Container for gridded fields + real, dimension(grd%isd:grd%ied, grd%jsd:grd%jed, 9), intent(inout) :: variable_on_ocean !< Gridded field to augment + real, intent(in) :: Var !< Variable to be spread accross cell + real, intent(in) :: yDxL !< Weight for the cell at i-1,j-1 + real, intent(in) :: yDxC !< Weight for the cell at i-1,j + real, intent(in) :: yDxR !< Weight for the cell at i-1,j+1 + real, intent(in) :: yCxL !< Weight for the cell at i,j-1 + real, intent(in) :: yCxC !< Weight for the cell at i,j + real, intent(in) :: yCxR !< Weight for the cell at i,j-1 + real, intent(in) :: yUxL !< Weight for the cell at i+1,j-1 + real, intent(in) :: yUxC !< Weight for the cell at i+1,j + real, intent(in) :: yUxR !< Weight for the cell at i+1,j+1 + real, intent(in) :: I_fraction_used !< Amount of iceberg used (inverse) + integer, intent(in) :: i !< i-index of cell containing center of berg + integer, intent(in) :: j !< j-index of cell containing center of berg !Spreading the iceberg mass onto the ocean variable_on_ocean(i,j,1)=variable_on_ocean(i,j,1)+(yDxL*Var*I_fraction_used) @@ -2148,23 +2177,37 @@ subroutine spread_variable_across_cells(grd, variable_on_ocean, Var,i,j, & end subroutine spread_variable_across_cells +!> Returns area of a triangle real function Area_of_triangle(Ax, Ay, Bx, By, Cx, Cy) -! Arguments -real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy - Area_of_triangle = abs( 0.5*((Ax*(By-Cy))+(Bx*(Cy-Ay))+(Cx*(Ay-By))) ); + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: Cx !< x-position of corner C + real, intent(in) :: Cy !< y-position of corner C + Area_of_triangle = abs( 0.5*((Ax*(By-Cy))+(Bx*(Cy-Ay))+(Cx*(Ay-By))) ) end function Area_of_triangle +!> Returns x rounded of to sig_fig +!! \todo What the heck is this for? -AJA real function roundoff(x,sig_fig) -! Arguments -real, intent(in) :: x -integer, intent(in) :: sig_fig + ! Arguments + real, intent(in) :: x !< A quantity with 15 significant figures of useful information + integer, intent(in) :: sig_fig !< Number of significant figures to keep !roundoff=round(x*(10**(sig_fig)) - roundoff=(FLOAT (INT(x * (10.**sig_fig) + 0.5)) / (10.**sig_fig)) + roundoff=(FLOAT(INT(x * (10.**sig_fig) + 0.5)) / (10.**sig_fig)) end function roundoff +!> Returns true of a point is in or on the rectangle with opposite corners A and B logical function point_in_interval(Ax, Ay, Bx, By, px, py) -! Arguments -real, intent(in) :: Ax,Ay,Bx,By,px,py + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: px !< x-position of point + real, intent(in) :: py !< y-position of point point_in_interval=.False. if ((px <= max(Ax,Bx)) .and. (px >= min(Ax,Bx))) then if ((py <= max(Ay,By)) .and. (py >= min(Ay,By))) then @@ -2173,17 +2216,24 @@ logical function point_in_interval(Ax, Ay, Bx, By, px, py) endif end function point_in_interval -logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) -! Arguments -real, intent(in) :: Ax,Ay,Bx,By,qx,qy -real :: tol, dxc,dyc,dxl,dyl,cross - !tol=1.e-12; - tol=0.0; - dxc = qx - Ax; - dyc = qy - Ay; - dxl = Bx - Ax; - dyl = By - Ay; - cross = dxc * dyl - dyc * dxl; +!> Returns true if point q is on a line through points A and B +logical function point_is_on_the_line(Ax, Ay, Bx, By, qx, qy) + ! Arguments + real, intent(in) :: Ax !< x-position of point A + real, intent(in) :: Ay !< y-position of point A + real, intent(in) :: Bx !< x-position of point B + real, intent(in) :: By !< y-position of point B + real, intent(in) :: qx !< x-position of point q + real, intent(in) :: qy !< y-position of point q + ! Local variables + real :: tol, dxc,dyc,dxl,dyl,cross + !tol=1.e-12 + tol=0.0 + dxc = qx - Ax + dyc = qy - Ay + dxl = Bx - Ax + dyl = By - Ay + cross = dxc * dyl - dyc * dxl if (abs(cross)<=tol) then point_is_on_the_line=.True. else @@ -2191,23 +2241,32 @@ logical function point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) endif end function point_is_on_the_line -logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy) -!This function decides whether a point (qx,qy) is inside the triangle ABC. -!There is also the option to include the boundary of the triangle. -! Arguments -real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy,qx,qy -! Local variables -real :: l0,l1,l2,p0,p1,p2 -real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 +!> Returns True if a point q is inside a triangle ABC +!! +!! This function decides whether a point (qx,qy) is inside the triangle ABC. +!! There is also the option to include the boundary of the triangle. +logical function point_in_triangle(Ax, Ay, Bx, By, Cx, Cy, qx, qy) + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: Cx !< x-position of corner C + real, intent(in) :: Cy !< y-position of corner C + real, intent(in) :: qx !< x-position of point q + real, intent(in) :: qy !< y-position of point q + ! Local variables + real :: l0,l1,l2,p0,p1,p2 + real :: v0x,v1x,v2x,v0y,v1y,v2y,dot00,dot01,dot02,dot11,dot12 point_in_triangle = .False. - if ((Ax==qx .and. Ay==qy) .or. (Bx==qx .and. By==qy) .or. (Cx==qx .and. Cy==qy)) then !Exclude the pathelogical case + if ((Ax==qx .and. Ay==qy) .or. (Bx==qx .and. By==qy) .or. (Cx==qx .and. Cy==qy)) then ! Exclude the pathelogical case point_in_triangle = .False. else if (((point_is_on_the_line(Ax,Ay,Bx,By,qx,qy) .or. (point_is_on_the_line(Ax,Ay,Cx,Cy,qx,qy))) .or. (point_is_on_the_line(Bx,By,Cx,Cy,qx,qy)))) then point_in_triangle = .False. else - !Compute point in triangle using Barycentric coordinates (the same as sum_sign_dot_prod routines) + ! Compute point in triangle using Barycentric coordinates (the same as sum_sign_dot_prod routines) l0=(qx-Ax)*(By-Ay)-(qy-Ay)*(Bx-Ax) l1=(qx-Bx)*(Cy-By)-(qy-By)*(Cx-Bx) l2=(qx-Cx)*(Ay-Cy)-(qy-Cy)*(Ax-Cx) @@ -2221,56 +2280,74 @@ logical function point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,qx,qy) endif end function point_in_triangle -subroutine Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axis1,Area_positive, Area_negative) !You should change this name a little, so that it not similar the other routine. -!This function calculates the area of a triangle on opposited sides of an axis when the triangle is split with two points on one side, and one point on the other. -!In this fuction, A is the point on one side of the axis, and B,C are on the opposite sides -! Arguments -real , intent(in) :: Ax,Ay,Bx,By,Cx,Cy -character , intent(in) :: axis1 -real, intent(out) :: Area_positive, Area_negative -real :: pABx, pABy, pACx, pACy, A0 -real :: A_half_triangle, A_triangle +!> Calculates the two areas of a triangle divided by an axis line +!! +!! This function calculates the area of a triangle on opposite sides of an axis when the +!! triangle is split with two points on one side, and one point on the other. +!! In this function, A is the point on one side of the axis, and B,C are on the opposite sides. +!! \todo You should change this name a little, so that it not similar the other routine. +subroutine Area_of_triangle_across_axes(Ax, Ay, Bx, By, Cx, Cy, axis1, Area_positive, Area_negative) + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: Cx !< x-position of corner C + real, intent(in) :: Cy !< y-position of corner C + character, intent(in) :: axis1 !< Either 'x' or 'y' + real, intent(out) :: Area_positive !< Area on negative side of axis line + real, intent(out) :: Area_negative !< Area on positive side of axis line + ! Local variables + real :: pABx, pABy, pACx, pACy, A0 + real :: A_half_triangle, A_triangle - A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); + A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) - call intercept_of_a_line(Ax,Ay,Bx,By,axis1,pABx, pABy); - call intercept_of_a_line(Ax,Ay,Cx,Cy,axis1,pACx, pACy); + call intercept_of_a_line(Ax,Ay,Bx,By,axis1,pABx, pABy) + call intercept_of_a_line(Ax,Ay,Cx,Cy,axis1,pACx, pACy) if (axis1=='x') A0=Ay; !Value used for if statements (deciding up/down vs left/right) if (axis1=='y') A0=Ax; !Value used for if statements (deciding up/down vs left/right) - A_half_triangle=Area_of_triangle(Ax,Ay,pABx,pABy,pACx,pACy); + A_half_triangle=Area_of_triangle(Ax,Ay,pABx,pABy,pACx,pACy) if (A0>=0.) then - Area_positive= A_half_triangle; + Area_positive= A_half_triangle Area_negative= A_triangle-A_half_triangle else - Area_positive= A_triangle-A_half_triangle; - Area_negative= A_half_triangle; + Area_positive= A_triangle-A_half_triangle + Area_negative= A_half_triangle endif end subroutine Area_of_triangle_across_axes -subroutine intercept_of_a_line(Ax,Ay,Bx,By,axes1,x0,y0) -!This routine returns the position (x0,y0) at which a line AB intercepts the x or y axis -!The value No_intercept_val is returned when the line does not intercept the axis -!Arguments -real, intent(in) :: Ax,Ay,Bx,By -character, intent(in) ::axes1 -real, intent(out) :: x0,y0 -real :: No_intercept_val !Huge value used to make sure that the intercept is outside the triange in the parralel case. +!> Returns the axis intercept of a line AB +!! +!! This routine returns the position (x0,y0) at which a line AB intercepts the x or y axis. +!! The value No_intercept_val is returned when the line does not intercept the axis. +subroutine intercept_of_a_line(Ax, Ay, Bx, By, axes1, x0, y0) + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + character, intent(in) :: axes1 !< Either 'x' or 'y' + real, intent(out) :: x0 !< x-position of intercept + real, intent(out) :: y0 !< y-position of intercept + ! Local variables + real :: No_intercept_val ! Huge value used to make sure that the intercept is outside the triangle in the parallel case. - No_intercept_val=100000000000.; !Huge value used to make sure that the intercept is outside the triange in the parralel case. + No_intercept_val=100000000000. ! Huge value used to make sure that the intercept is outside the triangle in the parallel case. x0=No_intercept_val y0=No_intercept_val - if (axes1=='x') then !x intercept + if (axes1=='x') then ! x intercept if (Ay.ne.By) then x0=Ax -(((Ax-Bx)/(Ay-By))*Ay) y0=0. endif endif - if (axes1=='y') then !y intercept + if (axes1=='y') then ! y intercept if (Ax.ne.Bx) then x0=0. y0=-(((Ay-By)/(Ax-Bx))*Ax)+Ay @@ -2278,71 +2355,80 @@ subroutine intercept_of_a_line(Ax,Ay,Bx,By,axes1,x0,y0) endif end subroutine intercept_of_a_line -subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative) -!This routine gives you the area of a triangle on opposite sides of the axis specified. -!It also takes care of the special case where the triangle is totally on one side -!This routine calls Area_of_triangle_across_axes to calculate the areas when the triangles are split. -!Arguments -real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy -character, intent(in) ::axes1 -real, intent(out) :: Area_positive, Area_negative -real :: A0,B0,C0 -real A_triangle - - if (axes1=='x') then !Use the y-coordinates for if statements to see which side of the line you are on +!> Calculates the area of a triangle on either side of an axis, if any. +!! +!! This routine gives you the area of a triangle on opposite sides of the axis specified. +!! It also takes care of the special case where the triangle is totally on one side. +!! This routine calls Area_of_triangle_across_axes to calculate the areas when the triangles are split. +subroutine divding_triangle_across_axes(Ax, Ay, Bx, By, Cx, Cy, axes1, Area_positive, Area_negative) + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: Cx !< x-position of corner C + real, intent(in) :: Cy !< y-position of corner C + character, intent(in) :: axes1 !< Either 'x' or 'y' + real, intent(out) :: Area_positive !< Area on negative side of axis line + real, intent(out) :: Area_negative !< Area on positive side of axis line + ! Local variables + real :: A0,B0,C0 + real A_triangle + + if (axes1=='x') then ! Use the y-coordinates for if statements to see which side of the line you are on A0=Ay B0=By C0=Cy endif - if (axes1=='y') then !Use the y-coordinates for if statements to see which side of the line you are on + if (axes1=='y') then ! Use the y-coordinates for if statements to see which side of the line you are on A0=Ax B0=Bx C0=Cx endif - A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); - if ((B0*C0)>0.) then !B and C are on the same side (and non-zero) - if ((A0*B0).ge.0.) then !all three on the the same side (if it equals zero, then A0=0 and the otehrs are not) + A_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) + if ((B0*C0)>0.) then ! B and C are on the same side (and non-zero) + if ((A0*B0).ge.0.) then ! all three on the same side (if it equals zero, then A0=0 and the others are not) if ((A0>0.) .or. ((A0==0.) .and. (B0>0.))) then - Area_positive= A_triangle; - Area_negative= 0.; + Area_positive= A_triangle + Area_negative= 0. else - Area_positive= 0.; - Area_negative= A_triangle; + Area_positive= 0. + Area_negative= A_triangle endif else !A is on the opposite side to B and C - call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative); + call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative) endif elseif ((B0*C0)<0.) then !B and C are on the opposite sides if ((A0*B0).ge. 0.) then !C is all alone - call Area_of_triangle_across_axes(Cx,Cy,Bx,By,Ax,Ay,axes1,Area_positive, Area_negative); + call Area_of_triangle_across_axes(Cx,Cy,Bx,By,Ax,Ay,axes1,Area_positive, Area_negative) else !B is all alone - call Area_of_triangle_across_axes(Bx,By,Cx,Cy,Ax,Ay,axes1,Area_positive, Area_negative); + call Area_of_triangle_across_axes(Bx,By,Cx,Cy,Ax,Ay,axes1,Area_positive, Area_negative) endif else !This is the case when either B or C is equal to zero (or both), A0 could be zero too. if (((A0.eq.0.) .and. (B0.eq.0.)) .and. (C0.eq.0.)) then - Area_positive= 0.; - Area_negative= 0.; + Area_positive= 0. + Area_negative= 0. elseif ((A0*B0<0.) .or. (A0*C0<0.)) then !A, B are on opposite sides, and C is zero. OR A, C are on opposite sides, and B is zero. - call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative); + call Area_of_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, Area_negative) elseif (((A0*B0>0.) .or. (A0*C0>0.)) .or. (((abs(A0)>0.) .and. (B0==0.)) .and. (C0==0.))) then if (A0>0.) then - Area_positive= A_triangle; - Area_negative= 0.; + Area_positive= A_triangle + Area_negative= 0. else - Area_positive= 0.; - Area_negative= A_triangle; + Area_positive= 0. + Area_negative= A_triangle endif elseif (A0.eq. 0.) then !(one of B,C is zero too) if ((B0>0.) .or. (C0>0.)) then - Area_positive= A_triangle; - Area_negative= 0.; + Area_positive= A_triangle + Area_negative= 0. elseif ((B0<0.) .or. (C0<0.)) then - Area_positive= 0.; - Area_negative= A_triangle; + Area_positive= 0. + Area_negative= A_triangle else call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle dividing routine', FATAL) endif @@ -2352,38 +2438,49 @@ subroutine divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,axes1,Area_positive, A endif end subroutine divding_triangle_across_axes - -subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4) -!This routine takes a triangle, and finds the intersection with the four quadrants -!Arguments -real, intent(in) :: Ax,Ay,Bx,By,Cx,Cy -real, intent(out) :: Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4 -real :: Area_Upper, Area_Lower, Area_Right, Area_Left -real :: px, py , qx , qy -real :: Area_key_quadrant,Error -real :: tol -integer :: Key_quadrant -integer ::sig_fig -integer :: stderrunit +!> Areas of a triangle divided into quadrants +!! +!! This routine takes a triangle, and finds the intersection with the four quadrants. +subroutine Triangle_divided_into_four_quadrants(Ax, Ay, Bx, By, Cx, Cy, Area_triangle, Area_Q1, Area_Q2 ,Area_Q3 ,Area_Q4) + ! Arguments + real, intent(in) :: Ax !< x-position of corner A + real, intent(in) :: Ay !< y-position of corner A + real, intent(in) :: Bx !< x-position of corner B + real, intent(in) :: By !< y-position of corner B + real, intent(in) :: Cx !< x-position of corner C + real, intent(in) :: Cy !< y-position of corner C + real, intent(out) :: Area_triangle !< Are of triangle + real, intent(out) :: Area_Q1 !< Are in quadrant 1 + real, intent(out) :: Area_Q2 !< Are in quadrant 2 + real, intent(out) :: Area_Q3 !< Are in quadrant 2 + real, intent(out) :: Area_Q4 !< Are in quadrant 4 + ! Local variables + real :: Area_Upper, Area_Lower, Area_Right, Area_Left + real :: px, py , qx , qy + real :: Area_key_quadrant,Error + real :: tol + integer :: Key_quadrant + integer ::sig_fig + integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() tol=1.e-10 - Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy); + Area_triangle=Area_of_triangle(Ax,Ay,Bx,By,Cx,Cy) - !Calculating area across axes - call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'x',Area_Upper ,Area_Lower); - call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'y',Area_Right ,Area_Left); + ! Calculating area across axes + call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'x',Area_Upper ,Area_Lower) + call divding_triangle_across_axes(Ax,Ay,Bx,By,Cx,Cy,'y',Area_Right ,Area_Left) - !Decide if the origin is in the triangle. If so, then you have to divide the area 4 ways - !This is done by finding a quadrant where the intersection between the triangle and quadrant forms a new triangle - !(This occurs when on of the sides of the triangle intersects both the x and y axis) + ! Decide if the origin is in the triangle. If so, then you have to divide the area 4 ways + ! This is done by finding a quadrant where the intersection between the triangle and quadrant forms a new triangle + ! (This occurs when on of the sides of the triangle intersects both the x and y axis) if (point_in_triangle(Ax,Ay,Bx,By,Cx,Cy,0.,0.)) then - !Find a line in the triangle that cuts both axes in/on the trianlge + ! Find a line in the triangle that cuts both axes in/on the triangle call intercept_of_a_line(Ax,Ay,Bx,By,'x',px,py); !x_intercept call intercept_of_a_line(Ax,Ay,Bx,By,'y',qx,qy); !y_intercept - !Note that the 1. here means that we include points on the boundary of the triange. + ! Note that the 1. here means that we include points on the boundary of the triangle. if (.not.((point_in_interval(Ax,Ay,Bx,By,px,py)) .and. (point_in_interval(Ax,Ay,Bx,By,qx,qy)))) then call intercept_of_a_line(Ax,Ay,Cx,Cy,'x',px,py); !x_intercept call intercept_of_a_line(Ax,Ay,Cx,Cy,'y',qx,qy); !y_intercept @@ -2391,7 +2488,7 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, call intercept_of_a_line(Bx,By,Cx,Cy,'x',px,py); !x_intercept call intercept_of_a_line(Bx,By,Cx,Cy,'y',qx,qy); !y_intercept if (.not.((point_in_interval(Bx,By,Cx,Cy,px,py)) .and. (point_in_interval(Bx,By,Cx,Cy,qx,qy)))) then - !You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. + ! You should not get here, but there might be some bugs in the code to do with points exactly falling on axes. !if (mpp_pe().eq.12) then write(stderrunit,*) 'diamonds,corners', Ax,Ay,Bx,By,Cx,Cy !endif @@ -2400,14 +2497,14 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, endif endif - !Assigning quadrants. Key_quadrant is the quadrant with the baby triangle in it. + ! Assigning quadrants. Key_quadrant is the quadrant with the baby triangle in it. Area_key_quadrant=Area_of_triangle(px,py,qx,qy,0.,0.) if ((px.ge. 0.) .and. (qy.ge. 0.)) then !First quadrant - Key_quadrant=1; + Key_quadrant=1 elseif ((px.lt.0.) .and. (qy.ge. 0.)) then !Second quadrant Key_quadrant=2 elseif ((px.lt. 0.) .and. (qy.lt. 0.)) then !Third quadrant - Key_quadrant=3; + Key_quadrant=3 elseif ((px.ge. 0.) .and. (qy.lt. 0.)) then !Forth quadrant Key_quadrant=4 else ! @@ -2415,54 +2512,53 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, write(stderrunit,*) 'diamonds, Triangle, px,qy', px,qy endif - else !At least one quadrant is empty, and this can be used to find the areas in the other quadrant. Assigning quadrants. Key_quadrant is the empty quadrant. - Area_key_quadrant=0; + else ! At least one quadrant is empty, and this can be used to find the areas in the other quadrant. Assigning quadrants. Key_quadrant is the empty quadrant. + Area_key_quadrant=0 if ( (.not. ((((Ax>0.) .and. (Ay>0.)) .or. ((Bx>0.) .and. (By> 0.))) .or. ((Cx>0.) .and. (Cy> 0.)))) .and. ((Area_Upper+Area_Right).le.Area_triangle) ) then - !No points land in this quadrant and triangle does not cross the quadrant - Key_quadrant=1; + ! No points land in this quadrant and triangle does not cross the quadrant + Key_quadrant=1 elseif ( (.not. ((((Ax<0.) .and. (Ay>0)) .or. ((Bx<0.) .and. (By>0.))) .or. ((Cx<0.) .and. (Cy>0.)))) .and. ((Area_Upper+Area_Left).le. Area_triangle) ) then Key_quadrant=2 elseif ( (.not. ((((Ax<0.) .and. (Ay<0.)) .or. ((Bx<0.) .and. (By< 0.))) .or. ((Cx<0.) .and. (Cy< 0.)))) .and. ((Area_Lower+Area_Left) .le.Area_triangle) ) then - Key_quadrant=3; + Key_quadrant=3 else Key_quadrant=4 endif endif - - !Assign values to quadrants + ! Assign values to quadrants if (Key_quadrant .eq. 1) then - Area_Q1=Area_key_quadrant; - Area_Q2=Area_Upper-Area_Q1; - Area_Q4=Area_Right-Area_Q1; - !Area_Q3=Area_Left-Area_Q2; !These lines have been changes so that the sum of the 4 quadrants exactly matches the triangle area. - Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); + Area_Q1=Area_key_quadrant + Area_Q2=Area_Upper-Area_Q1 + Area_Q4=Area_Right-Area_Q1 + !Area_Q3=Area_Left-Area_Q2 ! These lines have been changes so that the sum of the 4 quadrants exactly matches the triangle area. + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4) elseif (Key_quadrant .eq. 2) then - Area_Q2=Area_key_quadrant; - Area_Q1=Area_Upper-Area_Q2; - Area_Q4=Area_Right-Area_Q1; - !Area_Q3=Area_Left-Area_Q2; - Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); + Area_Q2=Area_key_quadrant + Area_Q1=Area_Upper-Area_Q2 + Area_Q4=Area_Right-Area_Q1 + !Area_Q3=Area_Left-Area_Q2 + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4) elseif (Key_quadrant==3) then - Area_Q3=Area_key_quadrant; - Area_Q2=Area_Left-Area_Q3; - Area_Q1=Area_Upper-Area_Q2; - !Area_Q4=Area_Right-Area_Q1; - Area_Q4=Area_triangle-(Area_Q1+Area_Q2+Area_Q3); + Area_Q3=Area_key_quadrant + Area_Q2=Area_Left-Area_Q3 + Area_Q1=Area_Upper-Area_Q2 + !Area_Q4=Area_Right-Area_Q1 + Area_Q4=Area_triangle-(Area_Q1+Area_Q2+Area_Q3) elseif (Key_quadrant==4) then - Area_Q4=Area_key_quadrant; - Area_Q1=Area_Right-Area_Q4; - Area_Q2=Area_Upper-Area_Q1; - !Area_Q3=Area_Left-Area_Q2; - Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4); + Area_Q4=Area_key_quadrant + Area_Q1=Area_Right-Area_Q4 + Area_Q2=Area_Upper-Area_Q1 + !Area_Q3=Area_Left-Area_Q2 + Area_Q3=Area_triangle-(Area_Q1+Area_Q2+Area_Q4) else call error_mesg('diamonds, iceberg_run', 'Logical error inside triangle into four quadrants. Should not get here.', FATAL) endif - Area_Q1=max(Area_Q1,0.); - Area_Q2=max(Area_Q2,0.); - Area_Q3=max(Area_Q3,0.); - Area_Q4=max(Area_Q4,0.); + Area_Q1=max(Area_Q1,0.) + Area_Q2=max(Area_Q2,0.) + Area_Q3=max(Area_Q3,0.) + Area_Q4=max(Area_Q4,0.) Error=abs(Area_Q1+Area_Q2+Area_Q3+Area_Q4-Area_triangle) @@ -2482,29 +2578,44 @@ subroutine Triangle_divided_into_four_quadrants(Ax,Ay,Bx,By,Cx,Cy,Area_triangle, end subroutine Triangle_divided_into_four_quadrants -subroutine rotate_and_translate(px,py,theta,x0,y0) - !This function takes a point px,py, and rotates it clockwise around the origin by theta degrees, and then translates by (x0,y0) +!> Rotates a point clockwise about origin and then translates by x0,y0 +subroutine rotate_and_translate(px, py, theta, x0, y0) ! Arguments - real, intent(in) :: x0,y0,theta - real, intent(inout) :: px,py + real, intent(in) :: x0 !< x-direction shift + real, intent(in) :: y0 !< y-direction shift + real, intent(in) :: theta !< Angle to rotate (degrees) + real, intent(inout) :: px !< x-coordinate of point + real, intent(inout) :: py !< y-coordinate of point + ! Local variables real :: px_temp,py_temp - !Rotation + ! Rotation px_temp = ( cos(theta*pi/180)*px) + (sin(theta*pi/180)*py) py_temp = (-sin(theta*pi/180)*px) + (cos(theta*pi/180)*py) - !Translation + ! Translation px= px_temp + x0 py= py_temp + y0 end subroutine rotate_and_translate -subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4) - !This subroutine divides a regular hexagon centered at x0,y0 with apothen H, and orientation theta into its intersection with the 4 quadrants - !Theta=0 assumes that the apothen points upwards. (also the rotation is not working yet) - !Script works by finding the corners of the 6 triangles, and then finding the intersection of each of these with each quadrant. - !Arguments - real, intent(in) :: x0,y0,H,theta - real, intent(out) :: Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4 +!> Areas of a hexagon divided into quadrants +!! +!! This subroutine divides a regular hexagon centered at x0,y0 with apothem H, and orientation theta into its intersection with the 4 quadrants. +!! Theta=0 assumes that the apothem points upwards. +!! Routine works by finding the corners of the 6 triangles, and then finding the intersection of each of these with each quadrant. +!! \todo (also the rotation is not working yet) +subroutine Hexagon_into_quadrants_using_triangles(x0, y0, H, theta, Area_hex ,Area_Q1, Area_Q2, Area_Q3, Area_Q4) + ! Arguments + real, intent(in) :: x0 !< x-coordinate of center of hexagon + real, intent(in) :: y0 !< y-coordinate of center of hexagon + real, intent(in) :: H !< Apothem (inner radius of hexagon) + real, intent(in) :: theta !< Orientation angle of hexagon + real, intent(out) :: Area_hex !< Area of hexagon + real, intent(out) :: Area_Q1 !< Are in quadrant 1 + real, intent(out) :: Area_Q2 !< Are in quadrant 2 + real, intent(out) :: Area_Q3 !< Are in quadrant 2 + real, intent(out) :: Area_Q4 !< Are in quadrant 4 + ! Local variables real :: C1x, C2x, C3x, C4x, C5x, C6x real :: C1y, C2y, C3y, C4y, C5y, C6y real :: T12_Area, T12_Q1, T12_Q2, T12_Q3, T12_Q4 @@ -2521,10 +2632,10 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q stderrunit = stderr() tol=1.e-10 - !Length of side of Hexagon + ! Length of side of Hexagon S=(2/sqrt(3.))*H - !Finding positions of corners + ! Finding positions of corners C1x=S ; C1y=0. !Corner 1 (right) C2x=H/sqrt(3.) ; C2y=H; !Corner 2 (top right) C3x=-H/sqrt(3.) ; C3y=H; !Corner 3 (top left) @@ -2532,7 +2643,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q C5x=-H/sqrt(3.) ; C5y=-H; !Corner 5 (bottom left) C6x=H/sqrt(3.) ; C6y=-H; !Corner 6 (bottom right) - !Finding positions of corners + ! Finding positions of corners call rotate_and_translate(C1x,C1y,theta,x0,y0) call rotate_and_translate(C2x,C2y,theta,x0,y0) call rotate_and_translate(C3x,C3y,theta,x0,y0) @@ -2540,7 +2651,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q call rotate_and_translate(C5x,C5y,theta,x0,y0) call rotate_and_translate(C6x,C6y,theta,x0,y0) - !Area of Hexagon is the sum of the triangles + ! Area of Hexagon is the sum of the triangles call Triangle_divided_into_four_quadrants(x0,y0,C1x,C1y,C2x,C2y,T12_Area,T12_Q1,T12_Q2,T12_Q3,T12_Q4); !Triangle 012 call Triangle_divided_into_four_quadrants(x0,y0,C2x,C2y,C3x,C3y,T23_Area,T23_Q1,T23_Q2,T23_Q3,T23_Q4); !Triangle 023 call Triangle_divided_into_four_quadrants(x0,y0,C3x,C3y,C4x,C4y,T34_Area,T34_Q1,T34_Q2,T34_Q3,T34_Q4); !Triangle 034 @@ -2548,17 +2659,17 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q call Triangle_divided_into_four_quadrants(x0,y0,C5x,C5y,C6x,C6y,T56_Area,T56_Q1,T56_Q2,T56_Q3,T56_Q4); !Triangle 056 call Triangle_divided_into_four_quadrants(x0,y0,C6x,C6y,C1x,C1y,T61_Area,T61_Q1,T61_Q2,T61_Q3,T61_Q4); !Triangle 061 - !Summing up the triangles - Area_hex=T12_Area+T23_Area+T34_Area+T45_Area+T56_Area+T61_Area; - Area_Q1=T12_Q1+T23_Q1+T34_Q1+T45_Q1+T56_Q1+T61_Q1; - Area_Q2=T12_Q2+T23_Q2+T34_Q2+T45_Q2+T56_Q2+T61_Q2; - Area_Q3=T12_Q3+T23_Q3+T34_Q3+T45_Q3+T56_Q3+T61_Q3; - Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4; + ! Summing up the triangles + Area_hex=T12_Area+T23_Area+T34_Area+T45_Area+T56_Area+T61_Area + Area_Q1=T12_Q1+T23_Q1+T34_Q1+T45_Q1+T56_Q1+T61_Q1 + Area_Q2=T12_Q2+T23_Q2+T34_Q2+T45_Q2+T56_Q2+T61_Q2 + Area_Q3=T12_Q3+T23_Q3+T34_Q3+T45_Q3+T56_Q3+T61_Q3 + Area_Q4=T12_Q4+T23_Q4+T34_Q4+T45_Q4+T56_Q4+T61_Q4 - Area_Q1=max(Area_Q1,0.); - Area_Q2=max(Area_Q2,0.); - Area_Q3=max(Area_Q3,0.); - Area_Q4=max(Area_Q4,0.); + Area_Q1=max(Area_Q1,0.) + Area_Q2=max(Area_Q2,0.) + Area_Q3=max(Area_Q3,0.) + Area_Q4=max(Area_Q4,0.) Error=Area_hex-(Area_Q1+Area_Q2+Area_Q3+Area_Q4) if ((abs(Error)>tol))then @@ -2584,7 +2695,7 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q endif endif - !Adjust Areas so that the error is zero by subtracting the error from the largest sector. + ! Adjust Areas so that the error is zero by subtracting the error from the largest sector. if (((Area_Q1>=Area_Q2) .and. (Area_Q1>=Area_Q3)) .and. (Area_Q1>=Area_Q4)) then Area_Q1=Area_Q1+Error elseif (((Area_Q2>=Area_Q1) .and. (Area_Q2>=Area_Q3)) .and. (Area_Q2>=Area_Q4)) then @@ -2604,20 +2715,33 @@ subroutine Hexagon_into_quadrants_using_triangles(x0,y0,H,theta,Area_hex ,Area_Q end subroutine Hexagon_into_quadrants_using_triangles subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi) -! Arguments -type(icebergs_gridded), pointer :: grd -integer, intent(in) :: i, j -real, intent(in) :: xi, yj -real, intent(out) :: uo, vo, ui, vi, ua, va, ssh_x, ssh_y, sst, sss, cn, hi -! Local variables -real :: cos_rot, sin_rot + ! Arguments + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + integer, intent(in) :: i !< i-index of cell in which to interpolate + integer, intent(in) :: j !< j-index of cell in which to interpolate + real, intent(in) :: xi !< Non-dimensional x-position within cell to interpolate to + real, intent(in) :: yj !< Non-dimensional y-position within cell to interpolate to + real, intent(out) :: uo !< Ocean zonal velocity at point xi,yj (m/s) + real, intent(out) :: vo !< Ocean meridional velocity at point xi,yj (m/s) + real, intent(out) :: ui !< Ice zonal velocity at point xi,yj (m/s) + real, intent(out) :: vi !< Ice meridional velocity at point xi,yj (m/s) + real, intent(out) :: ua !< Atmospheric zonal velocity at point xi,yj (m/s) + real, intent(out) :: va !< Atmospheric meridional velocity at point xi,yj (m/s) + real, intent(out) :: ssh_x !< Zonal slope of sea-surface height (nondim) + real, intent(out) :: ssh_y !< Meridional slope of sea-surface height (nondim) + real, intent(out) :: sst !< Sea-surface temperature (C) + real, intent(out) :: sss !< Sea-surface salinity (1e-3) + real, intent(out) :: cn !< Sea-ice concentration (nondim) + real, intent(out) :: hi !< Sea-ice thickness (m) + ! Local variables + real :: cos_rot, sin_rot #ifdef USE_OLD_SSH_GRADIENT -real :: dxm, dx0, dxp + real :: dxm, dx0, dxp #endif -real :: hxm, hxp -real, parameter :: ssh_coast=0.00 -integer :: stderrunit -integer :: ii, jj + real :: hxm, hxp + real, parameter :: ssh_coast=0.00 + integer :: stderrunit + integer :: ii, jj ! Get the stderr unit number stderrunit = stderr() @@ -2719,36 +2843,44 @@ subroutine interp_flds(grd, i, j, xi, yj, uo, vo, ui, vi, ua, va, ssh_x, ssh_y, call error_mesg('diamonds, interp fields', 'field interpaolations has NaNs', FATAL) endif + contains + !> Returns zonal slope of sea-surface height across the east face of cell i,j real function ddx_ssh(grd,i,j) - ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i, j - ! Local variables - real :: dxp,dx0 + ! Arguments + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + integer, intent(in) :: i !< i-index of cell + integer, intent(in) :: j !< j-index of cell + ! Local variables + real :: dxp,dx0 dxp=0.5*(grd%dx(i+1,j)+grd%dx(i+1,j-1)) dx0=0.5*(grd%dx(i,j)+grd%dx(i,j-1)) ddx_ssh=2.*(grd%ssh(i+1,j)-grd%ssh(i,j))/(dx0+dxp)*grd%msk(i+1,j)*grd%msk(i,j) end function ddx_ssh + !> Returns meridional slope of sea-surface height across the northern face of cell i,j real function ddy_ssh(grd,i,j) - ! Arguments - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i, j - ! Local variables - real :: dyp,dy0 + ! Arguments + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + integer, intent(in) :: i !< i-index of cell + integer, intent(in) :: j !< j-index of cell + ! Local variables + real :: dyp,dy0 dyp=0.5*(grd%dy(i,j+1)+grd%dy(i-1,j+1)) dy0=0.5*(grd%dy(i,j)+grd%dy(i-1,j)) ddy_ssh=2.*(grd%ssh(i,j+1)-grd%ssh(i,j))/(dy0+dyp)*grd%msk(i,j+1)*grd%msk(i,j) end function ddy_ssh + ! Rotates vector (u,v) using rotation matrix with elements cos_rot and sin_rot subroutine rotate(u, v, cos_rot, sin_rot) - ! Arguments - real, intent(inout) :: u, v - real, intent(in) :: cos_rot, sin_rot - ! Local variables - real :: u_old, v_old + ! Arguments + real, intent(inout) :: u !< x-component of vector + real, intent(inout) :: v !< y-component of vector + real, intent(in) :: cos_rot !< Cosine of rotation angle + real, intent(in) :: sin_rot !< Sine of rotation angle + ! Local variables + real :: u_old, v_old u_old=u v_old=v @@ -2759,16 +2891,16 @@ end subroutine rotate end subroutine interp_flds - +!> Calculates bergs%grd%mass_on_ocean subroutine calculate_mass_on_ocean(bergs, with_diagnostics) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(iceberg), pointer :: berg -type(icebergs_gridded), pointer :: grd -logical, intent(in) :: with_diagnostics -! Local variables -integer :: grdj, grdi -integer :: j, i + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + logical, intent(in) :: with_diagnostics + ! Local variables + type(iceberg), pointer :: berg + type(icebergs_gridded), pointer :: grd + integer :: grdj, grdi + integer :: j, i ! For convenience grd=>bergs%grd @@ -2801,66 +2933,82 @@ subroutine calculate_mass_on_ocean(bergs, with_diagnostics) contains - subroutine calculate_sum_over_bergs_diagnositcs(bergs,grd,berg,i,j) - ! Arguments - type(icebergs), pointer :: bergs !< Container for all types and memory - type(iceberg), pointer :: berg - type(icebergs_gridded), pointer :: grd - integer, intent(in) :: i, j - ! Local variables - real :: Abits, Lbits, Mbits - - !Virtual area diagnostic - if (grd%id_virtual_area>0) then - if (bergs%bergy_bit_erosion_fraction>0.) then - Lbits=min(berg%length,berg%width,berg%thickness,40.) ! assume bergy bits are smallest dimension or 40 meters - Abits=(berg%mass_of_bits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) - else - Abits=0.0 - endif - grd%virtual_area(i,j)=grd%virtual_area(i,j)+(berg%width*berg%length+Abits)*berg%mass_scaling ! m^2 - endif + !> Projects additional diagnostics of bergs on to the grid + subroutine calculate_sum_over_bergs_diagnositcs(bergs, grd, berg, i, j) + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(icebergs_gridded), pointer :: grd !< Container for gridded fields + type(iceberg), pointer :: berg !< An iceberg + integer, intent(in) :: i !< i-index of cell containing berg + integer, intent(in) :: j !< j-index of cell containing berg + ! Local variables + real :: Abits, Lbits, Mbits + + !Virtual area diagnostic + if (grd%id_virtual_area>0) then + if (bergs%bergy_bit_erosion_fraction>0.) then + Lbits=min(berg%length,berg%width,berg%thickness,40.) ! assume bergy bits are smallest dimension or 40 meters + Abits=(berg%mass_of_bits/bergs%rho_bergs)/Lbits ! Effective bottom area (assuming T=Lbits) + else + Abits=0.0 + endif + grd%virtual_area(i,j)=grd%virtual_area(i,j)+(berg%width*berg%length+Abits)*berg%mass_scaling ! m^2 + endif - !Mass diagnostic (also used in u_iceberg, v_iceberg - if ((grd%id_mass>0 ) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & - & grd%mass(i,j)=grd%mass(i,j)+berg%mass/grd%area(i,j)*berg%mass_scaling ! kg/m2 + !Mass diagnostic (also used in u_iceberg, v_iceberg + if ((grd%id_mass>0 ) .or. ((grd%id_u_iceberg>0) .or. (grd%id_v_iceberg>0))) & + & grd%mass(i,j)=grd%mass(i,j)+berg%mass/grd%area(i,j)*berg%mass_scaling ! kg/m2 - !Finding the average iceberg velocity in a grid cell (mass weighted) - if (grd%id_u_iceberg>0) & - grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%uvel) ! kg/m2 - if (grd%id_v_iceberg>0) & - grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%vvel) ! kg/m2 + !Finding the average iceberg velocity in a grid cell (mass weighted) + if (grd%id_u_iceberg>0) & + grd%u_iceberg(i,j)=grd%u_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%uvel) ! kg/m2 + if (grd%id_v_iceberg>0) & + grd%v_iceberg(i,j)=grd%v_iceberg(i,j)+((berg%mass/grd%area(i,j)*berg%mass_scaling)*berg%vvel) ! kg/m2 - !Mass of bergy bits - if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& - & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+berg%mass_of_bits/grd%area(i,j)*berg%mass_scaling ! kg/m2 - end subroutine calculate_sum_over_bergs_diagnositcs + !Mass of bergy bits + if (grd%id_bergy_mass>0 .or. bergs%add_weight_to_ocean)& + & grd%bergy_mass(i,j)=grd%bergy_mass(i,j)+berg%mass_of_bits/grd%area(i,j)*berg%mass_scaling ! kg/m2 + end subroutine calculate_sum_over_bergs_diagnositcs end subroutine calculate_mass_on_ocean +!> The main driver the steps updates icebergs subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, sst, calving_hflx, cn, hi, & stagger, stress_stagger, sss, mass_berg, ustar_berg, area_berg) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(time_type), intent(in) :: time -real, dimension(:,:), intent(inout) :: calving, calving_hflx -real, dimension(:,:), intent(in) :: uo, vo, ui, vi, tauxa, tauya, ssh, sst, cn, hi -integer, optional, intent(in) :: stagger, stress_stagger -real, dimension(:,:), optional, intent(in) :: sss -real, dimension(:,:), optional, pointer :: mass_berg, ustar_berg, area_berg -! Local variables -integer :: iyr, imon, iday, ihr, imin, isec, k -type(icebergs_gridded), pointer :: grd -logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality -real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area -real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel -integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off -real :: mask, max_SST -real, dimension(:,:), allocatable :: uC_tmp, vC_tmp, uA_tmp, vA_tmp -integer :: vel_stagger, str_stagger -real, dimension(:,:), allocatable :: iCount -integer :: nbonds -integer :: stderrunit + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + type(time_type), intent(in) :: time !< Model time + real, dimension(:,:), intent(inout) :: calving !< Calving (kg/s). This field is updated with melt by bergs. + real, dimension(:,:), intent(inout) :: calving_hflx !< Calving heat flux (W/m2) + real, dimension(:,:), intent(in) :: uo !< Ocean zonal velocity (m/s) + real, dimension(:,:), intent(in) :: vo !< Ocean meridional velocity (m/s) + real, dimension(:,:), intent(in) :: ui !< Ice zonal velocity (m/s) + real, dimension(:,:), intent(in) :: vi !< Ice meridional velocity (m/s) + real, dimension(:,:), intent(in) :: tauxa !< Zonal wind stress (Pa) + real, dimension(:,:), intent(in) :: tauya !< Meridional wind stress (Pa) + real, dimension(:,:), intent(in) :: ssh !< Effective sea-surface height (m) + real, dimension(:,:), intent(in) :: sst !< Sea-surface temperature (C or K) + real, dimension(:,:), intent(in) :: cn !< Sea-ice concentration (nondim) + real, dimension(:,:), intent(in) :: hi !< Sea-ice thickness (m) + integer, optional, intent(in) :: stagger + integer, optional, intent(in) :: stress_stagger + real, dimension(:,:), optional, intent(in) :: sss !< Sea-surface salinity (1e-3) + real, dimension(:,:), optional, pointer :: mass_berg !< Mass of bergs (kg) + real, dimension(:,:), optional, pointer :: ustar_berg !< Friction velocity on base of bergs (m/s) + real, dimension(:,:), optional, pointer :: area_berg !< Area of bergs (m2) + ! Local variables + integer :: iyr, imon, iday, ihr, imin, isec, k + type(icebergs_gridded), pointer :: grd + logical :: lerr, sample_traj, write_traj, lbudget, lverbose, check_bond_quality + real :: unused_calving, tmpsum, grdd_berg_mass, grdd_bergy_mass,grdd_spread_mass, grdd_spread_area + real :: grdd_u_iceberg, grdd_v_iceberg, grdd_ustar_iceberg, grdd_spread_uvel, grdd_spread_vvel + integer :: i, j, Iu, ju, iv, Jv, Iu_off, ju_off, iv_off, Jv_off + real :: mask, max_SST + real, dimension(:,:), allocatable :: uC_tmp, vC_tmp, uA_tmp, vA_tmp + integer :: vel_stagger, str_stagger + real, dimension(:,:), allocatable :: iCount + integer :: nbonds + integer :: stderrunit ! Get the stderr unit number stderrunit = stderr() @@ -3084,7 +3232,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, grd%hi(grd%isc-1:grd%iec+1,grd%jsc-1:grd%jec+1)=hi(:,:) call mpp_update_domains(grd%hi, grd%domain) - !Adding gridded salinity. + ! Adding gridded salinity. if (present(sss)) then grd%sss(grd%isc:grd%iec,grd%jsc:grd%jec)=sss(:,:) else @@ -3094,9 +3242,9 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, endif endif - !Make sure that gridded values agree with mask (to get ride of NaN values) + ! Make sure that gridded values agree with mask (to get ride of NaN values) do i=grd%isd,grd%ied ; do j=grd%jsd,grd%jed - !Initializing all gridded values to zero + ! Initializing all gridded values to zero if (grd%msk(i,j).lt. 0.5) then grd%ua(i,j) = 0.0 ; grd%va(i,j) = 0.0 grd%uo(i,j) = 0.0 ; grd%vo(i,j) = 0.0 @@ -3169,7 +3317,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, if (debug) call checksum_gridded(bergs%grd, 's/r run after exchange') call mpp_clock_end(bergs%clock_com) - !Caculate mass on ocean before thermodynamics, to use in melt rate calculation + ! Calculate mass on ocean before thermodynamics, to use in melt rate calculation if (bergs%find_melt_using_spread_mass) then call calculate_mass_on_ocean(bergs, with_diagnostics=.false.) grd%spread_mass_old(:,:)=0. @@ -3294,10 +3442,10 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, call mpp_clock_end(bergs%clock_dia) - !This is the point in the algorithem which determines which fields get passed to the ice model - !Return what ever calving we did not use and additional icebergs melt + ! This is the point in the algorithm which determines which fields get passed to the ice model + ! Return what ever calving we did not use and additional icebergs melt - !Making sure that spread_mass has the correct mass + ! Making sure that spread_mass has the correct mass !grd%spread_mass(:,:)=0.0 !call icebergs_incr_mass(bergs, grd%spread_mass(grd%isc:grd%iec,grd%jsc:grd%jec), within_iceberg_model=.True.) @@ -3361,7 +3509,7 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, !bergs%u_iceberg_end=sum_mass(bergs) !Not sure what this is !bergs%v_iceberg_end=sum_mass(bergs) !Not sure what this is bergs%floating_heat_end=sum_heat(bergs) - grd%tmpc(:,:)=0.; + grd%tmpc(:,:)=0. !Finding spread mass call mpp_clock_end(bergs%clock); call mpp_clock_end(bergs%clock_dia) ! To enable calling of public s/r call sum_up_spread_fields(bergs, grd%tmpc, 'mass') @@ -3515,135 +3663,171 @@ subroutine icebergs_run(bergs, time, calving, uo, vo, ui, vi, tauxa, tauya, ssh, contains - subroutine report_state(budgetstr,budgetunits,startstr,startval,endstr,endval,delstr,nbergs) - ! Arguments - character*(*), intent(in) :: budgetstr, budgetunits, startstr, endstr, delstr - real, intent(in) :: startval, endval - integer, intent(in), optional :: nbergs - ! Local variables - if (present(nbergs)) then - write(*,100) budgetstr//' state:', & - startstr//' start',startval,budgetunits, & - endstr//' end',endval,budgetunits, & - 'Delta '//delstr,endval-startval,budgetunits, & - '# of bergs',nbergs - else - write(*,100) budgetstr//' state:', & - startstr//' start',startval,budgetunits, & - endstr//' end',endval,budgetunits, & - delstr//'Delta',endval-startval,budgetunits - endif - 100 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a12,i8) + !> Prints summary of start and end states + subroutine report_state(budgetstr, budgetunits, startstr, startval, endstr, endval, delstr, nbergs) + ! Arguments + character*(*), intent(in) :: budgetstr !< Budget title + character*(*), intent(in) :: budgetunits !< Units of budgeted quantity + character*(*), intent(in) :: startstr !< Start label + real, intent(in) :: startval !< Start value for budget + character*(*), intent(in) :: endstr !< End label + real, intent(in) :: endval !< End value for budget + character*(*), intent(in) :: delstr !< Delta label + integer, intent(in), optional :: nbergs !< Number of bergs + ! Local variables + if (present(nbergs)) then + write(*,100) budgetstr//' state:', & + startstr//' start',startval,budgetunits, & + endstr//' end',endval,budgetunits, & + 'Delta '//delstr,endval-startval,budgetunits, & + '# of bergs',nbergs + else + write(*,100) budgetstr//' state:', & + startstr//' start',startval,budgetunits, & + endstr//' end',endval,budgetunits, & + delstr//'Delta',endval-startval,budgetunits + endif + 100 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a12,i8) end subroutine report_state - subroutine report_consistant(budgetstr,budgetunits,startstr,startval,endstr,endval) - ! Arguments - character*(*), intent(in) :: budgetstr, budgetunits, startstr, endstr - real, intent(in) :: startval, endval - ! Local variables - write(*,200) budgetstr//' check:', & - startstr,startval,budgetunits, & - endstr,endval,budgetunits, & - 'error',(endval-startval)/((endval+startval)+1e-30),'nd' - 200 format("diamonds: ",a19,10(a18,"=",es14.7,x,a2,:,",")) + !> Prints consistency summary of start and end states + subroutine report_consistant(budgetstr, budgetunits, startstr, startval, endstr, endval) + ! Arguments + character*(*), intent(in) :: budgetstr !< Budget title + character*(*), intent(in) :: budgetunits !< Units of budgeted quantity + character*(*), intent(in) :: startstr !< Start label + real, intent(in) :: startval !< Start value for budget + character*(*), intent(in) :: endstr !< End label + real, intent(in) :: endval !< End value for budget + ! Local variables + write(*,200) budgetstr//' check:', & + startstr,startval,budgetunits, & + endstr,endval,budgetunits, & + 'error',(endval-startval)/((endval+startval)+1e-30),'nd' + 200 format("diamonds: ",a19,10(a18,"=",es14.7,x,a2,:,",")) end subroutine report_consistant - subroutine report_budget(budgetstr,budgetunits,instr,inval,outstr,outval,delstr,startval,endval) - ! Arguments - character*(*), intent(in) :: budgetstr, budgetunits, instr, outstr, delstr - real, intent(in) :: inval, outval, startval, endval - ! Local variables - write(*,200) budgetstr//' budget:', & - instr//' in',inval,budgetunits, & - outstr//' out',outval,budgetunits, & - 'Delta '//delstr,inval-outval,budgetunits, & - 'error',((endval-startval)-(inval-outval))/max(1.e-30,max(abs(endval-startval),abs(inval-outval))),'nd' - 200 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a8,"=",es10.3,x,a2) + !> Prints a budget + subroutine report_budget(budgetstr, budgetunits, instr, inval, outstr, outval, delstr, startval, endval) + ! Arguments + character*(*), intent(in) :: budgetstr !< Budget title + character*(*), intent(in) :: budgetunits !< Units of budgeted quantity + character*(*), intent(in) :: instr !< Incoming label + real, intent(in) :: inval !< Incoming value + character*(*), intent(in) :: outstr !< Outgoing label + real, intent(in) :: outval !< Outgoing value + character*(*), intent(in) :: delstr !< Delta label + real, intent(in) :: startval !< Start value for budget + real, intent(in) :: endval !< End value for budget + ! Local variables + write(*,200) budgetstr//' budget:', & + instr//' in',inval,budgetunits, & + outstr//' out',outval,budgetunits, & + 'Delta '//delstr,inval-outval,budgetunits, & + 'error',((endval-startval)-(inval-outval))/max(1.e-30,max(abs(endval-startval),abs(inval-outval))),'nd' + 200 format("diamonds: ",a19,3(a18,"=",es14.7,x,a2,:,","),a8,"=",es10.3,x,a2) end subroutine report_budget - subroutine report_istate(budgetstr,startstr,startval,endstr,endval,delstr) - ! Arguments - character*(*), intent(in) :: budgetstr, startstr, endstr, delstr - integer, intent(in) :: startval, endval - ! Local variables - write(*,100) budgetstr//' state:', & - startstr//' start',startval, & - endstr//' end',endval, & - delstr//'Delta',endval-startval - 100 format("diamonds: ",a19,3(a18,"=",i14,x,:,",")) + !> Prints summary of start and end states + subroutine report_istate(budgetstr, startstr, startval, endstr, endval, delstr) + ! Arguments + character*(*), intent(in) :: budgetstr !< Budget title + character*(*), intent(in) :: startstr !< Start label + integer, intent(in) :: startval !< Start value for budget + character*(*), intent(in) :: endstr !< End label + integer, intent(in) :: endval !< End value for budget + character*(*), intent(in) :: delstr !< Delta label + ! Local variables + write(*,100) budgetstr//' state:', & + startstr//' start',startval, & + endstr//' end',endval, & + delstr//'Delta',endval-startval + 100 format("diamonds: ",a19,3(a18,"=",i14,x,:,",")) end subroutine report_istate + !> Prints a budget subroutine report_ibudget(budgetstr,instr,inval,outstr,outval,delstr,startval,endval) - ! Arguments - character*(*), intent(in) :: budgetstr, instr, outstr, delstr - integer, intent(in) :: inval, outval, startval, endval - ! Local variables - write(*,200) budgetstr//' budget:', & - instr//' in',inval, & - outstr//' out',outval, & - 'Delta '//delstr,inval-outval, & - 'error',((endval-startval)-(inval-outval)) - 200 format("diamonds: ",a19,10(a18,"=",i14,x,:,",")) + ! Arguments + character*(*), intent(in) :: budgetstr !< Budget title + character*(*), intent(in) :: instr !< Incoming label + integer, intent(in) :: inval !< Incoming value + character*(*), intent(in) :: outstr !< Outgoing label + integer, intent(in) :: outval !< Outgoing value + character*(*), intent(in) :: delstr !< Delta label + integer, intent(in) :: startval !< Start value for budget + integer, intent(in) :: endval !< End value for budget + ! Local variables + write(*,200) budgetstr//' budget:', & + instr//' in',inval, & + outstr//' out',outval, & + 'Delta '//delstr,inval-outval, & + 'error',((endval-startval)-(inval-outval)) + 200 format("diamonds: ",a19,10(a18,"=",i14,x,:,",")) end subroutine report_ibudget - subroutine get_running_mean_calving(bergs,calving,calving_hflx) - ! Arguments - type(icebergs), pointer :: bergs !< Container for all types and memory - real, dimension(:,:), intent(inout) :: calving, calving_hflx - ! Local variables - real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) - real :: tau !Relaxation timescale in seconds - real :: beta ! = 1-alpha (0<=beta<1) - !This subroutine takes in the new calving and calving_hflx, and uses them to time step a running-mean_calving value - !The time stepping uses a time scale tau. When tau is equal to zero, the - !running mean is exactly equal to the new calving value. - - ! For the first time-step, initialize the running mean with the current data - if (.not. bergs%grd%rmean_calving_initialized) then - bergs%grd%rmean_calving(:,:)=calving(:,:) - bergs%grd%rmean_calving_initialized=.true. - endif - if (.not. bergs%grd%rmean_calving_hflx_initialized) then - bergs%grd%rmean_calving_hflx(:,:)=calving_hflx(:,:) - bergs%grd%rmean_calving_hflx_initialized=.true. - endif + !> Time-filter calving and calving_hflx with a running mean. + !! + !! This subroutine takes in the new calving and calving_hflx, and uses them to time step a running-mean_calving value. + !! The time stepping uses a time scale tau. When tau is equal to zero, the + !! running mean is exactly equal to the new calving value. + subroutine get_running_mean_calving(bergs, calving, calving_hflx) + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + real, dimension(:,:), intent(inout) :: calving !< Calving (kg/s) + real, dimension(:,:), intent(inout) :: calving_hflx !< Calving heat flux (W/m2) + ! Local variables + real :: alpha !Parameter used for calving relaxation time stepping. (0<=alpha<1) + real :: tau !Relaxation timescale in seconds + real :: beta ! = 1-alpha (0<=beta<1) + + ! For the first time-step, initialize the running mean with the current data + if (.not. bergs%grd%rmean_calving_initialized) then + bergs%grd%rmean_calving(:,:)=calving(:,:) + bergs%grd%rmean_calving_initialized=.true. + endif + if (.not. bergs%grd%rmean_calving_hflx_initialized) then + bergs%grd%rmean_calving_hflx(:,:)=calving_hflx(:,:) + bergs%grd%rmean_calving_hflx_initialized=.true. + endif - !Applying "Newton cooling" with timescale tau, to smooth out the calving field. - tau=bergs%tau_calving/(365.*24*60*60) !Converting time scale from years to seconds - alpha=tau/(tau+bergs%dt) - if (alpha==0.) return ! Avoids unnecessary copying of arrays - if (alpha>0.5) then ! beta is small - beta=bergs%dt/(tau+bergs%dt) - alpha=1.-beta - else ! alpha is small - beta=1.-alpha - endif + !Applying "Newton cooling" with timescale tau, to smooth out the calving field. + tau=bergs%tau_calving/(365.*24*60*60) !Converting time scale from years to seconds + alpha=tau/(tau+bergs%dt) + if (alpha==0.) return ! Avoids unnecessary copying of arrays + if (alpha>0.5) then ! beta is small + beta=bergs%dt/(tau+bergs%dt) + alpha=1.-beta + else ! alpha is small + beta=1.-alpha + endif - ! For non-negative alpha and beta, these expressions for the running means are sign preserving - bergs%grd%rmean_calving(:,:)=beta*calving(:,:) + alpha*bergs%grd%rmean_calving(:,:) - bergs%grd%rmean_calving_hflx(:,:)=beta*calving_hflx(:,:) + alpha*bergs%grd%rmean_calving_hflx(:,:) + ! For non-negative alpha and beta, these expressions for the running means are sign preserving + bergs%grd%rmean_calving(:,:)=beta*calving(:,:) + alpha*bergs%grd%rmean_calving(:,:) + bergs%grd%rmean_calving_hflx(:,:)=beta*calving_hflx(:,:) + alpha*bergs%grd%rmean_calving_hflx(:,:) - !Setting calving used by the iceberg model equal to the running mean - calving(:,:)=bergs%grd%rmean_calving(:,:) - calving_hflx(:,:)=bergs%grd%rmean_calving_hflx(:,:) + !Setting calving used by the iceberg model equal to the running mean + calving(:,:)=bergs%grd%rmean_calving(:,:) + calving_hflx(:,:)=bergs%grd%rmean_calving_hflx(:,:) end subroutine get_running_mean_calving end subroutine icebergs_run +!> Increments a gridded mass field with the mass of bergs (called from outside icebergs_run) +!! +!! This routine is called from SIS, (and older versions of SIS2), but not within +!! the iceberg model. The routine adds the spread iceberg mass to mass provided +!! the add weight to ocean flag is on, and passive mode is off. It also appears to +!! play some role in diagnostics subroutine icebergs_incr_mass(bergs, mass, Time) -! Arguments -type(icebergs), pointer :: bergs !< Container for all types and memory -type(time_type), intent(in), optional :: Time -type(icebergs_gridded), pointer :: grd -integer :: i, j -logical :: lerr -real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass - -!This routine is called from SIS, (and older versions of SIS2), but not within -!the iceberg model. The routine adds the spread iceberg mass to mass provided -!the add weight to ocean flag is on, and passive mode is off. It also appears to -!play some role in diagnostics + ! Arguments + type(icebergs), pointer :: bergs !< Container for all types and memory + real, dimension(bergs%grd%isc:bergs%grd%iec,bergs%grd%jsc:bergs%grd%jec), intent(inout) :: mass !< Mass field to increment + type(time_type), intent(in), optional :: Time !< Model time + ! Local variables + type(icebergs_gridded), pointer :: grd + integer :: i, j + logical :: lerr if (.not. associated(bergs)) return if (.not. bergs%add_weight_to_ocean) return @@ -4595,7 +4779,7 @@ end subroutine rotvec_from_tang subroutine adjust_index_and_ground(grd, lon, lat, uvel, vvel, i, j, xi, yj, bounced, error, iceberg_num) ! Arguments -type(icebergs_gridded), pointer :: grd +type(icebergs_gridded), pointer :: grd !< Container for gridded fields real, intent(inout) :: lon, lat, uvel, vvel, xi, yj integer, intent(inout) :: i,j integer, intent(in) :: iceberg_num From 7b35c7ab4c2932f8e43ebb3f8b594deba589d103 Mon Sep 17 00:00:00 2001 From: Alistair Adcroft Date: Tue, 28 Mar 2017 00:01:24 -0400 Subject: [PATCH 214/361] Added doxygen configuration files - Added Doxyfile based on that for MOM6. - Likewise layout.xml - Placed in docs, in anticipation of hosting on RTD. --- docs/.gitignore | 2 + docs/Doxyfile | 2434 +++++++++++++++++++++++++++++++++++++++++++++++ docs/layout.xml | 191 ++++ 3 files changed, 2627 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/Doxyfile create mode 100644 docs/layout.xml diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..8bbe7ac --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +html +doxygen.log diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 0000000..40cc078 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,2434 @@ +# Doxyfile 1.8.12 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "icebergs" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +#OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = YES + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = YES + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = layout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = doxygen.log + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, +# *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.f90 \ + *.f \ + *.for \ + *.F90 + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = makedep.py + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = ../README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 900 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /