6 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
14 use mom_io, only : east_face, north_face
15 use mom_io, only : slasher, read_data, field_size, single_file
20 use time_interp_external_mod
, only : init_external_field, time_interp_external
26 implicit none ;
private 28 #include <MOM_memory.h> 59 character(len=8) :: name
60 real,
pointer,
dimension(:,:,:) :: buffer_src=>null()
63 real,
dimension(:,:,:),
pointer :: dz_src=>null()
64 real,
dimension(:,:,:),
pointer :: buffer_dst=>null()
65 real,
dimension(:,:),
pointer :: bt_vel=>null()
79 logical :: values_needed
85 character(len=32),
pointer,
dimension(:) :: field_names=>null()
93 real,
pointer,
dimension(:,:) :: cg=>null()
95 real,
pointer,
dimension(:,:) :: htot=>null()
96 real,
pointer,
dimension(:,:,:) :: h=>null()
97 real,
pointer,
dimension(:,:,:) :: e=>null()
98 real,
pointer,
dimension(:,:,:) :: normal_vel=>null()
100 real,
pointer,
dimension(:,:,:) :: normal_trans=>null()
102 real,
pointer,
dimension(:,:) :: normal_vel_bt=>null()
104 real,
pointer,
dimension(:,:) :: normal_trans_bt=>null()
106 real,
pointer,
dimension(:,:) :: eta=>null()
107 real,
pointer,
dimension(:,:,:) :: grad_normal=>null()
109 real,
pointer,
dimension(:,:,:) :: rx_normal=>null()
111 real,
pointer,
dimension(:,:,:) :: nudged_normal_vel=>null()
113 real,
pointer,
dimension(:,:,:) :: t=>null()
115 real,
pointer,
dimension(:,:,:) :: s=>null()
117 type(hor_index_type) :: hi
122 integer :: number_of_segments = 0
124 logical :: open_u_bcs_exist_globally = .false.
126 logical :: open_v_bcs_exist_globally = .false.
128 logical :: flather_u_bcs_exist_globally = .false.
130 logical :: flather_v_bcs_exist_globally = .false.
132 logical :: oblique_bcs_exist_globally = .false.
134 logical :: nudged_u_bcs_exist_globally = .false.
136 logical :: nudged_v_bcs_exist_globally = .false.
138 logical :: specified_u_bcs_exist_globally = .false.
140 logical :: specified_v_bcs_exist_globally = .false.
142 logical :: user_bcs_set_globally = .false.
144 logical :: update_obc = .false.
145 logical :: needs_io_for_data = .false.
146 logical :: zero_vorticity = .false.
147 logical :: freeslip_vorticity = .false.
149 logical :: zero_strain = .false.
150 logical :: freeslip_strain = .false.
152 logical :: zero_biharmonic = .false.
154 logical :: extend_segments = .false.
160 integer,
pointer,
dimension(:,:) :: &
161 segnum_u => null(), &
184 real :: tide_flow = 3.0e6
189 character(len=32) :: name
196 logical :: locked = .false.
202 character(len=40) ::
mdl =
"MOM_open_boundary" 204 #include "version_variable.h" 221 character(len=15) :: segment_param_str
222 character(len=100) :: segment_str
223 character(len=200) :: config1
227 call log_version(param_file,
mdl, version,
"Controls where open boundaries are located, what "//&
228 "kind of boundary condition to impose, and what data to apply, if any.")
229 call get_param(param_file,
mdl,
"OBC_NUMBER_OF_SEGMENTS", obc%number_of_segments, &
230 "The number of open boundary segments.", &
232 call get_param(param_file,
mdl,
"G_EARTH", obc%g_Earth, &
233 "The gravitational acceleration of the Earth.", &
234 units=
"m s-2", default = 9.80)
235 call get_param(param_file,
mdl,
"OBC_USER_CONFIG", config1, &
236 "A string that sets how the open boundary conditions are \n"//&
237 " configured: \n", default=
"none", do_not_log=.true.)
239 "The number of model layers", default=0, do_not_log=.true.)
241 if (config1 .ne.
"none") obc%user_BCs_set_globally = .true.
245 call get_param(param_file,
mdl,
"EXTEND_OBC_SEGMENTS", obc%extend_segments, &
246 "If true, extend OBC segments. This option is used to recover\n"//&
247 "legacy solutions dependent on an incomplete implementaion of OBCs.\n"//&
248 "This option will be obsoleted in the future.", default=.false.)
250 if (obc%number_of_segments > 0)
then 251 call get_param(param_file,
mdl,
"OBC_ZERO_VORTICITY", obc%zero_vorticity, &
252 "If true, sets relative vorticity to zero on open boundaries.", &
254 call get_param(param_file,
mdl,
"OBC_FREESLIP_VORTICITY", obc%freeslip_vorticity, &
255 "If true, sets the normal gradient of tangential velocity to\n"// &
256 "zero in the relative vorticity on open boundaries. This cannot\n"// &
257 "be true if OBC_ZERO_VORTICITY is True.", default=.false.)
258 if (obc%zero_vorticity .and. obc%freeslip_vorticity)
call mom_error(fatal, &
259 "MOM_open_boundary.F90, open_boundary_config: "//&
260 "Only one of OBC_ZERO_VORTICITY and OBC_FREESLIP_VORTICITY can be True at once.")
261 call get_param(param_file,
mdl,
"OBC_ZERO_STRAIN", obc%zero_strain, &
262 "If true, sets the strain used in the stress tensor to zero on open boundaries.", &
264 call get_param(param_file,
mdl,
"OBC_FREESLIP_STRAIN", obc%freeslip_strain, &
265 "If true, sets the normal gradient of tangential velocity to\n"// &
266 "zero in the strain use in the stress tensor on open boundaries. This cannot\n"// &
267 "be true if OBC_ZERO_STRAIN is True.", default=.false.)
268 if (obc%zero_strain .and. obc%freeslip_strain)
call mom_error(fatal, &
269 "MOM_open_boundary.F90, open_boundary_config: "//&
270 "Only one of OBC_ZERO_STRAIN and OBC_FREESLIP_STRAIN can be True at once.")
271 call get_param(param_file,
mdl,
"OBC_ZERO_BIHARMONIC", obc%zero_biharmonic, &
272 "If true, zeros the Laplacian of flow on open boundaries in the biharmonic\n"//&
273 "viscosity term.", default=.false.)
276 allocate(obc%segment(0:obc%number_of_segments))
277 do l=0,obc%number_of_segments
278 obc%segment(l)%Flather = .false.
279 obc%segment(l)%radiation = .false.
280 obc%segment(l)%oblique = .false.
281 obc%segment(l)%nudged = .false.
282 obc%segment(l)%specified = .false.
283 obc%segment(l)%open = .false.
284 obc%segment(l)%gradient = .false.
285 obc%segment(l)%values_needed = .false.
287 obc%segment(l)%is_N_or_S = .false.
288 obc%segment(l)%is_E_or_W = .false.
289 obc%segment(l)%Tnudge_in = 0.0
290 obc%segment(l)%Tnudge_out = 0.0
291 obc%segment(l)%num_fields = 0.0
293 allocate(obc%segnum_u(g%IsdB:g%IedB,g%jsd:g%jed)) ; obc%segnum_u(:,:) =
obc_none 294 allocate(obc%segnum_v(g%isd:g%ied,g%JsdB:g%JedB)) ; obc%segnum_v(:,:) =
obc_none 296 do l = 1, obc%number_of_segments
297 write(segment_param_str(1:15),
"('OBC_SEGMENT_',i3.3)") l
298 call get_param(param_file,
mdl, segment_param_str, segment_str, &
299 "Documentation needs to be dynamic?????", &
300 fail_if_missing=.true.)
302 if (segment_str(1:2) ==
'I=')
then 304 elseif (segment_str(1:2) ==
'J=')
then 307 call mom_error(fatal,
"MOM_open_boundary.F90, open_boundary_config: "//&
308 "Unable to interpret "//segment_param_str//
" = "//trim(segment_str))
317 if ((obc%open_u_BCs_exist_globally .or. obc%open_v_BCs_exist_globally) .and. &
318 .not.g%symmetric )
call mom_error(fatal, &
319 "MOM_open_boundary, open_boundary_config: "//&
320 "Symmetric memory must be used when using Flather OBCs.")
322 if (.not.(obc%specified_u_BCs_exist_globally .or. obc%specified_v_BCs_exist_globally .or. &
323 obc%open_u_BCs_exist_globally .or. obc%open_v_BCs_exist_globally))
then 331 use mpp_mod
, only : mpp_pe, mpp_set_current_pelist, mpp_get_current_pelist,mpp_npes
337 integer :: n,m,num_fields
338 character(len=256) :: segstr, filename
339 character(len=20) :: segnam, suffix
340 character(len=32) :: varnam, fieldname
343 character(len=32),
dimension(MAX_OBC_FIELDS) :: fields
344 character(len=128) :: inputdir
346 character(len=32) :: remappingScheme
347 logical :: check_reconstruction, check_remapping, force_bounds_in_subcell
348 integer,
dimension(4) :: siz,siz2
349 integer :: is, ie, js, je
350 integer :: isd, ied, jsd, jed
351 integer :: IsdB, IedB, JsdB, JedB
352 integer,
dimension(:),
allocatable :: saved_pelist
353 integer :: current_pe
354 integer,
dimension(1) :: single_pelist
356 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
363 call get_param(pf,
mdl,
"INPUTDIR", inputdir, default=
".")
364 inputdir = slasher(inputdir)
366 call get_param(pf,
mdl,
"REMAPPING_SCHEME", remappingscheme, &
367 "This sets the reconstruction scheme used\n"//&
368 "for vertical remapping for all variables.\n"//&
369 "It can be one of the following schemes:\n"//&
370 trim(remappingschemesdoc), default=remappingdefaultscheme,do_not_log=.true.)
371 call get_param(pf,
mdl,
"FATAL_CHECK_RECONSTRUCTIONS", check_reconstruction, &
372 "If true, cell-by-cell reconstructions are checked for\n"//&
373 "consistency and if non-monotonicity or an inconsistency is\n"//&
374 "detected then a FATAL error is issued.", default=.false.,do_not_log=.true.)
375 call get_param(pf,
mdl,
"FATAL_CHECK_REMAPPING", check_remapping, &
376 "If true, the results of remapping are checked for\n"//&
377 "conservation and new extrema and if an inconsistency is\n"//&
378 "detected then a FATAL error is issued.", default=.false.,do_not_log=.true.)
379 call get_param(pf,
mdl,
"REMAP_BOUND_INTERMEDIATE_VALUES", force_bounds_in_subcell, &
380 "If true, the values on the intermediate grid used for remapping\n"//&
381 "are forced to be bounded, which might not be the case due to\n"//&
382 "round off.", default=.false.,do_not_log=.true.)
384 allocate(obc%remap_CS)
385 call initialize_remapping(obc%remap_CS, remappingscheme, boundary_extrapolation = .false., &
386 check_reconstruction=check_reconstruction, &
387 check_remapping=check_remapping, force_bounds_in_subcell=force_bounds_in_subcell)
389 if (obc%user_BCs_set_globally)
return 394 allocate(saved_pelist(0:mpp_npes()-1))
395 call mpp_get_current_pelist(saved_pelist)
396 current_pe = mpp_pe()
397 single_pelist(1) = current_pe
398 call mpp_set_current_pelist(single_pelist)
400 do n=1, obc%number_of_segments
401 segment => obc%segment(n)
403 write(segnam,
"('OBC_SEGMENT_',i3.3,'_DATA')") n
404 write(suffix,
"('_segment_',i3.3)") n
408 if (num_fields == 0)
then 409 print *,
'num_fields = 0';cycle
412 allocate(segment%field(num_fields))
414 if (segment%Flather)
then 415 if (num_fields /= 3)
call mom_error(fatal, &
416 "MOM_open_boundary, initialize_segment_data: "//&
417 "Need three inputs for Flather")
419 segment%num_fields = 3
422 allocate(segment%field_names(segment%num_fields))
423 segment%field_names(:)=
'None' 424 segment%field_names(1)=
'UO' 425 segment%field_names(2)=
'VO' 426 segment%field_names(3)=
'ZOS' 433 isd = segment%HI%isd ; ied = segment%HI%ied
434 jsd = segment%HI%jsd ; jed = segment%HI%jed
435 isdb = segment%HI%IsdB ; iedb = segment%HI%IedB
436 jsdb = segment%HI%JsdB ; jedb = segment%HI%JedB
440 call parse_segment_data_str(trim(segstr), var=trim(fields(m)),
value=
value, filenam=filename, fieldnam=fieldname)
441 if (trim(filename) /=
'none')
then 442 obc%update_OBC = .true.
443 obc%needs_IO_for_data = .true.
445 segment%values_needed = .true.
446 segment%field(m)%name = trim(fields(m))
447 filename = trim(inputdir)//trim(filename)
448 fieldname = trim(fieldname)//trim(suffix)
449 call field_size(filename,fieldname,siz,no_domain=.true.)
450 if (siz(4) == 1) segment%values_needed = .false.
451 if (segment%on_pe)
then 452 if (modulo(siz(1),2) == 0 .or. modulo(siz(2),2) == 0)
then 453 call mom_error(fatal,
'segment data are not on the supergrid')
465 if (segment%is_E_or_W)
then 466 allocate(segment%field(m)%buffer_src(isdb:iedb,jsd:jed,siz2(3)))
468 allocate(segment%field(m)%buffer_src(isd:ied,jsdb:jedb,siz2(3)))
470 segment%field(m)%buffer_src(:,:,:)=0.0
471 segment%field(m)%fid = init_external_field(trim(filename),&
472 trim(fieldname),ignore_axis_atts=.true.,threading=single_file)
474 fieldname =
'dz_'//trim(fieldname)
475 call field_size(filename,fieldname,siz,no_domain=.true.)
476 if (segment%is_E_or_W)
then 477 allocate(segment%field(m)%dz_src(isdb:iedb,jsd:jed,siz(3)))
479 allocate(segment%field(m)%dz_src(isd:ied,jsdb:jedb,siz(3)))
481 segment%field(m)%dz_src(:,:,:)=0.0
482 segment%field(m)%nk_src=siz(3)
483 segment%field(m)%fid_dz = init_external_field(trim(filename),trim(fieldname),&
484 ignore_axis_atts=.true.,threading=single_file)
486 segment%field(m)%nk_src=1
490 segment%field(m)%fid = -1
491 segment%field(m)%value =
value 496 call mpp_set_current_pelist(saved_pelist)
505 integer,
intent(in) :: Is_obc
506 integer,
intent(in) :: Ie_obc
507 integer,
intent(in) :: Js_obc
508 integer,
intent(in) :: Je_obc
510 integer :: Isg,Ieg,Jsg,Jeg
516 if (ie_obc<is_obc)
then 517 isg=ie_obc;ieg=is_obc
519 isg=is_obc;ieg=ie_obc
521 if (je_obc<js_obc)
then 522 jsg=je_obc;jeg=js_obc
524 jsg=js_obc;jeg=je_obc
528 seg%HI%IsgB = isg ; seg%HI%IegB = ieg
529 seg%HI%isg = isg+1 ; seg%HI%ieg = ieg
530 seg%HI%JsgB = jsg ; seg%HI%JegB = jeg
531 seg%HI%jsg = jsg+1 ; seg%HI%Jeg = jeg
534 isg = isg - g%idg_offset
535 jsg = jsg - g%jdg_offset
536 ieg = ieg - g%idg_offset
537 jeg = jeg - g%jdg_offset
541 seg%HI%IsdB = min( max(isg, g%HI%IsdB), g%HI%IedB)
542 seg%HI%IedB = min( max(ieg, g%HI%IsdB), g%HI%IedB)
543 seg%HI%isd = min( max(isg+1, g%HI%isd), g%HI%ied)
544 seg%HI%ied = min( max(ieg, g%HI%isd), g%HI%ied)
545 seg%HI%IscB = min( max(isg, g%HI%IscB), g%HI%IecB)
546 seg%HI%IecB = min( max(ieg, g%HI%IscB), g%HI%IecB)
547 seg%HI%isc = min( max(isg+1, g%HI%isc), g%HI%iec)
548 seg%HI%iec = min( max(ieg, g%HI%isc), g%HI%iec)
552 seg%HI%JsdB = min( max(jsg, g%HI%JsdB), g%HI%JedB)
553 seg%HI%JedB = min( max(jeg, g%HI%JsdB), g%HI%JedB)
554 seg%HI%jsd = min( max(jsg+1, g%HI%jsd), g%HI%jed)
555 seg%HI%jed = min( max(jeg, g%HI%jsd), g%HI%jed)
556 seg%HI%JscB = min( max(jsg, g%HI%JscB), g%HI%JecB)
557 seg%HI%JecB = min( max(jeg, g%HI%JscB), g%HI%JecB)
558 seg%HI%jsc = min( max(jsg+1, g%HI%jsc), g%HI%jec)
559 seg%HI%jec = min( max(jeg, g%HI%jsc), g%HI%jec)
567 character(len=*),
intent(in) :: segment_str
568 integer,
intent(in) :: l_seg
570 integer :: I_obc, Js_obc, Je_obc
572 character(len=32) :: action_str(5)
575 call parse_segment_str(g%ieg, g%jeg, segment_str, i_obc, js_obc, je_obc, action_str )
579 i_obc = i_obc - g%idg_offset
580 js_obc = js_obc - g%jdg_offset
581 je_obc = je_obc - g%jdg_offset
584 if (obc%extend_segments)
then 585 if (js_obc<je_obc)
then 586 js_obc = js_obc - 1 ; je_obc = je_obc + 1
588 js_obc = js_obc + 1 ; je_obc = je_obc - 1
592 if (je_obc>js_obc)
then 594 else if (je_obc<js_obc)
then 596 j=js_obc;js_obc=je_obc;je_obc=j
599 obc%segment(l_seg)%on_pe = .false.
602 if (len_trim(action_str(a_loop)) == 0)
then 604 elseif (trim(action_str(a_loop)) ==
'FLATHER')
then 605 obc%segment(l_seg)%Flather = .true.
606 obc%segment(l_seg)%open = .true.
607 obc%Flather_u_BCs_exist_globally = .true.
608 obc%open_u_BCs_exist_globally = .true.
609 elseif (trim(action_str(a_loop)) ==
'ORLANSKI')
then 610 obc%segment(l_seg)%radiation = .true.
611 obc%segment(l_seg)%open = .true.
612 obc%open_u_BCs_exist_globally = .true.
613 elseif (trim(action_str(a_loop)) ==
'OBLIQUE')
then 614 obc%segment(l_seg)%oblique = .true.
615 obc%segment(l_seg)%open = .true.
616 obc%oblique_BCs_exist_globally = .true.
617 obc%open_u_BCs_exist_globally = .true.
618 elseif (trim(action_str(a_loop)) ==
'NUDGED')
then 619 obc%segment(l_seg)%nudged = .true.
620 obc%segment(l_seg)%Tnudge_in = 1.0/(3*86400)
621 obc%segment(l_seg)%Tnudge_out = 1.0/(360*86400)
622 obc%nudged_u_BCs_exist_globally = .true.
623 elseif (trim(action_str(a_loop)) ==
'GRADIENT')
then 624 obc%segment(l_seg)%gradient = .true.
625 obc%segment(l_seg)%open = .true.
626 obc%open_u_BCs_exist_globally = .true.
627 elseif (trim(action_str(a_loop)) ==
'LEGACY')
then 628 obc%segment(l_seg)%Flather = .true.
629 obc%segment(l_seg)%radiation = .true.
630 obc%Flather_u_BCs_exist_globally = .true.
631 obc%open_u_BCs_exist_globally = .true.
632 elseif (trim(action_str(a_loop)) ==
'SIMPLE')
then 633 obc%segment(l_seg)%specified = .true.
634 obc%specified_u_BCs_exist_globally = .true.
636 if (obc%extend_segments)
then 641 call mom_error(fatal,
"MOM_open_boundary.F90, setup_u_point_obc: "//&
642 "String '"//trim(action_str(a_loop))//
"' not understood.")
645 if (i_obc<g%HI%IsdB .or. i_obc>g%HI%IedB)
return 646 if (js_obc<g%HI%JsdB .and. je_obc<g%HI%JsdB)
return 647 if (js_obc>g%HI%JedB)
return 650 obc%segment(l_seg)%on_pe = .true.
651 obc%segment(l_seg)%is_E_or_W = .true.
653 do j=g%HI%jsd, g%HI%jed
654 if (j>js_obc .and. j<=je_obc)
then 655 obc%segnum_u(i_obc,j) = l_seg
658 obc%segment(l_seg)%Is_obc = i_obc
659 obc%segment(l_seg)%Ie_obc = i_obc
660 obc%segment(l_seg)%Js_obc = js_obc
661 obc%segment(l_seg)%Je_obc = je_obc
670 character(len=*),
intent(in) :: segment_str
671 integer,
intent(in) :: l_seg
673 integer :: J_obc, Is_obc, Ie_obc
675 character(len=32) :: action_str(5)
678 call parse_segment_str(g%ieg, g%jeg, segment_str, j_obc, is_obc, ie_obc, action_str )
682 j_obc = j_obc - g%jdg_offset
683 is_obc = is_obc - g%idg_offset
684 ie_obc = ie_obc - g%idg_offset
687 if (obc%extend_segments)
then 688 if (is_obc<ie_obc)
then 689 is_obc = is_obc - 1 ; ie_obc = ie_obc + 1
691 is_obc = is_obc + 1 ; ie_obc = ie_obc - 1
695 if (ie_obc>is_obc)
then 697 else if (ie_obc<is_obc)
then 699 i=is_obc;is_obc=ie_obc;ie_obc=i
702 obc%segment(l_seg)%on_pe = .false.
705 if (len_trim(action_str(a_loop)) == 0)
then 707 elseif (trim(action_str(a_loop)) ==
'FLATHER')
then 708 obc%segment(l_seg)%Flather = .true.
709 obc%segment(l_seg)%open = .true.
710 obc%Flather_v_BCs_exist_globally = .true.
711 obc%open_v_BCs_exist_globally = .true.
712 elseif (trim(action_str(a_loop)) ==
'ORLANSKI')
then 713 obc%segment(l_seg)%radiation = .true.
714 obc%segment(l_seg)%open = .true.
715 obc%open_v_BCs_exist_globally = .true.
716 elseif (trim(action_str(a_loop)) ==
'OBLIQUE')
then 717 obc%segment(l_seg)%oblique = .true.
718 obc%segment(l_seg)%open = .true.
719 obc%oblique_BCs_exist_globally = .true.
720 obc%open_v_BCs_exist_globally = .true.
721 elseif (trim(action_str(a_loop)) ==
'NUDGED')
then 722 obc%segment(l_seg)%nudged = .true.
723 obc%segment(l_seg)%Tnudge_in = 1.0/(3*86400)
724 obc%segment(l_seg)%Tnudge_out = 1.0/(360*86400)
725 obc%nudged_v_BCs_exist_globally = .true.
726 elseif (trim(action_str(a_loop)) ==
'GRADIENT')
then 727 obc%segment(l_seg)%gradient = .true.
728 obc%segment(l_seg)%open = .true.
729 obc%open_v_BCs_exist_globally = .true.
730 elseif (trim(action_str(a_loop)) ==
'LEGACY')
then 731 obc%segment(l_seg)%radiation = .true.
732 obc%segment(l_seg)%Flather = .true.
733 obc%Flather_v_BCs_exist_globally = .true.
734 obc%open_v_BCs_exist_globally = .true.
735 elseif (trim(action_str(a_loop)) ==
'SIMPLE')
then 736 obc%segment(l_seg)%specified = .true.
737 obc%specified_v_BCs_exist_globally = .true.
739 if (obc%extend_segments)
then 744 call mom_error(fatal,
"MOM_open_boundary.F90, setup_v_point_obc: "//&
745 "String '"//trim(action_str(a_loop))//
"' not understood.")
748 if (j_obc<g%HI%JsdB .or. j_obc>g%HI%JedB)
return 749 if (is_obc<g%HI%IsdB .and. ie_obc<g%HI%IsdB)
return 750 if (is_obc>g%HI%IedB)
return 753 obc%segment(l_seg)%on_pe = .true.
754 obc%segment(l_seg)%is_N_or_S = .true.
756 do i=g%HI%isd, g%HI%ied
757 if (i>is_obc .and. i<=ie_obc)
then 758 obc%segnum_v(i,j_obc) = l_seg
761 obc%segment(l_seg)%Is_obc = is_obc
762 obc%segment(l_seg)%Ie_obc = ie_obc
763 obc%segment(l_seg)%Js_obc = j_obc
764 obc%segment(l_seg)%Je_obc = j_obc
770 subroutine parse_segment_str(ni_global, nj_global, segment_str, l, m, n, action_str )
771 integer,
intent(in) :: ni_global
772 integer,
intent(in) :: nj_global
773 character(len=*),
intent(in) :: segment_str
774 integer,
intent(out) :: l
775 integer,
intent(out) :: m
776 integer,
intent(out) :: n
777 character(len=*),
intent(out) :: action_str(:)
779 character(len=24) :: word1, word2, m_word, n_word
787 if (word1(1:2)==
'I=')
then 790 if (.not. (word2(1:2)==
'J='))
call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
791 "Second word of string '"//trim(segment_str)//
"' must start with 'J='.")
792 elseif (word1(1:2)==
'J=')
then 795 if (.not. (word2(1:2)==
'I='))
call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
796 "Second word of string '"//trim(segment_str)//
"' must start with 'I='.")
798 call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str"//&
799 "String '"//segment_str//
"' must start with 'I=' or 'J='.")
804 if (l<0 .or. l>l_max)
then 805 call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
806 "First value from string '"//trim(segment_str)//
"' is outside of the physical domain.")
812 if (m<-1 .or. m>mn_max+1)
then 813 call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
814 "Beginning of range in string '"//trim(segment_str)//
"' is outside of the physical domain.")
820 if (n<-1 .or. n>mn_max+1)
then 821 call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
822 "End of range in string '"//trim(segment_str)//
"' is outside of the physical domain.")
825 if (abs(n-m)==0)
then 826 call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str: "//&
827 "Range in string '"//trim(segment_str)//
"' must span one cell.")
831 do j = 1,
size(action_str)
839 character(len=*),
intent(in) :: string
840 integer,
intent(in) :: imax
844 slen = len_trim(string)
845 if (slen==0)
call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str"//&
846 "Parsed string was empty!")
847 if (len_trim(string)==1 .and. string(1:1)==
'N')
then 849 elseif (string(1:1)==
'N')
then 856 911
call mom_error(fatal,
"MOM_open_boundary.F90, parse_segment_str"//&
857 "Problem reading value from string '"//trim(string)//
"'.")
863 character(len=*),
intent(in) :: segment_str
864 character(len=*),
intent(in),
optional :: var
865 character(len=*),
intent(out),
optional :: filenam
866 character(len=*),
intent(out),
optional :: fieldnam
867 real,
intent(out),
optional ::
value 868 character(len=*),
dimension(MAX_OBC_FIELDS),
intent(out),
optional :: fields
869 integer,
intent(out),
optional :: num_fields
870 logical,
intent(in),
optional :: debug
872 character(len=128) :: word1, word2, word3, method
873 integer :: lword, nfields, n, m, orient
874 logical :: continue,dbg
875 character(len=32),
dimension(MAX_OBC_FIELDS) :: flds
880 if (
PRESENT(debug)) dbg=debug
884 if (trim(word1) ==
'')
exit 887 flds(nfields) = trim(word2)
890 if (
PRESENT(fields))
then 896 if (
PRESENT(num_fields))
then 902 if (
PRESENT(var))
then 904 if (trim(var)==trim(flds(n)))
then 918 if (trim(word2) == trim(var))
then 920 lword=len_trim(method)
921 if (method(lword-3:lword) ==
'file')
then 926 lword=len_trim(fieldnam)
927 fieldnam = fieldnam(1:lword-1)
929 elseif (method(lword-4:lword) ==
'value')
then 933 lword=len_trim(word1)
934 read(word1(1:lword),*,end=986,err=987)
value 940 986
call mom_error(fatal,
'End of record while parsing segment data specification! '//trim(segment_str))
941 987
call mom_error(fatal,
'Error while parsing segment data specification! '//trim(segment_str))
952 if (.not.
associated(obc))
return 954 if ( obc%Flather_u_BCs_exist_globally .or. obc%Flather_v_BCs_exist_globally )
then 955 call get_param(param_file,
mdl,
"OBC_RADIATION_MAX", obc%rx_max, &
956 "The maximum magnitude of the baroclinic radiation \n"//&
957 "velocity (or speed of characteristics). This is only \n"//&
958 "used if one of the open boundary segments is using Orlanski.", &
959 units=
"m s-1", default=10.0)
960 call get_param(param_file,
mdl,
"OBC_RAD_VEL_WT", obc%gamma_uv, &
961 "The relative weighting for the baroclinic radiation \n"//&
962 "velocities (or speed of characteristics) at the new \n"//&
963 "time level (1) or the running mean (0) for velocities. \n"//&
964 "Valid values range from 0 to 1. This is only used if \n"//&
965 "one of the open boundary segments is using Orlanski.", &
966 units=
"nondim", default=0.3)
967 call get_param(param_file,
mdl,
"OBC_RAD_THICK_WT", obc%gamma_h, &
968 "The relative weighting for the baroclinic radiation \n"//&
969 "velocities (or speed of characteristics) at the new \n"//&
970 "time level (1) or the running mean (0) for thicknesses. \n"//&
971 "Valid values range from 0 to 1. This is only used if \n"//&
972 "one of the open boundary segments is using Orlanski.", &
973 units=
"nondim", default=0.2)
976 id_clock_pass = cpu_clock_id(
'(Ocean OBC halo updates)', grain=clock_routine)
980 logical function open_boundary_query(OBC, apply_open_OBC, apply_specified_OBC, apply_Flather_OBC, apply_nudged_OBC, needs_ext_seg_data)
982 logical,
optional,
intent(in) :: apply_open_OBC
983 logical,
optional,
intent(in) :: apply_specified_OBC
984 logical,
optional,
intent(in) :: apply_Flather_OBC
985 logical,
optional,
intent(in) :: apply_nudged_OBC
986 logical,
optional,
intent(in) :: needs_ext_seg_data
988 if (.not.
associated(obc))
return 990 obc%open_v_BCs_exist_globally
991 if (
present(apply_specified_obc))
open_boundary_query = obc%specified_u_BCs_exist_globally .or. &
992 obc%specified_v_BCs_exist_globally
993 if (
present(apply_flather_obc))
open_boundary_query = obc%Flather_u_BCs_exist_globally .or. &
994 obc%Flather_v_BCs_exist_globally
995 if (
present(apply_nudged_obc))
open_boundary_query = obc%nudged_u_BCs_exist_globally .or. &
996 obc%nudged_v_BCs_exist_globally
1004 if (.not.
associated(obc))
return 1005 if (
associated(obc%segment))
deallocate(obc%segment)
1006 if (
associated(obc%segnum_u))
deallocate(obc%segnum_u)
1007 if (
associated(obc%segnum_v))
deallocate(obc%segnum_v)
1021 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: depth
1026 if (.not.
associated(obc))
return 1028 if (.not.(obc%open_u_BCs_exist_globally .or. obc%open_v_BCs_exist_globally)) &
1031 do n=1,obc%number_of_segments
1032 segment=>obc%segment(n)
1033 if (.not. segment%on_pe .or. segment%specified) cycle
1036 do j=segment%HI%jsd,segment%HI%jed
1037 depth(i+1,j) = depth(i,j)
1041 do j=segment%HI%jsd,segment%HI%jed
1042 depth(i,j) = depth(i+1,j)
1046 do i=segment%HI%isd,segment%HI%ied
1047 depth(i,j+1) = depth(i,j)
1051 do i=segment%HI%isd,segment%HI%ied
1052 depth(i,j) = depth(i,j+1)
1065 real,
dimension(SZIB_(G),SZJ_(G)),
intent(inout) :: areaCu
1066 real,
dimension(SZI_(G),SZJB_(G)),
intent(inout) :: areaCv
1070 logical :: any_U, any_V
1072 if (.not.
associated(obc))
return 1074 do n=1,obc%number_of_segments
1075 segment=>obc%segment(n)
1076 if (.not. segment%on_pe .or. segment%specified) cycle
1077 if (segment%is_E_or_W)
then 1080 do j=segment%HI%jsd,segment%HI%jed
1081 if (g%mask2dCu(i,j) == 0) obc%segnum_u(i,j) =
obc_none 1086 do i=segment%HI%isd,segment%HI%ied
1087 if (g%mask2dCv(i,j) == 0) obc%segnum_v(i,j) =
obc_none 1092 do n=1,obc%number_of_segments
1093 segment=>obc%segment(n)
1094 if (.not. segment%on_pe .or. .not. segment%specified) cycle
1095 if (segment%is_E_or_W)
then 1098 do j=segment%HI%jsd,segment%HI%jed
1100 areacu(i,j) = g%areaT(i,j)
1103 areacu(i,j) = g%areaT(i+1,j)
1110 do i=segment%HI%isd,segment%HI%ied
1112 areacv(i,j) = g%areaT(i,j+1)
1115 areacu(i,j) = g%areaT(i,j)
1128 do n=1,obc%number_of_segments
1129 segment=>obc%segment(n)
1130 if (.not. segment%on_pe) cycle
1131 if (segment%is_E_or_W)
then 1133 do j=segment%HI%jsd,segment%HI%jed
1134 if (obc%segnum_u(i,j) /=
obc_none) any_u = .true.
1138 do i=segment%HI%isd,segment%HI%ied
1139 if (obc%segnum_v(i,j) /=
obc_none) any_v = .true.
1145 if (.not.(any_u .or. any_v)) obc%OBC_pe = .false.
1153 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: u_new
1154 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u_old
1155 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: v_new
1156 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v_old
1157 real,
intent(in) :: dt
1159 real :: dhdt, dhdx, dhdy, gamma_u, gamma_h, gamma_v
1160 real :: cff, Cx, Cy, tau
1161 real :: rx_max, ry_max
1162 real :: rx_new, rx_avg
1163 real :: ry_new, ry_avg
1164 real,
parameter :: eps = 1.0e-20
1166 integer :: i, j, k, is, ie, js, je, nz, n
1167 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1169 if (.not.
associated(obc))
return 1171 if (.not.(obc%open_u_BCs_exist_globally .or. obc%open_v_BCs_exist_globally)) &
1174 gamma_u = obc%gamma_uv ; gamma_v = obc%gamma_uv ; gamma_h = obc%gamma_h
1175 rx_max = obc%rx_max ; ry_max = obc%rx_max
1176 do n=1,obc%number_of_segments
1177 segment=>obc%segment(n)
1178 if (.not. segment%on_pe) cycle
1182 do k=1,nz ;
do j=segment%HI%jsc,segment%HI%jec
1183 if (segment%radiation)
then 1184 dhdt = u_old(i-1,j,k)-u_new(i-1,j,k)
1185 dhdx = u_new(i-1,j,k)-u_new(i-2,j,k)
1187 if (dhdt*dhdx > 0.0) rx_new = min( (dhdt/dhdx), rx_max)
1188 rx_avg = (1.0-gamma_u)*segment%rx_normal(i,j,k) + gamma_u*rx_new
1189 segment%rx_normal(i,j,k) = rx_avg
1190 segment%normal_vel(i,j,k) = (u_old(i,j,k) + rx_avg*u_new(i-1,j,k)) / (1.0+rx_avg)
1191 elseif (segment%oblique)
then 1192 dhdt = u_old(i-1,j,k)-u_new(i-1,j,k)
1193 dhdx = u_new(i-1,j,k)-u_new(i-2,j,k)
1195 if (dhdt*(segment%grad_normal(j,1,k) + segment%grad_normal(j-1,1,k)) > 0.0)
then 1196 dhdy = segment%grad_normal(j-1,1,k)
1197 elseif (dhdt*(segment%grad_normal(j,1,k) + segment%grad_normal(j-1,1,k)) == 0.0)
then 1200 dhdy = segment%grad_normal(j,1,k)
1203 if (dhdt*dhdx < 0.0) dhdt = 0.0
1204 if (dhdx == 0.0) dhdx=eps
1205 cx = min(dhdt/dhdx,rx_max)
1207 cff = max(dhdx*dhdx,eps)
1209 cff = max(dhdx*dhdx + dhdy*dhdy, eps)
1210 if (dhdy==0.) dhdy=eps
1211 cy = min(cff,max(dhdt/dhdy,-cff))
1213 segment%normal_vel(i,j,k) = ((cff*u_old(i,j,k) + cx*u_new(i-1,j,k)) - &
1214 (max(cy,0.0)*segment%grad_normal(j-1,2,k) + min(cy,0.0)*segment%grad_normal(j,2,k))) / (cff + cx)
1215 elseif (segment%gradient)
then 1216 segment%normal_vel(i,j,k) = u_new(i-1,j,k)
1218 if ((segment%radiation .or. segment%oblique) .and. segment%nudged)
then 1219 if (dhdt*dhdx < 0.0)
then 1220 tau = segment%Tnudge_in
1222 tau = segment%Tnudge_out
1224 segment%normal_vel(i,j,k) = u_new(i,j,k) + dt*tau*(segment%nudged_normal_vel(i,j,k) - u_old(i,j,k))
1231 do k=1,nz ;
do j=segment%HI%jsc,segment%HI%jec
1232 if (segment%radiation)
then 1233 dhdt = u_old(i+1,j,k)-u_new(i+1,j,k)
1234 dhdx = u_new(i+1,j,k)-u_new(i+2,j,k)
1236 if (dhdt*dhdx > 0.0) rx_new = min( (dhdt/dhdx), rx_max)
1237 rx_avg = (1.0-gamma_u)*segment%rx_normal(i,j,k) + gamma_u*rx_new
1238 segment%rx_normal(i,j,k) = rx_avg
1239 segment%normal_vel(i,j,k) = (u_old(i,j,k) + rx_avg*u_new(i+1,j,k)) / (1.0+rx_avg)
1240 elseif (segment%oblique)
then 1241 dhdt = u_old(i+1,j,k)-u_new(i+1,j,k)
1242 dhdx = u_new(i+1,j,k)-u_new(i+2,j,k)
1244 if (dhdt*(segment%grad_normal(j,1,k) + segment%grad_normal(j-1,1,k)) > 0.0)
then 1245 dhdy = segment%grad_normal(j-1,1,k)
1246 elseif (dhdt*(segment%grad_normal(j,1,k) + segment%grad_normal(j-1,1,k)) == 0.0)
then 1249 dhdy = segment%grad_normal(j,1,k)
1252 if (dhdt*dhdx < 0.0) dhdt = 0.0
1253 if (dhdx == 0.0) dhdx=eps
1254 cx = min(dhdt/dhdx,rx_max)
1256 cff = max(dhdx*dhdx, eps)
1258 cff = max(dhdx*dhdx + dhdy*dhdy, eps)
1259 if (dhdy==0.) dhdy=eps
1260 cy = min(cff,max(dhdt/dhdy,-cff))
1262 segment%normal_vel(i,j,k) = ((cff*u_old(i,j,k) + cx*u_new(i+1,j,k)) - &
1263 (max(cy,0.0)*segment%grad_normal(j-1,2,k) + min(cy,0.0)*segment%grad_normal(j,2,k))) / (cff + cx)
1264 elseif (segment%gradient)
then 1265 segment%normal_vel(i,j,k) = u_new(i+1,j,k)
1267 if ((segment%radiation .or. segment%oblique) .and. segment%nudged)
then 1268 if (dhdt*dhdx < 0.0)
then 1269 tau = segment%Tnudge_in
1271 tau = segment%Tnudge_out
1273 segment%normal_vel(i,j,k) = u_new(i,j,k) + dt*tau*(segment%nudged_normal_vel(i,j,k) - u_old(i,j,k))
1280 do k=1,nz ;
do i=segment%HI%isc,segment%HI%iec
1281 if (segment%radiation)
then 1282 dhdt = v_old(i,j-1,k)-v_new(i,j-1,k)
1283 dhdy = v_new(i,j-1,k)-v_new(i,j-2,k)
1285 if (dhdt*dhdy > 0.0) ry_new = min( (dhdt/dhdy), ry_max)
1286 ry_avg = (1.0-gamma_v)*segment%rx_normal(i,j,k) + gamma_v*ry_new
1287 segment%rx_normal(i,j,k) = ry_avg
1288 segment%normal_vel(i,j,k) = (v_old(i,j,k) + ry_avg*v_new(i,j-1,k)) / (1.0+ry_avg)
1289 elseif (segment%oblique)
then 1290 dhdt = v_old(i,j-1,k)-v_new(i,j-1,k)
1291 dhdy = v_new(i,j-1,k)-v_new(i,j-2,k)
1293 if (dhdt*(segment%grad_normal(i,1,k) + segment%grad_normal(i-1,1,k)) > 0.0)
then 1294 dhdx = segment%grad_normal(i-1,1,k)
1295 elseif (dhdt*(segment%grad_normal(i,1,k) + segment%grad_normal(i-1,1,k)) == 0.0)
then 1298 dhdx = segment%grad_normal(i,1,k)
1301 if (dhdt*dhdy < 0.0) dhdt = 0.0
1302 if (dhdy == 0.0) dhdy=eps
1303 cy = min(dhdt/dhdy,rx_max)
1305 cff = max(dhdy*dhdy, eps)
1307 cff = max(dhdx*dhdx + dhdy*dhdy, eps)
1308 if (dhdx==0.) dhdx=eps
1309 cx = min(cff,max(dhdt/dhdx,-cff))
1311 segment%normal_vel(i,j,k) = ((cff*v_old(i,j,k) + cy*v_new(i,j-1,k)) - &
1312 (max(cx,0.0)*segment%grad_normal(i-1,2,k) + min(cx,0.0)*segment%grad_normal(i,2,k))) / (cff + cy)
1313 elseif (segment%gradient)
then 1314 segment%normal_vel(i,j,k) = v_new(i,j-1,k)
1316 if ((segment%radiation .or. segment%oblique) .and. segment%nudged)
then 1317 if (dhdt*dhdy < 0.0)
then 1318 tau = segment%Tnudge_in
1320 tau = segment%Tnudge_out
1322 segment%normal_vel(i,j,k) = v_new(i,j,k) + dt*tau*(segment%nudged_normal_vel(i,j,k) - v_old(i,j,k))
1330 do k=1,nz ;
do i=segment%HI%isc,segment%HI%iec
1331 if (segment%radiation)
then 1332 dhdt = v_old(i,j+1,k)-v_new(i,j+1,k)
1333 dhdy = v_new(i,j+1,k)-v_new(i,j+2,k)
1335 if (dhdt*dhdy > 0.0) ry_new = min( (dhdt/dhdy), ry_max)
1336 ry_avg = (1.0-gamma_v)*segment%rx_normal(i,j,k) + gamma_v*ry_new
1337 segment%rx_normal(i,j,k) = ry_avg
1338 segment%normal_vel(i,j,k) = (v_old(i,j,k) + ry_avg*v_new(i,j+1,k)) / (1.0+ry_avg)
1339 elseif (segment%oblique)
then 1340 dhdt = v_old(i,j+1,k)-v_new(i,j+1,k)
1341 dhdy = v_new(i,j+1,k)-v_new(i,j+2,k)
1343 if (dhdt*(segment%grad_normal(i,1,k) + segment%grad_normal(i-1,1,k)) > 0.0)
then 1344 dhdx = segment%grad_normal(i-1,1,k)
1345 elseif (dhdt*(segment%grad_normal(i,1,k) + segment%grad_normal(i-1,1,k)) == 0.0)
then 1348 dhdx = segment%grad_normal(i,1,k)
1351 if (dhdt*dhdy < 0.0) dhdt = 0.0
1352 if (dhdy == 0.0) dhdy=eps
1353 cy = min(dhdt/dhdy,rx_max)
1355 cff = max(dhdy*dhdy, eps)
1357 cff = max(dhdx*dhdx + dhdy*dhdy, eps)
1358 if (dhdx==0.) dhdx=eps
1359 cx = min(cff,max(dhdt/dhdx,-cff))
1361 segment%normal_vel(i,j,k) = ((cff*v_old(i,j,k) + cy*v_new(i,j+1,k)) - &
1362 (max(cx,0.0)*segment%grad_normal(i-1,2,k) + min(cx,0.0)*segment%grad_normal(i,2,k))) / (cff + cy)
1363 elseif (segment%gradient)
then 1364 segment%normal_vel(i,j,k) = v_new(i,j+1,k)
1366 if ((segment%radiation .or. segment%oblique) .and. segment%nudged)
then 1367 if (dhdt*dhdy < 0.0)
then 1368 tau = segment%Tnudge_in
1370 tau = segment%Tnudge_out
1372 segment%normal_vel(i,j,k) = v_new(i,j,k) + dt*tau*(segment%nudged_normal_vel(i,j,k) - v_old(i,j,k))
1382 call pass_vector(u_new, v_new, g%Domain)
1391 type(ocean_grid_type),
intent(inout) :: G
1392 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: u
1393 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: v
1395 integer :: i, j, k, n
1398 if (.not.
associated(obc))
return 1400 do n=1,obc%number_of_segments
1401 segment => obc%segment(n)
1402 if (.not. segment%on_pe)
then 1404 elseif (segment%radiation .or. segment%oblique .or. segment%gradient)
then 1405 if (segment%is_E_or_W)
then 1407 do k=1,g%ke ;
do j=segment%HI%jsc,segment%HI%jec
1408 u(i,j,k) = segment%normal_vel(i,j,k)
1410 elseif (segment%is_N_or_S)
then 1412 do k=1,g%ke ;
do i=segment%HI%isc,segment%HI%iec
1413 v(i,j,k) = segment%normal_vel(i,j,k)
1425 type(ocean_grid_type),
intent(inout) :: G
1426 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: u
1427 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: v
1429 integer :: i, j, k, n
1432 if (.not.
associated(obc))
return 1434 do n=1,obc%number_of_segments
1435 segment => obc%segment(n)
1436 if (.not. segment%on_pe)
then 1438 elseif (segment%is_E_or_W)
then 1440 do k=1,g%ke ;
do j=segment%HI%jsc,segment%HI%jec
1443 elseif (segment%is_N_or_S)
then 1445 do k=1,g%ke ;
do i=segment%HI%isc,segment%HI%iec
1455 type(ocean_grid_type),
intent(in) :: G
1457 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: uvel
1458 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: vvel
1461 if (.not. segment%on_pe)
return 1463 if (segment%is_E_or_W)
then 1465 if (.not.
ASSOCIATED(segment%grad_normal))
then 1466 allocate(segment%grad_normal(segment%HI%JscB:segment%HI%JecB,2,g%ke))
1472 do j=segment%HI%JscB,segment%HI%JecB
1473 segment%grad_normal(j,1,k) = (uvel(i-1,j+1,k)-uvel(i-1,j,k)) * g%mask2dBu(i-1,j)
1474 segment%grad_normal(j,2,k) = (uvel(i,j+1,k)-uvel(i,j,k)) * g%mask2dBu(i,j)
1480 do j=segment%HI%JscB,segment%HI%JecB
1481 segment%grad_normal(j,1,k) = (uvel(i+1,j+1,k)-uvel(i+1,j,k)) * g%mask2dBu(i+1,j)
1482 segment%grad_normal(j,2,k) = (uvel(i,j+1,k)-uvel(i,j,k)) * g%mask2dBu(i,j)
1486 else if (segment%is_N_or_S)
then 1488 if (.not.
ASSOCIATED(segment%grad_normal))
then 1489 allocate(segment%grad_normal(segment%HI%IscB:segment%HI%IecB,2,g%ke))
1495 do i=segment%HI%IscB,segment%HI%IecB
1496 segment%grad_normal(i,1,k) = (vvel(i+1,j-1,k)-vvel(i,j-1,k)) * g%mask2dBu(i,j-1)
1497 segment%grad_normal(i,2,k) = (vvel(i+1,j,k)-vvel(i,j,k)) * g%mask2dBu(i,j)
1503 do i=segment%HI%IscB,segment%HI%IecB
1504 segment%grad_normal(i,1,k) = (vvel(i+1,j+1,k)-vvel(i,j+1,k)) * g%mask2dBu(i,j+1)
1505 segment%grad_normal(i,2,k) = (vvel(i+1,j,k)-vvel(i,j,k)) * g%mask2dBu(i,j)
1518 type(ocean_grid_type),
intent(inout) :: G
1520 type(thermo_var_ptrs),
intent(inout) :: tv
1521 real,
dimension(SZI_(G),SZJ_(G), SZK_(G)),
intent(inout) :: h
1522 type(param_file_type),
intent(in) :: PF
1523 type(tracer_registry_type),
pointer :: tracer_Reg
1525 integer :: i, j, k, itt, is, ie, js, je, isd, ied, jsd, jed, nz, n
1526 integer :: isd_off, jsd_off
1527 integer :: IsdB, IedB, JsdB, JedB
1529 character(len=40) :: mdl =
"set_tracer_data" 1530 character(len=200) :: filename, OBC_file, inputdir
1532 real :: temp_u(g%domain%niglobal+1,g%domain%njglobal)
1533 real :: temp_v(g%domain%niglobal,g%domain%njglobal+1)
1535 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1536 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1537 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1543 if (
associated(tv%T))
then 1545 call pass_var(tv%T, g%Domain)
1546 call pass_var(tv%S, g%Domain)
1548 do n=1,obc%number_of_segments
1549 segment => obc%segment(n)
1550 if (.not. segment%on_pe) cycle
1552 if (segment%is_E_or_W)
then 1553 if (.not.
ASSOCIATED(segment%T))
then 1554 allocate(segment%T(segment%HI%IsdB,segment%HI%jsd:segment%HI%jed,g%ke))
1555 allocate(segment%S(segment%HI%IsdB,segment%HI%jsd:segment%HI%jed,g%ke))
1557 else if (segment%is_N_or_S)
then 1558 if (.not.
ASSOCIATED(segment%T))
then 1559 allocate(segment%T(segment%HI%isd:segment%HI%ied,segment%HI%JsdB,g%ke))
1560 allocate(segment%S(segment%HI%isd:segment%HI%ied,segment%HI%JsdB,g%ke))
1566 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1567 segment%T(i,j,k) = tv%T(i,j,k)
1568 segment%S(i,j,k) = tv%S(i,j,k)
1572 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1573 segment%T(i,j,k) = tv%T(i+1,j,k)
1574 segment%S(i,j,k) = tv%S(i+1,j,k)
1578 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1579 segment%T(i,j,k) = tv%T(i,j,k)
1580 segment%S(i,j,k) = tv%S(i,j,k)
1584 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1585 segment%T(i,j,k) = tv%T(i,j+1,k)
1586 segment%S(i,j,k) = tv%S(i,j+1,k)
1591 do n=1,obc%number_of_segments
1592 segment => obc%segment(n)
1593 if (.not. segment%on_pe) cycle
1597 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1598 tv%T(i+1,j,k) = tv%T(i,j,k) ; tv%S(i+1,j,k) = tv%S(i,j,k)
1602 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1603 tv%T(i,j,k) = tv%T(i+1,j,k) ; tv%S(i,j,k) = tv%S(i+1,j,k)
1607 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1608 tv%T(i,j+1,k) = tv%T(i,j,k) ; tv%S(i,j+1,k) = tv%S(i,j,k)
1612 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1613 tv%T(i,j,k) = tv%T(i,j+1,k) ; tv%S(i,j,k) = tv%S(i,j+1,k)
1619 do n=1,obc%number_of_segments
1620 segment => obc%segment(n)
1621 if (.not. segment%on_pe) cycle
1625 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1626 h(i+1,j,k) = h(i,j,k)
1630 do k=1,g%ke ;
do j=segment%HI%jsd,segment%HI%jed
1631 h(i,j,k) = h(i+1,j,k)
1635 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1636 h(i,j+1,k) = h(i,j,k)
1640 do k=1,g%ke ;
do i=segment%HI%isd,segment%HI%ied
1641 h(i,j,k) = h(i,j+1,k)
1650 character(len=32),
intent(in) :: field
1651 integer :: lookup_seg_field
1656 do n=1,obc_seg%num_fields
1657 if (trim(field) == obc_seg%field_names(n))
then 1673 integer :: isd, ied, jsd, jed
1674 integer :: IsdB, IedB, JsdB, JedB
1675 character(len=40) :: mdl =
"allocate_OBC_segment_data" 1677 isd = segment%HI%isd ; ied = segment%HI%ied
1678 jsd = segment%HI%jsd ; jed = segment%HI%jed
1679 isdb = segment%HI%IsdB ; iedb = segment%HI%IedB
1680 jsdb = segment%HI%JsdB ; jedb = segment%HI%JedB
1682 if (.not. segment%on_pe)
return 1684 if (segment%is_E_or_W)
then 1686 allocate(segment%Cg(isdb:iedb,jsd:jed)); segment%Cg(:,:)=0.
1687 allocate(segment%Htot(isdb:iedb,jsd:jed)); segment%Htot(:,:)=0.0
1688 allocate(segment%h(isdb:iedb,jsd:jed,obc%ke)); segment%h(:,:,:)=0.0
1689 allocate(segment%eta(isdb:iedb,jsd:jed)); segment%eta(:,:)=0.0
1690 allocate(segment%normal_trans_bt(isdb:iedb,jsd:jed)); segment%normal_trans_bt(:,:)=0.0
1691 allocate(segment%rx_normal(isdb:iedb,jsd:jed,obc%ke)); segment%rx_normal(:,:,:)=0.0
1692 allocate(segment%normal_vel(isdb:iedb,jsd:jed,obc%ke)); segment%normal_vel(:,:,:)=0.0
1693 allocate(segment%normal_vel_bt(isdb:iedb,jsd:jed)); segment%normal_vel_bt(:,:)=0.0
1694 allocate(segment%normal_trans(isdb:iedb,jsd:jed,obc%ke)); segment%normal_trans(:,:,:)=0.0
1695 if (segment%nudged)
then 1696 allocate(segment%nudged_normal_vel(isdb:iedb,jsd:jed,obc%ke)); segment%nudged_normal_vel(:,:,:)=0.0
1700 if (segment%is_N_or_S)
then 1702 allocate(segment%Cg(isd:ied,jsdb:jedb)); segment%Cg(:,:)=0.
1703 allocate(segment%Htot(isd:ied,jsdb:jedb)); segment%Htot(:,:)=0.0
1704 allocate(segment%h(isd:ied,jsdb:jedb,obc%ke)); segment%h(:,:,:)=0.0
1705 allocate(segment%eta(isd:ied,jsdb:jedb)); segment%eta(:,:)=0.0
1706 allocate(segment%normal_trans_bt(isd:ied,jsdb:jedb)); segment%normal_trans_bt(:,:)=0.0
1707 allocate(segment%rx_normal(isd:ied,jsdb:jedb,obc%ke)); segment%rx_normal(:,:,:)=0.0
1708 allocate(segment%normal_vel(isd:ied,jsdb:jedb,obc%ke)); segment%normal_vel(:,:,:)=0.0
1709 allocate(segment%normal_vel_bt(isd:ied,jsdb:jedb)); segment%normal_vel_bt(:,:)=0.0
1710 allocate(segment%normal_trans(isd:ied,jsdb:jedb,obc%ke)); segment%normal_trans(:,:,:)=0.0
1711 if (segment%nudged)
then 1712 allocate(segment%nudged_normal_vel(isd:ied,jsdb:jedb,obc%ke)); segment%nudged_normal_vel(:,:,:)=0.0
1722 type(ocean_grid_type),
intent(in) :: G
1724 real,
dimension(SZIB_(G),SZJ_(G), SZK_(G)),
intent(inout) :: u
1725 real,
dimension(SZI_(G),SZJB_(G), SZK_(G)),
intent(inout) :: v
1727 integer :: i, j, k, n
1728 real,
parameter :: silly_value = 1.e40
1730 if (.not.
associated(obc))
return 1732 do n = 1, obc%number_of_segments
1734 if (obc%segment(n)%is_N_or_S)
then 1735 j = obc%segment(n)%HI%JsdB
1737 do i = obc%segment(n)%HI%IsdB, obc%segment(n)%HI%IedB
1738 u(i,j+1,k) = silly_value
1741 do i = obc%segment(n)%HI%IsdB, obc%segment(n)%HI%IedB
1742 u(i,j,k) = silly_value
1745 elseif (obc%segment(n)%is_E_or_W)
then 1746 i = obc%segment(n)%HI%IsdB
1748 do j = obc%segment(n)%HI%JsdB, obc%segment(n)%HI%JedB
1749 v(i+1,j,k) = silly_value
1752 do j = obc%segment(n)%HI%JsdB, obc%segment(n)%HI%JedB
1753 v(i,j,k) = silly_value
1766 type(ocean_grid_type),
intent(in) :: G
1768 real,
dimension(SZI_(G),SZJ_(G), SZK_(G)),
intent(inout) :: h
1770 integer :: i, j, k, n
1771 real,
parameter :: silly_value = 1.e40
1773 if (.not.
associated(obc))
return 1775 do n = 1, obc%number_of_segments
1777 if (obc%segment(n)%is_N_or_S)
then 1778 j = obc%segment(n)%HI%JsdB
1780 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1781 h(i,j+1,k) = silly_value
1784 do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1785 h(i,j,k) = silly_value
1788 elseif (obc%segment(n)%is_E_or_W)
then 1789 i = obc%segment(n)%HI%IsdB
1791 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
1792 h(i+1,j,k) = silly_value
1795 do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
1796 h(i,j,k) = silly_value
1807 type(ocean_grid_type),
intent(in) :: G
1808 type(verticalgrid_type),
intent(in) :: GV
1810 type(thermo_var_ptrs),
intent(in) :: tv
1811 real,
dimension(SZI_(G),SZJ_(G), SZK_(G)),
intent(inout) :: h
1814 type(time_type),
intent(in) :: Time
1817 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed
1818 integer :: IsdB, IedB, JsdB, JedB, n, m, nz
1819 character(len=40) :: mdl =
"set_OBC_segment_data" 1820 character(len=200) :: filename, OBC_file, inputdir
1822 integer,
dimension(4) :: siz,siz2
1824 integer :: ni_seg, nj_seg
1826 integer :: is_obc, ie_obc, js_obc, je_obc
1827 integer :: ishift, jshift
1828 real,
dimension(:,:),
pointer :: seg_vel => null()
1829 real,
dimension(:,:),
pointer :: seg_trans => null()
1830 real,
dimension(:,:,:),
allocatable :: tmp_buffer
1832 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1833 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1834 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1837 if (.not.
associated(obc))
return 1839 do n = 1, obc%number_of_segments
1840 segment => obc%segment(n)
1842 if (.not. segment%on_pe) cycle
1844 ni_seg = segment%ie_obc-segment%is_obc+1
1845 nj_seg = segment%je_obc-segment%js_obc+1
1846 is_obc = max(segment%is_obc,isd-1)
1847 ie_obc = min(segment%ie_obc,ied)
1848 js_obc = max(segment%js_obc,jsd-1)
1849 je_obc = min(segment%je_obc,jed)
1852 if (segment%is_E_or_W)
then 1871 if (segment%is_E_or_W)
then 1874 do j=segment%HI%jsd,segment%HI%jed
1875 segment%Cg(i,j) = sqrt(gv%g_prime(1)*g%bathyT(i+ishift,j))
1877 segment%Htot(i,j) = g%bathyT(i+ishift,j)*gv%m_to_H
1882 segment%h(i,j,k) = h(i+ishift,j,k)
1890 do i=segment%HI%isd,segment%HI%ied
1891 segment%Cg(i,j) = sqrt(gv%g_prime(1)*g%bathyT(i,j+jshift))
1893 segment%Htot(i,j) = g%bathyT(i,j+jshift)*gv%m_to_H
1898 segment%h(i,j,k) = h(i,j+jshift,k)
1904 do m = 1,segment%num_fields
1905 if (segment%field(m)%fid > 0)
then 1906 siz(1)=
size(segment%field(m)%buffer_src,1)
1907 siz(2)=
size(segment%field(m)%buffer_src,2)
1908 siz(3)=
size(segment%field(m)%buffer_src,3)
1909 if (.not.
associated(segment%field(m)%buffer_dst))
then 1910 if (siz(3) /= segment%field(m)%nk_src)
call mom_error(fatal,
'nk_src inconsistency')
1911 if (segment%field(m)%nk_src > 1)
then 1912 allocate(segment%field(m)%buffer_dst(is_obc:ie_obc,js_obc:je_obc,g%ke))
1914 allocate(segment%field(m)%buffer_dst(is_obc:ie_obc,js_obc:je_obc,1))
1916 segment%field(m)%buffer_dst(:,:,:)=0.0
1917 if (trim(segment%field(m)%name) ==
'U' .or. trim(segment%field(m)%name) ==
'V')
then 1918 allocate(segment%field(m)%bt_vel(is_obc:ie_obc,js_obc:je_obc))
1919 segment%field(m)%bt_vel(:,:)=0.0
1924 allocate(tmp_buffer(1,nj_seg*2+1,segment%field(m)%nk_src))
1926 allocate(tmp_buffer(ni_seg*2+1,1,segment%field(m)%nk_src))
1929 call time_interp_external(segment%field(m)%fid,time, tmp_buffer)
1931 segment%field(m)%buffer_src(is_obc,:,:)=tmp_buffer(1,2*(js_obc+g%jdg_offset)-1:2*(je_obc+g%jdg_offset)-1:2,:)
1933 segment%field(m)%buffer_src(:,js_obc,:)=tmp_buffer(2*(is_obc+g%idg_offset)-1:2*(ie_obc+g%idg_offset)-1:2,1,:)
1935 if (segment%field(m)%nk_src > 1)
then 1936 call time_interp_external(segment%field(m)%fid_dz,time, tmp_buffer)
1938 segment%field(m)%dz_src(is_obc,:,:)=tmp_buffer(1,2*(js_obc+g%jdg_offset)-1:2*(je_obc+g%jdg_offset)-1:2,:)
1940 segment%field(m)%dz_src(:,js_obc,:)=tmp_buffer(2*(is_obc+g%idg_offset)-1:2*(ie_obc+g%idg_offset)-1:2,1,:)
1947 segment%field(m)%buffer_dst(i,j,:)=0.0
1948 if (g%mask2dT(i,j)>0.)
then 1949 call remapping_core_h(obc%remap_CS, &
1950 segment%field(m)%nk_src,segment%field(m)%dz_src(i,j,:), &
1951 segment%field(m)%buffer_src(i,j,:), &
1952 g%ke, h(i,j,:), segment%field(m)%buffer_dst(i,j,:))
1957 segment%field(m)%buffer_dst(:,:,1)=segment%field(m)%buffer_src(:,:,1)
1959 deallocate(tmp_buffer)
1961 if (.not.
ASSOCIATED(segment%field(m)%buffer_dst))
then 1962 allocate(segment%field(m)%buffer_dst(is_obc:ie_obc,js_obc:je_obc,g%ke))
1963 segment%field(m)%buffer_dst(:,:,:)=segment%field(m)%value
1964 if (trim(segment%field(m)%name) ==
'U' .or. trim(segment%field(m)%name) ==
'V')
then 1965 allocate(segment%field(m)%bt_vel(is_obc:ie_obc,js_obc:je_obc))
1966 segment%field(m)%bt_vel(:,:)=segment%field(m)%value
1971 if (trim(segment%field(m)%name) ==
'U' .or. trim(segment%field(m)%name) ==
'V')
then 1972 if (segment%field(m)%fid>0)
then 1973 if((trim(segment%field(m)%name) ==
'U' .and. segment%is_E_or_W) .or. &
1974 (trim(segment%field(m)%name) ==
'V' .and. segment%is_N_or_S))
then 1977 segment%normal_trans_bt(i,j) = 0.0
1979 segment%normal_vel(i,j,k) = segment%field(m)%buffer_dst(i,j,k)
1980 segment%normal_trans(i,j,k) = segment%field(m)%buffer_dst(i,j,k)*segment%h(i,j,k)
1981 segment%normal_trans_bt(i,j)= segment%normal_trans_bt(i,j)+segment%normal_trans(i,j,k)
1983 segment%normal_vel_bt(i,j) = segment%normal_trans_bt(i,j)/max(segment%Htot(i,j),1.e-12)
1984 if (
associated(segment%nudged_normal_vel)) segment%nudged_normal_vel(i,j,:) = segment%normal_vel(i,j,:)
1991 if (trim(segment%field(m)%name) ==
'SSH')
then 1994 segment%eta(i,j) = segment%field(m)%buffer_dst(i,j,1)
2006 character(len=32),
intent(in) :: name
2007 type(param_file_type),
intent(in) :: param_file
2010 character(len=256) :: mesg
2014 if (reg%nobc>=max_fields_)
then 2015 write(mesg,
'("Increase MAX_FIELDS_ in MOM_memory.h to at least ",I3," to allow for & 2016 &all the open boundaries being registered via register_OBC.")') reg%nobc+1
2017 call mom_error(fatal,
"MOM register_tracer: "//mesg)
2019 reg%nobc = reg%nobc + 1
2022 reg%OB(nobc)%name = name
2024 if (reg%locked)
call mom_error(fatal, &
2025 "MOM register_tracer was called for variable "//trim(reg%OB(nobc)%name)//&
2026 " with a locked tracer registry.")
2032 type(param_file_type),
intent(in) :: param_file
2035 integer,
save :: init_calls = 0
2037 #include "version_variable.h" 2038 character(len=40) :: mdl =
"MOM_open_boundary" 2039 character(len=256) :: mesg
2041 if (.not.
associated(reg))
then ;
allocate(reg)
2042 else ;
return ;
endif 2047 init_calls = init_calls + 1
2048 if (init_calls > 1)
then 2049 write(mesg,
'("OBC_registry_init called ",I3, & 2050 &" times with different registry pointers.")') init_calls
2051 if (is_root_pe())
call mom_error(warning,
"MOM_open_boundary"//mesg)
2058 type(param_file_type),
intent(in) :: param_file
2061 logical :: register_file_OBC
2062 character(len=32) :: casename =
"OBC file" 2064 if (
associated(cs))
then 2065 call mom_error(warning,
"register_file_OBC called with an "// &
2066 "associated control structure.")
2073 register_file_obc = .true.
2081 if (
associated(cs))
then Open boundary segment data from files (mostly).
integer, parameter, public obc_direction_s
Indicates the boundary is an effective southern boundary.
integer, parameter, public obc_direction_w
Indicates the boundary is an effective western boundary.
integer, parameter, public obc_direction_n
Indicates the boundary is an effective northern boundary.
character(len=3), public remappingdefaultscheme
Default remapping method.
Methods for testing for, and list of, obsolete run-time parameters.
subroutine open_boundary_dealloc(OBC)
Deallocate open boundary data.
subroutine initialize_segment_data(G, OBC, PF)
subroutine parse_segment_data_str(segment_str, var, value, filenam, fieldnam, fields, num_fields, debug)
Parse an OBC_SEGMENT_%%_DATA string.
subroutine, public file_obc_end(CS)
Clean up the file OBC from registry.
integer, parameter, public to_all
character(len=120) function, public extract_word(string, separators, n)
Returns the string corresponding to the nth word in the argument or "" if the string is not long enou...
subroutine setup_segment_indices(G, seg, Is_obc, Ie_obc, Js_obc, Je_obc)
Ocean grid type. See mom_grid for details.
subroutine, public open_boundary_test_extern_h(G, OBC, h)
Set thicknesses outside of open boundaries to silly values (used for checking the interior state is i...
Provides the ocean grid type.
Open boundary segment data structure.
Generates vertical grids as part of the ALE algorithm.
character(len=256), public remappingschemesdoc
Documentation for external callers.
Provides column-wise vertical remapping functions.
subroutine, public register_obc(name, param_file, Reg)
register open boundary objects for boundary updates.
subroutine, public open_boundary_config(G, param_file, OBC)
Enables OBC module and reads configuration parameters This routine is called from MOM_initialize_fixe...
This module contains I/O framework code.
subroutine allocate_obc_segment_data(OBC, segment)
Allocate segment data fields.
logical function, public open_boundary_query(OBC, apply_open_OBC, apply_specified_OBC, apply_Flather_OBC, apply_nudged_OBC, needs_ext_seg_data)
integer function lookup_seg_field(OBC_seg, field)
subroutine, public open_boundary_impose_normal_slope(OBC, G, depth)
Sets the slope of bathymetry normal to an open bounndary to zero.
subroutine, public open_boundary_apply_normal_flow(OBC, G, u, v)
Applies OBC values stored in segments to 3d u,v fields.
logical function, public register_file_obc(param_file, CS, OBC_Reg)
Add file to OBC registry.
Container for remapping parameters.
subroutine, public update_obc_segment_data(G, GV, OBC, tv, h, Time)
Update the OBC values on the segments.
integer, parameter, public obc_simple
subroutine, public open_boundary_end(OBC)
Close open boundary data.
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
integer, parameter, public obc_flather
subroutine, public obc_registry_init(param_file, Reg)
This routine include declares and sets the variable "version".
Regridding control structure.
subroutine setup_v_point_obc(OBC, G, segment_str, l_seg)
Parse an OBC_SEGMENT_%%% string starting with "J=" and configure placement and type of OBC accordingl...
Type to carry basic OBC information needed for updating values.
subroutine, public open_boundary_zero_normal_flow(OBC, G, u, v)
Applies zero values to 3d u,v fields on OBC segments.
subroutine gradient_at_q_points(G, segment, uvel, vvel)
Calculate the tangential gradient of the normal flow at the boundary q-points.
Type to carry something (what] for the OBC registry.
subroutine, public obsolete_int(param_file, varname, warning_val, hint)
Test for presence of obsolete INTEGER in parameter file.
Type to carry basic tracer information.
subroutine, public radiation_open_bdry_conds(OBC, u_new, u_old, v_new, v_old, G, dt)
Apply radiation conditions to 3D u,v at open boundaries.
subroutine, public open_boundary_init(G, param_file, OBC)
Initialize open boundary control structure.
logical function, public is_root_pe()
subroutine, public add_tracer_obc_values(name, Reg, OBC_inflow, OBC_in_u, OBC_in_v)
This subroutine adds open boundary condition concentrations for a tracer that has previously been reg...
subroutine parse_segment_str(ni_global, nj_global, segment_str, l, m, n, action_str)
Parse an OBC_SEGMENT_%%% string.
subroutine setup_u_point_obc(OBC, G, segment_str, l_seg)
Parse an OBC_SEGMENT_%%% string starting with "I=" and configure placement and type of OBC accordingl...
character(len=120) function, public remove_spaces(string)
Returns string with all spaces removed.
subroutine, public mom_mesg(message, verb, all_print)
integer, parameter max_obc_fields
Maximum number of data fields needed for OBC segments.
integer, parameter, public obc_direction_e
Indicates the boundary is an effective eastern boundary.
subroutine, public end_remapping(CS)
Destrcutor for remapping control structure.
Control structure for open boundaries that read from files. Probably lots to update here...
subroutine, public remapping_core_h(CS, n0, h0, u0, n1, h1, u1)
Remaps column of values u0 on grid h0 to grid h1 assuming the top edge is aligned.
integer, parameter, public obc_wall
subroutine, public obsolete_char(param_file, varname, hint)
Test for presence of obsolete STRING in parameter file.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
integer, parameter, public obc_none
Controls where open boundary conditions are applied.
subroutine, public initialize_remapping(CS, remapping_scheme, boundary_extrapolation, check_reconstruction, check_remapping, force_bounds_in_subcell)
Constructor for remapping control structure.
subroutine, public open_boundary_test_extern_uv(G, OBC, u, v)
Set tangential velocities outside of open boundaries to silly values (used for checking the interior ...
subroutine, public set_tracer_data(OBC, tv, h, G, PF, tracer_Reg)
Sets the initial values of the tracer and h open boundary conditions. Also allocates and fills the se...
subroutine, public open_boundary_impose_land_mask(OBC, G, areaCu, areaCv)
Reconcile masks and open boundaries, deallocate OBC on PEs where it is not needed. Also adjust u- and v-point cell area on specified open boundaries.
subroutine, public mom_error(level, message, all_print)
subroutine, public obsolete_logical(param_file, varname, warning_val, hint)
Test for presence of obsolete LOGICAL in parameter file.
integer function interpret_int_expr(string, imax)
subroutine, public obsolete_real(param_file, varname, warning_val, hint)
Test for presence of obsolete REAL in parameter file.
integer, parameter, public obc_radiation