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
52 changes: 52 additions & 0 deletions heatrapy/dimension_1/solvers/_latent_heat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Shared latent heat computation for 1D solvers."""

import copy


def apply_latent_heat(nx, obj):
"""Apply latent heat corrections to computed temperatures.

Handles phase transitions by absorbing/releasing energy when the
temperature crosses a transition threshold.

Parameters
----------
nx : list
New temperatures for each grid point (modified in place).
obj : Object
Thermal object with current state.

Returns
-------
lheat : list
Updated latent heat accumulation state.

"""
lheat = copy.copy(obj.lheat)
for i in range(1, obj.num_points - 1):
j = 0
for lh in obj.latent_heat[i]:
temper = obj.temperature[i][0]
# heating: crossing transition from below
if nx[i] > lh[0] and temper <= lh[0] and lheat[i][j][1] != lh[1]:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - temper)
if en + lheat[i][j][1] >= lh[1]:
lheat[i][j][1] = lh[1]
energy_temp = lheat[i][j][1] + en - lh[1]
nx[i] = temper + energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = temper
# cooling: crossing transition from above
if nx[i] < lh[0] and temper >= lh[0] and lheat[i][j][1] != 0:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - temper)
if en + lheat[i][j][1] <= 0.:
lheat[i][j][1] = 0.
energy_temp = (en + lheat[i][j][1])
nx[i] = temper + energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = temper
j += 1

return lheat
105 changes: 39 additions & 66 deletions heatrapy/dimension_1/solvers/explicit_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

"""

import copy
import numpy as np

from ._latent_heat import apply_latent_heat


def explicit_general(obj):
Expand All @@ -14,75 +16,46 @@ def explicit_general(obj):
conductivity.

"""
x = copy.deepcopy(obj.temperature)

# computes
for i in range(1, obj.num_points - 1):

alpha = obj.dt * \
obj.k[i] / (obj.rho[i] * obj.Cp[i] *
obj.dx * obj.dx)
beta = obj.dt / (obj.rho[i] * obj.Cp[i])

t_new = ((1 + beta * obj.Q[i]) * obj.temperature[i][0] +
alpha * (obj.temperature[i - 1][0] - 2 *
obj.temperature[i][0] + obj.temperature[i + 1][0]) +
beta * (obj.Q0[i] - obj.Q[i] * obj.amb_temperature))
x[i][1] = t_new

# left boundary for next time step
n = obj.num_points
s = slice(1, n - 1)

# extract current temperatures and material properties as arrays
T = np.array([obj.temperature[i][0] for i in range(n)], dtype=float)
k = np.array([obj.k[i] if obj.k[i] is not None else 0.0 for i in range(n)])
rho = np.array([obj.rho[i] if obj.rho[i] is not None else 1.0
for i in range(n)])
Cp = np.array([obj.Cp[i] if obj.Cp[i] is not None else 1.0
for i in range(n)])
Q = np.array([obj.Q[i] if obj.Q[i] is not None else 0.0
for i in range(n)])
Q0 = np.array([obj.Q0[i] if obj.Q0[i] is not None else 0.0
for i in range(n)])

# vectorized FDM stencil for interior points
alpha = obj.dt * k[s] / (rho[s] * Cp[s] * obj.dx * obj.dx)
beta = obj.dt / (rho[s] * Cp[s])

nx = T.copy()
nx[s] = ((1 + beta * Q[s]) * T[s] +
alpha * (T[0:n-2] - 2 * T[s] + T[2:n]) +
beta * (Q0[s] - Q[s] * obj.amb_temperature))

# boundaries
if obj.boundaries[0] == 0:
x[0][1] = obj.temperature[1][1]
nx[0] = T[1]
else:
x[0][1] = obj.boundaries[0]
nx[0] = obj.boundaries[0]

# right boundary for next time step
if obj.boundaries[1] == 0:
x[obj.num_points - 1][1] = obj.temperature[obj.num_points - 2][1]
nx[n - 1] = T[n - 2]
else:
x[obj.num_points - 1][1] = obj.boundaries[1]

# updates temperature for next iteration
for i in range(0, obj.num_points):
x[i][0] = x[i][1]

nx = []
for i in range(len(x)):
nx.append(x[i][0])

# latent heat
lheat = copy.copy(obj.lheat)
for i in range(1, obj.num_points - 1):
j = 0
for lh in obj.latent_heat[i]:
temper = obj.temperature[i][0]
if nx[i] > lh[0] and temper <= lh[0] and lheat[i][j][1] != lh[1]:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - obj.temperature[i][0])
if en + lheat[i][j][1] >= lh[1]:
lheat[i][j][1] = lh[1]
energy_temp = lheat[i][j][1] + en - lh[1]
nx[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = obj.temperature[i][0]
if nx[i] < lh[0] and temper >= lh[0] and lheat[i][j][1] != 0:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - obj.temperature[i][0])
if en + lheat[i][j][1] <= 0.:
lheat[i][j][1] = 0.
energy_temp = (en + lheat[i][j][1])
nx[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = obj.temperature[i][0]
j += 1

y = copy.deepcopy(obj.temperature)

# updates the temperature list
for i in range(obj.num_points):
y[i][1] = nx[i]
y[i][0] = nx[i]
nx[n - 1] = obj.boundaries[1]

# latent heat (per-element, branching logic)
nx_list = nx.tolist()
lheat = apply_latent_heat(nx_list, obj)

# pack into [current, next] pairs expected by the caller
y = [[nx_list[i], nx_list[i]] for i in range(n)]

return y, lheat
107 changes: 41 additions & 66 deletions heatrapy/dimension_1/solvers/explicit_k.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

"""

import copy
import numpy as np

from ._latent_heat import apply_latent_heat


def explicit_k(obj):
Expand All @@ -14,75 +16,48 @@ def explicit_k(obj):
conductivity.

"""
x = copy.deepcopy(obj.temperature)

# computes
for i in range(1, obj.num_points - 1):
eta = obj.dt / (2. * obj.rho[i] * obj.Cp[i] * obj.dx * obj.dx)
beta = obj.dt / (obj.rho[i] * obj.Cp[i])

t_new = ((1 + beta * obj.Q[i]) * obj.temperature[i][0] +
eta * ((obj.k[i + 1] + obj.k[i]) * obj.temperature[i + 1][0] -
(obj.k[i - 1] + obj.k[i + 1] + 2 * obj.k[i]) *
obj.temperature[i][0] + (obj.k[i - 1] + obj.k[i]) *
obj.temperature[i - 1][0]) +
beta * (obj.Q0[i] - obj.Q[i] * obj.amb_temperature))

x[i][1] = t_new

# left boundary for next time step
n = obj.num_points
s = slice(1, n - 1)

# extract current temperatures and material properties as arrays
T = np.array([obj.temperature[i][0] for i in range(n)], dtype=float)
k = np.array([obj.k[i] if obj.k[i] is not None else 0.0 for i in range(n)])
rho = np.array([obj.rho[i] if obj.rho[i] is not None else 1.0
for i in range(n)])
Cp = np.array([obj.Cp[i] if obj.Cp[i] is not None else 1.0
for i in range(n)])
Q = np.array([obj.Q[i] if obj.Q[i] is not None else 0.0
for i in range(n)])
Q0 = np.array([obj.Q0[i] if obj.Q0[i] is not None else 0.0
for i in range(n)])

# vectorized FDM stencil for interior points (k varies with x)
eta = obj.dt / (2.0 * rho[s] * Cp[s] * obj.dx * obj.dx)
beta = obj.dt / (rho[s] * Cp[s])

nx = T.copy()
nx[s] = ((1 + beta * Q[s]) * T[s] +
eta * ((k[2:n] + k[s]) * T[2:n] -
(k[0:n-2] + k[2:n] + 2 * k[s]) * T[s] +
(k[0:n-2] + k[s]) * T[0:n-2]) +
beta * (Q0[s] - Q[s] * obj.amb_temperature))

# boundaries
if obj.boundaries[0] == 0:
x[0][1] = obj.temperature[1][1]
nx[0] = T[1]
else:
x[0][1] = obj.boundaries[0]
nx[0] = obj.boundaries[0]

# right boundary for next time step
if obj.boundaries[1] == 0:
x[obj.num_points - 1][1] = obj.temperature[obj.num_points - 2][1]
nx[n - 1] = T[n - 2]
else:
x[obj.num_points - 1][1] = obj.boundaries[1]

# updates temperature for next iteration
for i in range(0, obj.num_points):
x[i][0] = x[i][1]

nx = []
for i in range(len(x)):
nx.append(x[i][0])

# latent heat
lheat = copy.copy(obj.lheat)
for i in range(1, obj.num_points - 1):
j = 0
for lh in obj.latent_heat[i]:
temper = obj.temperature[i][0]
if nx[i] > lh[0] and temper <= lh[0] and lheat[i][j][1] != lh[1]:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - obj.temperature[i][0])
if en + lheat[i][j][1] >= lh[1]:
lheat[i][j][1] = lh[1]
energy_temp = lheat[i][j][1] + en - lh[1]
nx[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = obj.temperature[i][0]
if nx[i] < lh[0] and temper >= lh[0] and lheat[i][j][1] != 0:
en = obj.Cp[i] * obj.rho[i] * (nx[i] - obj.temperature[i][0])
if en + lheat[i][j][1] <= 0.:
lheat[i][j][1] = 0.
energy_temp = (en + lheat[i][j][1])
nx[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
nx[i] = obj.temperature[i][0]
j += 1

y = copy.deepcopy(obj.temperature)

# updates the temperature list
for i in range(obj.num_points):
y[i][1] = nx[i]
y[i][0] = nx[i]
nx[n - 1] = obj.boundaries[1]

# latent heat (per-element, branching logic)
nx_list = nx.tolist()
lheat = apply_latent_heat(nx_list, obj)

# pack into [current, next] pairs expected by the caller
y = [[nx_list[i], nx_list[i]] for i in range(n)]

return y, lheat
56 changes: 15 additions & 41 deletions heatrapy/dimension_1/solvers/implicit_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"""

import numpy as np
import copy

from ._latent_heat import apply_latent_heat


def implicit_general(obj):
Expand All @@ -15,9 +16,11 @@ def implicit_general(obj):
conductivity.

"""
n = obj.num_points

# initializes the matrixes for the equation systems
a = np.zeros((obj.num_points, obj.num_points))
b = np.zeros(obj.num_points)
a = np.zeros((n, n))
b = np.zeros(n)

# left boundary
a[0][0] = 1
Expand All @@ -27,15 +30,14 @@ def implicit_general(obj):
b[0] = obj.boundaries[0]

# right boundary
a[obj.num_points - 1][obj.num_points - 1] = 1
a[n - 1][n - 1] = 1
if obj.boundaries[1] == 0:
value = obj.temperature[obj.num_points - 2][0]
b[obj.num_points - 1] = value
b[n - 1] = obj.temperature[n - 2][0]
else:
b[obj.num_points - 1] = obj.boundaries[1]
b[n - 1] = obj.boundaries[1]

# creates the matrixes and solves the equation systems
for i in range(1, obj.num_points - 1):
for i in range(1, n - 1):
beta = obj.k[i] * obj.dt / \
(2 * obj.rho[i] * obj.Cp[i] * obj.dx * obj.dx)
sigma = obj.dt / (obj.rho[i] * obj.Cp[i])
Expand All @@ -52,38 +54,10 @@ def implicit_general(obj):
x = np.linalg.solve(a, b)

# latent heat
lheat = copy.copy(obj.lheat)
for i in range(1, obj.num_points - 1):
j = 0
for lh in obj.latent_heat[i]:
temper = obj.temperature[i][0]
if x[i] > lh[0] and temper <= lh[0] and lheat[i][j][1] != lh[1]:
en = obj.Cp[i] * obj.rho[i] * (x[i] - obj.temperature[i][0])
if en + lheat[i][j][1] >= lh[1]:
lheat[i][j][1] = lh[1]
energy_temp = lheat[i][j][1] + en - lh[1]
x[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
x[i] = obj.temperature[i][0]
if x[i] < lh[0] and temper >= lh[0] and lheat[i][j][1] != 0:
en = obj.Cp[i] * obj.rho[i] * (x[i] - obj.temperature[i][0])
if en + lheat[i][j][1] <= 0.:
lheat[i][j][1] = 0.
energy_temp = (en + lheat[i][j][1])
x[i] = obj.temperature[i][0] + \
energy_temp / (obj.Cp[i] * obj.rho[i])
else:
lheat[i][j][1] += en
x[i] = obj.temperature[i][0]
j += 1

y = copy.deepcopy(obj.temperature)

# updates the temperature list
for i in range(obj.num_points):
y[i][1] = x[i]
y[i][0] = x[i]
nx_list = x.tolist()
lheat = apply_latent_heat(nx_list, obj)

# pack into [current, next] pairs expected by the caller
y = [[nx_list[i], nx_list[i]] for i in range(n)]

return y, lheat
Loading
Loading