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

Refactor optional argument implementation for isotopes, snwgrain, therm1 and therm2 #423

Merged
merged 4 commits into from
Jan 24, 2023

Conversation

apcraig
Copy link
Contributor

@apcraig apcraig commented Jan 11, 2023

PR checklist

- Use argcheck design
- Eliminate local copies of optional data
- Pass optional arguments down the calling tree
- Some minor format cleanup
@apcraig
Copy link
Contributor Author

apcraig commented Jan 11, 2023

This refactors the isotope implementation using the newer design, passing optional arguments down the calling tree and using the argcheck design. If this seems reasonable, I will refactor other Icepack features in a similar way where reasonable. Do we want a PR for each feature refactor or just one (or a few) PRs to cover multiple feature refactors? Would like to get some feedback before moving forward.

This should be bit-for-bit and has no impact on the public interfaces. Will run comprehensive tests to confirm TBD.

Copy link
Contributor

@dabail10 dabail10 left a comment

Choose a reason for hiding this comment

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

Sorry for not responding to the email. This looks fine to me.

uvel=l_uvel, vvel=l_vvel, &
Uref=l_Uref, zlvs=zlvs)
Qa_iso=Qa_iso, &
Qref_iso=Qref_iso, &
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if present(Qref_iso)=F? Is this robust across all compilers/platforms? You probably tested that previously...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is robust. The optional attribute and "present" state is passed down the calling tree. As long as optional is set in the calling routine for this field if want to check it's "present" state (determined by the original caller) and/or the optional argument is not used unless it exists, all should be fine. You can definitely get into trouble if you pass the optional argument down the calling tree and use it if it wasn't passed. Hopefully, we'll avoid that with the logic we have setup.

columnphysics/icepack_mechred.F90 Outdated Show resolved Hide resolved
@eclare108213
Copy link
Contributor

Do we want a PR for each feature refactor or just one (or a few) PRs to cover multiple feature refactors?

One or a few to cover multiple features would be fine, but if something is particularly complicated, then just do that by itself. E.g. I imagine that the thermodynamics will be complicated, since there are many options that feed into it.

…ocn, H2_16O_ocn, H2_18O_ocn

- Modify fsloss optional argument implementation
- Modify rsnwn, smicen, smliqn optional argument implementation
@apcraig apcraig marked this pull request as ready for review January 14, 2023 18:10
@apcraig
Copy link
Contributor Author

apcraig commented Jan 14, 2023

I think it may be worth reviewing and merging this now. Most of the therm1 and therm2 optional arguments have been refactored. Still waiting on some additional insight about meltsliq, but that can be done in a separate PR.

@apcraig apcraig changed the title Refactor isotope implementation with respect to optional arguments Refactor optional argument implementation for isotopes, snwgrain, therm1 and therm2 Jan 16, 2023
@apcraig
Copy link
Contributor Author

apcraig commented Jan 16, 2023

Icepack and CICE test suites are bit-for-bit.

Comment on lines 904 to 907
!------------------------------------------------------------
! Check optional arguments
! This is used for ocean and ice sfctype, need to be careful
!------------------------------------------------------------
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I understand this comment, why does it say

This is used for ocean and ice sfctype

but then we just check sfctype == 'ice' ? What is "This" referring to?

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 atmo_boundary_layer is also called from the ocean mixed layer routine, in which case the surface type that the atmosphere sees is ocean instead of ice. The mixed layer routine is not used for coupled simulations, usually, and isotopes might not be implemented in a separate ocean component model, which would then require some care 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.

I need to clean up this comment.

@phil-blain
Copy link
Member

This refactors the isotope implementation using the newer design, passing optional arguments down the calling tree and using the argcheck design. If this seems reasonable, I will refactor other Icepack features in a similar way where reasonable.

I think this is a nice clean up, it improves readability, I think. Also, gotta love a PR that removes more lines of code than it adds ;)

Do we want a PR for each feature refactor or just one (or a few) PRs to cover multiple feature refactors? Would like to get some feedback before moving forward.

If I were doing it, I think I would probably do it that way:

  • 1 PR per module (so 1 per file)
  • In each PR, one commit per subroutine: removing l_* local variable, using argcheck to validate arguments, and adjusting calls to other subroutines if need be.

This would be very much more pleasant to review, at least for me :)

Also I would avoid changing the order of the variables attributes (like moving optional to be the last attributes, with no other changes). This adds a lot of noise to the diffs. If we want to make such changes, that's OK, but I'd prefer if it were done in separate commits.

Thanks a lot for starting the work on this! :)

!------------------------------------------------------------

if (sfctype == 'ice') then
if (argcheck == 'always' .or. (argcheck == 'first' .and. first_call_ice)) then
Copy link
Member

Choose a reason for hiding this comment

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

The logic in this line is duplicated a few times. Would it make sense to isolate it to a function somewhere ? Then we could use that function instead of the argcheck variable.

The function could receive that boolean fist_call (or here first_call_ice) as argument and return a boolean...

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 think that's a good idea, I'll take care of it.

Copy link
Contributor

@eclare108213 eclare108213 left a comment

Choose a reason for hiding this comment

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

Just a few comments and questions -

I do worry a bit about Phil's comment here, regarding non-Fortran codes being able to use Icepack with Fortran keywords and optional arguments. What should we do about that?

do n = 1, n_iso
ratio = c0
if (Qa_iso(2) > puny) ratio = Qa_iso(n)/Qa_iso(2)
Qref_iso(n) = Qa_iso(n) - ratio*delq*fac
Copy link
Contributor

Choose a reason for hiding this comment

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

Farther down in the comments for this module, you say

You can definitely get into trouble if you pass the optional argument down the calling tree and use it if it wasn't passed.

So are Qa_iso and Qref_iso safe to use here without checking their 'present' status because the call to this subroutine isn't the first call in which those arguments are declared optional? It appears that you are checking it in what would be the first call into icepack, icepack_atm_boundary. Is there some easy way to track when an optional argument needs to be checked 'if present' and when it doesn't? It's probably not as simple as just checking in icepack's interface routines.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right, we have already checked the arguments in the highest level Icepack interface. So they are safe to use here without checking. That's our current design. As I mentioned the other day, there are pros and cons to doing it this way. A pro is that we check all the optional arguments early leveraging parameter flags and then we should be OK after that without having to check over and over. A negative is that you have to keep track of what's going on in different layers of the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, thank you.

Comment on lines 904 to 907
!------------------------------------------------------------
! Check optional arguments
! This is used for ocean and ice sfctype, need to be careful
!------------------------------------------------------------
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 atmo_boundary_layer is also called from the ocean mixed layer routine, in which case the surface type that the atmosphere sees is ocean instead of ice. The mixed layer routine is not used for coupled simulations, usually, and isotopes might not be implemented in a separate ocean component model, which would then require some care here.

@@ -1194,6 +1194,7 @@ subroutine drain_snow (nslyr, vsnon, aicen, &
else
sliq = meltsliq ! computed in thickness_changes
endif
!tcx??
meltsliq = meltsliq
Copy link
Contributor

Choose a reason for hiding this comment

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

This line can be commented out. This section of the code was rewritten a bit and corrected, and this line was the logical culmination of that process.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we want a PR for each feature refactor or just one (or a few) PRs to cover multiple feature refactors? Would like to get some feedback before moving forward.

If I were doing it, I think I would probably do it that way:

* 1 PR per module (so 1 per file)

* In each PR, one commit per subroutine: removing `l_*` local variable, using `argcheck` to validate arguments, and adjusting calls to other subroutines if need be.

I don't think 1 PR per module will work well. The optional argument checking will depend on the underlying implementation and that needs to be coordinated. Removing the l_ variables might result in further optimizations down the calling tree. So maybe 1 PR per feature. I also understand about general cleanup (formatting) with updating features. I agree, it's just hard not to fix things when I see an opportunity, and I'm worried I may not circle back if I don't. I'll try to be more careful.

@@ -1852,15 +1853,15 @@ subroutine add_new_ice (ncat, nilyr, &
enddo
endif

frazil_conc = c0
Copy link
Contributor

Choose a reason for hiding this comment

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

This line is still present in a similar section of code, above. The code is hard-wired for n_iso=3, apparently, so maybe this line should stay in case for some reason n_iso > 3?

(present(fswthru_vdf) .and. .not.present(fswthrun_vdf)) .or. &
(present(fswthru_idr) .and. .not.present(fswthrun_idr)) .or. &
(present(fswthru_idf) .and. .not.present(fswthrun_idf))) then
call icepack_warnings_add(subname//' error in fswthru [iv]d[rf] arguments')
Copy link
Contributor

Choose a reason for hiding this comment

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

@apcraig @dabail10 Is this the logic we want here? Often it's fine to have category-aggregated variables and not keep the category-specific ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's really the underlying implementation. The implementation in Icepack with this update will always computed the aggregated variables if they are passed, and that requires the category specific arguments too. We could change the implementation so both have to be passed for the category aggregate to be computed. The optional argument checking is determined to a large degree on the underlying implementation.

@apcraig
Copy link
Contributor Author

apcraig commented Jan 17, 2023

Just a few comments and questions -

I do worry a bit about Phil's comment here, regarding non-Fortran codes being able to use Icepack with Fortran keywords and optional arguments. What should we do about that?

One option is for the non-Fortran interfaces to NOT adopt the optional arguments in their interfaces/uses. So non-Fortran might pass all arguments even if they are not needed. I don't actually know whether that will work for all languages, but we should explore as an appropriate time. I think for now, we should continue to add optional arguments moving forward. It provide backwards compatibility in the current community. If at some point in the future, we decide to not have optional arguments in icepack, we just remove the optional attribute on the Icepack interfaces and then update any interfaces in CICE/Icepack that do not conform. Everyone in the community would have to do the same, also anytime Icepacks is updated with any new arguments. That's the downside overall. I don't think we should abandon optional arguments until there is a clear reason to do so.

@eclare108213
Copy link
Contributor

Just a few comments and questions -
I do worry a bit about Phil's comment here, regarding non-Fortran codes being able to use Icepack with Fortran keywords and optional arguments. What should we do about that?

One option is for the non-Fortran interfaces to NOT adopt the optional arguments in their interfaces/uses. So non-Fortran might pass all arguments even if they are not needed. I don't actually know whether that will work for all languages, but we should explore as an appropriate time. I think for now, we should continue to add optional arguments moving forward. It provide backwards compatibility in the current community. If at some point in the future, we decide to not have optional arguments in icepack, we just remove the optional attribute on the Icepack interfaces and then update any interfaces in CICE/Icepack that do not conform. Everyone in the community would have to do the same, also anytime Icepacks is updated with any new arguments. That's the downside overall. I don't think we should abandon optional arguments until there is a clear reason to do so.

The voice of reason - sounds good to me.

@eclare108213
Copy link
Contributor

Looks like there are just a few minor changes that could be made here. @apcraig let us know when you're ready to merge.

@apcraig
Copy link
Contributor Author

apcraig commented Jan 20, 2023

cheyenne was down this week and i'm away from home, should be able to make progress next few days. will update conversation when updates are ready.

@apcraig
Copy link
Contributor Author

apcraig commented Jan 23, 2023

I've updated the PR and running a full test suite now. Added icepack_chkoptargflag logical function and cleaned up a few other things associated with comments above. Feel free to review, will report updated results in the next day or so.

@apcraig
Copy link
Contributor Author

apcraig commented Jan 24, 2023

CICE testing is complete with latest changes and everything looks good.

Copy link
Member

@phil-blain phil-blain left a comment

Choose a reason for hiding this comment

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

Thanks, latest version looks good!

@eclare108213 eclare108213 merged commit 24aef08 into CICE-Consortium:main Jan 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants