Skip to content
Open
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
24 changes: 24 additions & 0 deletions solarfarmer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@
EnergyCalculationOptions,
HorizonType,
IAMModelTypeForOverride,
IndexedObject3D,
Inverter,
InverterOverPowerShutdownMode,
InverterType,
Layout,
Location,
MeteoFileFormat,
MiniSimpleTerrainDto,
MissingMetDataMethod,
ModelChainResponse,
MonthlyAlbedo,
Expand All @@ -52,11 +54,21 @@
PanFileSupplements,
PVPlant,
PVSystem,
QuadDouble,
Rack,
Racks,
ShadingObjects,
SimpleTerrain,
TerrainRowDto,
TerrainRowStartEndColumnsDto,
Tracker,
Trackers,
TrackerSystem,
Transformer,
TransformerLossModelTypes,
TransformerSpecification,
ValidationMessage,
Vector3Double,
)
from .weather import (
TSV_COLUMNS,
Expand Down Expand Up @@ -99,12 +111,14 @@
"EnergyCalculationOptions",
"HorizonType",
"IAMModelTypeForOverride",
"IndexedObject3D",
"Inverter",
"InverterOverPowerShutdownMode",
"InverterType",
"Layout",
"Location",
"MeteoFileFormat",
"MiniSimpleTerrainDto",
"MissingMetDataMethod",
"ModelChainResponse",
"MonthlyAlbedo",
Expand All @@ -116,16 +130,26 @@
"PanFileSupplements",
"PVPlant",
"PVSystem",
"QuadDouble",
"Rack",
"Racks",
"run_energy_calculation",
"service",
"ShadingObjects",
"SimpleTerrain",
"SolarFarmerAPIError",
"TerrainRowDto",
"TerrainRowStartEndColumnsDto",
"terminate_calculation",
"Tracker",
"TrackerSystem",
"Trackers",
"TSV_COLUMNS",
"Transformer",
"TransformerLossModelTypes",
"TransformerSpecification",
"ValidationMessage",
"Vector3Double",
"from_dataframe",
"from_pvlib",
"from_solcast",
Expand Down
24 changes: 24 additions & 0 deletions solarfarmer/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
OrderColumnsPvSystFormatTimeSeries,
TransformerLossModelTypes,
)
from .indexed_object3d import IndexedObject3D
from .inverter import Inverter
from .layout import Layout
from .location import Location
from .mini_simple_terrain_dto import MiniSimpleTerrainDto
from .model_chain_response import ModelChainResponse
from .monthly_albedo import MonthlyAlbedo
from .mounting_type_specification import MountingTypeSpecification
Expand All @@ -28,9 +30,19 @@
from .pvsystem.plant_defaults import InverterType, MountingType, OrientationType
from .pvsystem.pvsystem import PVSystem
from .pvsystem.validation import ValidationMessage
from .quad_double import QuadDouble
from .rack import Rack
from .racks import Racks
from .shading_objects import ShadingObjects
from .simple_terrain import SimpleTerrain
from .terrain_row_dto import TerrainRowDto
from .terrain_row_start_end_columns_dto import TerrainRowStartEndColumnsDto
from .tracker import Tracker
from .tracker_system import TrackerSystem
from .trackers import Trackers
from .transformer import Transformer
from .transformer_specification import TransformerSpecification
from .vector3double import Vector3Double

__all__ = [
"AuxiliaryLosses",
Expand All @@ -41,12 +53,14 @@
"EnergyCalculationOptions",
"HorizonType",
"IAMModelTypeForOverride",
"IndexedObject3D",
"Inverter",
"InverterOverPowerShutdownMode",
"InverterType",
"Layout",
"Location",
"MeteoFileFormat",
"MiniSimpleTerrainDto",
"MissingMetDataMethod",
"ModelChainResponse",
"MonthlyAlbedo",
Expand All @@ -58,10 +72,20 @@
"PanFileSupplements",
"PVPlant",
"PVSystem",
"QuadDouble",
"Rack",
"Racks",
"ShadingObjects",
"SimpleTerrain",
"SolarFarmerBaseModel",
"TerrainRowDto",
"TerrainRowStartEndColumnsDto",
"Tracker",
"TrackerSystem",
"Trackers",
"Transformer",
"TransformerLossModelTypes",
"TransformerSpecification",
"ValidationMessage",
"Vector3Double",
]
36 changes: 36 additions & 0 deletions solarfarmer/models/indexed_object3d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .vector3double import Vector3Double


class IndexedObject3D(SolarFarmerBaseModel):
"""A 3D object defined by an indexed mesh of vertices and face indices.

Represents a shading obstacle or building in the 3D scene. The mesh is
described by a set of 3D vertices plus face connectivity expressed as
lists of vertex indices — either quadrilateral faces (``quad_indices``)
or triangular faces (``triangle_indices``).

Attributes
----------
is_building : bool
Whether the object should be treated as a building (affects shading
and irradiance modelling assumptions)
name : str
Descriptive name for this object in the 3D scene
quad_indices : list[list[int]]
Face connectivity for quadrilateral faces. Each inner list contains
four vertex indices referencing entries in ``vertices``
triangle_indices : list[list[int]]
Face connectivity for triangular faces. Each inner list contains
three vertex indices referencing entries in ``vertices``
vertices : list[Vector3Double]
3D vertex positions shared by both quad and triangle faces
"""

is_building: bool
name: str
quad_indices: list[list[int]] = Field(default_factory=list)
triangle_indices: list[list[int]] = Field(default_factory=list)
vertices: list[Vector3Double] = Field(default_factory=list)
35 changes: 35 additions & 0 deletions solarfarmer/models/mini_simple_terrain_dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .terrain_row_dto import TerrainRowDto
from .vector3double import Vector3Double


class MiniSimpleTerrainDto(SolarFarmerBaseModel):
"""A single terrain tile in a simple terrain representation.

Describes one rectangular patch of terrain as a regular grid of
vertices. The grid dimensions are given by ``num_vertices_across``
(columns) and ``num_vertices_down`` (rows); the actual 3D positions
are stored in ``vertices`` in row-major order.

The ``terrain_rows`` list mirrors the row structure and records which
column ranges within each row are active (contain valid data).

Attributes
----------
num_vertices_across : int
Number of vertices along the horizontal (column) axis of the grid
num_vertices_down : int
Number of vertices along the vertical (row) axis of the grid
terrain_rows : list[TerrainRowDto]
Per-row active column ranges, one entry per row of the grid
vertices : list[Vector3Double]
3D vertex positions in row-major order (``num_vertices_down`` ×
``num_vertices_across`` entries)
"""

num_vertices_across: int
num_vertices_down: int
terrain_rows: list[TerrainRowDto] = Field(default_factory=list)
vertices: list[Vector3Double] = Field(default_factory=list)
31 changes: 31 additions & 0 deletions solarfarmer/models/pv_plant.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from __future__ import annotations

from typing import Any

from pydantic import model_validator

from ._base import SolarFarmerBaseModel
from .auxiliary_losses import AuxiliaryLosses
from .indexed_object3d import IndexedObject3D
from .mounting_type_specification import MountingTypeSpecification
from .rack import Rack
from .simple_terrain import SimpleTerrain
from .tracker import Tracker
from .tracker_system import TrackerSystem
from .transformer import Transformer
from .transformer_specification import TransformerSpecification
Expand Down Expand Up @@ -33,6 +39,24 @@ class PVPlant(SolarFarmerBaseModel):
HTTP 400 error. The key must match ``Transformer.transformer_spec_id``.
auxiliary_losses : AuxiliaryLosses or None
Plant-level auxiliary losses
racks : list[Rack] or None
Fixed-tilt rack objects for 3D calculations. Not required for 2D
shading_objects : list[IndexedObject3D] or None
3D shading obstacles (buildings, terrain features, etc.). Used for
3D calculations; ignored for 2D
simple_terrain : SimpleTerrain or None
Ground surface terrain model for 3D calculations. Ignored for 2D
trackers : list[Tracker] or None
Single-axis tracker objects for 3D calculations. Not required for 2D
inverter_specifications : dict[str, Any] or None
Inverter specifications keyed by spec ID. Not required when the
inverter spec is populated from OND files
module_specifications : dict[str, Any] or None
Module specifications keyed by spec ID. Not required when the
module spec is populated from PAN files
optimizer_specifications : dict[str, Any] or None
Power optimizer specifications keyed by spec ID. Not required when
the optimizer spec is populated from DCO files
"""

transformers: list[Transformer]
Expand All @@ -41,6 +65,13 @@ class PVPlant(SolarFarmerBaseModel):
tracker_systems: dict[str, TrackerSystem] | None = None
transformer_specifications: dict[str, TransformerSpecification] | None = None
auxiliary_losses: AuxiliaryLosses | None = None
racks: list[Rack] | None = None
shading_objects: list[IndexedObject3D] | None = None
simple_terrain: SimpleTerrain | None = None
trackers: list[Tracker] | None = None
inverter_specifications: dict[str, Any] | None = None
module_specifications: dict[str, Any] | None = None
optimizer_specifications: dict[str, Any] | None = None

@model_validator(mode="after")
def _check_transformer_spec_references(self) -> PVPlant:
Expand Down
26 changes: 26 additions & 0 deletions solarfarmer/models/quad_double.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from ._base import SolarFarmerBaseModel
from .vector3double import Vector3Double


class QuadDouble(SolarFarmerBaseModel):
"""A quadrilateral in 3D space defined by four corner vertices.

Represents the footprint or boundary of a rack or similar planar object,
where the four points define the corners of a quadrilateral face.

Attributes
----------
p1 : Vector3Double
First corner vertex of the quadrilateral
p2 : Vector3Double
Second corner vertex of the quadrilateral
p3 : Vector3Double
Third corner vertex of the quadrilateral
p4 : Vector3Double
Fourth corner vertex of the quadrilateral
"""

p1: Vector3Double
p2: Vector3Double
p3: Vector3Double
p4: Vector3Double
35 changes: 35 additions & 0 deletions solarfarmer/models/rack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .quad_double import QuadDouble


class Rack(SolarFarmerBaseModel):
"""A fixed-tilt rack in a 3D plant layout.

Represents a single physical rack structure placed in the 3D scene,
identified by an integer ID and referencing a mounting type. The rack
geometry is described by a quadrilateral (``quad``) in world coordinates.

Attributes
----------
id : int
Unique integer identifier for this rack within the layout
mounting_type_id : str
Reference to a mounting type specification. Must match a key in
``PVPlant.mounting_type_specifications``
pitch_to_back : float or None
Row-to-row pitch to the adjacent rack behind this one, in metres.
``None`` if this rack has no neighbour behind it (e.g. last row)
pitch_to_front : float or None
Row-to-row pitch to the adjacent rack in front of this one, in metres.
``None`` if this rack has no neighbour in front of it (e.g. first row)
quad : QuadDouble
3D quadrilateral defining the four corner vertices of the rack surface
"""

id: int
mounting_type_id: str = Field(..., alias="mountingTypeID", min_length=1)
pitch_to_back: float | None = None
pitch_to_front: float | None = None
quad: QuadDouble
16 changes: 16 additions & 0 deletions solarfarmer/models/racks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .rack import Rack


class Racks(SolarFarmerBaseModel):
"""A collection of fixed-tilt racks in a 3D plant layout.

Attributes
----------
racks : list[Rack]
The individual rack objects making up this collection
"""

racks: list[Rack] = Field(default_factory=list)
19 changes: 19 additions & 0 deletions solarfarmer/models/shading_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .indexed_object3d import IndexedObject3D


class ShadingObjects(SolarFarmerBaseModel):
"""A collection of 3D shading obstacles in the plant scene.

Holds all near-shading objects (buildings, terrain features, etc.)
that cast shadows onto the PV plant.

Attributes
----------
objects : list[IndexedObject3D]
The individual 3D shading objects in this collection
"""

objects: list[IndexedObject3D] = Field(default_factory=list)
19 changes: 19 additions & 0 deletions solarfarmer/models/simple_terrain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pydantic import Field

from ._base import SolarFarmerBaseModel
from .mini_simple_terrain_dto import MiniSimpleTerrainDto


class SimpleTerrain(SolarFarmerBaseModel):
"""A simple terrain representation composed of one or more terrain tiles.

Aggregates multiple :class:`MiniSimpleTerrainDto` tiles that together
describe the ground surface beneath and around a 3D PV plant layout.

Attributes
----------
mini_simple_terrains : list[MiniSimpleTerrainDto]
Individual terrain tiles that make up the full terrain surface
"""

mini_simple_terrains: list[MiniSimpleTerrainDto] = Field(default_factory=list)
Loading
Loading