Beispiel #1
0
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
Beispiel #2
0
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')
Beispiel #3
0
class HeatExchangerTwoStreams(ThermodynamicalProcessTwoStreams):
    label = "Heat Exchanger (two streams)"
    description = F.ModelDescription(
        "Parameteric model for heat exchange between two streams", show=True)
    figure = F.ModelFigure(
        src="ThermoFluids/img/ModuleImages/HeatExchanger.svg")
    heatExchanger = F.SubModelGroup(TC.HeatExchangerTwoStreams,
                                    'FG',
                                    label='Heat exchanger')
    inputs = F.SuperGroup(['fluidSource1', 'fluidSource2', heatExchanger])

    def __init__(self):
        self.fluidSource2.T2 = (350, 'K')

    def compute(self):
        self.cycleDiagram.enable = False
        self.initCompute(self.fluidSource1.fluidName)
        # Connect components
        self.connectPorts(self.fluidSource1.outlet, self.heatExchanger.inlet1)
        self.connectPorts(self.heatExchanger.outlet1, self.fluidSink1.inlet)
        self.connectPorts(self.fluidSource2.outlet,
                          self.heatExchanger.inlet2,
                          fluid=self.fluidSource2.fluidName)
        self.connectPorts(self.heatExchanger.outlet2,
                          self.fluidSink2.inlet,
                          fluid=self.fluidSource2.fluidName)
        self.fluidSource1.compute()
        self.fluidSource2.compute()
        self.heatExchanger.compute()
        self.heatExchanger.computeStream1()
        self.heatExchanger.computeStream2()
        self.postProcess(self.heatExchanger)
Beispiel #4
0
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)
Beispiel #5
0
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
Beispiel #6
0
class Compression(ThermodynamicalProcess):
    label = "Compression"
    description = F.ModelDescription(
        "Parameteric model for compression process: isentropic and isothermal",
        show=True)
    figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/Compression.svg")
    compressor = F.SubModelGroup(TC.Compressor, 'FG', label='Compressor')
    inputs = F.SuperGroup(['fluidSource', 'fluidSink', compressor])

    def compute(self):
        self.initCompute(self.fluidSource.fluidName)
        # Connect components
        self.connectPorts(self.fluidSource.outlet, self.compressor.inlet)
        self.connectPorts(self.compressor.outlet, self.fluidSink.inlet)
        self.fluidSource.compute()
        self.compressor.compute(self.fluidSink.p)
        self.postProcess(self.compressor)
Beispiel #7
0
class Cooling(ThermodynamicalProcess):
    label = "Cooling"
    description = F.ModelDescription("Cooling process at constant pressure",
                                     show=True)
    figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/Cooling.svg")
    condenser = F.SubModelGroup(TC.Condenser, 'FG', label='Condenser')
    inputs = F.SuperGroup(['fluidSource', condenser])

    ############# Methods ###############
    def compute(self):
        self.initCompute(self.fluidSource.fluidName)
        # Connect components
        self.connectPorts(self.fluidSource.outlet, self.condenser.inlet)
        self.connectPorts(self.condenser.outlet, self.fluidSink.inlet)
        self.fluidSource.compute()
        self.condenser.compute()
        self.postProcess(self.condenser)
Beispiel #8
0
class ABC(NumericalModel):
    showOnHome = False
    label = 'ABC'
    compressor = F.SubModelGroup(TC.Compressor, ['etaS', 'fQ', 'modelType'],
                                 label='Compressor')  #fields = )
    inputs = F.SuperGroup([compressor])
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputs],
                            autoFetch=True)
    resultView = F.ModelView(ioType="output", superGroups=[])

    testJs = JsBlock(srcType="file", src="TestPage.js")
    testHtml = HtmlBlock(srcType="file", src="TestPage.html")

    modelBlocks = [inputView, resultView, testJs, testHtml]

    def __init__(self):
        self.compressor.modelType = 'S'
        self.compressor.declared_fields['modelType'].show = 'false'

    def compute(self):
        pass
Beispiel #9
0
class ADM1H2CH4Bioreactors(NumericalModel):
    label = "(H2,CH4) Bioreactors"
    description = F.ModelDescription(
        "A model of the process of hydrogen and methane production by anaerobic digestion of organic wastes in a cascade of two continuously stirred bioreactors.",
        show=True)
    figure = F.ModelFigure(
        src="BioReactors/img/ModuleImages/ADM1H2CH4Bioreactors.png", show=True)

    async = True
    progressOptions = {'suffix': 'day', 'fractionOutput': True}

    #1. ############ Inputs ###############
    #1.1 Fields - Input values
    parametersRH2 = F.SubModelGroup(H2Bioreactor,
                                    'parametersSG',
                                    label='Parameters (R-H2)')
    concentrationsRH2 = F.SubModelGroup(H2Bioreactor,
                                        'concentrationsSG',
                                        label='Concentrations (R-H2)')

    parametersRCH4 = F.SubModelGroup(CH4Bioreactor,
                                     'parametersSG',
                                     label='Parameters (R-CH4)')
    concentrationsRCH4 = F.SubModelGroup(CH4Bioreactor,
                                         'concentrationsSG',
                                         label='Concentrations (R-CH4)')

    #1.3 Fields - Settings
    solverSettings = F.SubModelGroup(SolverSettings,
                                     'FG',
                                     label='H2 & CH4 - Bioreactors')
    settingsSG = F.SuperGroup([solverSettings], label='Solver settings')

    #1.4 Model view
    exampleAction = A.ServerAction(
        "loadEg",
        label="Examples",
        options=(
            #('exampleDef', 'Reset to default values'),
            ('exampleADM1', 'Reset to ADM1 values'), ))

    inputView = F.ModelView(
        ioType="input",
        superGroups=[
            parametersRH2, concentrationsRH2, parametersRCH4,
            concentrationsRCH4, settingsSG
        ],
        autoFetch=True,
        actionBar=A.ActionBar([exampleAction]),
    )

    #2. ############ Results ###############
    storage = F.HdfStorage(hdfFile=DM.dataStorageFilePath,
                           hdfGroup=DM.dataStorageDatasetPath)

    varTuples = (
        ('time', F.Quantity('Bio_Time', default=(1, 'day'))),  #0
        ('S_su_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #1
        ('S_aa_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #2
        ('S_fa_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #3
        ('S_ac_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #4
        ('X_c_RH2', F.Quantity('Bio_CODConcentration',
                               default=(1, 'gCOD/L'))),  #5
        ('X_ch_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #6
        ('X_pr_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #7
        ('X_li_RH2', F.Quantity('Bio_CODConcentration',
                                default=(1, 'gCOD/L'))),  #8
        ('X_suaa_RH2', F.Quantity('Bio_MassConcentration',
                                  default=(1, 'g/L'))),  #9
        ('X_fa_RH2', F.Quantity('Bio_MassConcentration',
                                default=(1, 'g/L'))),  #10
        ('intQ_h2_RH2',
         F.Quantity('Bio_CODConcentration', default=(1, 'gCOD/L'))),  #11
        ('S_ac_RCH4', F.Quantity('Bio_CODConcentration',
                                 default=(1, 'gCOD/L'))),  #12   
        ('X_ac_RCH4', F.Quantity('Bio_MassConcentration',
                                 default=(1, 'g/L'))),  #13
        ('intQ_ch4_RCH4',
         F.Quantity('Bio_CODConcentration', default=(1, 'gCOD/L'))),  #14
        ('Q_h2_RH2',
         F.Quantity('Bio_CODConcentrationFlowRate',
                    default=(1, 'gCOD/L/day'))),  #15
        ('Q_ch4_RCH4',
         F.Quantity('Bio_CODConcentrationFlowRate',
                    default=(1, 'gCOD/L/day'))),  #16
        ('D_RH2', F.Quantity('Bio_TimeRate', default=(1, '1/day'))),  #17
        ('D_RCH4', F.Quantity('Bio_TimeRate', default=(1, '1/day'))),  #18
    )

    plot1RH2 = F.PlotView(
        varTuples,
        label='R-H2 (S<sub>su</sub>, S<sub>aa</sub>, S<sub>fa</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 1, 2, 3],
        useHdfStorage=True,
        storage='storage',
    )

    plot2RH2 = F.PlotView(
        varTuples,
        label='R-H2 (X<sub>ch</sub>, X<sub>pr</sub>, X<sub>li</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 6, 7, 8],
        useHdfStorage=True,
        storage='storage',
    )

    plot3RH2 = F.PlotView(
        varTuples,
        label='R-H2 (X<sub>su-aa</sub>,X<sub>fa</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 9, 10],
        useHdfStorage=True,
        storage='storage',
    )

    plot4RH2 = F.PlotView(
        varTuples,
        label='R-H2 (H<sub>2</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 11, 15],
        useHdfStorage=True,
        storage='storage',
    )

    plot1RCH4 = F.PlotView(
        varTuples,
        label='R-CH4 (S<sub>ac</sub>, X<sub>ac</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 12, 13],
        useHdfStorage=True,
        storage='storage',
    )

    plot2RCH4 = F.PlotView(
        varTuples,
        label='R-CH4 (CH<sub>4</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 14, 16],
        useHdfStorage=True,
        storage='storage',
    )

    plotD = F.PlotView(
        varTuples,
        label='(D<sub>RH2</sub>, D<sub>RCH4</sub>)',
        options={'ylabel': None},
        visibleColumns=[0, 17, 18],
        useHdfStorage=True,
        storage='storage',
    )

    table = F.TableView(
        varTuples,
        label='Table',
        options={
            'title': 'Bioreactors',
            'formats': ['0.000']
        },
        useHdfStorage=True,
        storage='storage',
    )

    storageVG = F.ViewGroup([storage], show="false")
    resultsVG = F.ViewGroup([
        plot1RH2, plot2RH2, plot3RH2, plot4RH2, plot1RCH4, plot2RCH4, plotD,
        table
    ])
    resultsSG = F.SuperGroup([resultsVG, storageVG], label='Results')

    #2.1 Model view
    resultView = F.ModelView(ioType="output", superGroups=[resultsSG])

    ############# Page structure ########
    modelBlocks = [inputView, resultView]

    ############# Methods ###############
    def __init__(self):
        self.exampleADM1()

    def exampleDef(self):
        ############# H2 Bioreactor ###############
        #Stoichiometric parameter values
        self.parametersRH2.f_ch_xc = 0.5  #-
        self.parametersRH2.f_pr_xc = 0.15  #-
        self.parametersRH2.f_li_xc = 0.15  #-

        self.parametersRH2.f_su_li = 0.05  #-
        self.parametersRH2.f_fa_li = 0.9  #-

        self.parametersRH2.f_ac_su = 0.41  #-

        self.parametersRH2.f_ac_aa = 0.4  #-

        self.parametersRH2.Y_suaa = 0.1  #-
        self.parametersRH2.Y_fa = 0.06  #-

        #Biochemical parameter values
        self.parametersRH2.k_dis = (0.5, '1/day')

        self.parametersRH2.k_hyd_ch = (10.0, '1/day')
        self.parametersRH2.k_hyd_pr = (10.0, '1/day')
        self.parametersRH2.k_hyd_li = (10.0, '1/day')

        self.parametersRH2.k_m_suaa = (30.0, '1/day')
        self.parametersRH2.K_S_suaa = (0.5, 'g/L')

        self.parametersRH2.k_m_fa = (6.0, '1/day')
        self.parametersRH2.K_S_fa = (0.4, 'g/L')

        # Physiochemical parameter values
        self.parametersRH2.Y_h2_su = 1.0  #-
        self.parametersRH2.Y_h2_aa = 1.0  #-
        self.parametersRH2.Y_h2_fa = 1.0  #-

        # Volumetric flow rate values
        self.parametersRH2.D_liq_arr[0] = (10.0, 0.0)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[1] = (10.0, 0.1)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[2] = (10.0, 0.05)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[3] = (10.0, 0.15)  #(day, 1/day)

        # Input concentrations
        self.concentrationsRH2.S_su_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.S_aa_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.S_fa_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.S_ac_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.X_c_in = (2.0, 'gCOD/L')
        self.concentrationsRH2.X_ch_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.X_pr_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.X_li_in = (0.0, 'gCOD/L')
        self.concentrationsRH2.X_suaa_in = (0.0, 'g/L')
        self.concentrationsRH2.X_fa_in = (0.0, 'g/L')

        # Initial values of state variables
        self.concentrationsRH2.S_su_0 = (0.012, 'gCOD/L')
        self.concentrationsRH2.S_aa_0 = (0.005, 'gCOD/L')
        self.concentrationsRH2.S_fa_0 = (0.099, 'gCOD/L')
        self.concentrationsRH2.S_ac_0 = (0.20, 'gCOD/L')
        self.concentrationsRH2.X_c_0 = (30.0, 'gCOD/L')
        self.concentrationsRH2.X_ch_0 = (0.028, 'gCOD/L')
        self.concentrationsRH2.X_pr_0 = (0.10, 'gCOD/L')
        self.concentrationsRH2.X_li_0 = (0.03, 'gCOD/L')
        self.concentrationsRH2.X_suaa_0 = (0.42, 'g/L')
        self.concentrationsRH2.X_fa_0 = (0.24, 'g/L')

        ############# CH4 Bioreactor ###############
        #Stoichiometric parameter values
        self.parametersRCH4.Y_ac = 0.5  #-

        #Biochemical parameter values
        self.parametersRCH4.k_m_ac = (8.0, '1/day')
        self.parametersRCH4.K_S_ac = (0.15, 'g/L')

        # Physiochemical parameter values
        self.parametersRCH4.Y_ch4_ac = 1.0  #-

        # Physical parameter values
        self.parametersRCH4.V_liq_RCH4_del_V_liq_RH2 = (50.0, '-')  #L/L

        # Input concentrations
        self.concentrationsRCH4.X_ac_in = (0.0, 'g/L')

        # Initial values of state variables
        self.concentrationsRCH4.S_ac_0 = (0.0, 'gCOD/L')
        self.concentrationsRCH4.X_ac_0 = (2.0, 'g/L')

        ############# Solver settings ###############
        self.solverSettings.tFinal = (50.0, 'day')
        self.solverSettings.tPrint = (0.1, 'day')
        self.solverSettings.absTol = (1e-9, 'day')
        self.solverSettings.relTol = (1e-7, 'day')

    def exampleADM1(self):
        ############# H2 Bioreactor ###############
        #Stoichiometric parameter values
        self.parametersRH2.f_ch_xc = 0.2  #-
        self.parametersRH2.f_pr_xc = 0.2  #-
        self.parametersRH2.f_li_xc = 0.3  #-

        self.parametersRH2.f_su_li = 0.05  #-
        self.parametersRH2.f_fa_li = 0.95  #-

        self.parametersRH2.f_ac_su = 0.41  #-

        self.parametersRH2.f_ac_aa = 0.4  #-

        self.parametersRH2.Y_suaa = 0.1  #-
        self.parametersRH2.Y_fa = 0.06  #-

        #Biochemical parameter values
        self.parametersRH2.k_dis = (0.5, '1/day')

        self.parametersRH2.k_hyd_ch = (10.0, '1/day')
        self.parametersRH2.k_hyd_pr = (10.0, '1/day')
        self.parametersRH2.k_hyd_li = (10.0, '1/day')

        self.parametersRH2.k_m_suaa = (30.0, '1/day')
        self.parametersRH2.K_S_suaa = (0.5, 'g/L')

        self.parametersRH2.k_m_fa = (6.0, '1/day')
        self.parametersRH2.K_S_fa = (0.4, 'g/L')

        # Physiochemical parameter values
        self.parametersRH2.Y_h2_su = 1.0  #-
        self.parametersRH2.Y_h2_aa = 1.0  #-
        self.parametersRH2.Y_h2_fa = 1.0  #-

        # Volumetric flow rate values
        self.parametersRH2.D_liq_arr[0] = (10.0, 0.0)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[1] = (10.0, 0.1)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[2] = (10.0, 0.05)  #(day, 1/day)
        self.parametersRH2.D_liq_arr[3] = (10.0, 0.15)  #(day, 1/day)

        # Input concentrations
        self.concentrationsRH2.S_su_in = (0.01, 'gCOD/L')
        self.concentrationsRH2.S_aa_in = (0.001, 'gCOD/L')
        self.concentrationsRH2.S_fa_in = (0.001, 'gCOD/L')
        self.concentrationsRH2.S_ac_in = (0.001, 'gCOD/L')
        self.concentrationsRH2.X_c_in = (2.0, 'gCOD/L')
        self.concentrationsRH2.X_ch_in = (5.0, 'gCOD/L')
        self.concentrationsRH2.X_pr_in = (20.0, 'gCOD/L')
        self.concentrationsRH2.X_li_in = (5.0, 'gCOD/L')
        self.concentrationsRH2.X_suaa_in = (0.0, 'g/L')
        self.concentrationsRH2.X_fa_in = (0.01, 'g/L')

        # Initial values of state variables
        self.concentrationsRH2.S_su_0 = (0.012, 'gCOD/L')
        self.concentrationsRH2.S_aa_0 = (0.005, 'gCOD/L')
        self.concentrationsRH2.S_fa_0 = (0.099, 'gCOD/L')
        self.concentrationsRH2.S_ac_0 = (0.20, 'gCOD/L')
        self.concentrationsRH2.X_c_0 = (0.31, 'gCOD/L')
        self.concentrationsRH2.X_ch_0 = (0.028, 'gCOD/L')
        self.concentrationsRH2.X_pr_0 = (0.10, 'gCOD/L')
        self.concentrationsRH2.X_li_0 = (0.03, 'gCOD/L')
        self.concentrationsRH2.X_suaa_0 = (0.42, 'g/L')
        self.concentrationsRH2.X_fa_0 = (0.24, 'g/L')

        ############# CH4 Bioreactor ###############
        #Stoichiometric parameter values
        self.parametersRCH4.Y_ac = 0.05  #-

        #Biochemical parameter values
        self.parametersRCH4.k_m_ac = (8.0, '1/day')
        self.parametersRCH4.K_S_ac = (0.15, 'g/L')

        # Physiochemical parameter values
        self.parametersRCH4.Y_ch4_ac = 1.0  #-

        # Physical parameter values
        self.parametersRCH4.V_liq_RCH4_del_V_liq_RH2 = (50.0, '-')  #L/L

        # Input concentrations
        self.concentrationsRCH4.X_ac_in = (0.0, 'g/L')

        # Initial values of state variables
        self.concentrationsRCH4.S_ac_0 = (0.0, 'gCOD/L')
        self.concentrationsRCH4.X_ac_0 = (0.76, 'g/L')

        ############# Solver settings ###############
        self.solverSettings.tFinal = (50.0, 'day')
        self.solverSettings.tPrint = (0.1, 'day')
        self.solverSettings.absTol = (1e-12, 'day')
        self.solverSettings.relTol = (1e-10, 'day')

    def computeAsync(self):
        # Simulate RH2 and RCH4 Bioreactors
        bioreactor = DM.ADM1H2CH4Bioreactors(self, self.parametersRH2,
                                             self.concentrationsRH2,
                                             self.parametersRCH4,
                                             self.concentrationsRCH4)

        bioreactor.prepareSimulation(self.solverSettings)
        bioreactor.run(self.solverSettings)

        # Show results
        self.storage = bioreactor.resultStorage.simulationName
Beispiel #10
0
class VaporCompressionCycleWithRecuperator(VaporCompressionCycle):
    label = "Vapor compression cycle (recuperator)"
    figure = F.ModelFigure(
        src=
        "ThermoFluids/img/ModuleImages/VaporCompressionCycle_Recuperator.svg")
    description = F.ModelDescription(
        "Vapor compression cycle with a recuperator. The stream \
	 before the throttle valve is precooled, using the cold stream at the evaporator outlet. \
	 This increases the compressor cooling/heating capacity of the cycle and improves slightly the COP",
        show=True)
    #================ Inputs ================#
    #---------------- Fields ----------------#
    recuperator = F.SubModelGroup(TC.HeatExchangerTwoStreams,
                                  'FG',
                                  label='Recuperator')
    inputs = F.SuperGroup([
        'workingFluidGroup', 'compressor', recuperator, 'condenser',
        'evaporator'
    ],
                          label='Cycle definition')
    #--------------- Model view ---------------#

    #================ Results ================#
    #---------------- Energy flows -----------#
    recuperatorHeat = F.Quantity('HeatFlowRate',
                                 default=(0, 'kW'),
                                 label='recuperator heat rate')
    flowFieldGroup = F.FieldGroup([
        'compressorPower', recuperatorHeat, 'condenserHeat', 'evaporatorHeat'
    ],
                                  label='Energy flows')

    #---------------- Scheme -----------------#
    scheme_VaporCompression_recup = F.Image(
        default=
        "static/ThermoFluids/img/ModuleImages/VaporCompressionCycle_Recuperator.png"
    )
    SchemeVG = F.ViewGroup([scheme_VaporCompression_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):
        if (self.cycleTranscritical and self.condenser.computeMethod == 'dT'):
            raise ValueError(
                'In transcritical cycle, condenser sub-cooling cannot be used as input'
            )
        self.initCompute(fluid=self.fluidName)
        # Connect components
        self.connectPorts(self.evaporator.outlet, self.recuperator.inlet1)
        self.connectPorts(self.recuperator.outlet1, self.compressor.inlet)
        self.connectPorts(self.compressor.outlet, self.condenser.inlet)
        self.connectPorts(self.condenser.outlet, self.recuperator.inlet2)
        self.connectPorts(self.recuperator.outlet2, self.throttleValve.inlet)
        self.connectPorts(self.throttleValve.outlet, self.evaporator.inlet)
        # Initial guess
        for fl in self.flows:
            fl.mDot = self.mDot
        self.evaporator.outlet.state.update_pq(self.pLow, 1)
        if (self.cycleTranscritical):
            self.condenser.outlet.state.update_Tp(
                1.05 * self.fluid.critical['T'], self.pHigh)
        else:
            self.condenser.outlet.state.update_pq(self.pHigh, 0)
        # Cycle iterations
        self.solver.run()
        # Results
        self.postProcess()

    def computeCycle(self):
        self.recuperator.compute()
        self.recuperator.computeStream1()
        self.compressor.compute(self.pHigh)
        self.condenser.compute()
        self.recuperator.computeStream2()
        self.throttleValve.compute(self.pLow)
        self.evaporator.compute()

        if (self.cycleTranscritical and self.condenser.computeMethod == 'dT'):
            raise ValueError(
                'In transcritical cycle, condenser sub-cooling cannot be used as input'
            )

    def postProcess(self):
        super(VaporCompressionCycleWithRecuperator, self).postProcess()
        self.recuperatorHeat = self.recuperator.QDot

    def R134aCycle(self):
        super(VaporCompressionCycleWithRecuperator, self).R134aCycle()
        self.recuperator.eta = 0.7
Beispiel #11
0
class VaporCompressionCycle(HeatPumpCycle):
    label = "Vapor compression cycle"
    figure = F.ModelFigure(
        src="ThermoFluids/img/ModuleImages/VaporCompressionCycle.svg")
    description = F.ModelDescription(
        "Basic vapor compression cycle used in refrigerators and air conditioners",
        show=True)

    #================ Inputs ================#
    #---------------- Fields ----------------#
    # FieldGroup
    compressor = F.SubModelGroup(TC.Compressor, 'FG', label='Compressor')
    condenser = F.SubModelGroup(TC.Condenser, 'FG', label='Condenser')
    throttleValve = F.SubModelGroup(TC.ThrottleValve, 'FG', label='JT valve')
    evaporator = F.SubModelGroup(TC.Evaporator, 'FG', label='Evaporator')
    inputs = F.SuperGroup(
        ['workingFluidGroup', compressor, condenser, evaporator],
        label='Cycle definition')

    #---------------- Actions ----------------#
    exampleAction = ServerAction(
        "loadEg",
        label="Examples",
        options=(
            ('R134aCycle', 'Typical fridge with R134a as a refrigerant'),
            ('CO2TranscriticalCycle', 'CO2 transcritial cycle'),
        ))
    #--------------- Model view ---------------#
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputs, 'cycleDiagram', 'solver'],
                            actionBar=ActionBar([exampleAction]),
                            autoFetch=True)

    #================ Results ================#
    compressorPower = F.Quantity('Power',
                                 default=(1, 'kW'),
                                 label='compressor power')
    condenserHeat = F.Quantity('HeatFlowRate',
                               default=(1, 'kW'),
                               label='condenser heat out')
    evaporatorHeat = F.Quantity('HeatFlowRate',
                                default=(1, 'kW'),
                                label='evaporator heat in')
    flowFieldGroup = F.FieldGroup(
        [compressorPower, condenserHeat, evaporatorHeat], label='Energy flows')
    resultEnergy = F.SuperGroup([flowFieldGroup, 'efficiencyFieldGroup'],
                                label='Energy')
    resultView = F.ModelView(ioType="output",
                             superGroups=[
                                 'resultDiagrams', 'resultStates',
                                 resultEnergy, 'solverStats'
                             ])

    #============= Page structure =============#
    modelBlocks = [inputView, resultView]

    #================ Methods ================#
    def __init__(self):
        self.R134aCycle()

    def compute(self):
        if (self.cycleTranscritical and self.condenser.computeMethod == 'dT'):
            raise ValueError(
                'In transcritical cycle, condenser sub-cooling cannot be used as input'
            )
        if (self.cycleSupercritical and self.evaporator.computeMethod == 'dT'):
            raise ValueError(
                'In supercritical cycle, evaporator super-heating cannot be used as input'
            )
        self.initCompute(fluid=self.fluidName)
        # Connect components
        self.connectPorts(self.evaporator.outlet, self.compressor.inlet)
        self.connectPorts(self.compressor.outlet, self.condenser.inlet)
        self.connectPorts(self.condenser.outlet, self.throttleValve.inlet)
        self.connectPorts(self.throttleValve.outlet, self.evaporator.inlet)
        # Initial guess
        for fl in self.flows:
            fl.mDot = self.mDot
        self.evaporator.outlet.state.update_pq(self.pLow, 1)
        # Cycle iterations
        self.solver.run()
        # Results
        self.postProcess()

    def computeCycle(self):
        self.compressor.compute(self.pHigh)
        self.condenser.compute()
        self.throttleValve.compute(self.pLow)
        self.evaporator.compute()

    def postProcess(self):
        super(VaporCompressionCycle, self).postProcess(self.TAmbient)
        # Flows
        self.compressorPower = self.mDot * self.compressor.w
        self.compressorHeat = -self.mDot * self.compressor.qIn
        self.condenserHeat = -self.mDot * self.condenser.qIn
        self.evaporatorHeat = self.mDot * self.evaporator.qIn
        # Efficiencies
        self.COPCooling = self.evaporatorHeat / self.compressorPower
        self.COPHeating = self.condenserHeat / self.compressorPower

    def CO2TranscriticalCycle(self):
        self.fluidName = 'CarbonDioxide'
        self.pHighMethod = 'P'
        self.pHigh = (130, 'bar')
        self.pLowMethod = 'T'
        self.TEvaporation = (10, 'degC')
        self.compressor.modelType = 'S'
        self.compressor.etaS = 0.8
        self.compressor.fQ = 0.2
        self.condenser.computeMethod = 'T'
        self.condenser.TOutlet = (50, 'degC')
        self.evaporator.computeMethod = 'dT'
        self.evaporator.dTOutlet = (5, 'degC')

    def R134aCycle(self):
        self.fluidName = 'R134a'
        self.pHighMethod = 'P'
        self.pHigh = (10, 'bar')
        self.pLowMethod = 'T'
        self.TEvaporation = (-20, 'degC')
        self.compressor.modelType = 'S'
        self.compressor.etaS = 0.75
        self.compressor.fQ = 0.0
        self.condenser.computeMethod = 'T'
        self.condenser.TOutlet = (36, 'degC')
        self.evaporator.computeMethod = 'Q'
        self.evaporator.qOutlet = 1.0
Beispiel #12
0
class ThermodynamicalCycle(NumericalModel):
    abstract = True
    #================ Inputs ================#
    # Cycle diagram
    cycleDiagram = F.SubModelGroup(TC.CycleDiagram,
                                   'inputs',
                                   label='Diagram settings')
    # Solver settings
    solver = F.SubModelGroup(CycleIterator, 'solverSettings', label='Solver')
    #================ Results ================#
    #---------------- Fields ----------------#
    cycleStatesTable = F.TableView(
        (('T', F.Quantity('Temperature', default=(1, 'degC'))),
         ('p', F.Quantity('Pressure', default=(1, 'bar'))),
         ('rho', F.Quantity('Density', default=(1, 'kg/m**3'))),
         ('h', F.Quantity('SpecificEnthalpy', default=(1, 'kJ/kg'))),
         ('s', F.Quantity('SpecificEntropy', default=(1, 'kJ/kg-K'))),
         ('q', F.Quantity()),
         ('dT', F.Quantity('TemperatureDifference', default=(1, 'degC'))),
         ('mDot', F.Quantity('MassFlowRate', default=(1, 'kg/min'))),
         ('b', F.Quantity('SpecificEnergy', default=(1, 'kJ/kg')))),
        label="Cycle states")

    cycleStates = F.ViewGroup([cycleStatesTable], label="States")
    resultStates = F.SuperGroup([cycleStates], label="States")
    #---------------- Cycle diagram -----------#
    phDiagram = F.Image(default='')
    cycleDiagramVG = F.ViewGroup([phDiagram], label="P-H Diagram")
    resultDiagrams = F.SuperGroup([cycleDiagramVG], label="Diagrams")
    #---------------- Convergence parameters -----------#
    residualPlot = F.PlotView((('iteration #', F.Quantity('Dimensionless')),
                               ('h change', F.Quantity('SpecificEnthalpy'))),
                              label='Residual (plot)',
                              ylog=True)
    iterationTable = F.TableView((
        ('h1', F.Quantity('SpecificEnthalpy')),
        ('h2', F.Quantity('SpecificEnthalpy')),
        ('h3', F.Quantity('SpecificEnthalpy')),
        ('h4', F.Quantity('SpecificEnthalpy')),
        ('h5', F.Quantity('SpecificEnthalpy')),
        ('h6', F.Quantity('SpecificEnthalpy')),
        ('h7', F.Quantity('SpecificEnthalpy')),
        ('h8', F.Quantity('SpecificEnthalpy')),
        ('h9', F.Quantity('SpecificEnthalpy')),
        ('h10', F.Quantity('SpecificEnthalpy')),
        ('h11', F.Quantity('SpecificEnthalpy')),
        ('h12', F.Quantity('SpecificEnthalpy')),
        ('h13', F.Quantity('SpecificEnthalpy')),
        ('h14', F.Quantity('SpecificEnthalpy')),
        ('h15', F.Quantity('SpecificEnthalpy')),
        ('h16', F.Quantity('SpecificEnthalpy')),
        ('h17', F.Quantity('SpecificEnthalpy')),
        ('h18', F.Quantity('SpecificEnthalpy')),
        ('h19', F.Quantity('SpecificEnthalpy')),
        ('h20', F.Quantity('SpecificEnthalpy')),
    ),
                                 label='Residual (table)',
                                 options={'formats': (['0.0000E0'] * 20)})
    residualGroup = F.ViewGroup([residualPlot, iterationTable],
                                label='Iterations')
    solverStats = F.SuperGroup([residualGroup], label='Convergence')

    # Info fields
    cycleTranscritical = F.Boolean(default=False)
    cycleSupercritical = F.Boolean(default=False)

    def initCompute(self, fluid):
        # Create fluid points
        self.fluid = Fluid(fluid)
        self.fp = []  #[FluidState(fluid) for _ in range(numPoints)]
        self.flows = []
        self.solver.cycle = self

    def connectPorts(self, port1, port2, fluid=None):
        if fluid == None:
            fluid = self.fluid
        fp = FluidState(fluid)
        flow = P.FluidFlow()
        self.fp.append(fp)
        self.flows.append(flow)
        port1.state = fp
        port2.state = fp
        port1.flow = flow
        port2.flow = flow

    def solve(self):
        self.solver.run()
        self.residualPlot.resize(len(self.solver.change_hHistory))
        for i in range(len(self.solver.change_hHistory)):
            self.residualPlot[i] = (i + 1, self.solver.change_hHistory[i])
        self.iterationTable.resize(len(self.solver.hHistory))
        v = self.iterationTable.view(dtype=np.float).reshape(
            -1, len(self.iterationTable.dtype))
        numCols = len(self.solver.hHistory[0])
        for i in range(len(self.solver.hHistory)):
            v[i, :numCols] = self.solver.hHistory[i]


# 		print self.iterationTable
# 		iterRecord = np.zeros(1, dtype = self.iterationTable.dtype)
# 		numCols = len(self.solver.hHistory[0])
# 		for i in range(len(self.solver.hHistory)):
# 			for j in range(numCols):
# 				iterRecord[j] = self.solver.hHistory[i][j]
# 			self.iterationTable[i] = iterRecord

    def postProcess(self, TAmbient):
        ## State diagram
        if (self.cycleDiagram.enable):
            self.createStateDiagram()
        ## Table of states
        self.cycleStatesTable.resize(len(self.fp))
        for i in range(len(self.fp)):
            fp = self.fp[i]
            self.cycleStatesTable[i] = (fp.T, fp.p, fp.rho, fp.h, fp.s, fp.q,
                                        fp.dT, self.flows[i].mDot,
                                        fp.b(TAmbient))
        # Select the zero for the exergy scale
        fp = FluidState(self.fluid)
        fp.update_Tp(TAmbient, 1e5)
        b0 = fp.b(TAmbient)
        self.cycleStatesTable['b'] -= b0

    def createStateDiagram(self):
        ncp = len(self.fp)
        fluidLines = []
        for i in range(ncp):
            fluidLines.append((self.fp[i], self.fp[(i + 1) % ncp]))
        self.phDiagram = self.cycleDiagram.draw(self.fluid, self.fp,
                                                fluidLines)

    def setPLow(self, p):
        if (self.fluid.tripple['p'] < p < self.fluid.critical['p']):
            self.pLow = p
            sat = self.fluid.saturation_p(p)
            self.TEvaporation = sat['TsatL']
        elif (p > self.fluid.critical['p']):
            self.pLow = p
            self.cycleSupercritical = True
        else:
            raise ValueError(
                'PLow  ({} bar) must be between {} bar and {} bar'.format(
                    p / 1e5, self.fluid.tripple['p'] / 1e5,
                    self.fluid.critical['p'] / 1e5))

    def setPHigh(self, p):
        if (self.fluid.tripple['p'] < p < self.fluid.critical['p']):
            self.pHigh = p
            sat = self.fluid.saturation_p(p)
            self.TCondensation = sat['TsatL']
        elif (p > self.fluid.critical['p']):
            self.pHigh = p
            self.cycleTranscritical = True
        else:
            raise ValueError(
                'PHigh  ({} bar) must be between {} bar and {} bar'.format(
                    p / 1e5, self.fluid.tripple['p'] / 1e5,
                    self.fluid.critical['p'] / 1e5))
Beispiel #13
0
class ClaudeCycle(LindeHampsonCycle):
    label = "Claude cycle"
    figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/ClaudeCycle.svg",
                           height=300)
    description = F.ModelDescription(
        "Liquefaction cycle using an expander and 3 recurperators for increased efficiency",
        show=True)

    #================ Inputs ================#
    #---------------- Fields ----------------#
    # FieldGroup
    recuperator2 = F.SubModelGroup(TC.HeatExchangerTwoStreams,
                                   'FG',
                                   label='Recuperator 2')
    recuperator3 = F.SubModelGroup(TC.HeatExchangerTwoStreams,
                                   'FG',
                                   label='Recuperator 3')
    expander = F.SubModelGroup(TC.Turbine, 'FG', label='Expander')
    expanderFlowFraction = F.Quantity('Fraction', label='flow fraction')
    expanderEta = F.Quantity('Efficiency', label='efficiency')
    expanderFG = F.FieldGroup([expanderFlowFraction, expanderEta],
                              label='Expander')
    expanderSplitter = F.SubModelGroup(TC.FlowSplitter, 'FG')
    expanderJunction = F.SubModelGroup(TC.FlowJunction, 'FG')
    inputs = F.SuperGroup([
        'workingFluidGroup', 'compressor', 'cooler', expanderFG, 'recuperator',
        recuperator2, recuperator3
    ],
                          label='Cycle definition')
    #---------------- Actions ----------------#
    exampleAction = ServerAction(
        "loadEg",
        label="Examples",
        options=(
            ('NitrogenMediumP',
             'Nitrogen medium pressure (30 bar) liquefaction cycle'),
            ('NitrogenLowP',
             'Nitrogen low pressure (8 bar) liquefacton cycle'),
        ))
    #--------------- Model view ---------------#
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputs, 'cycleDiagram', 'solver'],
                            actionBar=ActionBar([exampleAction]),
                            autoFetch=True)

    #================ Results ================#
    #---------------- Scheme -----------------#
    scheme_Claude = F.Image(
        default="static/ThermoFluids/img/ModuleImages/ClaudeCycle.png")
    SchemeVG = F.ViewGroup([scheme_Claude], label="Process Scheme")
    SchemeSG = F.SuperGroup([SchemeVG], label="Scheme")

    resultView = F.ModelView(ioType="output",
                             superGroups=[
                                 'resultDiagrams', SchemeSG, 'resultStates',
                                 'resultEnergy', 'solverStats'
                             ])

    def __init__(self):
        self.cooler.computeMethod = 'eta'
        self.cooler.TExt = self.TAmbient
        self.NitrogenMediumP()

    def compute(self):
        self.initCompute(self.fluidName)
        self.expanderSplitter.frac1 = 1 - self.expanderFlowFraction
        self.expanderSplitter.frac2 = self.expanderFlowFraction
        self.expander.eta = self.expanderEta
        # Connect components
        self.connectPorts(self.gasSource.outlet, self.inletJunct.inletMain)
        self.connectPorts(self.inletJunct.outlet, self.compressor.inlet)
        self.connectPorts(self.compressor.outlet, self.cooler.inlet)
        self.connectPorts(self.cooler.outlet, self.recuperator.inlet1)
        self.connectPorts(self.recuperator.outlet1,
                          self.expanderSplitter.inlet)
        self.connectPorts(self.expanderSplitter.outlet1,
                          self.recuperator2.inlet1)
        self.connectPorts(self.recuperator2.outlet1, self.recuperator3.inlet1)
        self.connectPorts(self.recuperator3.outlet1, self.throttleValve.inlet)
        self.connectPorts(self.throttleValve.outlet, self.liqSeparator.inlet)
        self.connectPorts(self.liqSeparator.outletVapor,
                          self.secThrottleValve.inlet)
        self.connectPorts(self.secThrottleValve.outlet,
                          self.recuperator3.inlet2)
        self.connectPorts(self.recuperator3.outlet2,
                          self.expanderJunction.inletMain)
        self.connectPorts(self.expanderJunction.outlet,
                          self.recuperator2.inlet2)
        self.connectPorts(self.recuperator2.outlet2, self.recuperator.inlet2)
        self.connectPorts(self.recuperator.outlet2, self.inletJunct.inlet2)
        self.connectPorts(self.expanderSplitter.outlet2, self.expander.inlet)
        self.connectPorts(self.expander.outlet, self.expanderJunction.inlet2)
        self.connectPorts(self.liqSeparator.outletLiquid,
                          self.liquidSink.inlet)

        # Initial guess
        liqFractionGuess = 0.5
        for fl in self.flows:
            fl.mDot = 1.0 / liqFractionGuess * self.mDot
        for fp in self.fp:
            fp.update_Tp(self.TAmbient, self.pIn)

        # Initialize source
        self.gasSource.T = self.TIn
        self.gasSource.p = self.pIn
        self.gasSource.mDot = self.mDot
        self.gasSource.compute()
        # Run solver
        self.solve()
        # Results
        self.postProcess(self.TAmbient)

    def computeCycle(self):
        self.compressor.compute(self.pHigh)
        self.cooler.compute()
        self.recuperator.compute()
        self.recuperator.computeStream1()
        self.expanderSplitter.compute()
        self.recuperator2.compute()
        self.recuperator2.computeStream1()
        self.recuperator3.compute()
        self.recuperator3.computeStream1()
        self.throttleValve.compute(self.pLiquid)
        self.liqSeparator.compute()
        self.secThrottleValve.compute(self.pIn)
        self.recuperator3.computeStream2()
        self.expander.compute(self.pIn)
        self.expanderJunction.compute()
        self.recuperator2.computeStream2()
        self.recuperator.computeStream2()
        self.inletJunct.compute()

    def createStateDiagram(self):
        lineNumbers = [(2, 3), (3, 4), (4, 5), (6, 7), (7, 8), (8, 9), (9, 10),
                       (9, 18), (10, 11), (11, 12), (13, 14), (14, 15),
                       (16, 17)]
        fluidLines = []
        for i, j in lineNumbers:
            fluidLines.append((self.fp[i - 1], self.fp[j - 1]))
        self.phDiagram = self.cycleDiagram.draw(self.fluid, self.fp,
                                                fluidLines)

    def NitrogenLiquefaction(self):
        self.fluidName = "Nitrogen"
        self.pIn = (1, 'bar')
        self.TIn = self.TAmbient
        self.pHigh = (30, 'bar')
        self.pLiquid = (1.2, 'bar')
        self.compressor.modelType = 'T'
        self.compressor.etaT = 0.8
        self.compressor.dT = 50.
        self.cycleDiagram.defaultMaxP = False
        self.cycleDiagram.defaultMaxT = False
        self.cycleDiagram.maxPressure = (500, 'bar')
        self.cycleDiagram.maxTemperature = 350

    def NitrogenMediumP(self):
        self.fluidName = "Nitrogen"
        self.pIn = (1, 'bar')
        self.TIn = self.TAmbient
        self.mDot = (0.188, 'kg/s')
        self.pHigh = (30, 'bar')
        self.pLiquid = (1.2, 'bar')
        self.compressor.modelType = 'T'
        self.compressor.etaT = 0.8
        self.compressor.dT = 50
        self.cooler.computeMethod = 'eta'
        self.cooler.etaThermal = 1.
        self.cooler.TExt = (30, 'degC')
        self.expanderEta = 0.8
        self.expanderFlowFraction = 0.66
        self.recuperator.computeMethod = 'EG'
        self.recuperator.epsGiven = 0.99
        self.recuperator2.computeMethod = 'EN'
        self.recuperator2.UA = (1950, 'W/K')
        self.recuperator3.computeMethod = 'EG'
        self.recuperator3.epsGiven = 0
        self.cycleDiagram.defaultMaxT = False
        self.cycleDiagram.maxTemperature = 400

    def NitrogenLowP(self):
        self.fluidName = "Nitrogen"
        self.pIn = (1.1, 'bar')
        self.TIn = (300, 'K')
        self.mDot = (12.8, 'kg/h')
        self.pHigh = (8, 'bar')
        self.pLiquid = (1.2, 'bar')
        self.TAmbient = (300, 'K')
        self.compressor.modelType = 'S'
        self.compressor.etaS = 0.8
        self.compressor.fQ = 0.3
        self.cooler.computeMethod = 'eta'
        self.cooler.etaThermal = 1.
        self.cooler.TExt = (310, 'K')
        self.expanderEta = 0.5
        self.expanderFlowFraction = 0.94
        self.recuperator.computeMethod = 'EN'
        self.recuperator.UA = (1280, 'W/K')
        self.recuperator2.computeMethod = 'EN'
        self.recuperator2.UA = (90, 'W/K')
        self.recuperator3.computeMethod = 'EG'
        self.recuperator3.epsGiven = 0
        self.cycleDiagram.defaultMaxT = False
        self.cycleDiagram.maxTemperature = 550
Beispiel #14
0
class LindeHampsonCycle(LiquefactionCycle):
    label = "Linde-Hampson cycle"
    figure = F.ModelFigure(
        src="ThermoFluids/img/ModuleImages/LindeHampson.svg", height=300)
    description = F.ModelDescription(
        "Basic liquefaction cycle used e.g. for air liquefaction", show=True)

    #================ Inputs ================#
    #---------------- Fields ----------------#
    # FieldGroup
    gasSource = F.SubModelGroup(TC.FluidSource_TP, 'FG')
    inletJunct = F.SubModelGroup(TC.FlowJunction, 'FG')
    compressor = F.SubModelGroup(TC.Compressor, 'FG', label='Compressor')
    cooler = F.SubModelGroup(TC.Condenser, 'FG', label='Cooler')
    recuperator = F.SubModelGroup(TC.HeatExchangerTwoStreams,
                                  'FG',
                                  label='Recuperator')
    throttleValve = F.SubModelGroup(TC.ThrottleValve, 'FG', label='JT valve')
    liqSeparator = F.SubModelGroup(TC.PhaseSeparator,
                                   'FG',
                                   label='Liquid separator')
    secThrottleValve = F.SubModelGroup(TC.ThrottleValve,
                                       'FG',
                                       label='JT valve')
    liquidSink = F.SubModelGroup(TC.FluidSink, 'FG')
    inputs = F.SuperGroup(
        ['workingFluidGroup', compressor, cooler, recuperator],
        label='Cycle definition')

    #---------------- Actions ----------------#
    exampleAction = ServerAction("loadEg",
                                 label="Examples",
                                 options=(
                                     ('ArgonLiquefaction',
                                      'Argon liquefaction cycle'),
                                     ('NitrogenLiquefaction',
                                      'Nitrogen liquefacton cycle'),
                                 ))
    #--------------- Model view ---------------#
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputs, 'cycleDiagram', 'solver'],
                            actionBar=ActionBar([exampleAction]),
                            autoFetch=True)

    #================ Results ================#
    compressorPower = F.Quantity('Power',
                                 default=(1, 'kW'),
                                 label='compressor power')
    compressorHeat = F.Quantity('HeatFlowRate',
                                default=(1, 'kW'),
                                label='compressor heat')
    coolerHeat = F.Quantity('HeatFlowRate',
                            default=(1, 'kW'),
                            label='cooler heat out')
    flowFieldGroup = F.FieldGroup(
        [compressorPower, compressorHeat, coolerHeat], label='Flows')
    resultEnergy = F.SuperGroup([flowFieldGroup, 'efficiencyFieldGroup'],
                                label='Energy')
    #---------------- Scheme -----------------#
    scheme_LindeHampson = F.Image(
        default="static/ThermoFluids/img/ModuleImages/LindeHampson.png")
    SchemeVG = F.ViewGroup([scheme_LindeHampson], label="Process Scheme")
    SchemeSG = F.SuperGroup([SchemeVG], label="Scheme")

    resultView = F.ModelView(ioType="output",
                             superGroups=[
                                 'resultDiagrams', SchemeSG, 'resultStates',
                                 resultEnergy, 'solverStats'
                             ])

    #============= Page structure =============#
    modelBlocks = [inputView, resultView]

    #================ Methods ================#
    def __init__(self):
        self.cooler.computeMethod = 'eta'
        self.cooler.TExt = self.TAmbient
        self.ArgonLiquefaction()

    def compute(self):
        self.initCompute(self.fluidName)
        # Connect components
        self.connectPorts(self.gasSource.outlet, self.inletJunct.inletMain)
        self.connectPorts(self.inletJunct.outlet, self.compressor.inlet)
        self.connectPorts(self.compressor.outlet, self.cooler.inlet)
        self.connectPorts(self.cooler.outlet, self.recuperator.inlet1)
        self.connectPorts(self.recuperator.outlet1, self.throttleValve.inlet)
        self.connectPorts(self.throttleValve.outlet, self.liqSeparator.inlet)
        self.connectPorts(self.liqSeparator.outletVapor,
                          self.secThrottleValve.inlet)
        self.connectPorts(self.secThrottleValve.outlet,
                          self.recuperator.inlet2)
        self.connectPorts(self.recuperator.outlet2, self.inletJunct.inlet2)
        self.connectPorts(self.liqSeparator.outletLiquid,
                          self.liquidSink.inlet)
        # Initialize source
        self.gasSource.T = self.TIn
        self.gasSource.p = self.pIn
        self.gasSource.mDot = self.mDot
        self.gasSource.compute()
        # Initial guess
        liqFractionGuess = 0.5
        for fl in self.flows:
            fl.mDot = 1.0 / liqFractionGuess * self.mDot
        for fp in self.fp:
            fp.update_Tp(self.TAmbient, self.pIn)


# 		liqFractionGuess = 0.2
# 		self.compressor.inlet.flow.mDot = 1.0 / liqFractionGuess * self.gasSource.outlet.flow.mDot
# 		self.liqSeparator.outletVapor.flow.mDot = liqFractionGuess * self.mDot
#
# 		self.compressor.inlet.state.update_Tp(
# 			self.gasSource.outlet.state.T, self.gasSource.outlet.state.p)
# 		self.secThrottleValve.outlet.state.update_pq(self.pIn, 1)
# Run solver
        self.solve()
        # Results
        self.postProcess(self.TAmbient)

    def computeCycle(self):
        self.compressor.compute(self.pHigh)
        self.cooler.compute()
        self.recuperator.compute()
        self.recuperator.computeStream1()
        self.throttleValve.compute(self.pLiquid)
        self.liqSeparator.compute()
        self.secThrottleValve.compute(self.pIn)
        self.recuperator.computeStream2()
        self.inletJunct.compute()

    def postProcess(self, TAmbient):
        LiquefactionCycle.postProcess(self, TAmbient)
        self.compressor.postProcess()
        self.cooler.postProcess()
        # Flows
        self.compressorPower = self.compressor.WDot
        self.compressorHeat = -self.compressor.QDotIn
        self.coolerHeat = -self.cooler.QDotIn
        # Efficiencies
        self.liqEnergy = self.compressor.WDot / self.liqSeparator.outletLiquid.flow.mDot
        self.minLiqEnergy = self.liqSeparator.outletLiquid.state.b(self.TAmbient) \
         - self.gasSource.outlet.state.b(self.TAmbient)
        self.etaSecondLaw = self.minLiqEnergy / self.liqEnergy

    def createStateDiagram(self):
        lineNumbers = [(2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (6, 10), (7, 8),
                       (8, 9)]
        fluidLines = []
        for i, j in lineNumbers:
            fluidLines.append((self.fp[i - 1], self.fp[j - 1]))
        self.phDiagram = self.cycleDiagram.draw(self.fluid, self.fp,
                                                fluidLines)

    def ArgonLiquefaction(self):
        self.fluidName = "Argon"
        self.pIn = (1, 'bar')
        self.TIn = self.TAmbient
        self.pHigh = (200, 'bar')
        self.pLiquid = (1.2, 'bar')
        self.compressor.modelType = 'T'
        self.compressor.etaT = 0.8
        self.compressor.dT = 50.
        self.recuperator.eta = 0.99
        self.cycleDiagram.defaultMaxP = False
        self.cycleDiagram.maxPressure = (300, 'bar')

    def NitrogenLiquefaction(self):
        self.fluidName = "Nitrogen"
        self.pIn = (1, 'bar')
        self.TIn = self.TAmbient
        self.pHigh = (300, 'bar')
        self.pLiquid = (1.2, 'bar')
        self.compressor.modelType = 'T'
        self.compressor.etaT = 0.8
        self.compressor.dT = 50.
        self.recuperator.eta = 0.99
        self.cycleDiagram.defaultMaxP = False
        self.cycleDiagram.defaultMaxT = False
        self.cycleDiagram.maxPressure = (500, 'bar')
        self.cycleDiagram.maxTemperature = 350
Beispiel #15
0
class RankineCycle(HeatEngineCycle):
	label = "Rankine cycle"
	figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/RankineCycle.png",  height = 300)
	description = F.ModelDescription("Basic Rankine cycle used in power generation", show = True)
	
	#================ Inputs ================#
	#---------------- Fields ----------------#
	# FieldGroup
	pump = F.SubModelGroup(TC.Compressor, 'FG', label  = 'Pump')
	boiler = F.SubModelGroup(TC.Evaporator, 'FG', label = 'Boiler')
	turbine = F.SubModelGroup(TC.Turbine, 'FG', label = 'Turbine')
	condenser = F.SubModelGroup(TC.Condenser, 'FG', label = 'Condenser')
	inputs = F.SuperGroup(['workingFluidGroup', pump, boiler, turbine, condenser], label = 'Cycle definition')	
	#---------------- Actions ----------------#
	exampleAction = ServerAction("loadEg", label = "Examples", options = (
			('SteamPlant', 'Typical steam power plant'),
			('ORC1', 'Geothermal Organic Rankine Cycle with R134a'),
	))
	#--------------- Model view ---------------#
	inputView = F.ModelView(ioType = "input", superGroups = [inputs, 'cycleDiagram', 'solver'], 
		actionBar = ActionBar([exampleAction]), autoFetch = True)
	#================ Results ================#
	#---------------- Energy flows -----------#
	pumpPower = F.Quantity('Power', default = (1, 'kW'), label = 'pump power')
	boilerHeat = F.Quantity('HeatFlowRate', default = (1, 'kW'), label = 'boiler heat in')
	turbinePower = F.Quantity('HeatFlowRate', default = (1, 'kW'), label = 'turbine power')
	condenserHeat = F.Quantity('HeatFlowRate', default = (1, 'kW'), label = 'condenser heat out')
	flowFieldGroup = F.FieldGroup([pumpPower, boilerHeat, turbinePower, condenserHeat], label = 'Energy flows')
	resultEnergy = F.SuperGroup([flowFieldGroup, 'efficiencyFieldGroup'], label = 'Energy')
	resultView = F.ModelView(ioType = "output", superGroups = ['resultDiagrams', 'resultStates', resultEnergy, 'solverStats'])

	#============= Page structure =============#
	modelBlocks = [inputView, resultView]

	#================ Methods ================#
	def __init__(self):
		self.SteamPlant()
		
	def compute(self):
		if (self.cycleTranscritical and 
				(self.boiler.computeMethod == 'dT' or self.boiler.computeMethod == 'Q')):
			raise ValueError('In transcritical cycle, boiler super-heating cannot be used as input')
		if (self.cycleSupercritical and 
				(self.condenser.computeMethod == 'dT' or self.condenser.computeMethod == 'Q')):
			raise ValueError('In supercritical cycle condenser sub-cooling cannot be used as input')
		# Connect components to points
		self.initCompute(self.fluidName)
		self.connectPorts(self.condenser.outlet, self.pump.inlet)
		self.connectPorts(self.pump.outlet, self.boiler.inlet)
		self.connectPorts(self.boiler.outlet, self.turbine.inlet)
		self.connectPorts(self.turbine.outlet, self.condenser.inlet)
		# Initial guess
		for fl in self.flows:
			fl.mDot = self.mDot
		self.condenser.outlet.state.update_pq(self.pLow, 0)
		# Cycle iterations
		self.solver.run()
		# Results
		self.postProcess()
		
	def computeCycle(self):
		self.pump.compute(self.pHigh)
		self.boiler.compute()	
		self.turbine.compute(self.pLow)
		self.condenser.compute()
		
	def postProcess(self):
		super(RankineCycle, self).postProcess(self.TAmbient)
		# Flows
		self.pumpPower = self.mDot * self.pump.w 
		self.boilerHeat = self.mDot * self.boiler.qIn
		self.turbinePower = - self.mDot * self.turbine.w
		self.condenserHeat = - self.mDot * self.condenser.qIn 
		# Efficiencies
		self.eta = (self.turbinePower - self.pumpPower) / self.boilerHeat
		self.etaCarnot = 1 - self.condenser.outlet.state.T / self.boiler.outlet.state.T
		self.etaSecondLaw = self.eta / self.etaCarnot
	
	def SteamPlant(self):
		self.fluidName = 'Water'
		self.mDot = 25.
		self.pHighMethod = 'P'
		self.pHigh = (35, 'bar')
		self.pLowMethod = 'P'
		self.pLow = (0.5, 'bar')
		self.boiler.computeMethod = 'T'
		self.boiler.TOutlet = (400, 'degC')
		self.turbine.eta = 0.85
		self.condenser.computeMethod = 'Q'
		self.condenser.qOutlet = 0
	
	def ORC1(self):
		self.fluidName = 'R134a'
		self.mDot = (10, 'kg/min')
		self.pHighMethod = 'T'
		self.TEvaporation = (85, 'degC')
		self.pLowMethod = 'T'
		self.TCondensation = (40, 'degC')
		self.boiler.computeMethod = 'Q'
		self.boiler.qOutlet = 1
		self.turbine.eta = 0.8
		self.condenser.computeMethod = 'Q'
		self.condenser.qOutlet = 0
Beispiel #16
0
class CylindricalBlockHeatExchanger(NumericalModel):
    label = "Cylindrical heat exchanger"
    figure = F.ModelFigure(
        src="ThermoFluids/img/ModuleImages/HeatExchangerDesign.png",
        show=False)
    description = F.ModelDescription(
        """Model of heat exchanger made out of a solid cylindrical block, with
	central channels for one of the fluids and a spiraling
	channel around the block for the other fluid
	""")

    async = True
    progressOptions = {'suffix': '%', 'fractionOutput': False}

    #================ Inputs ================#
    #---------------- Fields ----------------#
    # Fields: geometry
    blockGeom = F.SubModelGroup(BlockGeometry, 'FG', 'Geometry')
    blockProps = F.SubModelGroup(BlockProperties, 'FG', 'Properties')
    blockSG = F.SuperGroup([blockGeom, blockProps], label='Block')

    # Fields: internal channels
    primaryChannelsGeom = F.SubModelGroup(ChannelGroupGeometry,
                                          'FG',
                                          label='Primary channels')
    secondaryChannelsGeom = F.SubModelGroup(ChannelGroupGeometry,
                                            'FG',
                                            label='Secondary channels')
    primaryFlowIn = F.SubModelGroup(FluidFlowInput,
                                    'FG',
                                    label='Primary flow inlet')
    secondaryFlowIn = F.SubModelGroup(FluidFlowInput,
                                      'FG',
                                      label='Secondary flow inlet')
    internalChannelSG = F.SuperGroup([
        primaryChannelsGeom, secondaryChannelsGeom, primaryFlowIn,
        secondaryFlowIn
    ],
                                     label='Channels')

    # Fields: external channel
    externalChannelGeom = F.SubModelGroup(ExternalChannelGeometry,
                                          'FG',
                                          label='Geometry')
    externalFlowIn = F.SubModelGroup(IncompressibleSolutionFlowInput,
                                     'incomSolFG',
                                     label='Inlet flow')
    externalChannelSG = F.SuperGroup([externalChannelGeom, externalFlowIn],
                                     label='External channel')

    # Fields: settings
    fvSolverSettings = F.SubModelGroup(FiniteVolumeSolverSettings,
                                       'FG',
                                       label='Finite volume solver')
    sectionResultsSettings = F.SubModelGroup(SectionResultsSettings,
                                             'FG',
                                             label='Section results plots')
    settingsSG = F.SuperGroup([fvSolverSettings, sectionResultsSettings],
                              label='Settings')

    #--------------- Model view ---------------#
    inputView = F.ModelView(ioType="input",
                            superGroups=[
                                blockSG, internalChannelSG, externalChannelSG,
                                settingsSG
                            ],
                            autoFetch=True)

    #================ Results ================#
    meshView = F.MPLPlot(label='Cross-section mesh')
    crossSectionProfileView = F.MPLPlot(label='Cross-section profile')
    longitudinalProfileView = F.MPLPlot(label='Longitudinal profile')
    primaryChannelProfileView = F.MPLPlot(label='Primary channel profile')
    secondaryChannelProfileView = F.MPLPlot(label='Secondary channel profile')
    geometryVG = F.ViewGroup([
        meshView, crossSectionProfileView, longitudinalProfileView,
        primaryChannelProfileView, secondaryChannelProfileView
    ],
                             label='Geometry/Mesh')
    geometrySG = F.SuperGroup([geometryVG], label='Geometry/mesh')

    primaryFlowOut = F.SubModelGroup(FluidFlowOutput,
                                     'FG',
                                     label='Primary flow outlet')
    secondaryFlowOut = F.SubModelGroup(FluidFlowOutput,
                                       'FG',
                                       label='Secondary flow outlet')
    externalFlowOut = F.SubModelGroup(FluidFlowOutput,
                                      'FG',
                                      label='External flow outlet')
    QDotChannels = F.SubModelGroup(HeatFlowChannels, 'FG', label='Heat flow')
    resultSG = F.SuperGroup(
        [primaryFlowOut, secondaryFlowOut, externalFlowOut, QDotChannels],
        label='Results')

    resultTable = F.TableView((
        ('xStart', F.Quantity('Length', default=(1, 'm'))),
        ('xEnd', F.Quantity('Length', default=(1, 'm'))),
        ('TPrimFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TPrimWall', F.Quantity('Temperature', default=(1, 'degC'))),
        ('RePrim', F.Quantity()),
        ('hConvPrim',
         F.Quantity('HeatTransferCoefficient', default=(1, 'W/m**2-K'))),
        ('QDotPrim', F.Quantity('HeatFlowRate', default=(1, 'W'))),
        ('TSecFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TSecWall', F.Quantity('Temperature', default=(1, 'degC'))),
        ('ReSec', F.Quantity()),
        ('hConvSec',
         F.Quantity('HeatTransferCoefficient', default=(1, 'W/m**2-K'))),
        ('QDotSec', F.Quantity('HeatFlowRate', default=(1, 'W'))),
        ('TExtFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TExtWall', F.Quantity('Temperature', default=(1, 'degC'))),
        ('ReExt', F.Quantity()),
        ('hConvExt',
         F.Quantity('HeatTransferCoefficient', default=(1, 'W/m**2-K'))),
        ('QDotExt', F.Quantity('HeatFlowRate', default=(1, 'W'))),
    ),
                              label='Detailed results')
    resultTPlot = F.PlotView((
        ('x', F.Quantity('Length', default=(1, 'm'))),
        ('TPrimFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TPrimWall', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TSecFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TSecWall', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TExtFluid', F.Quantity('Temperature', default=(1, 'degC'))),
        ('TExtWall', F.Quantity('Temperature', default=(1, 'degC'))),
    ),
                             label='Temperature plots')

    resultQPlot = F.PlotView((
        ('x', F.Quantity('Length', default=(1, 'm'))),
        ('QDotPrim', F.Quantity('HeatFlowRate', default=(1, 'W'))),
        ('QDotSec', F.Quantity('HeatFlowRate', default=(1, 'W'))),
        ('QDotExt', F.Quantity('HeatFlowRate', default=(1, 'W'))),
    ),
                             label='Heat flow plots')
    detailedResultVG = F.ViewGroup([resultTable, resultTPlot, resultQPlot],
                                   label='Detailed results')
    detailedResultSG = F.SuperGroup([detailedResultVG],
                                    label='Detailed results')

    sectionPlot1 = F.MPLPlot(label='Section 1')
    sectionPlot2 = F.MPLPlot(label='Section 2')
    sectionPlot3 = F.MPLPlot(label='Section 3')
    sectionPlot4 = F.MPLPlot(label='Section 4')
    sectionPlot5 = F.MPLPlot(label='Section 5')
    sectionResultsVG = F.ViewGroup(
        [sectionPlot1, sectionPlot2, sectionPlot3, sectionPlot4, sectionPlot5],
        label='Section temperatures')
    sectionResultsSG = F.SuperGroup([sectionResultsVG],
                                    label='Section results')

    resultView = F.ModelView(
        ioType="output",
        superGroups=[geometrySG, resultSG, detailedResultSG, sectionResultsSG])

    ############# Page structure ########
    modelBlocks = [inputView, resultView]

    ############# Methods ###############
    def __init__Internal(self):
        self.blockGeom.diameter = (58.0, 'mm')
        self.blockGeom.length = (0.8, 'm')
        self.blockProps.divisionStep = (0.1, 'm')
        self.blockProps.material = 'Aluminium6061'

        self.primaryChannelsGeom.number = 3
        self.primaryChannelsGeom.radialPosition = (7, 'mm')
        self.primaryChannelsGeom.startingAngle = (0, 'deg')
        self.primaryChannelsGeom.meshFineness = 4
        self.primaryChannelsGeom.channelName = "PrimaryChannel"

        self.primaryChannelsGeom.externalDiameter = (7.5, 'mm')
        self.primaryChannelsGeom.sections[0] = (0.002, 0.2)
        self.primaryChannelsGeom.sections[1] = (0.004, 0.1)
        self.primaryChannelsGeom.sections[2] = (0.006, 0.1)
        self.primaryChannelsGeom.sections[3] = (0.0065, 0.1)
        self.primaryChannelsGeom.sections[4] = (0.007, 0.3)

        self.secondaryChannelsGeom.number = 3
        self.secondaryChannelsGeom.radialPosition = (17.5, 'mm')
        self.secondaryChannelsGeom.startingAngle = (60, 'deg')
        self.secondaryChannelsGeom.meshFineness = 4
        self.secondaryChannelsGeom.channelName = "SecondaryChannel"

        self.secondaryChannelsGeom.externalDiameter = (7.5, 'mm')
        self.secondaryChannelsGeom.sections[0] = (0.002, 0.2)
        self.secondaryChannelsGeom.sections[1] = (0.004, 0.1)
        self.secondaryChannelsGeom.sections[2] = (0.006, 0.1)
        self.secondaryChannelsGeom.sections[3] = (0.0065, 0.1)
        self.secondaryChannelsGeom.sections[4] = (0.007, 0.3)

        self.primaryFlowIn.fluidName = 'ParaHydrogen'
        self.primaryFlowIn.flowRateChoice = 'm'
        self.primaryFlowIn.mDot = (1, 'kg/h')
        self.primaryFlowIn.T = (100, 'K')
        self.primaryFlowIn.p = (1, 'bar')

        self.secondaryFlowIn.fluidName = 'ParaHydrogen'
        self.secondaryFlowIn.flowRateChoice = 'm'
        self.secondaryFlowIn.mDot = (1, 'kg/h')
        self.secondaryFlowIn.T = (100, 'K')
        self.secondaryFlowIn.p = (1, 'bar')

        self.externalFlowIn.solName = 'MEG'
        self.externalFlowIn.solMassFraction = (50, '%')
        self.externalFlowIn.flowRateChoice = 'V'
        self.externalFlowIn.VDot = (3, 'm**3/h')
        self.externalFlowIn.T = (80, 'degC')
        self.externalFlowIn.p = (1, 'bar')

        self.externalChannelGeom.widthAxial = (30, 'mm')
        self.externalChannelGeom.heightRadial = (12, 'mm')
        self.externalChannelGeom.coilPitch = (32, 'mm')
        self.externalChannelGeom.meshFineness = 4

        self.sectionResultsSettings.setTRange = False
        self.sectionResultsSettings.Tmin = (100, 'K')
        self.sectionResultsSettings.Tmax = (380, 'K')

    def __init__(self):
        self.blockGeom.diameter = (60.0, 'mm')
        self.blockGeom.length = (1.0, 'm')
        self.blockProps.divisionStep = (0.1, 'm')
        self.blockProps.material = 'Aluminium6061'

        self.primaryChannelsGeom.number = 4
        self.primaryChannelsGeom.radialPosition = (10, 'mm')
        self.primaryChannelsGeom.startingAngle = (0, 'deg')
        self.primaryChannelsGeom.meshFineness = 3
        self.primaryChannelsGeom.channelName = "PrimaryChannel"

        self.primaryChannelsGeom.externalDiameter = (10, 'mm')
        self.primaryChannelsGeom.sections[0] = (0.000, 0.2)
        self.primaryChannelsGeom.sections[1] = (0.002, 0.2)
        self.primaryChannelsGeom.sections[2] = (0.004, 0.2)
        self.primaryChannelsGeom.sections[3] = (0.006, 0.2)
        self.primaryChannelsGeom.sections[4] = (0.008, 0.2)

        self.secondaryChannelsGeom.number = 6
        self.secondaryChannelsGeom.radialPosition = (22.5, 'mm')
        self.secondaryChannelsGeom.startingAngle = (60, 'deg')
        self.secondaryChannelsGeom.meshFineness = 3
        self.secondaryChannelsGeom.channelName = "SecondaryChannel"

        self.secondaryChannelsGeom.externalDiameter = (7, 'mm')
        self.secondaryChannelsGeom.sections[0] = (0.002, 0.2)
        self.secondaryChannelsGeom.sections[1] = (0.003, 0.2)
        self.secondaryChannelsGeom.sections[2] = (0.004, 0.2)
        self.secondaryChannelsGeom.sections[3] = (0.005, 0.2)
        self.secondaryChannelsGeom.sections[4] = (0.006, 0.2)

        self.primaryFlowIn.fluidName = 'Ammonia'
        self.primaryFlowIn.flowRateChoice = 'm'
        self.primaryFlowIn.mDot = (50, 'kg/h')
        self.primaryFlowIn.T = (400, 'K')
        self.primaryFlowIn.p = (20, 'bar')

        self.secondaryFlowIn.fluidName = 'Ammonia'
        self.secondaryFlowIn.flowRateChoice = 'm'
        self.secondaryFlowIn.mDot = (50, 'kg/h')
        self.secondaryFlowIn.T = (400, 'K')
        self.secondaryFlowIn.p = (20, 'bar')

        self.externalFlowIn.solName = 'MPG'
        self.externalFlowIn.solMassFraction = (50, '%')
        self.externalFlowIn.flowRateChoice = 'V'
        self.externalFlowIn.VDot = (0.5, 'm**3/h')
        self.externalFlowIn.T = (20, 'degC')
        self.externalFlowIn.p = (1, 'bar')

        self.externalChannelGeom.widthAxial = (40, 'mm')
        self.externalChannelGeom.heightRadial = (10, 'mm')
        self.externalChannelGeom.coilPitch = (43, 'mm')
        self.externalChannelGeom.meshFineness = 3

        self.sectionResultsSettings.setTRange = False
        self.sectionResultsSettings.Tmin = (200, 'K')
        self.sectionResultsSettings.Tmax = (350, 'K')

    def computeAsync(self):
        # PreComputation
        self.externalChannelGeom.compute(self.blockGeom.diameter)
        self.primaryChannelsGeom.compute()
        self.secondaryChannelsGeom.compute()

        self.primaryFlowIn.compute()
        self.secondaryFlowIn.compute()
        self.externalFlowIn.compute()

        # Validation
        self.validateInputs()

        # Create the mesh
        mesher = HeatExchangerMesher()
        mesher.create(self)

        # Create channel calculator objects
        solver = HeatExchangerSolver(self, mesher)
        solver.createChannelCalculators(self)

        # Produce geometry/mesh drawings
        self.drawGeometry(mesher, solver)

        solver.solve(self)

        # Produce results
        self.postProcess(mesher, solver)

    def drawGeometry(self, mesher, solver):
        # Draw the mesh
        vertexCoords = mesher.mesh.vertexCoords
        vertexIDs = mesher.mesh._orderedCellVertexIDs
        triPlotMesh = tri.Triangulation(vertexCoords[0], vertexCoords[1],
                                        np.transpose(vertexIDs))
        self.meshView.triplot(triPlotMesh)
        self.meshView.set_aspect('equal')
        self.meshView.set_title('%d elements' %
                                len(mesher.mesh.cellCenters[0]))

        # Draw the channels profiles
        ticks = ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x * 1e3))

        solver.primChannelCalc.plotGeometry(self.primaryChannelProfileView)
        self.primaryChannelProfileView.set_xlabel('[m]')
        self.primaryChannelProfileView.set_ylabel('[mm]')
        self.primaryChannelProfileView.yaxis.set_major_formatter(ticks)

        solver.secChannelCalc.plotGeometry(self.secondaryChannelProfileView)
        self.secondaryChannelProfileView.set_xlabel('[m]')
        self.secondaryChannelProfileView.set_ylabel('[mm]')
        self.secondaryChannelProfileView.yaxis.set_major_formatter(ticks)

        #Draw the cross-section profile
        crossSectionProfile = HeatExchangerCrossSectionProfile()
        crossSectionProfile.addBlock(self.blockGeom)
        crossSectionProfile.addChannels(self.primaryChannelsGeom)
        crossSectionProfile.addChannels(self.secondaryChannelsGeom)
        crossSectionProfile.plotGeometry(self.crossSectionProfileView)

        self.crossSectionProfileView.set_xlabel('[mm]')
        self.crossSectionProfileView.set_ylabel('[mm]')
        self.crossSectionProfileView.xaxis.set_major_formatter(ticks)
        self.crossSectionProfileView.yaxis.set_major_formatter(ticks)

        #Draw the longitudinal profile
        longitudinalProfile = HeatExchangerLongitudinalProfile()
        longitudinalProfile.addBlock(self.blockGeom)
        longitudinalProfile.addExternalChannel(self.externalChannelGeom)
        longitudinalProfile.plotGeometry(self.longitudinalProfileView)

        self.longitudinalProfileView.set_xlabel('[mm]')
        self.longitudinalProfileView.set_ylabel('[mm]')
        self.longitudinalProfileView.xaxis.set_major_formatter(ticks)
        self.longitudinalProfileView.yaxis.set_major_formatter(ticks)

    def postProcess(self, mesher, solver):
        # Get the value for the outlet conditions
        self.primaryFlowOut.compute(fState=solver.primChannelStateOut,
                                    mDot=self.primaryFlowIn.mDot)
        self.secondaryFlowOut.compute(fState=solver.secChannelStateOut,
                                      mDot=self.secondaryFlowIn.mDot)
        self.externalFlowOut.compute(fState=solver.extChannelStateOut,
                                     mDot=self.externalFlowIn.mDot)

        self.QDotChannels.QDotPrimaryChannels = self.primaryFlowIn.mDot * \
         abs(self.primaryFlowOut.fState.h - self.primaryFlowIn.fState.h)
        self.QDotChannels.QDotSecondaryChannels = self.secondaryFlowIn.mDot * \
         abs(self.secondaryFlowOut.fState.h - self.secondaryFlowIn.fState.h)
        self.QDotChannels.QDotExternalChannel = self.externalFlowIn.mDot * \
         abs(self.externalFlowOut.fState.h - self.externalFlowIn.fState.h)
        # Fill the table with values
        self.resultTable.resize(solver.numSectionSteps)
        self.resultTPlot.resize(solver.numSectionSteps)
        self.resultQPlot.resize(solver.numSectionSteps)

        for i in range(solver.numSectionSteps):
            self.resultTable[i] = (
                solver.primChannelCalc.sections[i].xStart,
                solver.primChannelCalc.sections[i].xEnd,
                solver.primChannelCalc.sections[i].fState.T,
                solver.primChannelCalc.sections[i].TWall,
                solver.primChannelCalc.sections[i].Re,
                solver.primChannelCalc.sections[i].hConv,
                abs(solver.primChannelCalc.sections[i].QDotWall),
                solver.secChannelCalc.sections[i].fState.T,
                solver.secChannelCalc.sections[i].TWall,
                solver.secChannelCalc.sections[i].Re,
                solver.secChannelCalc.sections[i].hConv,
                abs(solver.secChannelCalc.sections[i].QDotWall),
                solver.extChannelCalc.sections[i].fState.T,
                solver.extChannelCalc.sections[i].TWall,
                solver.extChannelCalc.sections[i].Re,
                solver.extChannelCalc.sections[i].hConv,
                abs(solver.extChannelCalc.sections[i].QDotWall),
            )

            self.resultTPlot[i] = (
                (solver.primChannelCalc.sections[i].xStart +
                 solver.primChannelCalc.sections[i].xEnd) / 2,
                solver.primChannelCalc.sections[i].fState.T,
                solver.primChannelCalc.sections[i].TWall,
                solver.secChannelCalc.sections[i].fState.T,
                solver.secChannelCalc.sections[i].TWall,
                solver.extChannelCalc.sections[i].fState.T,
                solver.extChannelCalc.sections[i].TWall,
            )

            self.resultQPlot[i] = (
                (solver.primChannelCalc.sections[i].xStart +
                 solver.primChannelCalc.sections[i].xEnd) / 2,
                abs(solver.primChannelCalc.sections[i].QDotWall),
                abs(solver.secChannelCalc.sections[i].QDotWall),
                abs(solver.extChannelCalc.sections[i].QDotWall),
            )

    def validateInputs(self):
        self.validateChannels(self.primaryChannelsGeom, "primary")
        self.validateChannels(self.secondaryChannelsGeom, "secondary")

        if self.externalChannelGeom.widthAxial > self.externalChannelGeom.coilPitch:
            raise ValueError(
                'The coil pitch of the external channel is less than the axial width.'
            )

    def validateChannels(self, channelsGeom, channelsName):
        if self.blockGeom.diameter <= channelsGeom.externalDiameter:
            raise ValueError(
                'The block diameter is less than the external diameter of the {0} channels.'
                .format(channelsName))

        if self.blockGeom.diameter / 2. <= (
                channelsGeom.radialPosition +
                channelsGeom.externalDiameter / 2.):
            raise ValueError(
                'The radial position of the {0} channels is too big (the channels are outside of the block).'
                .format(channelsName))

        if self.blockGeom.length != channelsGeom.length:
            raise ValueError(
                'The length of the block is different from the length of the {0} channels.'
                .format(channelsName))

        i = 0
        for section in channelsGeom.sections:
            if (section['length'] < self.blockProps.divisionStep):
                raise ValueError(
                    'The axial division step of the block is greater than the {0}-th section of the {1} channels'
                    .format(i, channelsName))

            if self.isDividedExactly(section['length'],
                                     self.blockProps.divisionStep) == False:
                raise ValueError(
                    'The axial division step of the block does not divide the {0}-th section of the {1} channels in equal parts.'
                    .format(i, channelsName))
            i += 1

    def isDividedExactly(self, a, b):
        bigE = 1e6
        return int(a * bigE) % int(b * bigE) == 0