Skip to content

Commit

Permalink
Merge branch 'osier_chapter' of github.com:arfc/2025-dotson-dissertat…
Browse files Browse the repository at this point in the history
…ion into osier_chapter
  • Loading branch information
samgdotson committed Jan 16, 2025
2 parents 4a11d86 + ea341fb commit 9824f6c
Show file tree
Hide file tree
Showing 11 changed files with 4,441 additions and 892 deletions.
2 changes: 2 additions & 0 deletions analysis/Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ rule collect_figures:
elasticity_plot = f"{docs_path}figures/elasticity.pgf",
example_pareto_plot = f"{docs_path}figures/truss2d_pareto.pgf",
near_optimal_plot = f"{docs_path}figures/near-optimal-pareto.pgf",
interior_points_plot = f"{docs_path}figures/nd-mga-paretofront.pgf",
pareto_3d = f"{docs_path}figures/3d-mga-paretofront.pgf"
output:
log = figure_log
Expand Down Expand Up @@ -82,6 +83,7 @@ rule plot_example_fronts:
input: "scripts/pareto_front.py"
output:
example_pareto_plot = f"{docs_path}figures/truss2d_pareto.pgf",
interior_points_plot = f"{docs_path}figures/nd-mga-paretofront.pgf",
near_optimal_plot = f"{docs_path}figures/near-optimal-pareto.pgf"
script: f"{input}"

Expand Down
196 changes: 196 additions & 0 deletions analysis/notebooks/energy-justice.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import requests\n",
"import matplotlib.pyplot as plt\n",
"import json\n",
"import numpy as np\n",
"import pandas as pd\n",
"import geopandas as gpd\n",
"import us\n",
"import os\n",
"from dotenv import load_dotenv\n",
"\n",
"load_dotenv(\"../../.env\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"eia_key = os.environ['EIA_API_KEY']"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Access power plant data"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"params = {\n",
" \"frequency\": \"monthly\",\n",
" \"data\": [\n",
" \"latitude\",\n",
" \"longitude\",\n",
" \"nameplate-capacity-mw\",\n",
" \"operating-year-month\"\n",
" ],\n",
" \"facets\": {\n",
" \"energy_source_code\": [\n",
" \"BIT\",\n",
" \"SUB\"\n",
" ]\n",
" },\n",
" \"start\": \"2024-09\",\n",
" \"end\": None,\n",
" \"sort\": [\n",
" {\n",
" \"column\": \"period\",\n",
" \"direction\": \"desc\"\n",
" }\n",
" ],\n",
" \"offset\": 0,\n",
" \"length\": 5000\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"BASE_URL = \"https://api.eia.gov/v2/\"\n",
"\n",
"dataset = \"electricity/operating-generator-capacity\"\n",
"route = dataset + \"/data\""
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"headers = {\n",
" \"X-Api-Key\": eia_key,\n",
" \"X-Params\": json.dumps(params),\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"r = requests.get(BASE_URL+route, headers=headers)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total records: 428\n"
]
}
],
"source": [
"response = r.json()['response']\n",
"\n",
"print(f\"Total records: {response['total']}\")\n",
"\n",
"data = response['data']\n",
"\n",
"df = pd.DataFrame(data)\n",
"df.drop(columns=['stateName','sector','sectorName','entityid',\n",
" 'balancing-authority-name','statusDescription', \n",
" 'entityName','nameplate-capacity-mw-units',\n",
" 'energy_source_code','generatorid','status',\n",
" 'unit', 'period'\n",
" ],\n",
" inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"df['nameplate-capacity-mw'] = df['nameplate-capacity-mw'].astype('float')"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"df = df.pivot_table(index=['stateid','plantid','balancing_authority_code','latitude','longitude'],\n",
" columns=['technology'],\n",
" values=['nameplate-capacity-mw']).reset_index(drop=False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "thesis",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.10"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
82 changes: 82 additions & 0 deletions analysis/scripts/farthest_first_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import pandas as pd
import itertools as it
from matplotlib import patches
from mycolorpy import colorlist as mcp

from scipy.optimize import nnls
from scipy.optimize import curve_fit
from scipy.spatial.distance import pdist
from scipy.spatial.distance import squareform

# pymoo imports
from pymoo.problems import get_problem
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.util.plotting import plot
from pymoo.visualization.scatter import Scatter

from osier import n_mga
from osier.utils import *
from osier import distance_matrix
from osier import farthest_first
from osier import check_if_interior

mpl.use("pgf")
plt.rcParams['pgf.texsystem'] = 'pdflatex'
plt.rcParams['text.usetex'] = True
plt.rcParams['pgf.rcfonts'] = False
plt.rcParams['figure.edgecolor'] = 'k'
plt.rcParams['figure.facecolor'] = 'w'
plt.rcParams['savefig.dpi'] = 600
plt.rcParams['savefig.bbox'] = 'tight'
plt.rcParams['font.family'] = "serif"



if __name__ == "__main__":
problem = get_problem("bnh")

pop_size = 100
n_gen = 200
algorithm = NSGA2(pop_size=pop_size)

res = minimize(problem,
algorithm,
('n_gen', n_gen),
seed=1,
verbose=False,
save_history=True
)

F = problem.pareto_front()
a = min(F[:,0])
b = max(F[:,0])
f1 = F[:,0]
f2 = F[:,1]
shift = 0.75
slack = 0.2
alpha = 0.5
F1 = f1 * (1+slack)
F2 = f2 * (1+slack)
X_hist = np.array([history.pop.get("X")
for history in res.history]).reshape(n_gen*pop_size,2)
F_hist = np.array([history.pop.get("F")
for history in res.history]).reshape(n_gen*pop_size,2)

slack_front = np.c_[F1,F2]
int_pts = check_if_interior(points=F_hist,
par_front=F,
slack_front=slack_front)
X_int = X_hist[int_pts]
F_int = F_hist[int_pts]

D = distance_matrix(X=X_int)

n_pts = 10
idxs = farthest_first(X=X_int, D=D, n_points=n_pts, seed=45)

F_select = F_int[idxs]
X_select = X_int[idxs]
35 changes: 34 additions & 1 deletion analysis/scripts/pareto_front.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,37 @@
ax.set_xlim(min(F1),max(F1))
ax.set_ylim(min(F2),max(F2))
ax.legend(fontsize=14)
plt.savefig("../docs/figures/near-optimal-pareto.pgf")
plt.savefig("../docs/figures/near-optimal-pareto.pgf")


"""
Visualize interior points
"""
F3 = F*(1+slack)

rng = np.random.default_rng(seed=1234)
R = rng.uniform(1000,2)
R[:,1] = R[:,1]*15e4
R[:,0] = R[:,0]*8e-2
R_sub = R[(R[:,1] < 12e4) & (R[:,0] < 0.06)]

interior_pts = []
for p in R_sub:
cond_1 = np.any((p < F3).sum(axis=1) == 2)
cond_2 = np.any((p > F).sum(axis=1) == 2)
if cond_1 and cond_2:
interior_pts.append(p)

fig, ax = plt.subplots(figsize=(8,6))
ax.plot(*zip(*F), color='black', lw=3, label='Pareto Front')
ax.plot(*zip(*F3), color='black', lw=1, alpha=0.2)
ax.scatter(*zip(*R_sub), c='tab:blue', s=3, label='Tested points')
ax.scatter(*zip(*np.array(interior_pts)), c='tab:red', s=20, label="Alternative solutions")
ax.fill(np.append(F[:,0], F3[:,0][::-1]), np.append(F[:,1],F3[:,1][::-1]), alpha=0.2, color='gray')
ax.fill_between(f1*0.98, f2*0.98, alpha=1, color='w')
ax.set_xlim(min(F1),max(F1))
ax.set_ylim(min(F2),max(F2))
ax.set_xlabel('f1', fontsize=14)
ax.set_ylabel('f2', fontsize=14)
ax.legend(fontsize=14, shadow=True, loc='upper right')
plt.savefig("../docs/figures/nd-mga-paretofront.pgf")
Loading

0 comments on commit 9824f6c

Please sign in to comment.