-
Notifications
You must be signed in to change notification settings - Fork 318
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
Ponded water/alternative solutions - object-oriented #192
Changes from 5 commits
3932256
3ce6202
0041a92
dd3ec25
98da3bf
cba171d
87406e2
b872d21
ea15490
e4d56cd
9133ffd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module computeFluxMod | ||
|
||
! provides interface for the flux modules | ||
|
||
use shr_kind_mod , only : r8 => shr_kind_r8 | ||
implicit none | ||
|
||
type, abstract :: flux_type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment from @martynpclark Sep 8, 2017 This is pedantic, I know, though can we call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment from @billsacks Sep 11, 2017 Fixed - thanks. Not pedantic at all - this is a very good point. |
||
contains | ||
procedure(getFlux_interface), deferred :: getFlux | ||
end type flux_type | ||
|
||
abstract interface | ||
subroutine getFlux_interface(this,x,f,dfdx) | ||
use shr_kind_mod , only : r8 => shr_kind_r8 | ||
import :: flux_type | ||
implicit none | ||
class(flux_type), intent(in) :: this | ||
real(r8), intent(in) :: x ! state | ||
real(r8), intent(out) :: f ! f(x) | ||
real(r8), intent(out), optional :: dfdx ! derivative | ||
end subroutine getFlux_interface | ||
end interface | ||
|
||
end module computeFluxMod |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
module implicitEulerMod | ||
|
||
use shr_kind_mod , only : r8 => shr_kind_r8 | ||
use computeFluxMod , only : flux_type | ||
implicit none | ||
|
||
contains | ||
|
||
subroutine implicitEuler(flux_inst, dt, xInit, xNew, err, message) | ||
! dummy variables | ||
class(flux_type), intent(in) :: flux_inst | ||
real(r8), intent(in) :: dt ! time step | ||
real(r8), intent(in) :: xInit ! initial state | ||
real(r8), intent(out) :: xNew ! updated state | ||
integer,intent(out) :: err ! error code | ||
character(*),intent(out) :: message ! error message | ||
! local variables | ||
integer :: iter ! iteration index | ||
integer,parameter :: maxiter=20 ! maximum number of iterations | ||
real(r8), parameter :: xTol=1.e-8_r8 ! convergence tolerance | ||
real(r8) :: flux ! flux | ||
real(r8) :: dfdx ! derivative | ||
real(r8) :: xRes ! residual error | ||
real(r8) :: delX ! state update | ||
! initialiuze routine | ||
err=0; message='implicitEuler/' | ||
|
||
! initialize | ||
xNew = xInit | ||
|
||
! iterate | ||
do iter=1,maxiter | ||
! get the flux and derivative | ||
call flux_inst%getFlux(xNew, flux, dfdx) | ||
! get the residual and the update | ||
xRes = xNew - (xInit + dt*flux) | ||
delX = -xRes/(1._r8 - dt*dfdx) | ||
! update and check for convergence | ||
xNew = xNew + delX | ||
if(abs(delX) < xTol) exit | ||
! check for non-convergence | ||
if(iter==maxiter)then | ||
message=trim(message)//'the implicit Euler solution did not converge!' | ||
err=20; return | ||
endif | ||
end do | ||
end subroutine implicitEuler | ||
|
||
end module implicitEulerMod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment from @martynpclark Sep 13, 2017
We should talk about how this is implemented. In principle it is possible to have multiple different numerical solutions for every single flux. This would provide scope to mix-and-match different numerical solutions in different parts of the code (sort of the way that CLM is developed now, although CLM does not have multiple numerical options for each flux). This would be incredibly cumbersome and likely confusing. At the other end of the spectrum we use the same numerical options everywhere in the code. This could be too restrictive.
I initially included these alternative options as (1) an example of how we can increase the accuracy of the operator splitting constrained explicit Euler solution without any increase in cost, expecting that there may be cases where people desire to retain operator splitting; and (2) begin the process of separating the physics from the numerical solution.
In my opinion the alternative numerical options for a single flux (as implemented here) may not be a representative use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment from @billsacks Sep 14, 2017
I'd also like to discuss this point further. And I'd be interested to see a more representative use case at some point.
One other concern I have is: If each flux has multiple possible parameterization options, each with multiple numerical solution options, the code is going to get very complex. (Much of the work I was doing earlier this week was to try to play around with ways to reduce that complexity, but there's no way to remove it entirely.)
Originally I had imagined that, for the most part, the choice of numerical solution method would just appear at high level in the code, not down at the level of individual fluxes. That would reduce this problem of a combinatorial explosion of complexity. I think that's what you're saying, too.