Ejemplo n.º 1
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)
Ejemplo n.º 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')
Ejemplo n.º 3
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)
Ejemplo n.º 4
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)
Ejemplo n.º 5
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)
Ejemplo n.º 6
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
Ejemplo n.º 7
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
Ejemplo n.º 8
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
Ejemplo n.º 9
0
class ChemostatDDE2_ESA(NumericalModel):
    label = "DDE Chemostat (Example 2 - ESA)"
    description = F.ModelDescription(
        "Chemostat model with delay differential equations (DDE) and extremum seeking algorithm (ESA) - Example 2",
        show=True)
    figure = F.ModelFigure(
        src="BioReactors/img/ModuleImages/SimpleChemostat.png", show=False)

    #1. ############ Inputs ###############
    #1.1 Fields - Input values
    # Parameters
    k1 = F.Quantity(
        default=0,
        minValue=0,
        maxValue=1e6,
        label='k<sub>1</sub>',
        description=
        'yield coefficient related to substrate-1 consumption from bacteria-1')
    k2 = F.Quantity(
        default=0,
        minValue=0,
        maxValue=1e6,
        label='k<sub>2</sub>',
        description=
        'yield coefficient related to substrate-2 production from bacteria-1')
    k3 = F.Quantity(
        default=0,
        minValue=0,
        maxValue=1e6,
        label='k<sub>3</sub>',
        description=
        'yield coefficient related to substrate-2 consumption from bacteria-2')
    k4 = F.Quantity(
        default=0,
        minValue=0,
        maxValue=1e6,
        label='k<sub>4</sub>',
        description=
        'yield coefficient of methane (biogas) on bacteria-2 and substrate-2')
    s1_in = F.Quantity('Bio_MassConcentration',
                       default=(0, 'g/L'),
                       label='s<sub>1</sub><sup>in</sub>',
                       description='input substrate-1 concentration')
    s2_in = F.Quantity('Bio_MassConcentration',
                       default=(0, 'g/L'),
                       label='s<sub>2</sub><sup>in</sub>',
                       description='input substrate-2 concentration')
    a = F.Quantity(
        'Fraction',
        default=(0, '-'),
        label='&#945',
        description=
        'proportion of organisms that are affected by the dilution rate D')
    D = F.Quantity('Bio_TimeRate',
                   default=(0, '1/day'),
                   minValue=(0, '1/day'),
                   label='D',
                   description='dilution rate')
    parametersFG = F.FieldGroup([s1_in, s2_in, k1, k2, k3, k4, a, D],
                                label='Parameters')

    # Parameters - specific growth rates
    m1 = F.Quantity('Bio_TimeRate',
                    default=(0, '1/day'),
                    minValue=(0, '1/day'),
                    label='m<sub>1</sub>',
                    description='maximum specific growth rate of bacteria-1')
    m2 = F.Quantity('Bio_TimeRate',
                    default=(0, '1/day'),
                    minValue=(0, '1/day'),
                    label='m<sub>2</sub>',
                    description='maximum specific growth rate of bacteria-2')
    k_s1 = F.Quantity('Bio_MassConcentration',
                      default=(0, 'g/L'),
                      label='k<sub>s1</sub>',
                      description='half saturation constant of bacteria-1')
    k_s2 = F.Quantity('Bio_MassConcentration',
                      default=(0, 'g/L'),
                      label='k<sub>s2</sub>',
                      description='half saturation constant of bacteria-2')
    k_I = F.Quantity('Dimensionless',
                     default=(0, '-'),
                     label='k<sub>I</sub>',
                     description='constant in unit: [ sqrt( g/L ) ]')
    parametersMuFG = F.FieldGroup([m1, m2, k_s1, k_s2, k_I],
                                  label='Parameters - specific growth rates')

    # Parameters - time delays
    tau1 = F.Quantity(
        'Bio_Time',
        default=(0, 'day'),
        minValue=(0, 'day'),
        label='&#964<sub>1</sub>',
        description=
        'time delay in conversion of the substrate-1 to viable biomass for bacteria-1'
    )
    tau2 = F.Quantity(
        'Bio_Time',
        default=(0, 'day'),
        minValue=(0, 'day'),
        label='&#964<sub>2</sub>',
        description=
        'time delay in conversion of the substrate-2 to viable biomass for bacteria-2'
    )
    parametersTauFG = F.FieldGroup([tau1, tau2],
                                   label='Parameters - time delay')

    # historical initial conditions
    s1_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0, 'g/L'),
        label='s<sub>1</sub><sup>&#91-&#964<sub>1</sub>, 0&#93</sup>',
        description='historical initial condition for substrate-1 concentration'
    )
    x1_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0, 'g/L'),
        label='x<sub>1</sub><sup>&#91-&#964<sub>1</sub>, 0&#93</sup>',
        description='historical initial condition for bacteria-1 concentration'
    )
    s2_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0, 'g/L'),
        label='s<sub>2</sub><sup>&#91-&#964<sub>2</sub>, 0&#93</sup>',
        description='historical initial condition for substrate-2 concentration'
    )
    x2_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0, 'g/L'),
        label='x<sub>2</sub><sup>&#91-&#964<sub>2</sub>, 0&#93</sup>',
        description='historical initial condition for bacteria-2 concentration'
    )
    parametersHistFG = F.FieldGroup(
        [s1_hist_vals, x1_hist_vals, s2_hist_vals, x2_hist_vals],
        label='Historical initial conditions')

    inputValuesSG = F.SuperGroup(
        [parametersMuFG, parametersFG, parametersTauFG, parametersHistFG],
        label="Input values")

    #1.2 Fields - Settings
    ESA_enable = F.Boolean(
        default=False,
        label='enable',
        description=
        'find the the maximum methane flow rate (i.e. run extremum seeking algorithm)'
    )
    ESA_DMin = F.Quantity('Bio_TimeRate',
                          default=(0, '1/day'),
                          minValue=(0.0, '1/day'),
                          label='D<sub>min</sub>',
                          description='minimum dilution rate',
                          show='self.ESA_enable')
    ESA_DMax = F.Quantity('Bio_TimeRate',
                          default=(0, '1/day'),
                          minValue=(0.0, '1/day'),
                          label='D<sub>max</sub>',
                          description='maximum dilution rate',
                          show='self.ESA_enable')
    ESA_eps = F.Quantity('Bio_TimeRate',
                         default=(0, '1/day'),
                         minValue=(1e-9, '1/day'),
                         maxValue=(1.0, '1/day'),
                         label='&#949*',
                         description='D max tolerance',
                         show='self.ESA_enable')
    ESA_h = F.Quantity('Bio_TimeRate',
                       default=(0, '1/day'),
                       minValue=(1e-8, '1/day'),
                       maxValue=(1.0, '1/day'),
                       label='h*',
                       description='seeking step of D max',
                       show='self.ESA_enable')
    ESA_eps_z = F.Quantity('Bio_MassConcentration',
                           default=(0, 'g/L'),
                           minValue=(1e-9, 'g/L'),
                           maxValue=(1.0, 'g/L'),
                           label='&#949<sub>z</sub>*',
                           description='equilibrium point tolerance',
                           show='self.ESA_enable')
    ESA_FG = F.FieldGroup(
        [ESA_enable, ESA_DMin, ESA_DMax, ESA_eps, ESA_h, ESA_eps_z],
        label='Extremum Seeking Algorithm (ESA)')

    DsQs_DMin = F.Quantity('Bio_TimeRate',
                           default=(0, '1/day'),
                           minValue=(0, '1/day'),
                           label='D<sub>min</sub>',
                           description='minimum dilution rate')
    DsQs_DMax = F.Quantity('Bio_TimeRate',
                           default=(0, '1/day'),
                           minValue=(0, '1/day'),
                           label='D<sub>max</sub>',
                           description='maximum dilution rate')
    DsQs_Step = F.Quantity('Bio_TimeRate',
                           default=(0, '1/day'),
                           minValue=(1e-4, '1/day'),
                           maxValue=(1.0, '1/day'),
                           label='D<sub>step</sub>',
                           description='step of dilution rate')
    DsQs_FG = F.FieldGroup([DsQs_DMin, DsQs_DMax, DsQs_Step],
                           label='Chart (Ds, Qs)')

    tFinal = F.Quantity('Bio_Time',
                        default=(100, 'day'),
                        minValue=(0, 'day'),
                        maxValue=(5000, 'day'),
                        label='simulation time')
    tPrint = F.Quantity('Bio_Time',
                        default=(0.1, 'day'),
                        minValue=(1e-5, 'day'),
                        maxValue=(100, 'day'),
                        label='print interval*')
    mainSimStep = F.Quantity('Bio_Time',
                             default=(10., 'day'),
                             minValue=(0.25, 'day'),
                             maxValue=(1e3, 'day'),
                             label='main simulation step*')
    absTol = F.Quantity('Bio_Time',
                        default=(1e-12, 'day'),
                        minValue=(1e-16, 'day'),
                        maxValue=(1e-5, 'day'),
                        label='absolute tolerance*')
    relTol = F.Quantity('Bio_Time',
                        default=(1e-12, 'day'),
                        minValue=(1e-16, 'day'),
                        maxValue=(1e-3, 'day'),
                        label='relative tolerance*')
    solverFG = F.FieldGroup([tFinal, tPrint, mainSimStep, absTol, relTol],
                            label='Solver')

    settingsSG = F.SuperGroup([solverFG, DsQs_FG, ESA_FG], label='Settings')

    #1.4 Model view
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputValuesSG, settingsSG],
                            autoFetch=True)

    #2. ############ Results ###############
    # 2.1. Results
    dataSeries = (
        ('time', F.Quantity('Bio_Time', default=(1, 'day'))),
        ('s1', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('x1', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('s2', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('x2', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('D', F.Quantity('Bio_TimeRate', default=(1, '1/day'))),
        ('Q',
         F.Quantity('Bio_MassConcentrationFlowRate', default=(1, 'g/L/day'))),
    )

    plot = F.PlotView(
        dataSeries,
        label='Plot',
        options={
            'ylabel': None,
            'title': 'Chemostat (DDE)'
        },
    )
    table = F.TableView(dataSeries,
                        label='Table',
                        options={
                            'title':
                            'Title',
                            'formats': [
                                '0.0000', '0.0000', '0.0000', '0.0000',
                                '0.0000', '0.0000', '0.0000'
                            ]
                        })

    chartS1S2 = F.MPLPlot(label='Chart (s<sub>1</sub>, s<sub>2</sub>)')
    chartX1X2 = F.MPLPlot(label='Chart (x<sub>1</sub>, x<sub>2</sub>)')
    chartS1X1 = F.MPLPlot(label='Chart (s<sub>1</sub>, x<sub>1</sub>)')
    chartS2X2 = F.MPLPlot(label='Chart (s<sub>2</sub>, x<sub>2</sub>)')
    chartS2X2 = F.MPLPlot(label='Chart (s<sub>2</sub>, x<sub>2</sub>)')
    chartDQ = F.MPLPlot(label='Chart (D, Q)')
    chartDsQs = F.MPLPlot(label='Chart (Ds, Qs)')

    resultsVG = F.ViewGroup([
        plot, table, chartS1S2, chartX1X2, chartS1X1, chartS2X2, chartDQ,
        chartDsQs
    ],
                            label='Results')
    resultsSG = F.SuperGroup([resultsVG], label="Results")

    # 2.2 Equilibrium point
    s1_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='s<sub>1</sub><sup>*</sup>',
        description='substrate-1 concentration at the equilibrium point')
    x1_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='x<sub>1</sub><sup>*</sup>',
        description='bacteria-1 concentration at the equilibrium point')
    s2_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='s<sub>2</sub><sup>*</sup>',
        description='substrate-2 concentration at the equilibrium point')
    x2_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='x<sub>2</sub><sup>*</sup>',
        description='bacteria-1 concentration at the equilibrium point')

    equilibriumPointFG = F.FieldGroup([s1_eqpnt, x1_eqpnt, s2_eqpnt, x2_eqpnt],
                                      label='Equilibrium point')
    equilibriumPointSG = F.SuperGroup([equilibriumPointFG],
                                      label='Equilibrium point')

    # 2.3 ESA Results
    resESA_QMaxIsFound = F.Boolean(label='Q<sub>max</sub> is found')
    resESA_DMax = F.Quantity('Bio_TimeRate',
                             default=(0, '1/day'),
                             label='D<sub>max</sub>',
                             description='maximum dilution rate')
    resESA_QMax = F.Quantity('Bio_MassConcentrationFlowRate',
                             default=(0, 'g/L/day'),
                             label='Q<sub>max</sub>',
                             description='maximum methane (biogas) flow rate')
    resESA_FG = F.FieldGroup([resESA_QMaxIsFound, resESA_DMax, resESA_QMax],
                             label='Results (ESA)')
    resESA_SG = F.SuperGroup([resESA_FG], label='Results (ESA)')

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

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

    def __init__(self):
        self.k1 = (10.53, '-')
        self.k2 = (28.6, '-')
        self.k3 = (1074, '-')
        self.k4 = (100, '-')
        self.s1_in = (7.5, 'g/L')
        self.s2_in = (75, 'g/L')
        self.a = (0.5, '-')
        self.m1 = (1.2, '1/day')
        self.m2 = (0.74, '1/day')
        self.k_s1 = (7.1, 'g/L')
        self.k_s2 = (9.28, 'g/L')
        self.k_I = (16, '-')
        self.D = (0.25, '1/day')
        self.tau1 = (2, 'day')
        self.tau2 = (7, 'day')
        self.s1_hist_vals = (2, 'g/L')
        self.x1_hist_vals = (0.1, 'g/L')
        self.s2_hist_vals = (10, 'g/L')
        self.x2_hist_vals = (0.05, 'g/L')

        self.DsQs_DMin = (0.0, '1/day')
        self.DsQs_DMax = (1.0, '1/day')
        self.DsQs_Step = (0.01, '1/day')

        self.tFinal = (2000, 'day')
        self.tPrint = (1.0, 'day')
        self.mainSimStep = (10., 'day')
        self.absTol = (1e-12, 'day')
        self.relTol = (1e-12, 'day')

        self.ESA_enable = True
        self.ESA_DMin = (0.01, '1/day')
        self.ESA_DMax = (0.33, '1/day')
        self.ESA_eps = (0.01, '1/day')
        self.ESA_h = (0.025, '1/day')
        self.ESA_eps_z = (0.01, 'g/L')

    def compute(self):
        chemostatDDE = DM.ChemostatDDE2_ESA(self)
        if self.ESA_enable:
            chemostatDDE.runESA(self)
        else:
            chemostatDDE.run(self)

        resESA = chemostatDDE.getResultsESA()
        self.resESA_QMaxIsFound = resESA['QMaxIsFound']
        self.resESA_DMax = (resESA['DMax'], '1/day')
        self.resESA_QMax = (resESA['QMax'], 'kg/m**3/day')

        res = chemostatDDE.getResults()
        results = np.array([
            res['t'], res['s1'], res['x1'], res['s2'], res['x2'], res['D'],
            res['Q']
        ]).transpose()
        self.plot = results
        self.table = results

        chemostatDDE.plotS1S2(self.chartS1S2)
        chemostatDDE.plotX1X2(self.chartX1X2)
        chemostatDDE.plotS1X1(self.chartS1X1)
        chemostatDDE.plotS2X2(self.chartS2X2)
        chemostatDDE.plotDQ(self.chartDQ)
        chemostatDDE.plotDsQs(self.chartDsQs)

        self.s1_eqpnt = (chemostatDDE.equilibriumPoint[0], 'kg/m**3')
        self.x1_eqpnt = (chemostatDDE.equilibriumPoint[1], 'kg/m**3')
        self.s2_eqpnt = (chemostatDDE.equilibriumPoint[2], 'kg/m**3')
        self.x2_eqpnt = (chemostatDDE.equilibriumPoint[3], 'kg/m**3')
Ejemplo n.º 10
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
Ejemplo n.º 11
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
Ejemplo n.º 12
0
class ChemostatDDE1(NumericalModel):
    label = "DDE Chemostat (Example 1)"
    description = F.ModelDescription(
        "Chemostat model with delay differential equations (DDE) - Example 1",
        show=True)
    figure = F.ModelFigure(
        src="BioReactors/img/ModuleImages/SimpleChemostat.png", show=False)

    #1. ############ Inputs ###############
    #1.1 Fields - Input values
    # Parameters
    k1 = F.Quantity(
        default=10.53,
        minValue=0,
        maxValue=1e6,
        label='k<sub>1</sub>',
        description=
        'yield coefficient related to substrate-1 consumption from bacteria-1')
    k2 = F.Quantity(
        default=28.6,
        minValue=0,
        maxValue=1e6,
        label='k<sub>2</sub>',
        description=
        'yield coefficient related to substrate-2 production from bacteria-1')
    k3 = F.Quantity(
        default=1074.,
        minValue=0,
        maxValue=1e6,
        label='k<sub>3</sub>',
        description=
        'yield coefficient related to substrate-2 consumption from bacteria-2')
    s1_in = F.Quantity('Bio_MassConcentration',
                       default=(7.5, 'g/L'),
                       label='s<sub>1</sub><sup>in</sub>',
                       description='input substrate-1 concentration')
    s2_in = F.Quantity('Bio_MassConcentration',
                       default=(75., 'g/L'),
                       label='s<sub>2</sub><sup>in</sub>',
                       description='input substrate-2 concentration')
    a = F.Quantity(
        'Fraction',
        default=(0.5, '-'),
        label='&#945',
        description=
        'proportion of organisms that are affected by the dilution rate D')
    D = F.Quantity('Bio_TimeRate',
                   default=(0.89, '1/day'),
                   minValue=(0, '1/day'),
                   label='D',
                   description='dilution rate')
    parametersFG = F.FieldGroup([s1_in, s2_in, k1, k2, k3, a, D],
                                label='Parameters')

    # Parameters - specific growth rates
    m1 = F.Quantity('Bio_TimeRate',
                    default=(1.20, '1/day'),
                    minValue=(0, '1/day'),
                    label='m<sub>1</sub>',
                    description='maximum specific growth rate of bacteria-1')
    m2 = F.Quantity('Bio_TimeRate',
                    default=(0.74, '1/day'),
                    minValue=(0, '1/day'),
                    label='m<sub>2</sub>',
                    description='maximum specific growth rate of bacteria-2')
    k_s1 = F.Quantity('Bio_MassConcentration',
                      default=(7.1, 'g/L'),
                      label='k<sub>s1</sub>',
                      description='half saturation constant of bacteria-1')
    k_s2 = F.Quantity('Bio_MassConcentration',
                      default=(9.28, 'g/L'),
                      label='k<sub>s2</sub>',
                      description='half saturation constant of bacteria-2')
    k_I = F.Quantity('Dimensionless',
                     default=(16., '-'),
                     label='k<sub>I</sub>',
                     description='constant in unit: [ sqrt( g/L ) ]')
    parametersMuFG = F.FieldGroup([m1, m2, k_s1, k_s2, k_I],
                                  label='Parameters - specific growth rates')

    # Parameters - time delays
    tau1 = F.Quantity(
        'Bio_Time',
        default=(10.1, 'day'),
        minValue=(0, 'day'),
        label='&#964<sub>1</sub>',
        description=
        'time delay in conversion of the substrate-1 to viable biomass for bacteria-1'
    )
    tau2 = F.Quantity(
        'Bio_Time',
        default=(5.7, 'day'),
        minValue=(0, 'day'),
        label='&#964<sub>2</sub>',
        description=
        'time delay in conversion of the substrate-2 to viable biomass for bacteria-2'
    )
    parametersTauFG = F.FieldGroup([tau1, tau2],
                                   label='Parameters - time delay')

    # historical initial conditions
    s1_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(3., 'g/L'),
        label='s<sub>1</sub><sup>&#91-&#964<sub>1</sub>, 0&#93</sup>',
        description='historical initial condition for substrate-1 concentration'
    )
    x1_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0.5, 'g/L'),
        label='x<sub>1</sub><sup>&#91-&#964<sub>1</sub>, 0&#93</sup>',
        description='historical initial condition for bacteria-1 concentration'
    )
    s2_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(15., 'g/L'),
        label='s<sub>2</sub><sup>&#91-&#964<sub>2</sub>, 0&#93</sup>',
        description='historical initial condition for substrate-2 concentration'
    )
    x2_hist_vals = F.Quantity(
        'Bio_MassConcentration',
        default=(0.1, 'g/L'),
        label='x<sub>2</sub><sup>&#91-&#964<sub>2</sub>, 0&#93</sup>',
        description='historical initial condition for bacteria-2 concentration'
    )
    parametersHistFG = F.FieldGroup(
        [s1_hist_vals, x1_hist_vals, s2_hist_vals, x2_hist_vals],
        label='Historical initial conditions')

    inputValuesSG = F.SuperGroup(
        [parametersMuFG, parametersFG, parametersTauFG, parametersHistFG],
        label="Input values")

    #1.2 Fields - Settings
    tFinal = F.Quantity('Bio_Time',
                        default=(100, 'day'),
                        minValue=(0, 'day'),
                        maxValue=(1000, 'day'),
                        label='simulation time')
    tPrint = F.Quantity('Bio_Time',
                        default=(0.1, 'day'),
                        minValue=(1e-5, 'day'),
                        maxValue=(100, 'day'),
                        label='print interval')
    absTol = F.Quantity('Bio_Time',
                        default=(1e-12, 'day'),
                        minValue=(1e-16, 'day'),
                        maxValue=(1e-5, 'day'),
                        label='absolute tolerance')
    relTol = F.Quantity('Bio_Time',
                        default=(1e-12, 'day'),
                        minValue=(1e-16, 'day'),
                        maxValue=(1e-3, 'day'),
                        label='relative tolerance')
    solverFG = F.FieldGroup([tFinal, tPrint, absTol, relTol], label='Solver')

    settingsSG = F.SuperGroup([solverFG], label='Settings')

    #1.4 Model view
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputValuesSG, settingsSG],
                            autoFetch=True)

    #2. ############ Results ###############
    dataSeries = (
        ('time', F.Quantity('Bio_Time', default=(1, 'day'))),
        ('s1', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('x1', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('s2', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
        ('x2', F.Quantity('Bio_MassConcentration', default=(1, 'g/L'))),
    )

    plot = F.PlotView(
        dataSeries,
        label='Plot',
        options={
            'ylabel': None,
            'title': 'Chemostat (DDE)'
        },
    )
    table = F.TableView(dataSeries,
                        label='Table',
                        options={
                            'title':
                            'Title',
                            'formats':
                            ['0.0000', '0.0000', '0.0000', '0.0000', '0.0000']
                        })

    chartS1S2 = F.MPLPlot(label='Chart (s<sub>1</sub>, s<sub>2</sub>)')
    chartX1X2 = F.MPLPlot(label='Chart (x<sub>1</sub>, x<sub>2</sub>)')
    chartS1X1 = F.MPLPlot(label='Chart (s<sub>1</sub>, x<sub>1</sub>)')
    chartS2X2 = F.MPLPlot(label='Chart (s<sub>2</sub>, x<sub>2</sub>)')

    resultsVG = F.ViewGroup(
        [plot, table, chartS1S2, chartX1X2, chartS1X1, chartS2X2],
        label='Results')
    resultsSG = F.SuperGroup([resultsVG], label="Results")

    # 2.2 Equilibrium point
    s1_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='s<sub>1</sub><sup>*</sup>',
        description='substrate-1 concentration at the equilibrium point')
    x1_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='x<sub>1</sub><sup>*</sup>',
        description='bacteria-1 concentration at the equilibrium point')
    s2_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='s<sub>2</sub><sup>*</sup>',
        description='substrate-2 concentration at the equilibrium point')
    x2_eqpnt = F.Quantity(
        'Bio_MassConcentration',
        default=(0., 'g/L'),
        label='x<sub>2</sub><sup>*</sup>',
        description='bacteria-1 concentration at the equilibrium point')

    equilibriumPointFG = F.FieldGroup([s1_eqpnt, x1_eqpnt, s2_eqpnt, x2_eqpnt],
                                      label='Equilibrium point')
    equilibriumPointSG = F.SuperGroup([equilibriumPointFG],
                                      label='Equilibrium point')

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

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

    def __init__(self):
        self.k1 = 10.53
        self.k2 = 28.6
        self.k3 = 1074
        self.s1_in = 7.5
        self.s2_in = 75
        self.a = 0.5
        self.m1 = 1.2
        self.m2 = 0.74
        self.k_s1 = 7.1
        self.k_s2 = 9.28
        self.k_I = 16
        self.D = 0.85
        self.tau1 = 2
        self.tau2 = 7
        self.s1_hist_vals = 2
        self.x1_hist_vals = 0.1
        self.s2_hist_vals = 10
        self.x2_hist_vals = 0.05

    def compute(self):
        chemostatDDE = DM.ChemostatDDE1(self)
        chemostatDDE.run(self)

        res = chemostatDDE.getResults()
        results = np.array(
            [res['t'], res['s1'], res['x1'], res['s2'],
             res['x2']]).transpose()
        self.plot = results
        self.table = results

        chemostatDDE.plotS1S2(self.chartS1S2)
        chemostatDDE.plotX1X2(self.chartX1X2)
        chemostatDDE.plotS1X1(self.chartS1X1)
        chemostatDDE.plotS2X2(self.chartS2X2)

        self.s1_eqpnt = (chemostatDDE.equilibriumPoint[0], 'kg/m**3')
        self.x1_eqpnt = (chemostatDDE.equilibriumPoint[1], 'kg/m**3')
        self.s2_eqpnt = (chemostatDDE.equilibriumPoint[2], 'kg/m**3')
        self.x2_eqpnt = (chemostatDDE.equilibriumPoint[3], 'kg/m**3')
Ejemplo n.º 13
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
Ejemplo n.º 14
0
class BiochemicalReactions(NumericalModel):
    label = "Biochemical reactions"
    description = F.ModelDescription(
        "Solver for elementary biochemical reactions", show=True)
    figure = F.ModelFigure(
        src="BioReactors/img/ModuleImages/BiochemicalReactions.png",
        show=False)

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

    #1. ############ Inputs ###############
    #1.1 Fields - Input values
    reactions = F.RecordArray(
        (
            ('reactionEquation',
             F.String('E + S <-> ES', label='Equation', inputBoxWidth=160)),
            ('rateConstnats',
             F.String('0.0, 0.0', label='Rate constants', inputBoxWidth=100)),
            ('reactionName',
             F.String('enzyme binding to a substrate',
                      label='Name',
                      inputBoxWidth=400,
                      showTooltip=True)),
        ),
        toggle=False,
        label='Reactions',
        numRows=2,
        description='Biochemical reactions',
    )
    reactionsFG = F.FieldGroup([reactions],
                               hideContainer=True,
                               label="Reactions")
    reactionsSG = F.SuperGroup([reactionsFG], label="Reactions")

    species = F.RecordArray(
        (
            ('speciesVariable',
             F.String('E', label='Variable', inputBoxWidth=70)),
            ('initialValue',
             F.Quantity('Bio_MolarConcentration',
                        default=(1, 'M'),
                        minValue=(0, 'M'),
                        label='Initial value',
                        inputBoxWidth=75)),
            ('speciesName', F.String('enzyme', label='Name',
                                     inputBoxWidth=270)),
        ),
        toggle=False,
        label='species',
        numRows=4,
        description='Species of the reactions',
    )
    speciesFG = F.FieldGroup([species], hideContainer=True, label="Species")
    speciesSG = F.SuperGroup([speciesFG], label="Species")

    #1.2 Fields - Settings
    tFinal = F.Quantity('Time',
                        default=(0.0, 's'),
                        minValue=(0, 's'),
                        maxValue=(1000, 's'),
                        label='simulation time')
    tPrint = F.Quantity('Time',
                        default=(0.0, 's'),
                        minValue=(1e-3, 's'),
                        maxValue=(100, 's'),
                        label='print interval')
    solverFG = F.FieldGroup([tFinal, tPrint], label='Solver')

    settingsSG = F.SuperGroup([solverFG], label='Settings')

    #1.4 Model view
    exampleAction = A.ServerAction(
        "loadEg",
        label="Examples",
        options=(
            ('exampleMMK', 'Michaelis-Menten kinetics'),
            ('exampleMMKI', 'Michaelis-Menten kinetics with inhibition'),
        ))

    inputView = F.ModelView(
        ioType="input",
        superGroups=[reactionsSG, speciesSG, settingsSG],
        autoFetch=True,
        actionBar=A.ActionBar([exampleAction]),
    )

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

    dataSeries = (
        ('time', F.Quantity('Time', default=(1, 's'))),
        ('E', F.Quantity('Bio_MolarConcentration', default=(1, 'M'))),
    )

    plot = F.PlotView(dataSeries,
                      label='Plot',
                      useHdfStorage=True,
                      storage='storage')

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

    storageVG = F.ViewGroup([storage], show="false")
    resultsVG = F.ViewGroup([plot, table], label='Results')
    resultsSG = F.SuperGroup([resultsVG, storageVG], label='Results')

    # 2.2 ODEs plot
    odesPlot = F.MPLPlot(label='ODEs')
    odesVG = F.ViewGroup([odesPlot], label='Ordinary differential equations')
    odesSG = F.SuperGroup([odesVG], label='ODEs')

    # 2.3 Results plot
    chartPlot = F.MPLPlot(label='Chart')
    chartPlotVG = F.ViewGroup([chartPlot], label='Chart')
    chartPlotSG = F.SuperGroup([chartPlotVG], label='Chart')

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

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

    def __init__(self):
        self.exampleMMK()

    def exampleMMK(self):
        self.species[0] = ('E', 4.0, 'enzyme')
        self.species[1] = ('S', 8.0, 'substrate')
        self.species[2] = ('ES', 0.0, 'complex')
        self.species[3] = ('P', 0.0, 'product')

        self.reactions[0] = (
            'E + S <=> ES', '2.0, 1.0',
            'an enzyme binding to a substrate form an enzyme-substrate complex (reversible process)'
        )
        self.reactions[1] = (
            'ES -> E + P', '1.5',
            'an enzyme-substrate complex decomposition to a product and the enzyme'
        )

        self.tFinal = 20.0
        self.tPrint = 0.01

    def exampleMMKI(self):
        self.species.resize(6)
        self.species[0] = ('E', 4.0, 'enzyme')
        self.species[1] = ('S', 8.0, 'substrate')
        self.species[2] = ('ES', 0.0, 'enzyme-substrate complex')
        self.species[3] = ('P', 0.0, 'product')
        self.species[4] = ('I', 5.0, 'inhibitor')
        self.species[5] = ('EI', 0.0, 'inactive enzyme-inhibitor complex')

        self.reactions.resize(3)
        self.reactions[0] = (
            'E + S <=> ES', '2.0, 1.0',
            'an enzyme binding to a substrate form an enzyme-substrate complex (reversible process)'
        )
        self.reactions[1] = (
            'ES -> E + P', '1.5',
            'an enzyme-substrate complex decomposition to a product and an enzyme'
        )
        self.reactions[2] = (
            'E + I <=> EI', '2.0, 0.5',
            'an inhibitor binding to the active site of an enzyme form an inactive enzyme-inhibitor complex (reversible processes)'
        )

        self.tFinal = 20.0
        self.tPrint = 0.01

    def computeAsync(self):
        # Redefine some fields
        self.redefineFileds()

        # Create the model
        model = DM.BiochemicalReactions(self)

        # Tun simulation
        model.prepareSimulation()
        model.run(self)

        # Show results
        self.storage = model.resultStorage.simulationName

        # Plot results
        model.plotODEsTxt(self.odesPlot)
        model.plotHDFResults(self.chartPlot)

    def redefineFileds(self):
        # Create tuples for species
        speciesTuples = (('time', F.Quantity('Time', default=(1, 's'))), )
        datasetColumns = ['t']
        for itSpecies in self.species:
            X = itSpecies[0]  #species variable
            speciesTuple = (('%s' % X,
                             F.Quantity('Bio_MolarConcentration',
                                        default=(1, 'M'))), )
            speciesTuples += speciesTuple
            datasetColumns.append('%s' % X)

        # Redefine Fields
        redefinedStorage = F.HdfStorage(
            hdfFile='BioReactors_SimulationResults.h5',
            hdfGroup='/BiochemicalReactions',
            datasetColumns=datasetColumns)
        self.redefineField('storage', 'storageVG', redefinedStorage)

        redefinedPlot = F.PlotView(speciesTuples,
                                   label='Plot',
                                   options={
                                       'ylabel': 'concentration',
                                       'title': ''
                                   },
                                   useHdfStorage=True,
                                   storage='storage')
        self.redefineField('plot', 'resultsVG', redefinedPlot)

        redefinedTable = F.TableView(
            speciesTuples,
            label='Table',
            options={'formats': ['0.000', '0.000', '0.000', '0.000']},
            useHdfStorage=True,
            storage='storage')
        self.redefineField('table', 'resultsVG', redefinedTable)
Ejemplo n.º 15
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
Ejemplo n.º 16
0
class ChemostatSimple(NumericalModel):
    label = "Simple Chemostat"
    description = F.ModelDescription(
        "Simple chemostat model with ordinary differential equations (ODE)",
        show=True)
    figure = F.ModelFigure(
        src="BioReactors/img/ModuleImages/SimpleChemostat.png", show=False)

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

    #1. ############ Inputs ###############
    #1.1 Fields - Input values
    S_in = F.Quantity('Bio_MassConcentration',
                      default=(5, 'g/L'),
                      minValue=(0, 'g/L'),
                      label='S<sub>in</sub>',
                      description='input substrate concentration')
    X_in = F.Quantity('Bio_MassConcentration',
                      default=(0.0, 'g/L'),
                      minValue=(0, 'g/L'),
                      label='X<sub>in</sub>',
                      description='input microorganisms concentration')
    m = F.Quantity(
        'Bio_TimeRate',
        default=(3, '1/day'),
        minValue=(0, '1/day'),
        label='m',
        description='maximum specific growth rate of the microorganisms')
    K = F.Quantity('Bio_MassConcentration',
                   default=(3.7, 'g/L'),
                   minValue=(0, 'g/L'),
                   label='K',
                   description='half saturation constant')
    gamma = F.Quantity(default=0.6,
                       minValue=0,
                       maxValue=1.0,
                       label='&#947',
                       description='yield coefficient of microorganisms')
    D_vals = F.RecordArray((
        ('time',
         F.Quantity('Bio_Time',
                    default=(20, 'day'),
                    minValue=(0, 'day'),
                    label='Duration')),
        ('D',
         F.Quantity('Bio_TimeRate',
                    default=(1, '1/day'),
                    minValue=(0, '1/day'),
                    label='D')),
    ),
                           label='D',
                           description='dilution (or washout) rate')
    parametersFG = F.FieldGroup([S_in, X_in, m, K, gamma, D_vals],
                                label="Parameters")

    S0 = F.Quantity('Bio_MassConcentration',
                    default=(0, 'g/L'),
                    minValue=0,
                    label='S<sub>0</sub>',
                    description='initial substrate concentration')
    X0 = F.Quantity('Bio_MassConcentration',
                    default=(0.5, 'g/L'),
                    minValue=0,
                    label='X<sub>0</sub>',
                    description='initial microorganisms concentration')
    initialValuesFG = F.FieldGroup([S0, X0], label="Initial values")

    inputValuesSG = F.SuperGroup([parametersFG, initialValuesFG],
                                 label="Input values")

    #1.2 Fields - Settings
    tFinal = F.Quantity('Bio_Time',
                        default=(100, 'day'),
                        minValue=(0, 'day'),
                        maxValue=(1000, 'day'),
                        label='simulation time')
    tPrint = F.Quantity('Bio_Time',
                        default=(0.1, 'day'),
                        minValue=(1e-5, 'day'),
                        maxValue=(100, 'day'),
                        label='print interval')
    solverFG = F.FieldGroup([tFinal, tPrint], label='Solver')

    settingsSG = F.SuperGroup([solverFG], label='Settings')

    #1.4 Model view
    inputView = F.ModelView(ioType="input",
                            superGroups=[inputValuesSG, settingsSG],
                            autoFetch=True)

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

    dataSeries = (('time', F.Quantity('Bio_Time', default=(1, 'day'))),
                  ('S', F.Quantity('Bio_MassConcentration',
                                   default=(1, 'g/L'))),
                  ('X', F.Quantity('Bio_MassConcentration',
                                   default=(1, 'g/L'))),
                  ('D', F.Quantity('Bio_TimeRate', default=(1, '1/day'))))

    plot = F.PlotView(dataSeries,
                      label='Plot',
                      options={'ylabel': None},
                      useHdfStorage=True,
                      storage='storage')

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

    resultsVG = F.ViewGroup([plot, table], label='Results')
    storageVG = F.ViewGroup([storage], show="false")
    resultsSG = F.SuperGroup([resultsVG, storageVG])

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

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

    def computeAsync(self):
        # Create the model
        chemostat = DM.ChemostatSimple(self)

        # Run simulation
        chemostat.prepareSimulation()
        chemostat.run(self)

        # Show results
        self.storage = chemostat.resultStorage.simulationName