Package: elektra
ElektraElektra is Molecule's core framework for block logic (i.e., how to compute mwh from 5x16, 2x16, etc. blocks). It's derived from a set of logic internal to the Molecule application, and we're happy to share it with the world -- because nobody should ever have to fight with North American power blockseveragain.Elektra is in pre-release, which means that signatures may change over time as we evolve the project to 1.0. Submissions are welcome; just submit a pull request with your change.Installing ElektraEither clone this repo, or use pip:pip3 install elektraUsing ElektraIn your python project,import elektraand use away. Usage examples are inexamples/examples.py. A sample input CSV is there too. For the examples below, we will use that CSV. You can also use the table of data at the end of this file.ParametersInternally, Elektra uses enums for ISO, Block, and Frequency. String inputs for these fields are converted to the enum when Elektra runs, and so must be provided in the exact format the Enum expects.iso: permitted values aremiso,isone,ercot,pjm,spp,aeso,nyiso,caisoblock: permitted values are7x8,5x16,2x16,7x24,7x16,1x1,wrap,6x16frequency: permitted values aredaily,monthly,hourlyMethodsThese are the primary methods available in Elektra. Other methods are available, but are undocumented.create_prices: Creates block prices from raw LMP inputscrub_hourly_prices: Verifies that enough hourly LMPs are presentconvert: Converts hours in one block, to equivalent hours in anothertranslate_blocks: Wrapsconvert, and adds MW and/or MWh conversionsis_dst_transition: Determines if a date is a DST changeover daycreate_pricesThis method creates block prices, given hourly prices for a period of time and a handful of other parameters. A key function of this method is that it validates whether enough prices have been submitted to do the calculation. So, if theblockis 5x16, but a price is missing for a Wednesday at 11 AM, an exception will be thrown. Daylight Savings Time is also contemplated.Thecreate_pricesmethod takes the following parameters:flow_date-date| The as of date for the power prices (i.e., the settlement/reporting date needed)ticker-string| The ticker symbol for the power product (Molecule ticker; used for identification, not calculation)node-string| The node on the power grid (used for identification, not calculation)iso-string| The name of the Independent System Operator (ISO). CAISO is not currently supported.block-string| The desired power block for the output pricesfrequencystring| The desired frequency for the output prices (eitherdailyormonthly)pricesDataFrame| A Pandas dataframe of prices consisting offlow_date,hour_ending, andpriceThe response from the method is a single floating-point price.Exampleimportelektraimportpandasaspdimportfilecmpimportdatetimeasdtflow_date=dt.datetime(2020,10,17)prices=pd.read_csv('lmps.csv')result=elektra.create_prices(flow_date,'M.XXXX','INDIANA.HUB','miso','2x16','daily',prices)print(result)scrub_hourly_pricesThis method validates that a submitted dataframe contains all the necessary hourly prices for a flow date, and returns a DataFrame with these prices. Daylight Savings Time (long-day and short-day) is contemplated.Thescrub_hourly_pricesmethod takes the following parameters:flow_date-date| The as of date for the power prices (i.e., the settlement/reporting date needed)ticker-string| The ticker symbol for the power product (Molecule ticker; used for identification, not calculation)node-string| The node on the power grid (used for identification, not calculation)iso-string| The name of the Independent System Operator (ISO). CAISO is not currently supported.pricesDataFrame| A Pandas dataframe of prices consisting offlow_date,hour_ending, andpriceThe response from the method is a Pandas dataframe with the following columns of data:Hour BeginningHour EndingRequiredSpecialValueExampleimportelektraimportpandasaspdimportfilecmpimportdatetimeasdtflow_date=dt.datetime(2020,10,17)prices=pd.read_csv('lmps.csv')result=elektra.scrub_hourly_prices(flow_date,'M.XXXX','116013753','pjm',prices)print(result)convertGiven a flow date and an input block (i.e., 5x16), this method returns the number of hours in another block.For example, if today is Wednesday, November 4, 2020, and I have a 7x24 block (24 hours), but I want to see how many 5x16 hours that implies -- I'll get 16. On the other hand, if today is Saturday, October 31, 2020, and I have a Wrap block (24 hours that day), that only implies 8 hours of 7x8. This is useful when trying to convert a position purchased in one block, to a volume of another block. It works in tandem with the TranslateBlocks method.Theconvertmethod takes the following parameters:flow_date-date| The as of date for the power prices (i.e., the settlement/reporting date needed)input_block-- (text: Wrap, 5x16, 2x16, 7x8, 7x16, 1x1) | The input block.output_block-- (text: Wrap, 5x16, 2x16, 7x8, 7x16, 1x1) | The block for which we want to see hours.The response from this method is an integer, representing the number of hours in the output block.Exampleimportelektraimportdatetimeasdtflow_date=dt.datetime(2020,10,17)result=elektra.convert(flow_date,'7x24','2x16')# 16: (October 17 2020 is a Saturday, and has 16 peak hours)result=elektra.convert(flow_date,'7x24','5x16')# 0: (October 17 2020 is a Saturday, and has 0 weekday peak hours)result=elektra.convert(flow_date,'5x16','2x16')# 0: (October 17 2020 is a Saturday, and there could not be a 5x16 input block)translate_blocksWrapper forconvert, which adds the ability to convert a MW position for a term block (i.e., 7x24 monthly) to another block (or blocks) for that same term (i.e., 5x16, 2x16).ThetranslateBlocksmethod takes the following parameters:iso-string| The short name of the Independent System Operator (Elektra.Iso). This is not currently used, so beware when using for CAISO.mw-decimal| The number of megawatts on the input block to be used for mw/mwh computationfrequency-string| monthly, daily, or hourly. Currently only monthly is implemented.contract_startdate| The first flow date of the block. This method will compute the last flow date.in_block-string| 7x24, 5x16, Wrap, 2x16, 7x8out_blocks-string array| accepted values include 7x24, 5x16, Wrap, 2x16, 7x8out_uom-string| Set toMWfor a megawatt number. Default ismwh.The response from this method is a DataFrame with the following columns:date (i.e., flow date)one column for eachout_block, representing the number of MW or MWh for each dateExampleimportelektraimportdatetimeasdtflow_date=dt.datetime(2020,10,1)result=elektra.translateBlocks('pjm',20,'monthly',flow_date,'7x24',['5x16','2x16'],'mwh')print(result)is_dst_transitionResponds with variables that indicate whether the input date is a DST transition day, and whether it is theshort dayof the year (i.e., spring DST transition day) or thelong dayof the year (fall). If the date is not the transition day, the short- and long- day returns are False.The method takes the following parameter:as_of-date| The date to testThe method returns the following parameters:is_tx-boolean| True, if the supplied date is one of the two yearly transition daysshort_day-boolean| True, if the supplied date is the short daylong_day-boolean| True, if the supplied date is the long dayExampleimportelektraimportdatetimeasdtflow_date=dt.datetime(2021,3,14)is_tx,short_day,long_day=elektra.is_dst_transition(flow_date)print(is_tx)# True; this is one of the transition datesprint(short_day)# True; this is the spring DST transition dateprint(long_day)# False; that would be the "fall back" dateSample DataThis data is suitable for inputs to the hourly and block price converters:flow_datehour_endingprice2020-10-171.026.482020-10-172.020.352020-10-173.017.192020-10-174.017.162020-10-175.020.282020-10-176.034.252020-10-177.021.242020-10-178.023.672020-10-179.022.372020-10-1710.020.812020-10-1711.021.102020-10-1712.019.282020-10-1713.018.942020-10-1714.018.072020-10-1715.019.432020-10-1716.018.942020-10-1717.018.852020-10-1718.022.402020-10-1719.060.502020-10-1720.019.122020-10-1721.020.362020-10-1722.019.392020-10-1723.017.672020-10-1724.017.55