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

Rts gmlc parser updates #209

Merged

Conversation

michaelbynum
Copy link
Collaborator

@michaelbynum michaelbynum commented Feb 19, 2021

From @darrylmelander in the previous PR:

The new RTS-GMLC parser is targeted at reading a full set of data in RTS-GMLC format, and then generating multiple Egret models for various time spans within the read-in data.

Here are some of the parsing details:

  • For branches, instead of using 'Cont Rating' for all three rating types, we now use:

    • rating_long_term: Cont Rating
    • rating_short_term: LTE Rating
    • rating_emergency: STE Rating
  • For buses:

    • the bus name (system['bus'][{bus name}]) is 'Bus Name' (was 'Bus ID')
    • the bus "id" is now 'Bus ID' (was 'Bus Name')
    • generators now refer to the bus by name instead of ID (system['generator'][{gen name}]['bus'] = {bus name})
  • Generators:

    • We omit the 'CSP' generator type
    • Because it only applies to CSP, we omit 'Natural Inflow' time series data
  • Reserves:

    • Reserves are identified entirely by a naming convention. For system-wide reserves, we use this mapping:
    RTS-GMLC Name Egret Name
    Spin_Up spinning_reserve
    Reg_Up regulation_up
    Reg_Down regulation_down
    Flex_Up flexible_ramp_up
    Flex_Down flexible_ramp_down
    • For area-specific reserves, we add a suffix to the system-wide names, namely "_R{Area Name}", such as "Spin_Up_RArea1" for the spinning reserve for an area named Area1.
    • We don't get reserve information from anywhere other than timeseries_pointers.csv. We don't use reserves.csv. We could use the "Requirement (MW)" column in this file to populate the skeleton with static values, and then overwrite them if they have a timeseries associated with them. But we don't, so reserves are only included if they have a timeseries associated with them.

@michaelbynum
Copy link
Collaborator Author

From the previous PR, @bknueven said:

We don't get reserve information from anywhere other than timeseries_pointers.csv. We don't use reserves.csv. We could use the "Requirement (MW)" column in this file to populate the skeleton with static values, and then overwrite them if they have a timeseries associated with them. But we don't, so reserves are only included if they have a timeseries associated with them.

I would be in favor of this -- it's not necessarily unusual to carry static amounts of certain types of reserves, and I believe Egret should already support having a single MW value for every reserve type.

Copy link
Collaborator

@bknueven bknueven left a comment

Choose a reason for hiding this comment

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

I attempted to load and solve an RTS-GMLC instance ... which proved to be somewhat troublesome. I believe I captured my issues in the comments.

egret/parsers/rts_gmlc/parser.py Show resolved Hide resolved
Comment on lines 71 to 97
begin_time : datetime.datetime or str
Beginning of time horizon. If str, date/time in "YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD" format,
the later of which assumes a midnight start.
end_time : datetime.datetime or str
End of time horizon. If str, date/time in "YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD" format,
the later of which assumes a midnight start.
simulation : str
Either "DAY_AHEAD" or "REAL_TIME", which specifies which time series the data is taken from,
default is "DAY_AHEAD".
t0_state : dict or Nonetype
Keys of this dict are thermal generator names, each element of which is another dictionary with
keys "initial_status", "initial_p_output", and "initial_q_output", which specify whether the
generator is on at t0, the real power output at t0, and the reactive power output at t0.
If this is None, default values are loaded.

Returns
-------
dict : A dictionary in the format required for the ModelData object.
"""
cache = parse_to_cache(rts_gmlc_dir, begin_time, end_time, t0_state)
model = cache.generate_model(simulation, begin_time, end_time)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function does not really support passing begin_time/end_time as a string because ParsedCache.generate_model wants them as datetime.datetime. I would suggest converting begin_time/end_time within this function.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Done

Comment on lines 69 to 70
rts_gmlc_dir : str
Path to RTS-GMLC directory
Copy link
Collaborator

@bknueven bknueven May 12, 2021

Choose a reason for hiding this comment

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

The code seems to assume this is RTS-GMLC/RTS_Data/SourceData, where RTS-GMLC is the directory the RTS-GMLC repo is cloned to. We should update the docstring to reflect that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Docstring updated


load_participation_factors = _compute_bus_load_participation_factors(model_data)

set_t0_data(model_data, rts_gmlc_dir, None)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should be passing t0_state into this function in place of None

Copy link
Collaborator

Choose a reason for hiding this comment

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

Fixed

egret/parsers/rts_gmlc/parser.py Outdated Show resolved Hide resolved
Comment on lines 80 to 84
t0_state : dict or Nonetype
Keys of this dict are thermal generator names, each element of which is another dictionary with
keys "initial_status", "initial_p_output", and "initial_q_output", which specify whether the
generator is on at t0, the real power output at t0, and the reactive power output at t0.
If this is None, default values are loaded.
Copy link
Collaborator

Choose a reason for hiding this comment

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

When None, we do not load default values, which we should do for convenience (perhaps with warning).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Fixed comment

egret/parsers/rts_gmlc/parser.py Outdated Show resolved Hide resolved
egret/parsers/rts_gmlc/parser.py Outdated Show resolved Hide resolved
Comment on lines 773 to 775
if len(end_time) == len(datestr):
end_time += midnight
end_time = datetime.strptime(end_time,datetime_format)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similar to above (probably want a function for this repeated code).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I created a function with the repeated code. I also switched from strptime with a fixed format to dateutil.parser.parse, which infers the date format from the string. See _convert_to_datetime().

egret/parsers/rts_gmlc/parser.py Outdated Show resolved Hide resolved
New parser is targeted at reading a full set of data in RTS-GMLC
format, and then generating multiple Egret models for various
time spans within the read-in data.
* Return dict (not ModelData) from create_model_data_dict()
* Parse dates if provided as strings
* Don't multiply timeseries by their Scaling Factor
They follow the same naming conventions as timeseries data.  The constant requirement values in reserves.csv are only used if there is not a corresponding timeseries in timeseries_pointers.csv; otherwise the constant value is replaced with timeseries values.
Initial state is taken from a passed in t0_state dict.  If none is
passed in, a file named "initial_status.csv" is read and data is pulled
from there.  That file can have 1, 2, or 3 data lines (initial_status,
initial_p_output, and initial_q_output).  It must have line 1, but if
it doens't have line 2 or 3, initial values are set to p_min and q_min.

Note that if you are caching the results of parsing, initial state is
not set (otherwise, every date range would end up with the same initial
state).  For models generated from the parsed cache, you can call
rts_gmlc_parser.set_t0_data() on the resulting model.

Also, treat ROR generators as HYDRO.
Shunt-related columns can be omitted if they are never used.

There is a variable number of fuel-related columns.  The files in the RTS-GMLC repository
use 5 columns, but the last of these 5 columns is never used (it is always 'NA').  The
parser was hard-coded to read 4 columns and ignore the 5th.  While this works for the
repository files, it is overly rigid.  The new code allows any number of columns, using
whatever columns are present and appropriately populated for each generator.
* Zone name can be any string, not just integers
* Don't include startup_cost or p_cost. Include startup_fuel, p_fuel, and non_fuel_startup_cost instead.
* More flexibility in how startup fuel is specified when you have fewer than 3 points. It no longer matters which of the 3 startup fuel columns you leave blank in this case, as long as the provided data is consistent (cold is longer than hot, for example).
* More flexibility in how p_fuel fuel curves are specified. You can have any number of columns (up to 50). For a fuel curve with N valid points, you only have to fill in the first N fuel curve columns and leave the rest blank.  The number of points in the fuel curve can be different for each generator.
* Omit several properties that were in the original RTS-GMLC parser but have no meaning to Egret.
* Some optional properties are now left out of the JSON if the corresponding cells in the csv are left blank
@darrylmelander darrylmelander force-pushed the rts-gmlc-parser-updates branch from 8e48435 to 689f359 Compare May 20, 2021 22:55
@bknueven bknueven merged commit 93a1345 into grid-parity-exchange:main May 21, 2021
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