Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coupler mixed precision #1353

Merged
merged 42 commits into from
Aug 30, 2023
Merged

Conversation

rem1776
Copy link
Contributor

@rem1776 rem1776 commented Aug 23, 2023

Description
Adds mixed precision support for the coupler subdirectory.

Majority of the changes are in coupler_types since it uses a few encapsulated types for 1-3 dimensional fields. The atmos_ocean_fluxes module has changes when needed to interact with the right type but does not take any required real arguments. Ensemble manager does not use reals (or the rest of this subdirectory) at all, so no changes have been made.

I noticed that in the FMScoupler only the coupler_Nd_bc_type is used so the r4/r8 split happens within it via the bc and bc_r4 members. This should be less disruptive for other codes using this type since theres nothing being removed for the most part, just the r4 stuff being added and used if needed.

Because the r4/r8 divide happens within the type, most routines that don't take reals just check which type has been associated (bc or bc_r4) and then use whats appropriate.

Fixes # (issue)

How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Please also note
any relevant details for your test configuration (e.g. compiler, OS). Include
enough information so someone can reproduce your tests.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published in downstream modules
  • New check tests, if applicable, are included
  • make distcheck passes

coupler/coupler_types.F90 Outdated Show resolved Hide resolved
coupler/coupler_types.F90 Outdated Show resolved Hide resolved
coupler/coupler_types.F90 Outdated Show resolved Hide resolved
coupler/coupler_types.F90 Outdated Show resolved Hide resolved
coupler/coupler_types.F90 Show resolved Hide resolved
logical, intent(in), dimension(:), optional :: flag !< flag
real, intent(in), optional :: mol_wt !< mol_wt
real(r8_kind), intent(in), optional :: mol_wt !< mol_wt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it'd be better if mol_wt was a class(*) here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's where it ends up being used in this routine:

if (present(mol_wt)) then
call fm_util_set_value('mol_wt', mol_wt)
else
call fm_util_set_value('mol_wt', 0.0)
endif

But then also again here:

gas_fluxes%bc(n)%mol_wt = fm_util_get_real('mol_wt', scalar = .true.)

I think fm_util_get_real is r8_kind only right cause of the read in strings?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that and because there was no way to tell what precision the user wanted based on the input arguments. I'm wondering if the users will pass in r4_kind mol_wt here because they're assuming that the r4 version of bc will be populated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah to be safe I'll switch it over to a class(*), since it's intent(in) should be fine.

gas_fluxes%bc_r4(n)%atm_tr_index = fm_util_get_integer('atm_tr_index', scalar = .true.)

! Save the molecular weight.
gas_fluxes%bc_r4(n)%mol_wt = fm_util_get_real('mol_wt', scalar = .true.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a real,r4_kind) around fm_util_get_real? I think fm_util_get_real returns an r8_kind

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just left the mol_wt and param fields as r8_kind regardless, this way they are always the value returned by the field manager.

allocate (gas_fluxes%bc(gas_fluxes%num_bcs))
allocate (gas_fields_atm%bc(gas_fields_atm%num_bcs))
allocate (gas_fields_ice%bc(gas_fields_ice%num_bcs))
if(present(use_r4_kind)) use_r4_kind_loc = use_r4_kind
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if this should go on top before the while loop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean, I have this if for allocation here and then the while loop below has another if within it for the parts that use reals.

@@ -424,7 +424,7 @@ end function aof_set_coupler_flux
!! @throw FATAL, "Num_flags is negative for [name]: [num_flags]"
!! @throw FATAL, "Problem dumping fluxes tracer tree"
!! @throw FATAL, "Number of fluxes does not match across the processors: [gas_fluxes%num_bcs] fluxes"
subroutine atmos_ocean_fluxes_init(gas_fluxes, gas_fields_atm, gas_fields_ice, verbosity)
subroutine atmos_ocean_fluxes_init(gas_fluxes, gas_fields_atm, gas_fields_ice, verbosity, use_r4_kind)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think there will be a case where the user wants these three fluxes to be set at different precisions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know honestly. It could be added using similar logic later on if we need it.

@@ -412,6 +562,9 @@ subroutine coupler_type_copy_1d_2d(var_in, var_out, is, ie, js, je,&
call mpp_error(FATAL, trim(error_header) // ' Number of output fields exceeds zero')
endif

if(associated(var_in%bc) .eq. associated(var_in%bc_r4)) &
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could there be a chance both are unassociated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah definitely, thats why its comparing the logical return values. If they are both associated or both not associated it will error out, this way it'll ensure that the r4/r8 field types used are mutually exclusive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code, the bc's could intentionally be not associated

Copy link
Contributor Author

@rem1776 rem1776 Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the previous code would seg fault if you did that, these routines all essentially assume the child type is previously allocated for intent(in) types. edit: i was wrong, its only allocated when num_bc > 0. the loops that use bc/bc_r4 just don't run otherwise.

Copy link
Contributor Author

@rem1776 rem1776 Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put in a fix, the check for allocation needed to be after the checks for the optional as_needed argument. I also made updates so that it'll only check for one kind allocated if var%set is true since it indicates initialization.

& var%bc(n)%field(m)%name, axes(1:3), Time,&
& var%bc(n)%field(m)%long_name, var%bc(n)%field(m)%units )
if(var%set) then
if(associated(var%bc) .eqv. associated(var%bc_r4)) &
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you missed one lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be all done now

@@ -625,6 +783,12 @@ subroutine CT_spawn_1d_2d(var_in, var, idim, jdim, suffix, as_needed)
if (.not.var_in%set)&
& call mpp_error(FATAL, trim(error_header) // ' The parent type has not been initialized.')

! check only one kind is used
if(var_in%set .and. var_in%num_bcs .gt. 0) then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the var_in%set needed here since it's checked above? (not that it significantly matters)

Copy link
Contributor Author

@rem1776 rem1776 Aug 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope (at least for the spawn routines), took these out with 27c6e87

@mlee03
Copy link
Contributor

mlee03 commented Aug 29, 2023

@rem1776 could you add @mcallic2 and @J-Lentz as reviewers?

do i=var%isc-halo,var%iec+halo
var%bc(n)%field(m)%values(i,j) = var_in%bc(n)%field(m)%values(i+i_off,j+j_off)
! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
if (associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be clearer if var_in%num_bcs .lt. n1?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also wondering if var_in%num_bcs.lt.1 should be separated into its own if else block for clarity

Copy link
Contributor Author

@rem1776 rem1776 Aug 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this is a little more clear. Some code within these is outside of loops so needs to run if either part of the conditional is true, otherwise will have to be repeated. could change the logic to use an .and. instead, but that would be more confusing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this need to be merged with the current mixedmode branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be updated, i left that one line deletion in axis utils cause that extra line will mess with the documentation parser.

@@ -319,6 +319,7 @@ foreach(kind ${kinds})
time_interp/include
tracer_manager/include
interpolator/include
coupler/include
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there one more place to add coupler/include?

@mlee03
Copy link
Contributor

mlee03 commented Aug 30, 2023

YAY! 🥳

@rem1776 rem1776 merged commit 3dbcd7e into NOAA-GFDL:mixedmode Aug 30, 2023
19 checks passed
rem1776 added a commit that referenced this pull request Sep 20, 2023
BREAKING CHANGE: In coupler_types.F90,  `coupler_nd_field_type` and `coupler_nd_values_type` have been renamed to indicate real kind value: `coupler_nd_real4/8_field_type` and `coupler_nd_real4/8_values_type`. The `bc` field within `coupler_nd_bc_type` was modified to use r8_kind within the value and field types, and an additional field added `bc_r4` to use r4_kind values.

Includes:

* feat: eliminate use of real numbers for mixed precision in `block_control` (#1195)

* feat: mixed precision field_manager  (#1205)

* feat: mixed precision random_numbers_mod (#1191)

* feat: mixed precision time_manager reals to r8 and clean up (#1196)

* feat: mixed Precision tracer_manager  (#1212)

* Mixed precision monin_obukhov (#1116)

* Mixed precision: `monin_obukhov` unit tests (#1272)

* mixed-precision diag_integral_mod  (#1217)

* mixed precision time_interp (#1252)

* mixed precision interpolator_mod  (#1305)

* Mixed precision astronomy (#1092)

* Mixed precision `data_override_mod` (#1323)

* mixed precision exchange (#1341)

* coupler mixed precision (#1353)

* Mixed precision topography_mod (#1250)

---------

Co-authored-by: rem1776 <[email protected]>
Co-authored-by: MiKyung Lee <[email protected]>
Co-authored-by: mlee03 <[email protected]>
Co-authored-by: Caitlyn McAllister <[email protected]>
Co-authored-by: Jesse Lentz <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants