class ThermodynamicalProcess(ThermodynamicalCycle): ############# Inputs ############# fluidSource = F.SubModelGroup(TC.FluidSource, 'FG', label='Initial State') fluidSink = F.SubModelGroup(TC.FluidSink, 'FG', label='Final State') inputs = F.SuperGroup([fluidSource, fluidSink]) # Model View inputView = F.ModelView(ioType="input", superGroups=[inputs], autoFetch=True) ############# Results ############# w = F.Quantity('SpecificEnergy', default=(0, 'kJ/kg'), label='specific work') qIn = F.Quantity('SpecificEnergy', default=(0, 'kJ/kg'), label='specific heat in') delta_h = F.Quantity('SpecificEnthalpy', label='enthalpy change (fluid)') WDot = F.Quantity('Power', default=(0, 'kW'), label='power') QDotIn = F.Quantity('HeatFlowRate', default=(0, 'kW'), label='heat flow rate in') deltaHDot = F.Quantity('Power', label='enthalpy change (fluid)') # Specific energy quantities specificEnergyResults = F.FieldGroup( [w, delta_h, qIn], label="Heat/work (specific quantities)") # Energy flow quantities energyFlowResults = F.FieldGroup([WDot, deltaHDot, QDotIn], label="Heat/work flows") energyBalanceResults = F.SuperGroup( [specificEnergyResults, energyFlowResults], label="Energy balance") # Model View resultView = F.ModelView( ioType="output", superGroups=['resultDiagrams', 'resultStates', energyBalanceResults]) ############# Page structure ######## modelBlocks = [inputView, resultView] ############# Methods ############### def postProcess(self, component): super(ThermodynamicalProcess, self).postProcess(300) component.postProcess() self.w = component.w self.qIn = component.qIn self.delta_h = component.delta_h self.WDot = component.WDot self.QDotIn = component.QDotIn self.deltaHDot = component.deltaHDot
class SolverSettings(NumericalModel): tFinal = F.Quantity('Bio_Time', default=(0.0, 'day'), minValue=(0, 'day'), maxValue=(1000, 'day'), label='simulation time') tPrint = F.Quantity('Bio_Time', default=(0.0, 'day'), minValue=(1e-5, 'day'), maxValue=(100, 'day'), label='print interval') absTol = F.Quantity('Bio_Time', default=(0.0, 'day'), minValue=(1e-16, 'day'), maxValue=(1e-5, 'day'), label='absolute tolerance') relTol = F.Quantity('Bio_Time', default=(0.0, 'day'), minValue=(1e-16, 'day'), maxValue=(1e-3, 'day'), label='relative tolerance') FG = F.FieldGroup([tFinal, tPrint, absTol, relTol], label='Solver') SG = F.SuperGroup([FG], label='Settings') modelBlocks = []
class RegenerativeRankineCycle(RankineCycle): label = "Regenerative Rankine cycle" figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/RankineCycle_Recuperator.svg", height = 300) description = F.ModelDescription("Rankine cycle with recuperator, \ using the temperature of the hot steam before the condenser to pre-heat the fluid before entering the boiler", show = True) #================ Inputs ================# #---------------- Fields ----------------# # FieldGroup recuperator = F.SubModelGroup(TC.HeatExchangerTwoStreams, 'FG', label = 'Recuperator') inputs = F.SuperGroup(['workingFluidGroup', 'pump', recuperator, 'boiler', 'turbine', 'condenser'], label = 'Cycle defininition') #--------------- Model view ---------------# #================ Results ================# #---------------- Energy flows -----------# recuperatorHeat = F.Quantity('HeatFlowRate', default = (0, 'kW'), label = 'recuperator heat rate') flowFieldGroup = F.FieldGroup(['pumpPower', recuperatorHeat, 'boilerHeat', 'turbinePower', 'condenserHeat'], label = 'Energy flows') #---------------- Scheme -----------------# scheme_Rankine_recup = F.Image(default="static/ThermoFluids/img/ModuleImages/RankineCycle_Recuperator.png") SchemeVG = F.ViewGroup([scheme_Rankine_recup], label="Process Scheme") SchemeSG = F.SuperGroup([SchemeVG], label="Scheme") resultView = F.ModelView(ioType = "output", superGroups = ['resultDiagrams', SchemeSG, 'resultStates', 'resultEnergy', 'solverStats']) #================ Methods ================# def compute(self): self.initCompute(self.fluidName) # Connect components self.connectPorts(self.condenser.outlet, self.pump.inlet) self.connectPorts(self.pump.outlet, self.recuperator.inlet1) self.connectPorts(self.recuperator.outlet1, self.boiler.inlet) self.connectPorts(self.boiler.outlet, self.turbine.inlet) self.connectPorts(self.turbine.outlet, self.recuperator.inlet2) self.connectPorts(self.recuperator.outlet2, self.condenser.inlet) # Initial guess for fl in self.flows: fl.mDot = self.mDot self.condenser.outlet.state.update_pq(self.pLow, 0) self.boiler.outlet.state.update_pq(self.pHigh, 1) self.turbine.compute(self.pLow) # Cycle iterations self.solver.run() # Results self.postProcess() def computeCycle(self): self.pump.compute(self.pHigh) self.recuperator.compute() self.recuperator.computeStream1() self.boiler.compute() self.turbine.compute(self.pLow) self.recuperator.computeStream2() self.condenser.compute() def postProcess(self): super(RegenerativeRankineCycle, self).postProcess() self.recuperatorHeat = self.recuperator.QDot def SteamPlant(self): RankineCycle.SteamPlant(self) self.pLow = (2, 'bar') self.boiler.TOutlet = (600, 'degC')
class LiquefactionCycle(ThermodynamicalCycle): abstract = True #================ Inputs ================# fluidName = F.Choices(Fluids, default='R134a', label='liquefied fluid') mDot = F.Quantity('MassFlowRate', default=(1, 'kg/min'), label='inlet flow rate') pIn = F.Quantity('Pressure', default=(1, 'bar'), label='inlet gas pressure') TIn = F.Quantity('Temperature', default=(15, 'degC'), label='inlet gas temperature') pHigh = F.Quantity('Pressure', default=(40, 'bar'), label='compressor high pressure') pLiquid = F.Quantity('Pressure', default=(2, 'bar'), label='liquid pressure') TAmbient = F.Quantity( 'Temperature', default=(15, 'degC'), label='ambient temperature', description='used as reference temperature to calculate exergy') workingFluidGroup = F.FieldGroup( ['fluidName', 'mDot', pIn, TIn, pHigh, pLiquid, TAmbient], label='Cycle parameters') #================ Results ================# liqEnergy = F.Quantity('SpecificEnergy', default=(1, 'kJ/kg'), label='liquefaction energy') minLiqEnergy = F.Quantity( 'SpecificEnergy', default=(1, 'kJ/kg'), label='min. liquefaction energy', description= 'minimum energy required for liquefaction in an ideal carnot cycle; \ equal to the difference in exergies between initial and final state') etaSecondLaw = F.Quantity( 'Efficiency', label='figure of merit (FOM)', description= 'minimum energy required for liquefaction to the actual energy required \ in the cycle; equivalent to second law efficiency') efficiencyFieldGroup = F.FieldGroup( [liqEnergy, minLiqEnergy, etaSecondLaw], label='Efficiency')
class CycleIterator(NumericalModel): hTolerance = F.Quantity('SpecificEnthalpy', default=1.0, label='enthalpy tolerance') maxNumIter = F.Quantity(default=500, label='max iterations', description='maximum number of iterations') convSettings = F.FieldGroup([hTolerance, maxNumIter], label='Convergence settings') solverSettings = F.SuperGroup([convSettings], label='Solver') modelBlocks = [] def run(self): self.converged = False self.ncp = len(self.cycle.fp) self.old_h = np.zeros((self.ncp)) self.old_T = np.zeros((self.ncp)) self.old_p = np.zeros((self.ncp)) self.hHistory = [] self.change_h = np.zeros((self.ncp)) self.change_hHistory = [] i = 0 self.cycle.computeCycle() while (i < self.maxNumIter): self.saveOldValues() self.cycle.computeCycle() self.checkConvergence() if (self.converged): break i += 1 if (not self.converged): raise E.ConvergenceError( 'Solution did not converge, delta_h = {:e}'.format( self.change_hHistory[-1])) def saveOldValues(self): for i in range(self.ncp): self.old_h[i] = self.cycle.fp[i].h self.old_T[i] = self.cycle.fp[i].T self.old_p[i] = self.cycle.fp[i].p #self.hHistory.append(self.old_h) def computeChange(self): for i in range(self.ncp): self.change_h[i] = self.cycle.fp[i].h - self.old_h[i] change = np.sqrt(np.sum(self.change_h**2)) self.hHistory.append([x for x in self.change_h]) self.change_hHistory.append(change) return change def checkConvergence(self): self.converged = self.computeChange() < self.hTolerance return self.converged def printValues(self): print[fp.T for fp in self.cycle.fp] print[fl.mDot for fl in self.cycle.flows]
class FiniteVolumeSolverSettings(NumericalModel): tolerance = F.Quantity(default=1e-6, label='tolerance') maxNumIterations = F.Integer(default=100, label='max number iterations') relaxationFactor = F.Quantity(default=1.0, label='relaxation factor') FG = F.FieldGroup([tolerance, maxNumIterations, relaxationFactor], label='Settings') modelBlocks = []
class ChannelGroupGeometry(NumericalModel): number = F.Integer(default=0, minValue=0, maxValue=30, label='number', description='number of channels') radialPosition = F.Quantity('Length', default=(0., 'mm'), minValue=(0, 'mm'), label='radial position', description='radial position of the channels') startingAngle = F.Quantity('Angle', default=(0., 'deg'), minValue=(-1e6, 'deg'), label='starting angle', description='starting angle of the first') cellSize = F.Quantity('Length', default=(0., 'mm'), label='mesh cell size', description='mesh cell size near the channels') meshFineness = F.Integer(default=1, minValue=1, maxValue=10, label='mesh fineness', description='mesh fineness near the channels') externalDiameter = F.Quantity( 'Length', default=(0., 'mm'), label='external diameter', description='external diameter of the channels') sections = F.RecordArray(( ('internalDiameter', F.Quantity('Length', default=(0, 'mm'), minValue=(0, 'mm'), label='internal diameter')), ('length', F.Quantity('Length', default=(0.2, 'm'), label='length')), ), label='sections', numRows=5) channelName = F.String() FG = F.FieldGroup([ number, radialPosition, startingAngle, externalDiameter, sections, meshFineness ], label='Parameters') modelBlocks = [] def compute(self): self.cellSize = self.externalDiameter / (self.meshFineness * 2.5) self.length = np.sum(self.sections['length'])
class Controller(NumericalModel): initialState = F.Choices( OrderedDict(( (TC.FUELING, 'fueling'), (TC.EXTRACTION, 'extraction'), )), label='start with', description='start the simulation with fueling or extraction') tWaitBeforeExtraction = F.Quantity( 'Time', default=(0., 's'), minValue=(0., 's'), maxValue=(1.e6, 's'), label='τ (extraction)', description='waiting time before each extraction') tWaitBeforeFueling = F.Quantity( 'Time', default=(0., 's'), minValue=(0., 's'), maxValue=(1.e6, 's'), label='τ (fueling)', description='waiting time before each fueling') pMin = F.Quantity( 'Pressure', default=(0., 'bar'), label='minimum pressure</sub>', description='minimum pressure in the gas storage for starting fueling') pMax = F.Quantity( 'Pressure', default=(0., 'bar'), label='maximum pressure', description='maximum pressure in the gas storage for stopping fueling') mDotExtr = F.Quantity('MassFlowRate', default=(0., 'kg/h'), label='extraction mass flow rate', description='extraction mass flow rate') nCompressor = F.Quantity('AngularVelocity', default=(0., 'rev/s'), minValue=(0, 'rev/s'), maxValue=(1e4, 'rev/s'), label='compressor speed', description='compressor speed') FG = F.FieldGroup([ initialState, pMin, pMax, mDotExtr, nCompressor, tWaitBeforeExtraction, tWaitBeforeFueling ], label='Parameters') SG = F.SuperGroup([FG], label="Parameters") modelBlocks = []
class BlockGeometry(NumericalModel): diameter = F.Quantity('Length', default=(0., 'mm'), label='diameter', description='block diameter') length = F.Quantity('Length', default=(0., 'm'), label='length', description='block length') FG = F.FieldGroup([diameter, length], label='Block geometry') modelBlocks = []
class TankRes(NumericalModel): compositeMass = F.Quantity('Mass', default=(0., 'kg'), label='composite mass', description='composite mass') linerMass = F.Quantity('Mass', default=(0., 'kg'), label='liner mass', description='liner mass') FG = F.FieldGroup([linerMass, compositeMass], label='Pressure vessel') modelBlocks = []
class FluidSource_TP(CycleComponent): T = F.Quantity('Temperature', label='temperature') p = F.Quantity('Pressure', label='pressure') mDot = F.Quantity('MassFlowRate', label='mass flow rate') FG = F.FieldGroup([T, p, mDot], label='Compressor') modelBlocks = [] #================== Ports =================# outlet = F.Port(P.ThermodynamicPort) #================== Methods =================# def compute(self): self.outlet.flow.mDot = self.mDot self.outlet.state.update_Tp(self.T, self.p)
class ThrottleValve(CycleComponent2FlowPorts): FG = F.FieldGroup([]) modelBlocks = [] #================== Methods =================# def compute(self, pOut): if (pOut > self.inlet.state.p): raise ValueError( 'Outlet pressure must be lower than inlet pressure') CycleComponent2FlowPorts.compute(self) self.outlet.state.update_ph(pOut, self.inlet.state.h) self.w = 0 self.qIn = 0 self.delta_h = 0
class BlockProperties(NumericalModel): material = F.ObjectReference(Solids, default='Aluminium6061', label='material', description='block material') divisionStep = F.Quantity('Length', default=(0., 'm'), minValue=(1, 'mm'), label='division step (axial)', description='axial division step') FG = F.FieldGroup([material, divisionStep], label='Block properties') modelBlocks = []
class FlowJunction(CycleComponent): FG = F.FieldGroup([]) modelBlocks = [] #================== Ports =================# inletMain = F.Port(P.ThermodynamicPort) inlet2 = F.Port(P.ThermodynamicPort) outlet = F.Port(P.ThermodynamicPort) #================== Methods =================# def compute(self): HDotIn = self.inletMain.flow.mDot * self.inletMain.state.h \ + self.inlet2.flow.mDot * self.inlet2.state.h mDotIn = self.inletMain.flow.mDot + self.inlet2.flow.mDot hOut = HDotIn / mDotIn self.outlet.state.update_ph(self.inletMain.state.p, hOut) self.outlet.flow.mDot = mDotIn
class Turbine(CycleComponent2FlowPorts): eta = F.Quantity(default=1, minValue=0, maxValue=1, label='efficiency') FG = F.FieldGroup([eta], label='Turbine') modelBlocks = [] #================== Methods =================# def compute(self, pOut): if (pOut > self.inlet.state.p): raise ValueError( 'Outlet pressure must be lower than inlet pressure') CycleComponent2FlowPorts.compute(self) self.outlet.state.update_ps(pOut, self.inlet.state.s) wIdeal = self.outlet.state.h - self.inlet.state.h self.w = wIdeal * self.eta self.qIn = 0 self.delta_h = self.w + self.qIn self.outlet.state.update_ph(pOut, self.inlet.state.h + self.delta_h)
class IncompressibleSolutionFlowInput(FluidFlowInput): solName = F.Choices(IncompressibleSolutions, default='MEG', label='fluid (name)', description='fluid (incompressible solutions)') solMassFraction = F.Quantity( 'Fraction', default=(0, '%'), label='fluid (mass fraction)', description='mass fraction of the substance other than water') incomSolFG = F.FieldGroup( [solName, solMassFraction, 'flowRateChoice', 'mDot', 'VDot', 'T', 'p'], label='Parameters') def createFluidState(self): return CP5.FluidStateFactory.createIncompressibleSolution( self.solName, self.solMassFraction)
class Compressor(NumericalModel): etaS = F.Quantity('Efficiency', default=(0., '-'), label='isentropic efficiency', description='isentropic efficiency') fQ = F.Quantity('Fraction', default=(0., '-'), label='heat loss fraction', description='heat loss fraction to ambient') V = F.Quantity('Volume', default=(0., 'L'), maxValue=(1e6, 'L'), label='displacement volume', description='displacement volume') FG = F.FieldGroup([etaS, fQ, V], label='Parameters') modelBlocks = []
class Compressor(CycleComponent2FlowPorts): modelType = F.Choices(OrderedDict(( ('S', 'isentropic'), ('T', 'isothermal'), )), label='compressor model') etaS = F.Quantity('Efficiency', label='isentropic efficiency', show="self.modelType == 'S'") fQ = F.Quantity('Fraction', default=0., label='heat loss factor', show="self.modelType == 'S'") etaT = F.Quantity('Efficiency', label='isosthermal efficiency', show="self.modelType == 'T'") dT = F.Quantity('TemperatureDifference', default=0, label='temperature increase', show="self.modelType == 'T'") FG = F.FieldGroup([modelType, etaS, fQ, etaT, dT], label='Compressor') modelBlocks = [] #================== Methods =================# def compute(self, pOut): CycleComponent2FlowPorts.compute(self) if (pOut < self.inlet.state.p): raise ValueError( 'Outlet pressure must be higher than inlet pressure') if (self.modelType == 'S'): self.outlet.state.update_ps(pOut, self.inlet.state.s) wIdeal = self.outlet.state.h - self.inlet.state.h self.w = wIdeal / self.etaS self.qIn = -self.fQ * self.w self.delta_h = self.w + self.qIn self.outlet.state.update_ph(pOut, self.inlet.state.h + self.delta_h) else: self.outlet.state.update_Tp(self.inlet.state.T + self.dT, pOut) self.qIn = (self.outlet.state.s - self.inlet.state.s) * self.inlet.state.T wIdeal = self.outlet.state.h - self.inlet.state.h - self.qIn self.w = wIdeal / self.etaT self.qIn -= (self.w - wIdeal)
class FluidStateSource(NumericalModel): sourceTypeTxt = F.Choices(OrderedDict(( ('TP', 'temperature, pressure'), ('PQ', 'pressure, vapour quality'), ('TQ', 'temperature, vapour quality'), )), label='state variables', description='choose the initial state variables') @property def sourceType(self): if self.sourceTypeTxt == 'TP': return DM.FluidStateSource.TP if self.sourceTypeTxt == 'PQ': return DM.FluidStateSource.PQ if self.sourceTypeTxt == 'TQ': return DM.FluidStateSource.TQ else: raise ValueError('Unsupported source type of FluidStateSource.') T = F.Quantity( 'Temperature', default=(0., 'degC'), label='temperature', description='temperature', show="self.sourceTypeTxt == 'TP' || self.sourceTypeTxt == 'TQ'") p = F.Quantity( 'Pressure', default=(0., 'bar'), label='pressure', description='pressure', show="self.sourceTypeTxt == 'TP' || self.sourceTypeTxt == 'PQ'") q = F.Quantity( 'VaporQuality', default=(0., '-'), minValue=0, maxValue=1, label='vapour quality', description='vapour quality', show="self.sourceTypeTxt == 'TQ' || self.sourceTypeTxt == 'PQ'") FG = F.FieldGroup([sourceTypeTxt, T, p, q], label='Parameters') modelBlocks = []
class SectionResultsSettings(NumericalModel): setTRange = F.Boolean( False, label='set temperature range', description= 'set temperature range (Tmin, Tmax) of the section results plots') Tmin = F.Quantity('Temperature', default=(0, 'K'), label='min temperature', description='minimum temperature', show='self.setTRange') Tmax = F.Quantity('Temperature', default=(0, 'K'), label='max temperature', description='maximum temperature', show='self.setTRange') FG = F.FieldGroup([setTRange, Tmin, Tmax], label='Settings') modelBlocks = []
class FlowSplitter(CycleComponent): frac1 = F.Quantity('Fraction', label='fraction to outlet 1') frac2 = F.Quantity('Fraction', label='fraction to outlet 2') FG = F.FieldGroup([frac1, frac2]) modelBlocks = [] #================== Ports =================# inlet = F.Port(P.ThermodynamicPort) outlet1 = F.Port(P.ThermodynamicPort) outlet2 = F.Port(P.ThermodynamicPort) #================== Methods =================# def compute(self): self.outlet1.flow.mDot = self.inlet.flow.mDot * self.frac1 / ( self.frac1 + self.frac2) self.outlet2.flow.mDot = self.inlet.flow.mDot * self.frac2 / ( self.frac1 + self.frac2) self.outlet1.state.update_Trho(self.inlet.state.T, self.inlet.state.rho) self.outlet2.state.update_Trho(self.inlet.state.T, self.inlet.state.rho)
class Condenser(IsobaricHeatExchanger): computeMethod = F.Choices(OrderedDict(( ('dT', 'sub-cooling'), ('Q', 'vapor quality'), ('eta', 'thermal efficiency'), ('T', 'temperature'), ('H', 'enthalpy'), )), label='compute outlet by') dTOutlet = F.Quantity('TemperatureDifference', default=(-10, 'degC'), minValue=-1e10, maxValue=-1e-3, label='outlet subcooling', show='self.computeMethod == "dT"') FG = F.FieldGroup([ 'computeMethod', 'etaThermal', 'TExt', 'dTOutlet', 'TOutlet', 'qOutlet', 'hOutlet' ], label='Condenser') modelBlocks = []
class PhaseSeparator(CycleComponent): FG = F.FieldGroup([]) modelBlocks = [] #================== Ports =================# inlet = F.Port(P.ThermodynamicPort) outletLiquid = F.Port(P.ThermodynamicPort) outletVapor = F.Port(P.ThermodynamicPort) #================== Methods =================# def compute(self): if (0 < self.inlet.state.q < 1): fq = self.inlet.state.q else: fq = 1.0 self.outletLiquid.state.update_pq(self.inlet.state.p, 0) self.outletLiquid.flow.mDot = (1 - fq) * self.inlet.flow.mDot #self.outletLiquid.flow.HDot = self.outletLiquid.flow.mDot * self.outletLiquid.state.h self.outletVapor.state.update_pq(self.inlet.state.p, 1) self.outletVapor.flow.mDot = fq * self.inlet.flow.mDot
class HeatFlowChannels(NumericalModel): QDotPrimaryChannels = F.Quantity( 'HeatFlowRate', default=(1.0, 'kW'), label='Primary channels', description='heat flow rate to the primary channels') QDotSecondaryChannels = F.Quantity( 'HeatFlowRate', default=(1.0, 'kW'), label='Secondary channels', description='heat flow rate to the secondary channels') QDotExternalChannel = F.Quantity( 'HeatFlowRate', default=(1.0, 'kW'), label='External channel', description='heat flow rate from the external channel') FG = F.FieldGroup( [QDotPrimaryChannels, QDotSecondaryChannels, QDotExternalChannel], label='Parameters') modelBlocks = []
class Cooler(NumericalModel): workingState = F.Choices(OrderedDict(( (0, 'no'), (1, 'yes'), )), label='enable cooler', description='enable cooler') epsilon = F.Quantity('Efficiency', default=(0., '-'), label='effectiveness', description='effectiveness', show="self.workingState") TCooler = F.Quantity('Temperature', default=(0., 'degC'), label='coolant temperature', description='coolant temperature', show="self.workingState") FG = F.FieldGroup([workingState, epsilon, TCooler], label='Parameters') modelBlocks = []
class Expansion(ThermodynamicalProcess): label = "Expansion" description = F.ModelDescription( "Parameteric model for expansion process: isentropic and isenthalpic", show=True) figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/Expansion.svg") turbine = F.SubModelGroup(TC.Turbine, 'FG', label='Turbine', show="self.processType == 'S'") throttleValve = F.SubModelGroup(TC.ThrottleValve, 'FG', show="false") processType = F.Choices(options=OrderedDict(( ('S', 'isentropic'), ('H', 'isenthalpic'), )), default='S', label="process type") processTypeFG = F.FieldGroup([processType], label="Process type") inputs = F.SuperGroup( ['fluidSource', 'fluidSink', processTypeFG, turbine, throttleValve]) def __init__(self): self.fluidSource.p1 = (10, 'bar') self.fluidSource.p2 = (10, 'bar') self.fluidSink.p = (1, 'bar') def compute(self): if (self.processType == 'S'): component = self.turbine elif (self.processType == 'H'): component = self.throttleValve self.initCompute(self.fluidSource.fluidName) # Connect components self.connectPorts(self.fluidSource.outlet, component.inlet) self.connectPorts(component.outlet, self.fluidSink.inlet) self.fluidSource.compute() component.compute(self.fluidSink.p) self.postProcess(component)
class ExternalChannelGeometry(NumericalModel): widthAxial = F.Quantity( 'Length', default=(0., 'mm'), label='width (axial)', description='axial width of the spiral rectangular channel') heightRadial = F.Quantity( 'Length', default=(0., 'mm'), label='radial height', description='radial height of the spiral rectangular channel') coilPitch = F.Quantity( 'Length', default=(0., 'mm'), label='coil pitch', description='coil pitch of the spiral rectangular channel') cellSize = F.Quantity( 'Length', default=(0., 'mm'), label='mesh cell size', description='mesh cell size near the outer block circle') meshFineness = F.Integer( default=1, minValue=1, maxValue=10, label='mesh fineness', description='mesh fineness near the outer side of the block') FG = F.FieldGroup([widthAxial, heightRadial, coilPitch, meshFineness], label='Channel geometry') modelBlocks = [] def compute(self, blockDiameter): self.averageCoilDiameter = blockDiameter + self.heightRadial self.cellSize = self.averageCoilDiameter / (self.meshFineness * 10.)
class FluidFlowInput(NumericalModel): fluidName = F.Choices(Fluids, default='ParaHydrogen', label='fluid') flowRateChoice = F.Choices(OrderedDict(( ('V', 'volume'), ('m', 'mass'), )), label='flow rate based on') mDot = F.Quantity('MassFlowRate', minValue=(0, 'kg/h'), default=(1., 'kg/h'), label='mass flow', description='mass flow rate', show='self.flowRateChoice == "m"') VDot = F.Quantity('VolumetricFlowRate', minValue=(0., 'm**3/h'), default=(1., 'm**3/h'), label='volume flow', description='volume flow rate', show='self.flowRateChoice == "V"') T = F.Quantity('Temperature', default=(300., 'K'), label='temperature') p = F.Quantity('Pressure', default=(1., 'bar'), label='pressure') FG = F.FieldGroup([fluidName, flowRateChoice, mDot, VDot, T, p], label='Parameters') modelBlocks = [] def createFluidState(self): return CP.FluidState(self.fluidName) def compute(self): self.fState = self.createFluidState() self.fState.update_Tp(self.T, self.p) if (self.flowRateChoice == 'm'): self.VDot = self.mDot / self.fState.rho else: self.mDot = self.VDot * self.fState.rho
class FluidFlowOutput(NumericalModel): VDot = F.Quantity('VolumetricFlowRate', minValue=(0., 'm**3/h'), default=(1., 'm**3/h'), label='volume flow', description='volume flow rate') mDot = F.Quantity('MassFlowRate', minValue=(0, 'kg/h'), default=(1., 'kg/h'), label='mass flow', description='mass flow rate') T = F.Quantity('Temperature', default=(300., 'K'), label='temperature') p = F.Quantity('Pressure', default=(1., 'bar'), label='pressure') FG = F.FieldGroup([mDot, VDot, T, p], label='Parameters') modelBlocks = [] def compute(self, fState, mDot): self.fState = fState self.T = fState.T self.p = fState.p self.mDot = mDot self.VDot = mDot / fState.rho
class ThermodynamicalProcessTwoStreams(ThermodynamicalCycle): ############# Inputs ############# fluidSource1 = F.SubModelGroup(TC.FluidSource, 'FG', label='Inlet 1') fluidSource2 = F.SubModelGroup(TC.FluidSource, 'FG', label='Inlet 2') fluidSink1 = F.SubModelGroup(TC.FluidSink, 'FG', label='Outlet 1') fluidSink2 = F.SubModelGroup(TC.FluidSink, 'FG', label='Outlet 2') inputs = F.SuperGroup([fluidSource1, fluidSource2, fluidSink1, fluidSink2]) # Model View inputView = F.ModelView(ioType="input", superGroups=[inputs], autoFetch=True) ############# Results ############# QDot = F.Quantity('HeatFlowRate', default=(0, 'kW'), label='heat flow rate in') NTU = F.Quantity(label='NTU') Cr = F.Quantity(label='capacity ratio') energyResults = F.FieldGroup([QDot, NTU, Cr], label="Energy") energyBalanceResults = F.SuperGroup([energyResults], label="Energy balance") # Model View resultView = F.ModelView( ioType="output", superGroups=['resultStates', energyBalanceResults]) ############# Page structure ######## modelBlocks = [inputView, resultView] ############# Methods ############### def postProcess(self, component): super(ThermodynamicalProcessTwoStreams, self).postProcess(300) self.QDot = component.QDot self.NTU = component.NTU self.Cr = component.Cr