Skip to content

Commit be9b6bd

Browse files
fix(thermal): correct semicon κ, add temp-dependent σ, fix RMS→peak current scaling (#34)
* debug(thermal) corrected kappa for semicon materials to 0.4 W/(m·K) (IEC 60287) from 148 W/(m·K) which was incorrect. Updated in materials library and all test files. Also added earth-air interface as physical group for thermal Dirichlet BC in space.jl. * debug(thermal): add support for temperature-dependent conductivity and register earth-air interface for thermal Dirichlet BC * fix(thermal): convert RMS current to peak current used in GetDP's complex formulation
1 parent cd5fb59 commit be9b6bd

6 files changed

Lines changed: 62 additions & 27 deletions

File tree

src/engine/fem/solver.jl

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct DefineResolution end
3030

3131
DefineJacobian()(getdp_problem, workspace)
3232
DefineIntegration()(getdp_problem)
33-
DefineMaterialProps()(getdp_problem, workspace)
33+
DefineMaterialProps()(getdp_problem, workspace; temp_dependent_sigma=false)
3434
DefineConstants()(getdp_problem, frequency)
3535
DefineDomainGroups()(getdp_problem, f, workspace, active_cond)
3636
DefineConstraint()(getdp_problem, f)
@@ -55,7 +55,7 @@ end
5555

5656
DefineJacobian()(getdp_problem, workspace)
5757
DefineIntegration()(getdp_problem)
58-
DefineMaterialProps()(getdp_problem, workspace)
58+
DefineMaterialProps()(getdp_problem, workspace; temp_dependent_sigma=true)
5959
DefineConstants()(getdp_problem, frequency, workspace)
6060
DefineDomainGroups()(getdp_problem, f, workspace)
6161
DefineConstraint()(getdp_problem, workspace)
@@ -118,7 +118,8 @@ end
118118

119119
end
120120

121-
@inline function (f::DefineMaterialProps)(problem::GetDP.Problem, workspace::FEMWorkspace)
121+
@inline function (f::DefineMaterialProps)(problem::GetDP.Problem, workspace::FEMWorkspace;
122+
temp_dependent_sigma::Bool=false)
122123
# Create material properties function
123124
func = GetDP.Function()
124125

@@ -132,12 +133,20 @@ end
132133
)
133134
add_space!(func)
134135
GetDP.add!(func, "nu", expression = 1 / (mat.mu_r * μ₀), region = [tag])
135-
GetDP.add!(
136-
func,
137-
"sigma",
138-
expression = isinf(mat.rho) ? 0.0 : 1 / mat.rho,
139-
region = [tag],
140-
)
136+
137+
sigma0 = isinf(mat.rho) ? 0.0 : 1 / mat.rho
138+
if temp_dependent_sigma && sigma0 != 0.0 && mat.alpha != 0.0
139+
# Temperature-dependent σ(T) = σ₀ / (1 + α·(T - T₀))
140+
# $1 receives {T} (Kelvin) from sigma[{T}] in Galerkin terms
141+
T0_K = mat.T0 + 273.15
142+
GetDP.add!(func, "sigma",
143+
expression = "$sigma0 / (1.0 + $(mat.alpha) * (\$1 - $T0_K))",
144+
region = [tag])
145+
else
146+
# Constant sigma (insulator, no temp coeff, or non-thermal formulation)
147+
GetDP.add!(func, "sigma", expression = sigma0, region = [tag])
148+
end
149+
141150
GetDP.add!(func, "epsilon", expression = mat.eps_r * ε₀, region = [tag])
142151
GetDP.add!(func, "k", expression = mat.kappa, region = [tag])
143152
end
@@ -296,6 +305,7 @@ end
296305
inds_reg = Int[]
297306
cables_reg = Dict{Int, Vector{Int}}()
298307
boundary_reg = Int[]
308+
earth_surface_reg = Int[]
299309
is_magneto_thermal = fem_formulation isa MagnetoThermal
300310

301311
for tag in keys(workspace.core.physical_groups)
@@ -320,7 +330,10 @@ end
320330
surface_type == 3 && push!(material_reg[:DomainInf], tag)
321331

322332
else
323-
decode_boundary_tag(tag)[1] == 2 && push!(boundary_reg, tag)
333+
curve_type, layer_idx, _ = decode_boundary_tag(tag)
334+
curve_type == 2 && push!(boundary_reg, tag)
335+
# Earth-air interface (curve_type=3, layer_idx=1) for thermal Dirichlet BC
336+
(curve_type == 3 && layer_idx == 1) && push!(earth_surface_reg, tag)
324337
end
325338
end
326339
inds_reg = sort(inds_reg)
@@ -371,7 +384,7 @@ end
371384

372385
GetDP.add!(group, "Domain_Mag", ["DomainCC", "DomainC"], "Region")
373386
GetDP.add!(group, "Sur_Dirichlet_Mag", boundary_reg, "Region")
374-
GetDP.add!(group, "Sur_Dirichlet_The", boundary_reg, "Region")
387+
GetDP.add!(group, "Sur_Dirichlet_The", vcat(boundary_reg, earth_surface_reg), "Region")
375388
GetDP.add!(group, "Sur_Convection_Thermal", [], "Region")
376389

377390
problem.group = group
@@ -429,9 +442,14 @@ end
429442
case!(voltage, "")
430443

431444
# Current_2D
445+
# GetDP's complex (frequency-domain) formulation uses peak amplitudes:
446+
# a(t) = Re[ Â · exp(jωt) ]
447+
# Time-averaged Joule losses: P = 0.5·σ·|E|² = (I_peak/√2)²·R = I_rms²·R
448+
# User specifies RMS currents, so we scale by √2 to get peak amplitudes.
432449
current = assign!(constraint, "Current_2D")
433450
for (idx, curr) in enumerate(workspace.energizations)
434-
case!(current, "Con_$idx", value = "Complex[$(real(curr)), $(imag(curr))]")
451+
peak_curr = curr * sqrt(2) # RMS → peak conversion
452+
case!(current, "Con_$idx", value = "Complex[$(real(peak_curr)), $(imag(peak_curr))]")
435453
end
436454

437455
temp = assign!(constraint, "DirichletTemp")
@@ -1029,20 +1047,34 @@ end
10291047
output_dir = joinpath("results", lowercase(resolution_name))
10301048
output_dir = replace(output_dir, "\\" => "/") # for compatibility with Windows paths
10311049

1032-
# Construct the final Operation vector
1033-
GetDP.add!(resolution, resolution_name, [sys_mag, sys_the],
1034-
Operation = [
1035-
"CreateDir[\"$(output_dir)\"]",
1036-
"InitSolution[Sys_Mag]",
1037-
"InitSolution[Sys_The]",
1050+
# Construct the final Operation vector with iterative Picard coupling
1051+
ops = [
1052+
"CreateDir[\"$(output_dir)\"]",
1053+
"InitSolution[Sys_Mag]",
1054+
"InitSolution[Sys_The]",
1055+
# Solve thermal with zero source to initialize T = Tambient everywhere
1056+
# (prevents negative sigma from T=0K initial condition)
1057+
"Generate[Sys_The]",
1058+
"Solve[Sys_The]",
1059+
]
1060+
# Picard iterations: Mag → The coupling with temperature-dependent σ
1061+
n_picard = 10
1062+
for _ in 1:n_picard
1063+
append!(ops, [
10381064
"Generate[Sys_Mag]",
10391065
"Solve[Sys_Mag]",
10401066
"Generate[Sys_The]",
10411067
"Solve[Sys_The]",
1042-
"SaveSolution[Sys_Mag]",
1043-
"SaveSolution[Sys_The]",
1044-
"PostOperation[LineParams]",
1045-
]
1068+
])
1069+
end
1070+
append!(ops, [
1071+
"SaveSolution[Sys_Mag]",
1072+
"SaveSolution[Sys_The]",
1073+
"PostOperation[LineParams]",
1074+
])
1075+
1076+
GetDP.add!(resolution, resolution_name, [sys_mag, sys_the],
1077+
Operation = ops
10461078
)
10471079
# Add the resolution to the problem
10481080
problem.resolution = resolution

src/engine/fem/space.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ function make_space_geometry(workspace::FEMWorkspace)
518518
@debug " Point $point_marker: ($(point_marker[1]), $(point_marker[2]), $(point_marker[3]))"
519519
end
520520

521+
# Register earth-air interface as physical group for thermal Dirichlet BC
522+
register_physical_group!(workspace, earth_interface_tag, get_earth_model_material(workspace, num_earth_layers))
523+
521524
@info "Earth interfaces created"
522525
end
523526

src/materials/materialslibrary.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ function _add_default_materials!(library::MaterialsLibrary)
8888
add!(
8989
library,
9090
"semicon1",
91-
Material(1000.0, 1000.0, 1.0, 20.0, 0.0, 148.0),
91+
Material(1000.0, 1000.0, 1.0, 20.0, 0.0, 0.4), # κ = 1/2.5 [W/(m·K)] (IEC 60287)
9292
)
9393
add!(
9494
library,
9595
"semicon2",
96-
Material(500.0, 1000.0, 1.0, 20.0, 0.0, 148.0),
96+
Material(500.0, 1000.0, 1.0, 20.0, 0.0, 0.4), # κ = 1/2.5 [W/(m·K)] (IEC 60287)
9797
)
9898
add!(
9999
library,

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ end
2424
copper_props = Material(1.7241e-8, 1.0, 1.0, 20.0, 0.00393, 401.0)
2525
aluminum_props = Material(2.8264e-8, 1.0, 1.0, 20.0, 0.00429, 237.0)
2626
insulator_props = Material(1e14, 2.3, 1.0, 20.0, 0.0, 0.5)
27-
semicon_props = Material(1000.0, 1000.0, 1.0, 20.0, 0.0, 148.0)
27+
semicon_props = Material(1000.0, 1000.0, 1.0, 20.0, 0.0, 0.4)
2828
end
2929

3030
@testsnippet cable_system_export begin

test/unit_DataModel/test_CableComponent.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
copper = get(materials, "copper", MAT.Material(1.7241e-8, 1.0, 1.0, 20.0, 0.00393, 401.0))
99
aluminum = get(materials, "aluminum", MAT.Material(2.826e-8, 1.0, 1.0, 20.0, 0.00429, 237.0))
1010
polyeth = get(materials, "polyethylene", MAT.Material(1e12, 2.3, 1.0, 20.0, 0.0, 0.44))
11-
semimat = get(materials, "semicon", MAT.Material(1e3, 3.0, 1.0, 20.0, 0.0, 148.0))
11+
semimat = get(materials, "semicon", MAT.Material(1e3, 3.0, 1.0, 20.0, 0.0, 0.4))
1212

1313
# --- Helpers ---------------------------------------------------------------
1414
make_conductor_group_F = function ()

test/unit_DataModel/test_CableDesign.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
copper_props = MAT.Material(1.7241e-8, 1.0, 1.0, 20.0, 0.00393, 401.0)
1414
alu_props = MAT.Material(2.82e-8, 1.0, 1.0, 20.0, 0.0039, 237.0)
1515
xlpe_props = MAT.Material(1e10, 2.3, 1.0, 20.0, 0.0, 0.3) # insulator-like
16-
semi_props = MAT.Material(1e3, 2.6, 1.0, 20.0, 0.0, 148.0) # semicon-ish
16+
semi_props = MAT.Material(1e3, 2.6, 1.0, 20.0, 0.0, 0.4) # semicon-ish
1717

1818
# geometry
1919
d_wire = 3e-3 # 3 mm

0 commit comments

Comments
 (0)