11'''
2- optimizer.py -- Optimization routines for PRMS parameters.
2+ optimizer.py -- holds ``Optimizer`` and ``OptimizationResult`` classes for
3+ optimization routines and management conducted on PRMS parameters.
34'''
45from __future__ import print_function
56import pandas as pd
2122
2223class Optimizer :
2324 '''
24- Container for a PRMS parameter optimization routine consisting of
25- stages similar to what is described in Hay, et al, 2006
25+ Container for PRMS parameter optimization routines that are
26+ defined as stages similar to what is described in Hay, et al, 2006
2627 (ftp://brrftp.cr.usgs.gov/pub/mows/software/luca_s/jawraHay.pdf).
28+ Currently the ``monte_carlo`` method provides random parameter
29+ resampling routines using uniform and normal random variables.
2730
2831 Example:
2932
@@ -33,10 +36,10 @@ class Optimizer:
3336 >>> control = 'path/to/control'
3437 >>> work_directory = 'path/to/create/simulations'
3538 >>> optr = Optimizer(params, data, control, work_directory, \
36- title='the title', description='desc')
39+ title='the title', description='desc')
3740 >>> measured = 'path/to/measured/csv'
3841 >>> statvar_name = 'basin_cfs' # or any other valid statvar
39- >>> params_to_resample = ['dday_intcp', 'dday_slope'] # list
42+ >>> params_to_resample = ['dday_intcp', 'dday_slope'] # list of params
4043 >>> optr.monte_carlo(measured, params_to_resample, statvar_name)
4144
4245 '''
@@ -97,9 +100,9 @@ def monte_carlo(self, reference_path, param_names, statvar_name, \
97100 stage , n_sims = 10 , method = 'uniform' , mu_factor = 1 ,\
98101 noise_factor = 0.1 , nproc = None ):
99102 '''
100- Optimize the monthly dday_intcp and dday_slope parameters
101- (two key parameters in the ddsolrad module in PRMS) by one of
102- multiple methods (in development): Monte Carlo default method
103+ The ``monte_carlo`` method of ``Optimizer`` performs parameter
104+ random resampling techniques to a set of PRMS parameters and
105+ executes and manages the corresponding simulations.
103106
104107 Args:
105108 reference_path (str): path to measured data for optimization
@@ -381,17 +384,17 @@ def resample_param(params, param_name, how='uniform', mu_factor=1,\
381384 taken from a uniform distribution, where the range of the uniform
382385 values is equal to the difference between the min and max of the allowable
383386 range from PRMS. The parameter min and max are set in Optimizer.param_ranges
384- If the resampling method (" how" argument) is set to 'normal', randomly
385- sample a normal distribution with mean = mean(parameter) X mu_factor and
386- sigma = param allowable range multiplied by noise_factor. If parameters have
387+ If the resampling method (`` how`` argument) is set to 'normal', randomly
388+ sample a normal distribution with mean = mean(parameter) X `` mu_factor`` and
389+ sigma = param allowable range multiplied by `` noise_factor`` . If parameters have
387390 array length <= 366 then individual parameter values are resampled otherwise
388391 resample all param values at once, e.g. by taking a single random value
389392 from the uniform distribution. If they are taking all at once using the
390393 normal method then the original values are scaled by mu_factor and a normal
391- random variable with mean=0 and std dev = parameter range X noise_factor.
394+ random variable with mean=0 and std dev = parameter range X `` noise_factor`` .
392395
393396 Args:
394- params (parameters.Parameters): parameter object
397+ params (parameters.Parameters): ``Parameters`` object
395398 param_name (str): name of PRMS parameter to resample
396399 Kwargs:
397400 how (str): distribution to resample parameters from in the case
@@ -400,10 +403,9 @@ def resample_param(params, param_name, how='uniform', mu_factor=1,\
400403 noise_factor (float): factor to multiply parameter range by,
401404 use the result as the standard deviation for the normal rand.
402405 variable used to add element wise noise. i.e. higher
403- noise facter will result in higher variance. Must be > 0.
406+ noise_factor will result in higher variance. Must be > 0.
404407 Returns:
405- ret (numpy.ndarry): ndarray of param after uniform random mean
406- shift or element-wise noise addition (normal r.v.)
408+ ret (numpy.ndarry): ndarray of param after resampling
407409 """
408410 p_min , p_max = Optimizer .param_ranges .get (param_name ,(- 1 ,- 1 ))
409411
@@ -501,8 +503,57 @@ def _mod_params(parameters, params, param_names):
501503
502504
503505class OptimizationResult :
504-
506+ """
507+ The ``OptimizationResult`` object serves to collect and manage output
508+ from an ``Optimizer`` method. Upon initialization and a given optimization
509+ stage that was used when running the Optimizer method, e.g. ``monte_carlo``,
510+ the class gathers all JSON metadata that was produced for the given stage.
511+ The ``OptimizationResult`` has three main user methods: first ``result_table``
512+ which returns the top n simulations according to four model performance
513+ metrics (Nash-Sutcliffe efficiency (NSE), root-mean squared-error (RMSE),
514+ percent bias (PBIAS), and the coefficient of determination (COEF_DET) as
515+ calculated against measured data. For example the table may look like:
516+
517+ >>> ddsolrad_res = OptimizationResult(work_directory, stage=stage)
518+ >>> top10 = ddsolrad_res.result_table(freq='monthly',top_n=10)
519+ >>> top10
520+ ======================== ======== ======= ========= ========
521+ ddsolrad parameters NSE RMSE PBIAS COEF_DET
522+ ======================== ======== ======= ========= ========
523+ orig_params 0.956267 39.4725 -0.885715 0.963116
524+ tmax_index_54.2224631748 0.921626 47.6092 -0.849256 0.94402
525+ tmax_index_44.8823940703 0.879965 58.9194 5.79603 0.922021
526+ tmax_index_47.6835387480 0.764133 82.5918 -4.78896 0.837582
527+ ======================== ======== ======= ========= ========
528+
529+ Second, the ``get_top_ranked_sims`` which returns a dictionary that map
530+ key information about the top n ranked simulations, an example returned
531+ dictionary may look like:
532+
533+ >>> {
534+ 'dir_name' : ['pathToSim1', 'pathToSim2'],
535+ 'param_path' : ['pathToSim1/input/parameters', 'pathToSim2/input/parameters'],
536+ 'statvar_path' : ['pathToSim1/output/statvar.dat', 'pathToSim2/output/statvar.dat'],
537+ 'params_adjusted' : [[param_names_sim1], [param_names_sim2]]
538+ }
539+
540+ The third method of ``OptimizationResult`` is ``archive`` which essentially
541+ opens all parameter and statvar files from each simulation of the given
542+ stage and archives the parameters that were modified and their modified values
543+ and the statistical variable (PRMS time series output) that is associated with
544+ the optimization stage. Other ``Optimizer`` simulation metadata is also gathered
545+ and new JSON metadata containing only this information is created and written
546+ within a newly created "archived" subdirectory within the same directory that
547+ the ``Optimizer`` routine managed simulations. The ``OptimizationResult.archive``
548+ method then recursively deletes the simulation data for each of the given stage.
549+ """
550+
505551 def __init__ (self , working_dir , stage ):
552+ """
553+ Create an ``OptimizationResult`` instance to manage output and analyse parameter-
554+ output relationships as produced by the use of an ``Optimizer`` method of a user
555+ defined optimization stage.
556+ """
506557 self .working_dir = working_dir
507558 self .stage = stage
508559 self .metadata_json_paths = self ._get_optr_jsons (working_dir , stage )
0 commit comments