|
| 1 | +# License for this file: MIT (expat) |
| 2 | +# Copyright 2023, DLR Institute of System Dynamics and Control |
| 3 | +# |
| 4 | +# This file is included in Modia/models/HeatTranser.jl |
| 5 | + |
| 6 | + |
| 7 | +# Structure holding the internal memory of the insulated rod |
| 8 | +mutable struct InsulatedRodStruct{FloatType} |
| 9 | + # Parameters |
| 10 | + path::String # path name of instance |
| 11 | + Ge::FloatType # = lambda*A/dx |
| 12 | + Ge2::FloatType # = 2*Ge |
| 13 | + k::FloatType # = Ge / (c*rho*A*dx) |
| 14 | + T_init::Vector{FloatType} # initial states |
| 15 | + |
| 16 | + # Internal states and state deriatives |
| 17 | + T::Vector{FloatType} # states |
| 18 | + der_T::Vector{FloatType} # state derivatives |
| 19 | + |
| 20 | + # Start index of state and state derivative vectors |
| 21 | + T_startIndex::Int |
| 22 | + |
| 23 | + InsulatedRodStruct{FloatType}(path::String) where {FloatType} = new(path,false) |
| 24 | +end |
| 25 | + |
| 26 | + |
| 27 | +# Called once before initialization of first simulation segment |
| 28 | +function initInsulatedRod2!(obj::InsulatedRodStruct{FloatType}; L, A, rho, lambda, c, T0, nT)::Nothing where {FloatType} |
| 29 | + #L, A, rho=7500.0u"kg/m^3", lambda=74.0u"W/(m*K)", c=450.0u"J/(kg*K)", T0=293.15u"K", nT=1)::Nothing where {FloatType} |
| 30 | + |
| 31 | + # Convert to SI units, strip units and check that values are positives |
| 32 | + path = obj.path |
| 33 | + #= |
| 34 | + @show L |
| 35 | + @Modia.strippedPositive!(path, L) |
| 36 | + @Modia.strippedPositive!(path, A) |
| 37 | + @Modia.strippedPositive!(path, rho) |
| 38 | + @Modia.strippedPositive!(path, lambda) |
| 39 | + @Modia.strippedPositive!(path, c) |
| 40 | + @Modia.strippedPositive!(path, T0) |
| 41 | + @Modia.strippedPositive!(path, nT) |
| 42 | + @show L |
| 43 | + @show A |
| 44 | + @show rho |
| 45 | + @show lambda |
| 46 | + =# |
| 47 | + L = stripUnit(L) |
| 48 | + A = stripUnit(A) |
| 49 | + rho = stripUnit(rho) |
| 50 | + lambda = stripUnit(lambda) |
| 51 | + c = stripUnit(c) |
| 52 | + T0 = stripUnit(T0) |
| 53 | + |
| 54 | + # Compute derived parameters |
| 55 | + dx = L/nT |
| 56 | + obj.Ge = lambda*A/dx |
| 57 | + obj.Ge2 = 2*obj.Ge |
| 58 | + obj.k = obj.Ge / ( c*rho*A*dx ) |
| 59 | + obj.T_init = fill(T0, nT) |
| 60 | + |
| 61 | + # Allocate and initialize internal states |
| 62 | + obj.T = copy(obj.T_init) |
| 63 | + obj.der_T = zeros(nT) |
| 64 | + return nothing |
| 65 | +end |
| 66 | + |
| 67 | + |
| 68 | +# Called from @instantiateModel(..) before getDerivatives!(..) is generated |
| 69 | +function buildInsulatedRod2!(model::AbstractDict, FloatType, TimeType, unitless::Bool, buildDict, path) |
| 70 | + pathAsString = Modia.modelPathAsString(path) |
| 71 | + extraModelCode = Model( # extra code to be merged with model |
| 72 | + insRod = Var(hideResult=true), # InsulatedRodStruct instance (an equation to return this variable is generated by _buildFunction) |
| 73 | + success = Var(hideResult=true), # Dummy return argument |
| 74 | + equations = :[ |
| 75 | + # copy states into insRod.T and return insRod |
| 76 | + insRod = openInsulatedRod!(instantiatedModel, $pathAsString) |
| 77 | + |
| 78 | + # equations at the boundaries |
| 79 | + port_a.Q_flow = getGe2(insRod, Val($unitless))*(port_a.T - getT1( insRod, Val($unitless))) |
| 80 | + port_b.Q_flow = getGe2(insRod, Val($unitless))*(port_b.T - getTend(insRod, Val($unitless))) |
| 81 | + |
| 82 | + # compute insRod.der_T and copy it into state derivatives |
| 83 | + success = computeInsulatedRodDerivatives!(instantiatedModel, insRod, port_a.T, port_b.T) # instantiatedModel is provided in the generated code |
| 84 | + ]) |
| 85 | + |
| 86 | + # Store build info in buildDict |
| 87 | + buildDict[pathAsString] = InsulatedRodStruct{FloatType}(pathAsString) |
| 88 | + return extraModelCode |
| 89 | +end |
| 90 | + |
| 91 | + |
| 92 | +# Called once before initialization of a new simulation segment |
| 93 | +function initInsulatedRod2ForNewSegment!(instantiatedModel::SimulationModel{FloatType,TimeType}, |
| 94 | + parameters::AbstractDict, path::String; log=false)::Nothing where {FloatType,TimeType} |
| 95 | + obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] |
| 96 | + |
| 97 | + if Modia.isFirstInitialOfAllSegments(instantiatedModel) |
| 98 | + initInsulatedRod2!(obj; parameters...) |
| 99 | + end |
| 100 | + |
| 101 | + # Define a vector of new state and state derivative variables |
| 102 | + obj.T_startIndex = Modia.new_x_segmented_variable!(instantiatedModel, path*".T", path*".der(T)", obj.T, "K") |
| 103 | + return nothing |
| 104 | +end |
| 105 | + |
| 106 | + |
| 107 | +# Open an initialized InsulatedRod2 model and return a reference to it |
| 108 | +function openInsulatedRod!(instantiatedModel::SimulationModel{FloatType,TimeType}, path::String)::InsulatedRodStruct{FloatType} where {FloatType,TimeType} |
| 109 | + obj::InsulatedRodStruct{FloatType} = instantiatedModel.buildDict[path] |
| 110 | + Modia.get_Vector_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.T) |
| 111 | + return obj |
| 112 | +end |
| 113 | + |
| 114 | + |
| 115 | +# Functions to inquire values from InsulatedRodStruct |
| 116 | +getT1( insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.T[1] |
| 117 | +getT1( insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.T[1]*u"K" |
| 118 | + |
| 119 | +getTend(insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.T[end] |
| 120 | +getTend(insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.T[end]*u"K" |
| 121 | + |
| 122 | +getGe2( insRod::InsulatedRodStruct, Unitless::Val{true}) = insRod.Ge2 |
| 123 | +getGe2( insRod::InsulatedRodStruct, Unitless::Val{false}) = insRod.Ge2*u"W/K" |
| 124 | + |
| 125 | +T_grad1(T,Ta,i) = if i == 1 ; (Ta - T[1])*2 else T[i-1] - T[i] end |
| 126 | +T_grad2(T,Tb,i) = if i == length(T); (T[i] - Tb)*2 else T[i] - T[i+1] end |
| 127 | + |
| 128 | +function computeInsulatedRodDerivatives!(instantiatedModel, obj::InsulatedRodStruct{FloatType}, Ta, Tb)::Bool where {FloatType} |
| 129 | + Ta::FloatType = stripUnit(Ta) |
| 130 | + Tb::FloatType = stripUnit(Tb) |
| 131 | + T = obj.T |
| 132 | + k = obj.k |
| 133 | + for i in 1:length(T) |
| 134 | + obj.der_T[i] = k*(T_grad1(T,Ta,i) - T_grad2(T,Tb,i)) |
| 135 | + end |
| 136 | + Modia.add_der_x_segmented_value!(instantiatedModel, obj.T_startIndex, obj.der_T) |
| 137 | + return true |
| 138 | +end |
0 commit comments