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

Added ability to convert VIC 4.2 ascii state files to VIC 5.0 netcdf #66

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from

Conversation

tbohn
Copy link
Contributor

@tbohn tbohn commented Jul 13, 2017

The state file feature required modifying 2 files: tonic/scripts/vic_utils (to add statefile-related arguments) and tonic/models/vic/grid_params.py.

Also modified .travis.yml to get miniconda working properly.

Copy link
Contributor

@dgergel dgergel left a comment

Choose a reason for hiding this comment

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

This looks mostly pretty good to me, but I have a few suggestions for changes.


self.soil_param['off_gmt'] = np.array([i])
i += 1

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a fan of repeating the i += 1 line over and over - this seems pretty clunky to me. And is i actually always the value that you want, because it doesn't seem to be resetting...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I'm making this more dynamic, although it might still be somewhat clunky. Can we improve the code on a separate PR?

k = mydict[var].shape[2]
l = mydict[var].shape[3]
out_dict[var] = np.ma.zeros((j, k, l, ysize, xsize),
dtype=dtype)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't you just return a tuple and put this into the np.ma.zeros line, e.g. out_dict[var] = np.ma.zeros((mydict[var].shape), ysize, xsize? I guess you might need to convert the tuple to an array but I think it'd be cleaner to combine these two steps...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The i, j, and k are used a couple lines later in the assignment of out_dict (e.g., line 1227: for jj in pyrange(j): etc., then line 1230: out_dict[var][jj, kk, ll, yi, xi] = mydict[var][:, jj, kk, ll]). Whoever had worked on grid_params.py as of spring 2016 (jhamman?) had implemented that logic. I assume the purpose was to map the mydict values, which only contain cells within the domain/basin, to out_dict, which additionally contains fill_values. I simply extended the logic to handle those state variables that have different dimensions than the variables found in the soil_param file. Can you suggest a better way of doing the assignment?

Personally I think that overhauling someone else's inefficient code should be part of a different PR. The purpose of my PR was simply to add needed functionality. If the code prior to this PR was OK to merge into the archive, then my PR should be held to the same standard.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough. Works for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Note: when I say "someone else's inefficient code" I don't in any way mean to imply that I'm a great python coder. I'm just saying that I hadn't budgeted for doing an overhaul of the code, and hadn't known at the time (last year) that there was anything in the existing code that needed overhauling.

Copy link
Contributor

Choose a reason for hiding this comment

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

No I totally agree. I think it's way better for version control to separate out PRs. Since this is a new feature it should be a standalone PR without any other overhauls.

Copy link
Contributor

Choose a reason for hiding this comment

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

So I'm completely in agreement with you that that should be a separate thing.

l = mydict[var].shape[3]
m = mydict[var].shape[4]
out_dict[var] = np.ma.zeros((j, k, l, m, ysize, xsize),
dtype=dtype)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same reply as above.

else:
new[:, :, :] = out_dicts['veg_dict'][var]
new[lib_bare_idx, :, :] += bare
# Ensure that Cvs sum to 1.0
new /= new.sum(axis=0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Throw a warning if they don't?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

shape = (nveg_classes, veglib_dict[lib_var].shape[1],
ysize, xsize)
new = np.full(shape, FILLVALUE_F)
if extra_class:
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't this be fill_val instead of the float or int specific ones?

Copy link
Contributor

Choose a reason for hiding this comment

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

since fill_val will have already been assigned to the integer or float fillvalue

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

Copy link
Contributor

Choose a reason for hiding this comment

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

This looks good to me.

Copy link
Contributor

@dgergel dgergel left a comment

Choose a reason for hiding this comment

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

@tbohn these changes look good to me.

shape = (nveg_classes, veglib_dict[lib_var].shape[1],
ysize, xsize)
new = np.full(shape, FILLVALUE_F)
if extra_class:
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks good to me.

@tbohn
Copy link
Contributor Author

tbohn commented Aug 8, 2017

Thanks @dgergel.

Copy link
Member

@jhamman jhamman left a comment

Choose a reason for hiding this comment

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

just some minor syntax comments. looks good though.

help="Flag indicating whether state "
"file contains carbon-cycle "
"variables (default=False)",
default=False)
Copy link
Member

Choose a reason for hiding this comment

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

for the options that are just boolean flags, lets do:

type=bool,
default=False,
action='store_true', 
help='...')

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, ok, that makes sense. I see that all of the code I've added in this function suffers from this problem. So I'll fix all instances of it, including instances from previous PRs. Not sure why I did it that way, perhaps initially I didn't know about the bool type; but along the way I did learn about the bool type yet I just mindlessly copied the existing code.

Copy link
Contributor Author

@tbohn tbohn Aug 22, 2017

Choose a reason for hiding this comment

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

I see some instances in ncparam2ascii_parser in which the default value of a str or int option is also False. I won't fix those, but I'm calling your attention to them in case you want to open an issue about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note as well that you are proposing a new option order (I realize this is a purely cosmetic issue). I've reordered as you requested for the boolean options. The other options are unchanged. Again, I propose that if you want all calls to add_argument() to have a consistent order, it should be a new issue/PR. But calling it to your attention.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, I had to roll back the changes that I made in response to your suggestion - they broke the travis build. I've kept the change in type to bool. But I've not added the action=store_true or the move of default=False to be second in the order.

Copy link
Member

Choose a reason for hiding this comment

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

What was the error you were getting? This should work.

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 had a problem with type not recognized or something like that. I don't have the error accessible anymore. The error message doesn't make sense of course, since type is still there in the same position in the arg list.

Can you look into that issue separately, and deal with it in some other PR? It's not related to the change I'm making.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I found my travis build log. The error was the same in python 2.7 and 3.4:
TypeError: init() got an unexpected keyword argument 'type'

Copy link
Member

Choose a reason for hiding this comment

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

Ok. Take a look at the docs. Looks like you just need the action='store_true'. No default/dtype is required.

https://docs.python.org/3/library/argparse.html#action

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I replaced the type=bool and default=False arguments with action='store_true'.

self.veg_param['sigma_slope'] = 'Std. deviation of terrain ' \
+ 'slope within veg tile'
self.veg_param['lag_one'] = 'Lag one gradient autocorrelation ' \
+ 'of terrain slope'
Copy link
Member

@jhamman jhamman Aug 22, 2017

Choose a reason for hiding this comment

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

the backslash and plus sign are not needed here. Python can do the string line continuation as:

a = 'start of the ' \
    'line'

Copy link
Member

Choose a reason for hiding this comment

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

apply this fix throughout your code above/below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I attempt that, my syntastic add-on to vim complains about an unexpected indent. But I'll make the change as you suggest regardless...

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 only does my editor complain, but when I attempt to run tonic in my python environment, python complains about unexpected indent on the continued lines. Restoring the \ and + appeases my python. I'm running Python 3.5.

Copy link
Member

Choose a reason for hiding this comment

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

@tbohn - My apologies, my comment was not entirely correct. You don't need the + or \ if you are inside parentheses. When you are not (as in this case), you need the backslash but not the plus sign.

ref: https://stackoverflow.com/questions/5437619/python-style-line-continuation-with-strings

new = np.full(shape, fill_val)
if extra_class:
new[:-1, :, :] = out_dicts['veg_dict'][var]
new[-1, :, :] = bare_vegparam[var]
Copy link
Member

Choose a reason for hiding this comment

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

trailing colons are not used in numpy. I see they were there before but they are not needed so lets remove them. While we're at it, let's rework this section to look like:

if extra_class:
    shape = (nveg_classes, ) + out_dicts['veg_dict'][var].shape[1:]
    new = np.full(shape, fill_val)
    new[:-1] = out_dicts['veg_dict'][var]
    new[-1] = bare_vegparam[var]
else:
    new = out_dicts['veg_dict'][var]

Copy link
Member

Choose a reason for hiding this comment

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

You don't have to fix this colon syntax everywhere, just in lines you've changed :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I'm wondering if the line shape = (nveg_classes, ) + out_dicts['veg_dict'][var].shape[1:] is correct... I need to properly test that case.

But sure, I'll get rid of the trailing colons.

Question: what exactly do you mean about trailing colons not being used in numpy? I've used them a lot and everything has worked fine. Do you mean that trailing colons are not necessary in numpy, and that you'd like to adopt a convention in which they're not used?

dtype_str = 'np.int'
else:
fill_val = FILLVALUE_F
dtype_str = 'np.float'
Copy link
Member

Choose a reason for hiding this comment

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

do these dtypes need to be cast to strings? I don't think they do...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, OK, I guess they are like pre-compiler constants in C/Fortran, rather than strings. Makes sense.

@tbohn
Copy link
Contributor Author

tbohn commented Aug 28, 2017

Please wait to merge this PR; I'm debugging something on a different branch that might impact this branch. Stay tuned...

@tbohn
Copy link
Contributor Author

tbohn commented Aug 28, 2017

OK, this is ready for merge now.

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