optiwindnet.api =============== .. py:module:: optiwindnet.api Module Contents --------------- .. py:class:: Router Bases: :py:obj:`abc.ABC` Abstract base class for routing algorithms in OptiWindNet. Each Router implementation must define a :meth:`route` method. .. py:method:: __repr__() -> str .. py:method:: route(P: networkx.PlanarEmbedding, A: networkx.Graph, cables: list[tuple[int, float | int]], cables_capacity: int, verbose: bool, **kwargs) -> tuple[networkx.Graph, networkx.Graph] :abstractmethod: Run the routing optimization. :param P: Navigation mesh for the location. :param A: Graph of available links. :param cables: set of cable specifications as [(capacity, linear_cost), ...]. :param cables_capacity: highest cable capacity in cables. :param verbose: Whether to print progress/logging info. :param \*\*kwargs: Additional router-specific parameters. :returns: Tuple of (solution topology (selected links), optimized route set). .. py:class:: WindFarmNetwork(cables: int | list[int] | list[tuple[int, float | int]] | numpy.ndarray, turbinesC: numpy.ndarray | None = None, substationsC: numpy.ndarray | None = None, borderC: numpy.ndarray = np.empty((0, 2), dtype=np.float64), obstacleC_: Sequence[numpy.ndarray] = [], name: str = '', handle: str = '', L: networkx.Graph | None = None, router: Router | None = None, verbose: bool = False) Wind farm electrical network. Wrapper of most of OptiWindNet's functionality (optimization, visualization, cost/length evaluation, and gradient calculation). An instance represents a wind farm location, which initially contains the number and positions of wind turbines and substations, the delimited area and eventual obstacles. A cable network may be provided or a :class:`Router` instance may be used to create an optimized network. Initialize a wind farm electrical network. :param cables: properties of the available cable types (see Cable Specs below) :param turbinesC: Turbine coordinates (T, 2): ``[(x, y), ...]``. :param substationsC: Substation coordinates (R, 2): ``[(x, y), ...]``. :param borderC: Polygonal border coordinates (_, 2): ``[(x, y), ...]``. :param obstacleC_: One or more polygons for exclusion zones list of (_, 2): ``[[(x, y), ...], ...]``. :param name: Human-readable instance name. Defaults to "". :param handle: Short instance identifier. Defaults to "". :param L: Location geometry (takes precedence over coordinate inputs). :param router: Routing algorithm instance. Defaults to :class:`EWRouter`. :param buffer_dist: Buffer distance to dilate borders / erode obstacles. Defaults to 0. **Cable Specs** (``capacity`` is in number of turbines): * List of 2-tuple cable specifications: ``[(capacity, linear_cost), ...]``. * List of capacity per cable type: ``[capacity, ...]``. * Maximum capacity of all available cables (single value): ``capacity``. .. note:: * If both ``L`` and coordinates are provided, ``L`` takes precedence. * Changing coordinate data after creation (``turbinesC`` and/or ``substationsC``) rebuilds ``L`` and refreshes the navigation mesh and available links. Example:: wfn = WindFarmNetwork( cables=[(3, 100.0), (5, 150.0)], turbinesC=np.array([[0, 0], [1, 0], [0, 1]]), substationsC=np.array([[10, 0]]), ) wfn.optimize() print(wfn.cost(), wfn.length()) .. py:attribute:: name :value: '' Instance name. .. py:attribute:: handle :value: '' Short instance identifier. .. py:property:: router :type: Router Router instance used for optimization. .. py:property:: cables :type: list[tuple[int, float | int]] Set of cable specifications as ``[(capacity, linear_cost), ...]``. .. py:attribute:: verbose :value: False Enable verbose logging. .. py:property:: L :type: networkx.Graph Location geometry (turbines, substations, borders, obstacles). .. py:property:: polygon :type: shapely.Polygon | shapely.MultiPolygon | None Shapely (Multi)Polygon that bounds the cable-laying area. .. py:property:: P :type: networkx.PlanarEmbedding Triangular mesh over ``L`` (navigation mesh). .. py:property:: A :type: networkx.Graph Available links graph (search space). .. py:property:: S :type: networkx.Graph Solution topology (selected links). .. py:property:: G :type: networkx.Graph Optimized network with cable routes and types. .. py:property:: buffer_dist :type: float Buffer distance applied to dilate borders / erode obstacles. .. py:method:: cost() -> float Get the total cost of the optimized network. .. py:method:: length() -> float Get the total cable length of the optimized network. .. py:method:: plot_original_vs_buffered(**kwargs) -> matplotlib.axes.Axes | None Plot original and buffered borders and obstacles on a single plot. :param \*\*kwargs: passed to matplotlib's pyplot.figure() :returns: matplotlib Axes instance. .. py:method:: from_own_yaml(filepath: str, **kwargs) :classmethod: Create a WindFarmNetwork instance from an OptiWindNet (OWN) YAML file. .. py:method:: from_yaml(filepath: str, **kwargs) :classmethod: Deprecated: use :meth:`from_own_yaml` instead. .. py:method:: from_pbf(filepath: pathlib.Path | str, **kwargs) :classmethod: Create a WindFarmNetwork instance from a .OSM.PBF file. .. py:method:: from_windIO(filepath: pathlib.Path | str, **kwargs) :classmethod: Create a WindFarmNetwork instance from WindIO yaml file. .. py:method:: __repr__() -> str Concise one-line summary for console/debugging. Defensive by design: instance attributes are getattr-guarded so the repr never raises, even on a partially-initialized instance (e.g. if :meth:`__init__` aborted before ``_T``/``_R`` were set). The solved-network branch is reached only when ``_is_stale_SG`` is ``False``, which guarantees ``_G`` exists. .. py:method:: plot(*args, **kwargs) Plot the optimized network. By default, this method utilizes the modern vector SVG-based plotting backend (:func:`svgplot`) which returns an :class:`SvgRepr` suitable for clean interactive inline displays in Jupyter notebooks. To switch to the Matplotlib-based plotting backend (:func:`gplot`), specify the ``ax`` parameter as a keyword argument. .. note:: Passing ``ax=None`` explicitly routes to the Matplotlib backend and automatically instantiates a new figure and axes on the fly, allowing Matplotlib figures to be created without importing ``matplotlib`` or ``pyplot`` directly in the user code. .. py:method:: plot_location(**kwargs) Plot the original location geometry. .. py:method:: plot_available_links(**kwargs) Plot available links from planar embedding. .. py:method:: plot_navigation_mesh(**kwargs) Plot navigation mesh (planar graph and adjacency). .. py:method:: plot_selected_links(**kwargs) Plot link selection (tentative feeder routes). .. py:method:: terse_links(*, routed: bool = False) -> optiwindnet.terse.TerseLinks Get a compact representation of the solution. By default the representation contains topology ``S`` and can be routed again against updated coordinates. With ``routed=True`` it contains the exact routeset ``G``, including contour and detour clone mappings. .. py:method:: update_from_terse_links(terse_links: optiwindnet.terse.TerseLinks | numpy.ndarray, turbinesC: numpy.ndarray | None = None, substationsC: numpy.ndarray | None = None, topology: optiwindnet.types.Topology | str | None = None) Update the network from terse link representation. A topology-scoped value is routed against this network's location; a routeset-scoped value restores its recorded contour and detour paths. Plain arrays remain accepted for topology input and may contain integers or integer-like floats (e.g., 3.0). Pass ``topology`` with a plain array when radial/branched identity must be retained. .. py:method:: get_network() Export the optimized network as a structured array. .. py:method:: map_detour_vertex() Map detour vertices back to their original coordinate indices. .. py:method:: merge_obstacles_into_border() .. py:method:: add_buffer(buffer_dist) Dilate the cable-laying area by ``buffer_dist``. Useful if boundaries are not strictly enforced during optimization. This may happen if boundary compliance is achieved through the application of penalties for violations. OptiWindNet will fail if turbines are outside the border, so choose a ``buffer_dist`` that is greater than the maximum single step in position. :param buffer_dist: Buffer distance to dilate borders / erode obstacles. .. py:method:: gradient(turbinesC=None, substationsC=None, gradient_type='length') Compute length/cost gradients with respect to node positions. .. py:method:: optimize(turbinesC=None, substationsC=None, router=None, verbose=False) Optimize electrical network. .. py:method:: solution_info() Get model and solver information of the latest solution (runtime, objective, gap, etc.). .. py:class:: EWRouter(maxiter: int = 10000, feeder_route: str = 'segmented', method: str = 'biased_EW', bias_margin: float | None = None, verbose: bool = False, **kwargs) Bases: :py:obj:`Router` A lightweight, ultra-fast router for electrical network optimization. * Uses a modified Esau-Williams (EW) heuristic (segmented or straight feeders). * Produces solutions in milliseconds, suitable for quick solutions or warm starts. Create a Esau-Williams-based router. Available Methods: ``'esau_williams'`` Esau-Williams C-MST heuristic modified to avoid crossings (EW). ``'biased_EW'`` EW with a bias towards moving radially (root-ward) on quasi-ties. ``'rootlust'`` EW with a tunable root-ward bias that increases as capacity decreases. ``'radial_EW'`` EW variant that produces radial subtrees (simple paths from root). ``'ringed'`` Closes each subtree into a ring: both endpoints connect to the same root (two feeders) joined at a zero-load link. ``cables_capacity`` is the per-arm limit, so a ring holds up to twice as many terminals. Unions are ranked by their total saving — the feeders shed at the two joined endpoints minus the connecting edge's length (Clarke-Wright style) — with a ``bias_margin`` window favoring the more root-ward union on quasi-ties. :param maxiter: Maximum iterations. :param feeder_route: Feeder routing mode (``'segmented'`` or ``'straight'``). :param method: one of the **Available Methods**, defaults to ``'biased_EW'``). :param bias_margin: Fractional margin within which candidates are considered equivalent, resolving the quasi-tie root-ward (used by ``'biased_EW'``, ``'radial_EW'`` and ``'ringed'``; for ``'ringed'`` the margin is a fraction of the best union ``saving`` rather than the edge ``extent``). Defaults to the constructor's built-in default (0.02) when ``None``. :param verbose: Enable verbose logging. .. py:attribute:: verbose :value: False .. py:attribute:: maxiter :value: 10000 .. py:attribute:: feeder_route :value: 'segmented' .. py:attribute:: method :value: 'biased_EW' .. py:attribute:: bias_margin :value: None .. py:method:: route(P, A, cables, cables_capacity, verbose=False, **kwargs) Run the routing optimization. :param P: Navigation mesh for the location. :param A: Graph of available links. :param cables: set of cable specifications as [(capacity, linear_cost), ...]. :param cables_capacity: highest cable capacity in cables. :param verbose: Whether to print progress/logging info. :param \*\*kwargs: Additional router-specific parameters. :returns: Tuple of (solution topology (selected links), optimized route set). .. py:class:: HGSRouter(time_limit: float, feeder_limit: int | None = None, feeder_exact: bool = False, max_retries: int = 10, balanced: bool = False, ringed: bool = False, seed: int | None = None, verbose: bool = False, **kwargs) Bases: :py:obj:`Router` A fast router based on Hybrid Genetic Search (HGS-CVRP). Uses the method and implementation by Vidal, 2022: Vidal, T. (2022). Hybrid genetic search for the CVRP: Open-source implementation and SWAP* neighborhood. Computers & Operations Research, 140, 105643. https://doi.org/10.1016/j.cor.2021.105643 * Balances solution quality and runtime. * Produces radial solutions, or RINGED (cycle) solutions with ``ringed=True``. Create an HGS-based router. :param time_limit: Maximum runtime for a single HGS run (in seconds). :param feeder_limit: Maximum number of feeders allowed (ignored if multiple substations); the exact number if ``feeder_exact``. :param feeder_exact: Whether ``feeder_limit`` is the exact number of feeders, instead of an upper bound (requires ``balanced=True`` and a single substation). :param max_retries: Maximum number of retries if a feasible solution is not found. :param balanced: Whether to balance turbines/loads across feeders. :param ringed: Whether to produce a RINGED topology (cycles) instead of a radial one. HGS then solves the closed CVRP, so each ring holds up to ``2 * cables_capacity`` turbines (two arms of ``cables_capacity`` each). :param seed: Set the seed of the pseudo-random number generator (reproducibility). :param verbose: Enable verbose logging. .. note:: The total runtime may reach up to ``(max_retries + 1) * time_limit`` in the worst case. .. py:attribute:: time_limit .. py:attribute:: verbose :value: False .. py:attribute:: max_retries :value: 10 .. py:attribute:: feeder_limit :value: None .. py:attribute:: feeder_exact :value: False .. py:attribute:: balanced :value: False .. py:attribute:: ringed :value: False .. py:attribute:: seed :value: None .. py:method:: route(P, A, cables, cables_capacity, verbose=False, **kwargs) Run the routing optimization. :param P: Navigation mesh for the location. :param A: Graph of available links. :param cables: set of cable specifications as [(capacity, linear_cost), ...]. :param cables_capacity: highest cable capacity in cables. :param verbose: Whether to print progress/logging info. :param \*\*kwargs: Additional router-specific parameters. :returns: Tuple of (solution topology (selected links), optimized route set). .. py:class:: MILPRouter(solver_name: str, time_limit: float, mip_gap: float, solver_options: dict | None = None, model_options: collections.abc.Mapping[str, Any] | None = None, verbose: bool = False, **kwargs) Bases: :py:obj:`Router` An exact router using mathematical programming. * Uses a Mixed-Integer Linear Programming (MILP) model of the problem. * Produces provably optimal or near-optimal networks (with quality metrics). * Requires a longer runtime than heuristics- and meta-heuristics-based routers. Create a MILP-based router. :param solver_name: Name of solver (e.g., ``'gurobi'``, ``'cbc'``, ``'ortools'``, ``'cplex'``, ``'highs'``, ``'scip'``). :param time_limit: Maximum runtime (seconds). :param mip_gap: Relative MIP optimality gap tolerance. :param solver_options: Extra solver-specific options. :param model_options: Options for the MILP model. A plain mapping is coerced into a :class:`.ModelOptions`. :param verbose: Enable verbose logging. .. py:attribute:: default_heuristic :value: 'rootlust' .. py:attribute:: time_limit .. py:attribute:: mip_gap .. py:attribute:: solver_name .. py:attribute:: solver_options .. py:attribute:: model_options .. py:attribute:: verbose :value: False .. py:attribute:: solver .. py:method:: route(P, A, cables, cables_capacity, verbose=False, S_warm=None, S_warm_has_detour=False, num_retries: int = 2, **kwargs) Run the routing optimization. :param P: Navigation mesh for the location. :param A: Graph of available links. :param cables: set of cable specifications as [(capacity, linear_cost), ...]. :param cables_capacity: highest cable capacity in cables. :param verbose: Whether to print progress/logging info. :param \*\*kwargs: Additional router-specific parameters. :returns: Tuple of (solution topology (selected links), optimized route set).