diff --git a/LICENSE.txt b/LICENSE.txt index 65ce6168b..c5bc80a63 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ -Copyright 2015 Tom Brown (FIAS),.... +Copyright 2015-2016 Tom Brown (FIAS), Jonas Hörsch (FIAS) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/README.rst b/README.rst index e1609a1fc..63e094bf5 100644 --- a/README.rst +++ b/README.rst @@ -4,32 +4,99 @@ Python for Power Systems Analysis ================================= -For load-flow and optimal power flow. +PyPSA stands for "Python for Power System Analysis". -In future: also dynamical stability. +PyPSA is a `free software +`_ toolbox for +simulating and optimising modern electric power systems that include +features such as variable wind and solar generation, storage units and +mixed alternating and direct current networks. +Documentation can be found in `sphinx +`_ reStructuredText format in +`doc `_ and as a `website `_. -Documentation -------------- -Can be found in pypsa/doc (which uses sphinx), which is also `on the -web `_. +As of 2016 PyPSA is under heavy development and therefore it +is recommended to use caution when using it in a production +environment. Some APIs may change - those liable to be updated are +listed in the doc/todo.rst. +PyPSA was initially developed by the `Renewable Energy Group +`_ +at `FIAS `_ to carry out simulations +for the `CoNDyNet project `_, financed by the +German Federal Ministry for Education and Research (BMBF). -Licence (GPL3) --------------- -Copyright 2015 Tom Brown (FIAS), Jonas H +What PyPSA does and does not do (yet) +======================================= -This program is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 3 of the -License, or (at your option) any later version. +PyPSA can calculate: -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +* static power flow (using both the full non-linear network equations and + the linearised network equations) +* linear optimal power flow (over several snapshots simultaneously for + optimisation of generation and storage dispatch and the capacities + of generation, storage and transmission) -You should have received a copy of the GNU General Public License -along with this program. If not, see http://www.gnu.org/licenses/ . +It has models for: + +* meshed multiply-connected AC and DC networks, with controllable + converters between AC and DC networks +* conventional dispatchable generators +* generators with time-varying power availability, such as + wind and solar generators +* storage units with efficiency losses + + + +Functionality that will definitely by added soon (see also :doc:`todo`): + +* Graphical plotting of networks with power flow +* Better modelling of hydroelectricity +* Distributed active power slack +* Non-linear power flow solution using `analytic continuation `_ in the complex plane + +Functionality that may be added in the future: + +* Unit Commitment using MILP +* Short-circuit current calculations +* Dynamic RMS simulations +* Small signal stability analysis +* Interactive web-based GUI +* AC OPF +* Dynamic EMT simulations +* Unbalanced load flow + + + +What PyPSA uses under the hood +=============================== + +PyPSA is written and tested with Python 2, but has included Python 3 +forward-compatibility (for e.g. printing and integer division) so that +minimal effort should be required to run it in Python 3. + +It leans heavily on the following Python packages: + +* `pandas `_ for storing data about components and time series +* numpy and `scipy `_ for calculations, such as + linear algebra and sparse matrix calculations +* `pyomo `_ for preparing optimisation problems (currently only linear) +* networkx for some network calculations (such as discovering connected networks) +* py.test for unit testing + +The optimisation uses pyomo so that it is independent of the preferred +solver (you can use e.g. the free software GLPK or the commercial +software Gurobi). + +The time-expensive calculations, such as solving sparse linear +equations, are carried out using the scipy.sparse libraries. + +Licence +========== + +PyPSA is released as free software under the `GPLv3 +`_, see `LICENSE.txt +`_.. diff --git a/components.py b/components.py index 8bd77dc18..b023994ea 100644 --- a/components.py +++ b/components.py @@ -210,7 +210,7 @@ class StorageUnit(Generator): state_of_charge_initial = Float() state_of_charge = Series(default=np.nan) - #maximum capacity in terms of hours at full output capacity p_nom + #maximum state of charge capacity in terms of hours at full output capacity p_nom max_hours = Float(1) #in MW diff --git a/doc/components.rst b/doc/components.rst index 635e74b94..d54d97247 100644 --- a/doc/components.rst +++ b/doc/components.rst @@ -20,51 +20,120 @@ Sub-Network are determined by calling: network.determine_network_topology() + + Bus ======= Fundamental electrical node of system. + +One-Ports: Generators, Storage Units, Loads, Shunt Impedances +============================================================ + +These components share the property that they all connect to a single +bus. + +They have attributes: + + ++------------+------------+-----------+---------------------------------------+ +| Name | Type | Unit |Description | ++============+============+===========+=======================================+ +| bus | string | |name of bus | +| | | |to which | +| | | |one-port is | +| | | |attached | +| | | | | ++------------+------------+-----------+---------------------------------------+ +| p |series |MW | active power (as calculated by PyPSA) | ++------------+------------+-----------+---------------------------------------+ +| q |series |MVar |reactive power (as calculated by PyPSA | ++------------+------------+-----------+---------------------------------------+ + + + Generator -============ +--------- + +Can have generator.dispatch in ["variable","flexible"], which dictates +how they behave in the OPF. + +"flexible" generators can dispatch +anywhere between gen.p_nom*(gen.p_nom_min_pu_fixed) and +gen.p_nom*(gen.p_nom_max_pu_fixed) at all times. + +"variable" generators have time series gen.p_max_pu which dictates the +active power availability for each snapshot. + + + + ++------------+------------+-----------+---------------------------------------+ +| Name | Type | Unit |Description | ++============+============+===========+=======================================+ +| dispatch | string |must be |Controllability of active power | +| | |"flexible" |dispatch | +| | |or | | +| | |"variable" | | +| | | | | ++------------+------------+-----------+---------------------------------------+ +| control |string |must be | P,Q,V control strategy | +| | |"PQ", "PV" | | +| | |or "Slack" | | ++------------+------------+-----------+---------------------------------------+ +| p_set |series |MW |active power set point (for PF) | +| | | | | ++------------+------------+-----------+---------------------------------------+ +| q_set |series |MVar |reactive power set point (for PF) | +| | | | | ++------------+------------+-----------+---------------------------------------+ + -Can have generator.dispatch in ["variable","flexible"] Storage Unit -============ +------------ Has a time-varying state of charge and various efficiencies. Load -====== +----- PQ load. Shunt Impedance -====== +--------------- Has voltage-dependent admittance. +Branches: Lines, Transformers, Converters, Transport Links +=========================================================== + +Have bus0 and bus1 to which they attached. + +Power flow at bus recorded in p0, p1, q0, q1. + + Line -===== +------ A transmission line connected line.bus0 to line.bus1. Can be DC or AC. Transformer -========== +------------ Converts from one AC voltage level to another. Converter -========== +---------- Converts AC to DC power. Transport Link -============== +-------------- Like a controllable point-to-point HVDC connector; equivalent to converter-(DC line)-converter. diff --git a/doc/optimal_power_flow.rst b/doc/optimal_power_flow.rst index 96781e22c..173f2dce6 100644 --- a/doc/optimal_power_flow.rst +++ b/doc/optimal_power_flow.rst @@ -8,11 +8,17 @@ See pypsa.opf. Linear Optimal Power Flow ========================= -network.lopf(snapshots) +network.lopf(snapshots,solver_name) + +where snapshots is an iterable of snapshots and solver_name is a +string, e.g. "gurobi" or "glpk". The linear OPF module can optimises the dispatch of generation and storage and the capacities of generation, storage and transmission. +The optimisation currently uses continuous variables. MILP unit commitment may be +added in the future. + The objective function is the total system cost for the snapshots optimised. @@ -24,14 +30,23 @@ Each transmission asset has a capital cost. Each generation and storage asset has a capital cost and a marginal cost. +WARNING: If the transmission capacity is changed in passive networks, +then the impedance will also change (i.e. if parallel lines are +installed). This is NOT reflected in the LOPF, so the network +equations may no longer be valid. Note also that all the expansion is +continuous. + + Optimising dispatch only: a market model ---------------------------------------- Capacity optimisation can be turned off so that only the dispatch is -optimised, like an electricity market model. For simplified -transmission representation using NTCs, there is a TransportLink -component which does controllable power flow like a transport model -(and can also represent a point-to-point HVDC link). +optimised, like an electricity market model. + +For simplified transmission representation using Net Transfer +Capacities (NTCs), there is a TransportLink component which does +controllable power flow like a transport model (and can also represent +a point-to-point HVDC link). @@ -40,8 +55,8 @@ Optimising total annual system costs To minimise annual system costs for meeting an inelastic electrical load, capital costs for transmission and generation should be set to -the discounted annualised investment costs in e.g. EUR/MW/a, marginal -costs for dispatch to e.g. EUR/MWh and the weightings chosen such that +the annualised investment costs in e.g. EUR/MW/a, marginal costs for +dispatch to e.g. EUR/MWh and the weightings chosen such that .. math:: diff --git a/doc/todo.rst b/doc/todo.rst index b82ee6871..1b90717d6 100644 --- a/doc/todo.rst +++ b/doc/todo.rst @@ -37,11 +37,52 @@ Create a 3d component pandas.Panel for time-varying quantities, e.g. -And only instantiate the items when necessary, e.g. at start of -network.pf() can instantiate "p" and "q" if they don't already exist. +Then sub_network.generators_t can slice the Panel, similarly for bus.generators_t. -Then sub_network.generators_t can slice the Panel. +And only instantiate the items "p", "p_set", etc. when necessary, +e.g. at start of network.pf() can instantiate "p" and "q" if they +don't already exist. + +Or have switch, so that all items generated automatically for newbies, +and experts can turn it off and only generate those which they need. + + + +Replace descriptors with __get__ and __set__ on objects +------------------------------------------------------- + +Can then use obj.attr for attr which are dynamically added to DataFrame + +.. code:: python + + def __set__(self,attr,val): + attr_type = self.__class__.attributes[attr]["type"] + + try: + val = attr_type(val) + except: + oops! + + df = getattr(self.network,self.__class__.list_name) + + if attr in df.columns: + df.loc[self.name,attr] = val + else: + + #return to normal object set + setattr(self,attr,val) + + +Store attributes in: + +.. code:: python + + class Branch: + + static_attributes = {{}} + + series_attributes = {{}} @@ -51,6 +92,20 @@ Improve regression testing Use classes to do multiple tests with same set-up +Ramp rate limits in OPF for generators +-------------------------------------- + +i.e. generator.ramp_rate_limit = x MW/h or per unit of p_nom/h + + +Spillage variables for storage +------------------------------- + +A variable per storage unit which can spill the state of charge +without generating electricity (e.g. if the inflow overwhelms the +storage) + + Regions for groups of buses --------------------------- @@ -67,6 +122,12 @@ I.e. other than rewriting lopf function. Example: Yearly import/export balances for zones +More non-linear pf examples +--------------------------- + +pypower import, scigrid non-linear + + Improve Python 3 support ------------------------ @@ -113,36 +174,6 @@ Also make v_mag per unit NOT kV -Replace descriptors with __get__ and __set__ on objects -------------------------------------------------------- - -Can then use obj.attr for attr which are dynamically added to DataFrame - -def __set__(attr,val): - -try: - val = attr_type(val) -except: - oops! - -if attr in df.columns: -df.loc[self.name,attr] = val - -else: - -#return to normal object set -setattr(self,attr,val) - - -Store attributes in - -class Branch: - - static_attributes = {{}} - - series_attributes = {{}} - - Changes which may be implemented ============================================