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

Switch 2.0.6 #115

Closed
wants to merge 159 commits into from
Closed

Switch 2.0.6 #115

wants to merge 159 commits into from

Conversation

mfripp
Copy link
Member

@mfripp mfripp commented Jun 21, 2019

(Note: most of this comment and Josiah's response have been moved to issue #129 for future implementation.)

This is a place to discuss the next release of Switch. These are my immediate goals:

  • simplify dependencies
    • drop dependencies where easy (sympy, numpy, testfixtures)
    • group most remaining dependencies into one additional set? (conda install switch_model_extras / pip install switch_model[extras])
    • require users to explicitly install some specialized dependencies ad hoc? (rpy2 and numpy for iterative demand response, psycopg2-binary or eventually google-cloud-bigquery for accessing the Hawaii back-end database)
    • should we include testing-oriented packages (pint, maybe testfixtures?) in extras, or just list them as something to add ad hoc if running tests? (may be moot if we can figure out a way to get our tests to run without needing pint, which pyomo needs during testing but does not include in the distribution)
  • streamline installation instructions
    • recommend this sequence for most users?
      1. conda install -c defaults -c conda-forge switch_model or pip install switch_model (+find glpk somewhere) for most users?
      • these users can look at the source code on github or in their system install directory if needed, which is how I interact with Pyomo
    • recommend this sequence only for people who want to edit the source code and contribute back?
      1. git clone https://github.com/switch-model/switch.git && cd switch
      2. if running anaconda: conda install --only-deps switch_model
      3. pip install --editable . or python setup.py develop (note: conda develop doesn't install command-line scripts or dependencies; see how to use conda develop? conda/conda-build#1992 (comment))
  • maybe add some commands to give easier access to source code hidden in a site-packages directory:
    • switch find <module>: report file path to specified module (possibly just a submodule within switch_model)
      • then users can view or edit source code via commands like atom `switch find switch_model` , mate `switch find pyomo` or maybe atom `switch find discrete_commit` .
    • switch install examples: copy examples directory to local directory
    • switch solve --trace [[<module>|<file>[:<function>|<line>]], [<module>[:<function>]], ...]: invoke the debugger (a) when particular callbacks are called, (b) when any callback in the specified module is called (if no function specified), or (c) whenever any callback is called (if no modules specified).
      • This could be implemented either via tests when we call callbacks, or by creating tracing wrappers for the specified callbacks, or by subclassing Pdb and setting breakpoints in the right places (that is nice and general but may run slower and ties us to Pdb?)

@mfripp
Copy link
Member Author

mfripp commented Jun 21, 2019

@rodrigomha and @josiahjohnston I added a commit with simplified code for the rhosetter in the PySP example, with no dependency on sympy. I think my code should work, but it seems like the underlying implementation was probably not working already. e.g., when I run the command below, I get a message that it has data for gen_max_capacity_factor, but the key for the data is not in the indexing set VARIABLE_GEN_TPS_RAW.

Since this is your code, would you be able to see what you can do to get it to work?

(I'm also thinking we should have a bigger test set that we run before each release to make sure all our examples (and some bigger ones) run and produce the same results as the previous release.)

Here's the command I used that gave an error:

python -m pdb `which runph` --model-directory=. --instance-directory=inputs/pysp_inputs --solver=gurobi --default-rho=1000.0 --traceback --rho-cfgfile=rhosetter.py  --solution-writer=pyomo.pysp.plugins.csvsolutionwriter --output-scenario-tree-solution

Here were the pdb commands I used to diagnose the error (a little):

l 861, 892
!key, val
!self._setitem_when_not_present(self._validate_index(key), val)
!self._validate_index(key)
!self.name
!list(self.keys())
!self.get_index_set().name

@josiahjohnston
Copy link
Contributor

Dependencies

Retiring the inefficient & roundabout sympy parsing in favor of direct Pyomo calls seems great.

Dropping the direct numpy dependency in the advanced section won't make a difference because pandas is a core dependency and it has a dependency on numpy.

Consolidating the rest of the optional dependencies into a single section called [extras] seems fine to me.

I'm not a fan of making users do ad-hoc installations, and I don't understand benefits of doing that vs registering them explicitly as optional bits in extras_require.

My preference is to keep testfixtures in the core requirements since the testing framework is an integral part of software development, and at this point Switch still seems best-suited for people can do some coding. Hopefully Switch will grow into a broader audience, but in the meanwhile, it seems important to make it easy for people to start developing Switch to expand the base of advanced users & contributors. Moving testfixtures into [extras] would be acceptable to me, although I don't understand the problem in having it as a core dependency.

Maybe you can elaborate on the motivation for reducing dependencies? Design esthetics or some practical problems?

Installations

The instructions for casual users seems fine to me. For advanced users who will be working with code, I strongly recommend using some kind of virtual environment. Conda's environments seem fine as far as I know, as is virtualenv. I started mucking with pipenv (which seems to be taking over from virtualenv), but I haven't gotten far enough with pipenv to recommend it or write instructions.

I always recommend using pip install path/to/src over python path/to/src/setup.py install. Pip has superseded direct execution of setup.py for several years. See StackOverflow for a summary of the benefits.

I've played with the idea of setting up a docker image for Switch, but didn't know of a concrete use case. If that ever seems of interest to anyone, I could do that pretty easily.

Source code access

I like your idea of switch find <module>; its implementation should be trivial and it will lower the learning curve for people who aren't yet python gurus.

I'm not sure how or if the switch install examples is better than having users download the examples directory and save it where ever they want. I don't think it would be a big help to casual users who prefer graphical interfaces to command line interfaces, and advanced users who don't mind command line interfaces can do a cp directly for greater transparency. Would that command also download the expamples from a corresponding version of the git repo?

Adding something like --trace [[<module>|<file>[:<function>|<line>]] argument to switch solve seems like a nice idea. I know pdb & ipdb have internal commands for setting arbitrary breakpoints in other files, but I don't know how to interface with them programatically. Ideally, our code would use the most advanced debugger library available in the running python environment (see code snippet below from a different project doing related stuff). Personally, I find the tab-completion & color highlighting in ipdb incredibly useful compared to pdb.

def get_debugger_func():
	"""Get a function that will drop the code into an interactive python
	session for debugging and development. Use the most sophisticated
	debugging library that is available (IPython > ipdb > pdb).
	N.B. these will not work in the context of parallel processing.
	"""
	try:
		from IPython import embed
		return embed
	except ImportError:
		from ipdb import set_trace
		return set_trace
	except ImportError:
		from pdb import set_trace
		return set_trace

def main():
	# ...
	debug_func = get_debugger_func()
	debug_func()

rhosetter & Progressive Hedging

The problem was that the input .dat files needed to be regenerated since VARIABLE_GEN_TPS_RAW was included in the model. After dealing with that, there were a few bugs in your refactored code from wrong variable names. I fixed them and pushed the updates. It runs to completion now. The expected cost of the objective function doesn't match the value in the README (135,349,802 now vs 111,517,401 in the README), and I don't know if that's due to the solver I used, bug fixes since the last time the README was updated, or some undiagnosed bug. @bmaluenda, would you mind taking a look?

@bmaluenda
Copy link
Member

I reviewed the PySP example and fixed several bugs, as well as updated the output files to match the format of PySP's current version.

I too am getting objective function values of about 135 MMUSD. I checked the output files and manually estimated the value of the OF and got closer to this value than to the previous ~110. I suspect that we hadn't re-generated the input files and re-run the example since I first uploaded it, so any changes to Switch's OF hadn't been reflected in the output files of this example.

I vote to keep these updated output files and consider them to be correct.

@josiahjohnston
Copy link
Contributor

Thanks Benjamin!

@josiahjohnston
Copy link
Contributor

Just pushed some more updates that pass all tests in both python 2 & 3:

  • -v, -vv & -vvv control level of verbosity via the logging python library, and validated its compatibility with old code that used model.options.verbose in conjunction with print statements.
    • Extra timepoints for renewable generation or hydro will yield summary warning messages if -v is specified, and detailed diagnostic data if -vv is specified.
  • Update ArgParser command line definitions to be easier to read on a small screen and easier to search (ex: --long-arg gets auto-converted to options.long_arg, so including dest="long_arg" allows searching between argument definitions & their use in the codebase)
  • Minor bug fixes detailed in commit messages.

@mfripp mfripp changed the title Switch 2.0.5 Switch 2.0.6 Aug 10, 2019
… extra timepoints warnings to avoid spamming user with messages at every run, but giving them access to as detailed information as they request.
…n, and easier to read on a laptop screen (adding `dest` and reformatting text wrap).
… were built before the start of the study's time horizon.
…elp messages. Before this fix, the bug appeared if you executed `switch solve --help` in the examples/production_cost_models/spinning_reserves directory which loads the spinning_reserves module.
…hon library `ggplot` has been abandoned for a few years, and `plotnine` is actively maintained and a drop-in replace for our simple use case.
…le. This allows tab completion & color highlighting, which enables much faster exploration & debugging.
…s warnings about matplotlib API deprecations & save paths for plotnine figures.
…ants used in high-flow conditions where river flow exceeds the capacity of the generator & reservoir. Also minor improvements to documentation and code formatting for improved readability & accuracy.
* New file with annual summary per-generation project that includes energy, capacity, costs & capacity factor
* New file with tech/annual summary for easily skimming results.
* Faster summation of tech/zone annual summary & tech/annual summary. Also include capacity, costs, and cap factor in those summary files.

Also, minor updates for python style.
…t some parameters are optional in the model and don't have to be specified in files. This simplifies the process of defining a bare-bones planning reserve margin for each load zone. I verified that all of the tests still pass.
…tion fuel costs associated with dispatching generators.

Also, reverting a typo bug in dispatch export.
…d in input files, so the implementation matches documentation.
…nts that are retired early and plants whose construction is not complete in the first period. Also minor documentation update.
mfripp added 28 commits October 20, 2022 17:35
…ng.__init__

This ensures that users can prevent all reporting by removing the reporting
module from the module list and avoids a crash if they tried to do that
previously (due to the gen_cap code trying to access model.options.sort_output,
which is defined in reporting.__init__).
Pyomo 5.7 made several changes that broke compatibility with earlier models:

- stopped assuming dimen values for sets when they were not specified, which
  crashed some of our input and output code.
- began preserving order in all Sets and emitting warnings if unordered
  containers such as standard Python sets are used to initialize them (this was
  done to improve determinism in the model setup).
- +inf, -inf, +infinity, -infinity and nan in the input files are now read in as
  strings instead of floating point values.
- a deprecation warning is issued saying that the default domain for Params will
  be Reals instead of Any, starting in version 6.0.
- "Simple" has been changed to "Scalar" in the names of SimpleSet,
  OrderedSimpleSet, AbstractOrderedSimpleSet and SimpleParam.

Pyomo 6.0 also began producing deprecation warnings when itervalues or iteritems
methods are used on Pyomo components.

To make Switch compatible with Pyomo 5.7 - 6.4, this commit makes the following
changes:

- assign dimen values to all sets (preferably as the first keyword argument)
- use lists instead of sets to initialize Set components
  (switch_model.utilities.unique_list(iter) is helpful for this.)
- replace "inf" in some fuel_supply_curves.csv example files with ".", which
  will cause them to use the default value, which is float("inf").
- don't specify rfm_supply_tier_limit when the fuel_costs.markets module reads
  additional fuels from fuel_costs.csv. They get a default value of float("inf")
  anyway.
- add a note to CHANGELOG.md that using "inf" and "nan" values in the input
  files will generate errors with Pyomo 5.7+.
- set all Params to have an explicit domain
- also check for ScalarSet, OrderedScalarSet, AbstractOrderedScalarSet and
  ScalarParam in the locations that check for SimpleSet, OrderedSimpleSet,
  AbstractOrderedSimpleSet and SimpleParam.
This commit applies --sorted-output automatically in reporting.write_tables
and explicitly in several locations where pandas dataframes are written to
.csv files. This ensures most outputs will be sorted when requested,
including dispatch.csv, dispatch-wide.csv (columns), gen_cap.csv,
gen_project_annual_summary.csv, load_balance.csv, local_td_energy_balance.csv,
local_td_energy_balance_wide.csv and transmission.csv.
…predetermined.csv

This also renames gen_predetermined_storage_energy_mwh (new in this release, 2.0.7) to
build_gen_energy_predetermined. The new names should be more consistent with each other
and also be a little clearer that this is the amount of new capacity built in each year,
not the total amount of capacity in place that year.
The new name is more consistent with other file names (which generally start with
"gen_"), and should be a little easier to remember and view in editor tabs.
…td_loss_rate

This change encapsulates the local_td data more completely within
the local_td module and also gives the parameter a more accurate name
and allows it to be varied between load_zones.
…e components

Both of these changes are needed for Pyomo 6+ compatibility. Pyomo issues a
deprecation warning for Params with default "Any" domain, due to future plans
to change this to "Reals". It also fails to clone models that use obj.keys()
to initialize components (probably not able to clone/pickle the iterator).
… members

`build` is a Python variable created as the sum of several Pyomo components.
We previously checked whether it was empty via `build is 0`, but Python now
gives a warning about `is` with a literal, so we changed it to `build == 0`,
but that forces evaluation of an unconstructed component, which crashes
Pyomo. So instead we check `isinstance(build, int) and build == 0`. The
second part is not actually needed, but clarifies what is happening.
To do this, I had to move the banner into SwitchAbstractModel.__init__
between the parameter parsing code and the define_components code
(or else split __init__ into multiple methods that have to be called
in the right order from switch_model.solve). To do that, I had to
make iteration_modules a part of the model instead of a temporary
variable in switch_model.solve, which seems reasonable anyway. This
commit also converts a number of print() calls into logger.info()
calls.
fix typo in planning_reserves and split storage_builds.csv into storage_builds.csv and storage_capacity.csv
…age values

This commit changes gen_cap.csv to include both power and energy (storage)
capacity in place in each period. gen_cap.csv also shows the annual capital
recovery and fixed O&M required for each project. This commit also adds a
gen_build.csv file that shows the amount of power and energy capacity _added_
in each period and the total capital outlay needed when those are built.
(Switch uses capital outlay to calculate capital recovery requirements, but
doesn't outlay the capital outlay directly. However, capital outlay is of
interest to some users.)
@mfripp
Copy link
Member Author

mfripp commented Oct 27, 2022

Closing this because it was actually the 2.0.6 branch, not the next_release branch.

@mfripp mfripp closed this Oct 27, 2022
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.

5 participants