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

Abg/update metadata #76

Merged
merged 12 commits into from
Dec 8, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name,external_reference,external_id
Solar - Photovoltaic - Unspecified,EECS Rules Fact Sheet 5 TYPES OF ENERGY INPUTS AND TECHNOLOGIES,T010100
Fossil - Solid - Hard Coal - Unspecified,EECS Rules Fact Sheet 5 TYPES OF ENERGY INPUTS AND TECHNOLOGIES,F02010100
Mechanical source or other - Wind - Unspecified, EECS Rules Fact Sheet 5 TYPES OF ENERGY INPUTS AND TECHNOLOGIES,F01050100
Thermal - Steam engine - Unspecified,EECS Rules Fact Sheet 5 TYPES OF ENERGY INPUTS AND TECHNOLOGIES,T050900
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Grid Node,Topology Level
US-WECC-CISO,1
US-WECC-PACW,0
US-WECC-BANC,1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
level,id
0,Interconnection
1,Balancing Area
2,Generating Plant
3,Generating Unit
4,Consumption Unit
120 changes: 91 additions & 29 deletions power_systems_data_api_demonstrator/src/api/metadata/views.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
from pydantic import BaseModel
from typing import Sequence
from sqlmodel import select

from sqlmodel import Session
from enum import Enum
from sqlmodel import Field
from datetime import datetime
from sqlmodel import SQLModel
from typing import Optional, Sequence

from fastapi import APIRouter, Request
import pandas as pd
from fastapi import APIRouter
from fastapi.param_functions import Depends
from power_systems_data_api_demonstrator.src.api.db import get_session
from pydantic import BaseModel
from sqlmodel import Field, Session, SQLModel, select

from power_systems_data_api_demonstrator.src.api.db import get_session

router = APIRouter()

Expand All @@ -20,7 +15,9 @@ class TopologyLevel(SQLModel, table=True):
id: str = Field(primary_key=True)
level: int | None = Field(
ge=0,
description="A number representing the hierarchy of this resource topology in relation to the other resource types. These levels **shall** include a sequential set of positive integers starting at 0.",
description="""A number representing the hierarchy of this resource topology in
relation to the other resource types. These levels **shall** include a
sequential set of positive integers starting at 0.""",
)


Expand All @@ -40,22 +37,87 @@ async def get_topology_levels(
return TopologyLevelsResponse(topology_levels=topology_levels)


class FuelTypeDescription(BaseModel):
name: str = Field(
description="A common name to use for the fuel type. If using AIB codes, it should be a concatenation of the three code descriptions with a dash between (i.e. 'Solar - Photovoltaic - Unspecified')."
)
external_id: str = Field(
description="A unique code (such as the AIB code) referencing the type of fuel."
)
class FuelSourceType(SQLModel, table=True):
name: str = Field(primary_key=True)
external_reference: Optional[str]
external_id: Optional[str]


class FuelTypesResponse(BaseModel):
external_reference: str = Field(
default="AIB EECS Rule Fact Sheet 5",
description="A reference that provides context for this specific fuel type.",
)
external_reference_url: str = Field(
default="https://www.aib-net.org/sites/default/files/assets/eecs/facts-sheets/AIB-2019-EECSFS-05%20EECS%20Rules%20Fact%20Sheet%2005%20-%20Types%20of%20Energy%20Inputs%20and%20Technologies%20-%20Release%207.7%20v5.pdf",
description="A unique code (such as the AIB code) referencing the type of fuel.",
)
types: list[FuelTypeDescription]
class FuelSourceTypesResponse(SQLModel):
types: list[FuelSourceType]


@router.get(
"/fuel-source/types",
summary="FUEL SOURCE TYPES",
)
async def get_fuel_source_types(
session: Session = Depends(get_session),
) -> FuelSourceTypesResponse:
result = session.execute(select(FuelSourceType))
types = result.scalars().all()
return FuelSourceTypesResponse(types=types)


class FuelSourceTechnologyReference(SQLModel):
aibCode: str
source_document: str


class FuelSourceTechnologyReferenceTable(FuelSourceTechnologyReference, table=True):
name: str = Field(primary_key=True)


class FuelSourceTechnology(SQLModel):
name: str
externalReference: FuelSourceTechnologyReference


class FuelSourceTechnologyResponse(SQLModel):
technologies: Sequence[FuelSourceTechnology]


@router.get(
"/fuel-source/technologies",
summary="FUEL SOURCE TECHNOLOGIES",
)
async def get_fuel_source_technologies(
session: Session = Depends(get_session),
) -> FuelSourceTechnologyResponse:
result = session.execute(select(FuelSourceTechnologyReferenceTable))
technologies = result.scalars().all()
df = pd.DataFrame(g.dict() for g in technologies)
technologies = []
for index, row in df.iterrows():
technologies.append(
FuelSourceTechnologyReferenceTable(
# FuelSourceTechnology(
AndBerna marked this conversation as resolved.
Show resolved Hide resolved
name=row["name"],
externalReference=FuelSourceTechnologyReference(
aibCode=row["aibCode"],
source_document=row["source_document"],
),
)
)
return FuelSourceTechnologyResponse(technologies=technologies)


# class FuelTypeDescription(BaseModel):
# name: str = Field(
# description="A common name to use for the fuel type. If using AIB codes, it should be a concatenation of the three code descriptions with a dash between (i.e. 'Solar - Photovoltaic - Unspecified')."# noqa: E501
# )
# external_id: str = Field(
# description="A unique code (such as the AIB code) referencing the type of fuel. # noqa: E501"
# )


# class FuelTypesResponse(BaseModel):
# external_reference: str = Field(
# default="AIB EECS Rule Fact Sheet 5",
# description="A reference that provides context for this specific fuel type.",
# )
# external_reference_url: str = Field(
# default="https://www.aib-net.org/sites/default/files/assets/eecs/facts-sheets/AIB-2019-EECSFS-05%20EECS%20Rules%20Fact%20Sheet%2005%20-%20Types%20of%20Energy%20Inputs%20and%20Technologies%20-%20Release%207.7%20v5.pdf",# noqa: E501
# description="A unique code (such as the AIB code) referencing the type of fuel # noqa: E501.",
# )
# types: list[FuelTypeDescription]
45 changes: 27 additions & 18 deletions power_systems_data_api_demonstrator/src/api/psr_metadata/views.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
from pydantic import BaseModel
from sqlmodel import select
from typing import Annotated, Optional

from sqlmodel import Session
from enum import Enum
from sqlmodel import Field
from datetime import datetime
from sqlmodel import SQLModel

from fastapi import APIRouter, Request
from fastapi import APIRouter, Path
from fastapi.param_functions import Depends
from power_systems_data_api_demonstrator.src.api.db import get_session
from sqlmodel import Field, Session, SQLModel, select

from power_systems_data_api_demonstrator.src.api.db import get_session

router = APIRouter()


class DescribeResponse(BaseModel):
pass
class PSRList(SQLModel, table=True):
id: str = Field(primary_key=True)
level: int
name: Optional[str]


class PSRListResponse(SQLModel):
psr_list: list[PSRList]


class PSRListReqest(SQLModel):
level: int


@router.get(
"/{id}/describe",
summary="TOPOLOGY DESCRIPTION",
"/power-system-resources",
summary="PSR LIST",
)
async def get_topology_levels(
id: int,
async def get_psr_list(
level: Annotated[Optional[int], Path(description="Filter by level")] | None = None,
session: Session = Depends(get_session),
) -> DescribeResponse:
return {}
) -> PSRListResponse:
if level is None:
result = session.execute(select(PSRList))
else:
result = session.execute(select(PSRList).filter_by(level=level))
psr_list = result.scalars().all()
return PSRListResponse(psr_list=psr_list)
89 changes: 77 additions & 12 deletions power_systems_data_api_demonstrator/src/api/seed.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,102 @@
from datetime import datetime
import os

import pandas as pd
from sqlmodel import Session
from sqlmodel import SQLModel
from power_systems_data_api_demonstrator.src.api.metadata.views import TopologyLevel

import power_systems_data_api_demonstrator.data
from power_systems_data_api_demonstrator.src.api.db import init_db
from power_systems_data_api_demonstrator.src.api.metadata.views import (
FuelSourceTechnologyReferenceTable,
FuelSourceType,
TopologyLevel,
)
from power_systems_data_api_demonstrator.src.api.psr_metadata.views import PSRList
from power_systems_data_api_demonstrator.src.api.psr_timeseries.views import (
GenerationByFuelSourceTable,
FuelType,
FuelTechnology,
GenerationByFuelSourceTable,
)
from power_systems_data_api_demonstrator.src.api.db import init_db
import power_systems_data_api_demonstrator.data

DATA_DIR = os.path.dirname(power_systems_data_api_demonstrator.data.__file__)


def seed() -> None:
engine = init_db()
topology_levels = [
TopologyLevel(id="Level 1", level=1),
TopologyLevel(id="Level 2", level=2),
]

topology_levels = []

for grid_source in ["example"]:
df = pd.read_csv(os.path.join(DATA_DIR, grid_source, "topology_metadata.csv"))

levels = df

for index, row in levels.iterrows():
topology_levels.extend([TopologyLevel(id=row["id"], level=row["level"])])

with Session(engine) as session:
seed_generation(session)
session.add_all(topology_levels)
seed_fuelsource(session)
seed_psr(session)
session.commit()


def seed_fuelsource(session: Session) -> None:
for grid_source in ["example"]:
df = pd.read_csv(
os.path.join(DATA_DIR, grid_source, "fuel_source_metadata.csv")
)

fuel_source_types = []
fuel_source_technologies = []

types = df[df["external_id"].str.contains("F")].reset_index()
technologies = df[~df["external_id"].str.contains("F")].reset_index()
for index, row in types.iterrows():
fuel_source_types.extend(
[
FuelSourceType(
name=row["name"],
external_id=row["external_id"],
external_reference=row["external_reference"],
)
]
)

for index, row in technologies.iterrows():
fuel_source_technologies.extend(
[
FuelSourceTechnologyReferenceTable(
name=row["name"],
aibCode=row["external_id"],
source_document=row["external_reference"],
)
]
)

# session.add_all(fuelsource_types)
# session.add_all(fuelsource_technologies)
session.add_all(fuel_source_types)
session.add_all(fuel_source_technologies)
session.commit()


def seed_psr(session: Session) -> None:
for grid_source in ["example"]:
df = pd.read_csv(os.path.join(DATA_DIR, grid_source, "psr_metadata.csv"))
psr_data = []
psr_list = df.groupby(["Grid Node"]).first().reset_index()

for index, row in psr_list.iterrows():
psr_data.extend([PSRList(id=row["Grid Node"], level=row["Topology Level"])])

session.add_all(psr_data)
session.commit()


def seed_generation(session: Session) -> None:
# Overall generation
fuel_types = []
fuel_technologies = []
# fuel_technologies = []
generation_interconnection_by_fuel_source = []
generation_balancing_area_by_fuel_source = []

Expand Down