#  -------------------------------------------------------------------------------
#       Copyright (C) 2026  Joel Kimmich, Tim Jourdan
#  ------------------------------------------------------------------------------
#   License
#       This file is part of PyRC, distributed under GPL-3.0-or-later.
#  ------------------------------------------------------------------------------
"""
Internal heat source example
=============================
This example creates and simulates a plate with a heat source in the middle and different boundary conditions on each
side.
"""
# sphinx_gallery_tags = ["network", "solving", "build", "stationary", "geometric"]
# sphinx_gallery_thumbnail_path = "_static/examples/internal_heat_source.svg"

import os
import numpy as np

from pyrc import (
    Node,
    InternalHeatSource,
    SolidBoundaryConditionCell,
    Viewer,
    connect_cells_with_resistors,
    RCNetwork,
    LinePlot,
)
from pyrc.core.materials import Copper


# %%
# Create the plate as grid of cells
# ----------------------------------

grid_resolution = 15
plate_thickness = 0.003
material = Copper()
grid = Node.create_grid(
    grid_size=(grid_resolution, grid_resolution, 1),
    delta=(1, 1, plate_thickness),
    material=material,
    temperature=20,
)
capacitors: list[Node] = grid.flatten().tolist()

# %%
# Add heat source in a circle at the center
# -----------------------------------------

radius = 2.5
center_x, center_y = (grid.shape[0] - 1) / 2, (grid.shape[1] - 1) / 2
x, y = np.ogrid[: grid.shape[0], : grid.shape[1]]
mask = (x - center_x) ** 2 + (y - center_y) ** 2 <= radius**2
cells_in_circle = grid[mask, 0]

for cell in cells_in_circle:
    cell.add_internal_heat_source(
        InternalHeatSource(
            node=cell,
            specific_power_in_w_per_meter_squared=1000,
            area_direction=np.array((0, 0, 1)),
        )
    )

# %%
# Create boundary conditions and place them adjacent to cell grid
# ----------------------------------------------------------------

bc_x_negative = SolidBoundaryConditionCell(temperature=-10, position=(0, 0, 0), delta=(0.1, 1, plate_thickness))
capacitors[0].place_adjacent(bc_x_negative, "-x")
bc_x_positive = SolidBoundaryConditionCell(temperature=-5, position=(0, 0, 0), delta=(0.1, 1, plate_thickness))
capacitors[-1].place_adjacent(bc_x_positive, "x")
bc_y_negative = SolidBoundaryConditionCell(temperature=-2, position=(0, 0, 0), delta=(1, 0.1, plate_thickness))
capacitors[0].place_adjacent(bc_y_negative, "-y")
bc_y_positive = SolidBoundaryConditionCell(temperature=3, position=(0, 0, 0), delta=(1, 0.1, plate_thickness))
capacitors[-1].place_adjacent(bc_y_positive, "y")

boundaries = [bc_x_negative, bc_x_positive, bc_y_negative, bc_y_positive]

# %%
# View the network with VPython (add debugger breakpoint to view)
# ----------------------------------------------------------------
# The coordinate system arrows are disabled because they are very big for this network.
# Comment out these lines if you just want to run the code. But during network build up it is nice to see if you placed
# everything correct.

viewer = Viewer(draw_coordinate_system=False)
viewer.add_new_from_list(capacitors)
viewer.add_new_from_list(boundaries)

# %%
# Connect everything with resistors between all Cells
# ----------------------------------------------------

resistors = connect_cells_with_resistors([*capacitors, *boundaries])

# %%
# Create RCNetwork
# -----------------

network = RCNetwork(load_from_pickle=False, load_solution=False)
network.rc_objects.set_lists(capacitors=capacitors, resistors=resistors, boundaries=boundaries)

# %%
# Solve network.
# ---------------
# We solve the network stationary (analytical).
network.solve_stationary()

# %%
# Parse the result to show it in ParaView
# ----------------------------------------
# Open the case in ParaView using the 00_simulation.pvd file

network.rc_solution.write_paraview_data(
    folder=os.path.normpath(r"/path/to/result/folder"),
    use_degrees_celsius=False,  # temperature is already in °C
)

# %%
# The result looks like this (or at least quite similar; the picture might be from an earlier version):

# %%
# .. image:: /_static/examples/internal_heat_source.svg
#    :width: 100%