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
Dev doeclim #206
Dev doeclim #206
Conversation
Project file to Xcode 6.; C++ runtime used is now compiler default (clang) instead of GNU C++; cleaned up header search paths; added linker flags for boost `filesystem` and `system`. This allows building on Mac OS X 10.11, Boost 1.60, and GSL 2.1.
linking boost and gsl libraries in both hector and hector-lib project files
Fix VS project
See issue #136. This commit changes `main.cpp` so it returns nonzero exit codes (1=program exception, 2=standard exception, 3=other exception).
- 'SOx', 'NH3', 'C6F14', 'HALON1202'
Xcode project file updates
Remove input variables which are not being used
boost (header only). This opens the door to release hector under different licenses that GPLv2.
Replace GSL algorithms including ODE integration with various libs from
information instead of including the license in each file. This will make less version control headache to release under different licenses.
Have header and source files reference LICENSE.md for licensing
instead just use the logger with cout echo turned on. This closes #123.
Remove duplicative cout statements in the carbon-cycle-solver
…windows for that matter) the Xcode and xcode directories get merged as one causing extra confusion.
Remove extra visual studio and Xcode project files.
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.
This looks like a great improvement to Hector, and nice job on the authorea document! Need more clarity in some spots, and more defensive programming in others (e.g. use of const
).
@@ -26,6 +26,7 @@ | |||
#define OH_COMPONENT_NAME "OH" | |||
#define N2O_COMPONENT_NAME "N2O" | |||
#define TEMPERATURE_COMPONENT_NAME "temperature" | |||
#define TEMP_DOECLIM_COMPONENT_NAME "temp_doeclim" |
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.
Should we use a more meaningful name?
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.
Ah, the "DOE" here doesn't refer to the department of energy. OK then.
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.
@bpbond and @rplzzz yea it's diffusive ocean energy climate model. are there any licensing issues we need to be aware of of linking this one model with Hector? Can we still call it Hector?
https://github.com/scrim-network/BRICK
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.
We are using DOEClim with the permission of its authors, right? If so, then it's fine. We should, however, acknowledge the code they donated. I have a note about that elsewhere.
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.
I have not done any investigations into permissions. DOECLIM has been used several times by Klaus Keller's group and I adapted their C++ implementation here. I'll check in with Ryan and Klaus about it.
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.
It looks like one or more versions of DOECLIM have been released under GPLv3. Just get verbal confirmation from one of the original authors that they're ok with us releasing it under GPLv2. (The differences aren't really relevant to what we're doing; I like v2 because it's shorter and written in plain language.) Then we can just indicate that the code is used with permission.
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.
renamed component. Still need to double check licensing.
(CH - tracking her changes)
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.
A short update on the permissions: we now have emailed permission from Elmar Kriegler (original creator of DOECLIM) to use DOECLIM in Hector under GPLv2. I'm waiting for a response from Klaus Keller (coauthor of the paper for which the GPLv3 version was written).
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.
We now also have emailed permission from the author of the DOECLIM version released under GPLv3
unitval k_max; //!< maximum ocean heat uptake efficiency, W/m2/K | ||
unitval k_min; //!< minimum ocean heat uptake efficiency, W/m2/K | ||
unitval slope; //!< slope of the curve, 1/K | ||
// unitval cp; //!< Specific heat |
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.
Why is this commented out? Remove?
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.
thanks, i missed that one.
double ak; // slope in climate feedback - land-sea heat exchange linear relationship | ||
double bk; // offset in climate feedback - land-sea heat exchange linear relationship, W/m2/K | ||
double csw; // specific heat capacity of seawater W*yr/m3/K | ||
double earth_area; // m2 |
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.
Seems like many of these should be const
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.
instead of doubles
?
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.
No, I mean, something like const double earth_area = x.xxx;
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.
Based on @rplzzz 's comment below it looks like we should move these initializations to the header (some are called in more than one function so if we want to keep them together they need to be there). Those with well-known values will have const static
, while those that are potentially tweakable will have const
. Does that sound like what we want?
double A[4]; | ||
double IB[4]; | ||
|
||
//Dependent DOECLIM parameters |
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.
Space after //
. Dependent on what? What's the difference between misreadocean_area
below and the same variable name above?
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.
@bpbond If these are just consts
then we don't actually need them in the header?
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.
Mmm. Feeling fuzzy on my C++. I think actually we'd want static const x = ...
. As for header or not, it depends; is it referred to in multiple component functions? If not, right, just move into the run method or wherever.
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.
const
means that once it's initialized, it can't be changed. static
means that there is one copy for the entire class, instead of one for each object created. A member can be either const
, static
, neither, or both, depending on what you are trying to accomplish. For physical constants like the area of the earth or the specific heat of seawater, static const
is the way to go. For something that might be a settable parameter (ak
, perhaps?), you would generally do that as a normal (i.e., not static) member.
A static member is initialized just like a global variable, irrespective of whether or not it happens to be const. In fact, static members are basically just namespaced global variables, except that C++ does respect their private
or protected
visibility.
A member that is const, but not static must be initialized in the constructor. This is one of the rare cases in which the distinction between initialization and assignment matters. In this case you have to use the :
notation to make it an initialization instead of an assignment. If you can't do that for some reason, such as because you have to construct the object before the initialization data is available, then you can't make the members const. Your best bet in this case is to make them ordinary members and to add a comment to the effect that once they are set they should be treated as const.
A constant that is only used in one method could be moved into that method, as Ben suggests, but sometimes it's best to make them const or static const. The reason why is that if someone wants to know, what are they using for the xyz parameter, it's a lot easier to find it if it's with all the other constants, rather than tucked away at the beginning of some particular method they might not know the name of. Also, if you end up refactoring so that more than one method uses the constant, then you'll have to make the constant a member anyhow. Starting it off that way future proofs your design a bit.
* \param[in] y Inverted 1-d matrix | ||
* \returns void, inverse is stored in y | ||
*/ | ||
void TempDOECLIMComponent::invert_1d_2x2_matrix(double * x, double * y) { |
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.
Since we depend on Boost anyway, why not use its ublas
library?
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.
Any Boost inversion implementation I saw in my cursory google search looked a good deal more complex than this simple algorithm for 2x2 inversion. But I could be wrong!
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.
That's correct. If you know the matrix is 2x2, you can invert it very simply using analytic formulae. It's similar to how you could solve an equation using the Newton-Raphson method, but if you happen to know it's quadratic, it's simpler to use the quadratic formula.
tauksl = (1.0 - flnd) * cas / kls; | ||
taukls = flnd * cal / kls; | ||
|
||
// First order |
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.
Some more documentation needed here--what's going on?
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.
@bvegawe can you add a few comments here? thank you!
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.
My guess is that this has all been explained in a paper somewhere. We should include a pointer to the paper and document any mappings between names used in the paper and names used here that aren't obvious.
//// to match a temperature record), need to track the Ftot that *would* have | ||
//// produced the observed temperature record. This way there's a smooth | ||
//// transition when we exit the constraint period, after which internal_Ftot | ||
//// will rise in parallel with the value reported by ForcingComponent. |
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.
Nice commenting and logic.
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.
@bpbond i think that was you back in the day!
Note also my comment about using Boost–I doubt we want to roll our own matrix-inversion functions, but will defer to @rplzzz here. |
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.
Lots of cleanup needed in various places, though most of it shouldn't be too much work. I did have a question about ocean heat flux that I would like to see some discussion on, but everything else is minor.
input/hector_rcp85_doeclim.ini
Outdated
@@ -0,0 +1,401 @@ | |||
; Config file for hector model: RCP85 |
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.
What is the story with this file? We have already added DOEclim to the rcp85.ini file above, so why is this one necessary?
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.
good point. this was our initial test case file.
@@ -1,87 +0,0 @@ | |||
/* Hector -- A Simple Climate Model |
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.
I really don't love that we are deleting the original temperature component entirely. The whole idea behind Hector's design is that we are supposed to be able to add and drop components as needed. I get that we don't want components to proliferate because then we have to maintain them all, but so far maintaining components hasn't been a huge amount of effort. Is the original temperature component really unable to coexist with the DOEClim temperature (in the code base, I mean; obviously only one of them can be active in any single run)?
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.
In my experience, it works fine with both components and just specifying which version you want to use in the .ini file. It does lead to a couple warnings like below:
WARNING:registerCapability: temperature is declaring capability Tgav previously registered
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.
They can exist together and do currently. My concern is that the old way was a hack with a bunch of bugs that were found. I don't think I want people having an easy option to get back incorrect results by turning on that old component.
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.
That sounds reasonable. Since that leaves the doeclim temperature component as the only temperature component, maybe we should just rename it to "temperature_component". (We would still explain its doeclim origins in comments in the source file, of course.)
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.
done
|
||
lastflux_annualized.set( 0.0, U_PGC ); | ||
|
||
// Register the data we can provide | ||
core->registerCapability( D_OCEAN_CFLUX, getComponentName() ); | ||
core->registerCapability( D_OCEAN_C, getComponentName() ); | ||
core->registerCapability( D_HEAT_FLUX, getComponentName() ); |
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.
I take it these heat flux capabilities have been moved to the DOEClim component?
Edit: Actually, it doesn't look like they have. Are we just not supporting retrieving the ocean heat flux anymore, or is it going to known by a different name going forward? Apart from being a serious backward-incompatible change, it would be kind of unfortunate if we could no longer get this information from the model.
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.
With DOECLIM, we calculate a flux into the mixed layer and a flux into the interior. For backward compatibility, I'll make a note to also do a total heat flux.
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.
Heat flux is calculated in the DOECLIM component now. @bvegawe that's a good idea to have total heat flux into the ocean.
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.
done
/*! \brief Calculates inverse of x and stores in y | ||
* \param[in] x Assume x is setup like x = [a,b,c,d] -> x = |a, b| | ||
* |c, d| | ||
* \param[in] y Inverted 1-d matrix |
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.
This should be documented as param[out]
or param[inout]
, depending on whether the function expects y
to be initialized.
/*! \brief Calculates element-wise sum of matrix x and y, stores in z | ||
* \param[in] x,y Assume x,y setup like x = [a,b,c,d] -> x = |a, b| | ||
* |c, d| | ||
* \param[in] z Summed 1-d matrix |
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.
This also is param[out]
.
// | ||
// If the user has supplied temperature data, use that (except if past its end) | ||
if( tgav_constrain.size() && runToDate <= tgav_constrain.lastdate() ) { | ||
// H_LOG( logger, Logger::NOTICE ) << "** Using user-supplied temperature" << std::endl; |
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.
Delete this line. Saving an old version of an error message in a commented line is perhaps the most egregious example of code hoarding I can think of.
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.
// H_LOG( logger, Logger::NOTICE ) << "** Using user-supplied temperature" << std::endl; | ||
H_LOG( logger, Logger::NOTICE ) << "** ERROR - DOECLIM can't currently handle user-supplied temperature" << std::endl; | ||
} | ||
// tgav = tgav_constrain.get( runToDate ); |
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.
Lots of commented-out code from here to line 385. Clean it up.
double aero_forcing = double(core->sendMessage( M_GETDATA, D_RF_BC ).value( U_W_M2 )) + double(core->sendMessage( M_GETDATA, D_RF_OC ).value( U_W_M2 )) + double(core->sendMessage( M_GETDATA, D_RF_SO2d ).value( U_W_M2 )) + double(core->sendMessage( M_GETDATA, D_RF_SO2i ).value( U_W_M2 )); | ||
forcing[tstep] = double(core->sendMessage( M_GETDATA, D_RF_TOTAL ).value( U_W_M2 )) - ( 1.0 - alpha ) * aero_forcing; | ||
|
||
// Initialize variables for time-stepping through the model |
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.
Are the next 80 lines or so copied/translated from the original DOEClim code base? If so, we should maybe include a pointer to that code, both so that anyone who wants to look at it can, and also to document that it was copied with the knowledge and permission of its authors and maintainers.
@@ -26,6 +26,7 @@ | |||
#define OH_COMPONENT_NAME "OH" | |||
#define N2O_COMPONENT_NAME "N2O" | |||
#define TEMPERATURE_COMPONENT_NAME "temperature" |
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.
If we are removing the old temperature component, then shouldn't we also remove this #define
?
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.
done
@@ -26,6 +26,7 @@ | |||
#define OH_COMPONENT_NAME "OH" | |||
#define N2O_COMPONENT_NAME "N2O" | |||
#define TEMPERATURE_COMPONENT_NAME "temperature" | |||
#define TEMP_DOECLIM_COMPONENT_NAME "temp_doeclim" |
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.
We are using DOEClim with the permission of its authors, right? If so, then it's fine. We should, however, acknowledge the code they donated. I have a note about that elsewhere.
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.
In addition to what I wrote before (which seems to be interspersed with the line comments for some reason, so you have to hunt for it a bit), here are two more things.
- Can we please get rid of this junk:
Wed Nov 22 02:46:24 2017:NOTICE:run: Attempting ODE solver 1878->1879 (1878->1879)
Wed Nov 22 02:46:24 2017:NOTICE:run: Success: we have reached 1879
Wed Nov 22 02:46:24 2017:NOTICE:run: ODE solver success at t= 1879 last dt= 0.5
As far as I can tell, it's useful only when something goes wrong, so we should downgrade it to debug level and make notice level output the default.
- The code is failing its tests, presumably because we've changed the model, so naturally the outputs no longer match. Once we are satisfied with the results using the new model, we need to update the comparison data for the tests.
additional descriptions of model parameters and calculations. added a total ocean heat flux output parameter to match the parameter output by the original temperature component
Dev doeclim: improved DOECLIM descriptions, total heat flux output
renamed temp_doeclim to temperature in code and ini files updates to header to include a few more parameters not specified
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.
My biggest comment has been addressed. There were a couple other things, but the world won't come to an end if they're not addressed, and we should move this thing along.
Forgot to add the factor for the slightly smaller surface area of the interior ocean
includes full citations and the fact that we have permission.
set hard-coded DOECLIM parameters to const; moved their initializations to the header. if these initializations are static I get a warning, so just const for now.
dev_doeclim: a bug fix, const parameters, updated references
This PR includes the a new temperature component (DOECLIM) to better represent ocean heat uptake and global mean temperature change.
This document contains more detailed information on the changes.