Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 9 additions & 21 deletions src/wecgrid/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,28 +280,16 @@ def generate_load_curves(
def g(h, mu, sig):
"""Return Gaussian weights for given hours.

Parameters
----------
h : array-like
Hours at which the Gaussian is evaluated. Values are
cast to a NumPy array to ensure vectorized
operations.
mu : float
Peak hour (mean) of the Gaussian curve.
sig : float
Spread of the curve (standard deviation).

Returns
-------
numpy.ndarray
Array of Gaussian weights corresponding to ``h``.

Notes
-----
Intended for shaping daily load profiles by combining
morning and evening peaks.
Args:
h: Hours at which the Gaussian is evaluated.
mu: Peak hour of the Gaussian curve.
sig: Standard deviation of the curve.

Returns:
numpy.ndarray: Gaussian weights for ``h``.

"""
h = np.asarray(h, dtype=float) # <-- belt-and-suspenders
h = np.asarray(h, dtype=float)
return np.exp(-0.5 * ((h - mu) / sig) ** 2)

s = g(hours, morning_peak_hour, morning_sigma_h) + g(
Expand Down
61 changes: 3 additions & 58 deletions src/wecgrid/util/database.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
"""WEC-Grid Database Interface Module.

SQLite database interface for WEC-Grid simulation data management, including
time series storage, configuration persistence, and result archival.
"""
"""Database utilities for WEC-Grid."""

# Standard library
import json
Expand Down Expand Up @@ -74,61 +70,10 @@ def _show_database_setup_message():


class WECGridDB:
"""SQLite database interface for WEC-Grid simulation data management.

Provides database operations for storing WEC simulation results, device
configurations, and time series data. Supports both raw SQL queries and
pandas DataFrame integration with multi-software backend support.

Database Schema Overview:
------------------------
Metadata Tables:
- grid_simulations: Grid simulation metadata and parameters
- wec_simulations: WEC-Sim simulation parameters and wave conditions
- wec_integrations: Links WEC farms to grid connection points

PSS®E Results Tables:
- psse_bus_results: Bus voltages, power injections [pu on S_base]
- psse_generator_results: Generator outputs [pu on S_base]
- psse_load_results: Load demands [pu on S_base]
- psse_line_results: Line loadings [% of thermal rating]

PyPSA Results Tables:
- pypsa_bus_results: Same schema as PSS®E for cross-platform comparison
- pypsa_generator_results: Same schema as PSS®E
- pypsa_load_results: Same schema as PSS®E
- pypsa_line_results: Same schema as PSS®E

WEC Simulation Data:
- wec_simulations: Metadata including wave spectrum, class, and conditions
- wec_power_results: High-resolution WEC device power output [Watts]

Key Design Features:
- Software-specific tables enable multi-backend comparisons
- All grid power values in per-unit on system S_base (MVA)
- GridState DataFrame schema alignment for direct data mapping
- Optional storage model - persist only when explicitly requested
- JSON configuration file for database path management
- User-guided setup for first-time configuration
- Support for downloaded or cloned database repositories

Database Location:
Configured via database_config.json in the same directory as this module.
Users can point to downloaded database file, cloned repository, or create new empty database.
"""SQLite interface for storing WEC-Grid results.

Attributes:
db_path (str): Path to SQLite database file (from JSON configuration).

Example:
>>> db = WECGridDB(engine) # Uses path from database_config.json
>>> # First run will prompt user to configure database path
>>> with db.connection() as conn:
... results = db.query("SELECT * FROM grid_simulations", return_type="df")

Notes:
Database path is configured via JSON file on first use.
Users are guided through setup process with clear instructions.
All database operations are transaction-safe with automatic rollback on errors.
db_path: Path to the SQLite database file.
"""

def __init__(self, engine):
Expand Down
51 changes: 7 additions & 44 deletions src/wecgrid/util/time.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# File: src/wecgrid/util/time.py

"""Time management and coordination for WEC-Grid simulations.

Provides the :class:`WECGridTime` dataclass for coordinating simulation
time across WEC-Grid components including power system modeling, WEC
device simulations, and data visualization with consistent temporal
alignment.
"""
"""Time management utilities for WEC-Grid."""

from dataclasses import dataclass, field
from datetime import datetime
Expand All @@ -15,40 +9,13 @@

@dataclass
class WECGridTime:
"""Centralized time coordination for WEC-Grid simulations.

Coordinates temporal aspects across power system modeling (PSS®E, PyPSA),
WEC simulations (WEC-Sim), and visualization components. Manages simulation
time windows, sampling intervals, and ensures cross-platform alignment.
"""Manage simulation time for WEC-Grid.

Attributes:
start_time (datetime): Simulation start timestamp. Defaults to current
date at midnight.
num_steps (int): Number of simulation time steps. Defaults to 288
(24 hours at 5-minute intervals).
freq (str): Pandas frequency string for time intervals. Defaults to "5min"
(5-minute intervals).

sim_stop (datetime): Calculated simulation end timestamp.
Automatically computed from start_time, sim_length, and freq.
Updated whenever simulation parameters change.

Example:
>>> # Default 24-hour simulation at 5-minute intervals
>>> time_mgr = WECGridTime()
>>> print(f"Duration: {time_mgr.num_steps} steps")
>>> print(f"Interval: {time_mgr.freq}")
Duration: 288 steps
Interval: 5T

>>> # Custom simulation period
>>> from datetime import datetime
>>> time_mgr = WECGridTime(
... start_time=datetime(2023, 6, 15, 0, 0, 0),
... sim_length=144, # 12 hours
... freq="5min"
... )
>>> print(f"Start: {time_mgr.start_time}")
start_time: Simulation start timestamp.
num_steps: Number of time steps.
freq: Pandas frequency string (e.g., ``"5min"``).
delta_time: Step size in seconds.
"""

start_time: datetime = field(
Expand All @@ -71,11 +38,7 @@ def _update_sim_stop(self):

@property
def snapshots(self) -> pd.DatetimeIndex:
"""Generate time snapshots for simulation time series.

Returns:
pd.DatetimeIndex: Simulation timestamps from start_time with length sim_length.
"""
"""Return simulation timestamps."""
return pd.date_range(
start=self.start_time,
periods=self.num_steps,
Expand Down
124 changes: 17 additions & 107 deletions src/wecgrid/wec/device.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
"""
Individual Wave Energy Converter device modeling for power system integration.

This module provides the WECDevice dataclass for representing individual Wave Energy
Converter (WEC) devices with their associated time-series data, grid connection
parameters, and simulation metadata. WECDevice objects form the building blocks
of WEC farms in power system studies.
"""
"""Data model for a single Wave Energy Converter device."""

# Standard library
from dataclasses import dataclass, field
Expand All @@ -18,42 +11,15 @@

@dataclass
class WECDevice:
"""Individual Wave Energy Converter device with time-series power output data.

Represents a single wave energy converter with simulation results, grid connection
parameters, and metadata. Contains time-series power output data from WEC-Sim
hydrodynamic simulations for realistic renewable generation modeling.
"""Wave Energy Converter with time-series power output.

Attributes:
name (str): Unique device identifier, typically "{model}_{sim_id}_{index}".
dataframe (pd.DataFrame): Primary time-series data for grid integration at
5-minute intervals. Columns: time, p [MW], q [MVAr], base [MVA].
dataframe_full (pd.DataFrame): High-resolution simulation data with complete
WEC-Sim output including wave elevation and device states.
base (float, optional): Base power rating [MVA] for per-unit calculations.
bus_location (int, optional): Power system bus number for grid connection.
model (str, optional): WEC device model type ("RM3", "LUPA", etc.).
sim_id (int, optional): Database simulation identifier for traceability.

Example:
>>> power_data = pd.DataFrame({
... 'p': [2.5, 3.1, 2.8], # MW
... 'q': [0.0, 0.0, 0.0], # MVAr
... 'base': [100.0] * 3 # MVA
... })
>>> device = WECDevice(
... name="RM3_101_0",
... dataframe=power_data,
... base=100.0,
... bus_location=14,
... model="RM3"
... )

Notes:
- Variable power output based on wave conditions
- Typically operates at unity power factor (zero reactive power)
- Primary dataframe at 5-minute resolution for grid compatibility
- Full dataframe contains high-resolution WEC-Sim results
name: Device identifier, usually ``"{model}_{sim_id}_{index}"``.
dataframe: 5-minute power time series with ``p`` and ``q`` columns
in per unit.
bus_location: Bus number for grid connection.
model: WEC model name (e.g., ``"RM3"``).
wec_sim_id: Simulation identifier in the database.
"""

name: str
Expand All @@ -63,68 +29,12 @@ class WECDevice:
wec_sim_id: Optional[int] = None

def __repr__(self) -> str:
"""Return a formatted string representation of the WEC device configuration.

Provides a hierarchical display of key device parameters for debugging,
logging, and user information. The format shows essential device
characteristics including identification, grid connection, and data status.

Returns:
str: Formatted multi-line string with device configuration details.
Includes device name, model type, grid connection parameters,
simulation metadata, base power rating, and data size in a
tree-like structure for easy reading.

Example:
>>> device = WECDevice(
... name="RM3_101_0",
... model="RM3",
... bus_location=14,
... sim_id=101,
... dataframe=power_data # 288 rows
... )
>>> print(device)
WECDevice:
├─ name: 'RM3_101_0'
├─ model: 'RM3'
├─ bus_location: 14
├─ sim_id: 101
└─ rows: 288

Display Format:
- **Tree structure**: Uses Unicode box-drawing characters
- **Device identification**: Name and model type in quotes
- **Grid parameters**: Bus location and simulation ID as integers
- **Data size**: Number of time-series data points

Information Categories:
- **Identity**: Device name (typically includes model and index)
- **Type**: WEC model for hydrodynamic characteristics
- **Grid connection**: Bus location for electrical network modeling
- **Simulation link**: Database ID for traceability
- **Data status**: Time-series length for validation

Use Cases:
- **Interactive debugging**: Quick device configuration inspection
- **Jupyter notebooks**: Clean display in research environments
- **Logging output**: Structured device information for log files
- **Data validation**: Verify device setup and data availability
- **Farm inspection**: Review individual devices in large collections

Notes:
- Name and model shown in quotes to distinguish strings
- Row count reflects primary dataframe length (grid integration data)
- Missing values displayed as None for optional parameters
- Unicode characters may not display properly in all terminals
- Format consistent with WECFarm.__repr__() for visual coherence

See Also:
WECFarm.__repr__: Similar formatting for farm-level display
"""
return f"""WECDevice:
├─ name: {self.name!r}
├─ model: {self.model!r}
├─ bus_location: {self.bus_location}
├─ sim_id: {self.wec_sim_id}
└─ rows: {len(self.dataframe)}
"""
"""Return a compact string describing the device."""
return (
f"WECDevice:\n"
f"├─ name: {self.name!r}\n"
f"├─ model: {self.model!r}\n"
f"├─ bus_location: {self.bus_location}\n"
f"├─ sim_id: {self.wec_sim_id}\n"
f"└─ rows: {len(self.dataframe)}"
)
Loading