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)
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
class ThermodynamicalCycle(NumericalModel): abstract = True #================ Inputs ================# # Cycle diagram cycleDiagram = F.SubModelGroup(TC.CycleDiagram, 'inputs', label='Diagram settings') # Solver settings solver = F.SubModelGroup(CycleIterator, 'solverSettings', label='Solver') #================ Results ================# #---------------- Fields ----------------# cycleStatesTable = F.TableView( (('T', F.Quantity('Temperature', default=(1, 'degC'))), ('p', F.Quantity('Pressure', default=(1, 'bar'))), ('rho', F.Quantity('Density', default=(1, 'kg/m**3'))), ('h', F.Quantity('SpecificEnthalpy', default=(1, 'kJ/kg'))), ('s', F.Quantity('SpecificEntropy', default=(1, 'kJ/kg-K'))), ('q', F.Quantity()), ('dT', F.Quantity('TemperatureDifference', default=(1, 'degC'))), ('mDot', F.Quantity('MassFlowRate', default=(1, 'kg/min'))), ('b', F.Quantity('SpecificEnergy', default=(1, 'kJ/kg')))), label="Cycle states") cycleStates = F.ViewGroup([cycleStatesTable], label="States") resultStates = F.SuperGroup([cycleStates], label="States") #---------------- Cycle diagram -----------# phDiagram = F.Image(default='') cycleDiagramVG = F.ViewGroup([phDiagram], label="P-H Diagram") resultDiagrams = F.SuperGroup([cycleDiagramVG], label="Diagrams") #---------------- Convergence parameters -----------# residualPlot = F.PlotView((('iteration #', F.Quantity('Dimensionless')), ('h change', F.Quantity('SpecificEnthalpy'))), label='Residual (plot)', ylog=True) iterationTable = F.TableView(( ('h1', F.Quantity('SpecificEnthalpy')), ('h2', F.Quantity('SpecificEnthalpy')), ('h3', F.Quantity('SpecificEnthalpy')), ('h4', F.Quantity('SpecificEnthalpy')), ('h5', F.Quantity('SpecificEnthalpy')), ('h6', F.Quantity('SpecificEnthalpy')), ('h7', F.Quantity('SpecificEnthalpy')), ('h8', F.Quantity('SpecificEnthalpy')), ('h9', F.Quantity('SpecificEnthalpy')), ('h10', F.Quantity('SpecificEnthalpy')), ('h11', F.Quantity('SpecificEnthalpy')), ('h12', F.Quantity('SpecificEnthalpy')), ('h13', F.Quantity('SpecificEnthalpy')), ('h14', F.Quantity('SpecificEnthalpy')), ('h15', F.Quantity('SpecificEnthalpy')), ('h16', F.Quantity('SpecificEnthalpy')), ('h17', F.Quantity('SpecificEnthalpy')), ('h18', F.Quantity('SpecificEnthalpy')), ('h19', F.Quantity('SpecificEnthalpy')), ('h20', F.Quantity('SpecificEnthalpy')), ), label='Residual (table)', options={'formats': (['0.0000E0'] * 20)}) residualGroup = F.ViewGroup([residualPlot, iterationTable], label='Iterations') solverStats = F.SuperGroup([residualGroup], label='Convergence') # Info fields cycleTranscritical = F.Boolean(default=False) cycleSupercritical = F.Boolean(default=False) def initCompute(self, fluid): # Create fluid points self.fluid = Fluid(fluid) self.fp = [] #[FluidState(fluid) for _ in range(numPoints)] self.flows = [] self.solver.cycle = self def connectPorts(self, port1, port2, fluid=None): if fluid == None: fluid = self.fluid fp = FluidState(fluid) flow = P.FluidFlow() self.fp.append(fp) self.flows.append(flow) port1.state = fp port2.state = fp port1.flow = flow port2.flow = flow def solve(self): self.solver.run() self.residualPlot.resize(len(self.solver.change_hHistory)) for i in range(len(self.solver.change_hHistory)): self.residualPlot[i] = (i + 1, self.solver.change_hHistory[i]) self.iterationTable.resize(len(self.solver.hHistory)) v = self.iterationTable.view(dtype=np.float).reshape( -1, len(self.iterationTable.dtype)) numCols = len(self.solver.hHistory[0]) for i in range(len(self.solver.hHistory)): v[i, :numCols] = self.solver.hHistory[i] # print self.iterationTable # iterRecord = np.zeros(1, dtype = self.iterationTable.dtype) # numCols = len(self.solver.hHistory[0]) # for i in range(len(self.solver.hHistory)): # for j in range(numCols): # iterRecord[j] = self.solver.hHistory[i][j] # self.iterationTable[i] = iterRecord def postProcess(self, TAmbient): ## State diagram if (self.cycleDiagram.enable): self.createStateDiagram() ## Table of states self.cycleStatesTable.resize(len(self.fp)) for i in range(len(self.fp)): fp = self.fp[i] self.cycleStatesTable[i] = (fp.T, fp.p, fp.rho, fp.h, fp.s, fp.q, fp.dT, self.flows[i].mDot, fp.b(TAmbient)) # Select the zero for the exergy scale fp = FluidState(self.fluid) fp.update_Tp(TAmbient, 1e5) b0 = fp.b(TAmbient) self.cycleStatesTable['b'] -= b0 def createStateDiagram(self): ncp = len(self.fp) fluidLines = [] for i in range(ncp): fluidLines.append((self.fp[i], self.fp[(i + 1) % ncp])) self.phDiagram = self.cycleDiagram.draw(self.fluid, self.fp, fluidLines) def setPLow(self, p): if (self.fluid.tripple['p'] < p < self.fluid.critical['p']): self.pLow = p sat = self.fluid.saturation_p(p) self.TEvaporation = sat['TsatL'] elif (p > self.fluid.critical['p']): self.pLow = p self.cycleSupercritical = True else: raise ValueError( 'PLow ({} bar) must be between {} bar and {} bar'.format( p / 1e5, self.fluid.tripple['p'] / 1e5, self.fluid.critical['p'] / 1e5)) def setPHigh(self, p): if (self.fluid.tripple['p'] < p < self.fluid.critical['p']): self.pHigh = p sat = self.fluid.saturation_p(p) self.TCondensation = sat['TsatL'] elif (p > self.fluid.critical['p']): self.pHigh = p self.cycleTranscritical = True else: raise ValueError( 'PHigh ({} bar) must be between {} bar and {} bar'.format( p / 1e5, self.fluid.tripple['p'] / 1e5, self.fluid.critical['p'] / 1e5))
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='α', 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='τ<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='τ<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>[-τ<sub>1</sub>, 0]</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>[-τ<sub>1</sub>, 0]</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>[-τ<sub>2</sub>, 0]</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>[-τ<sub>2</sub>, 0]</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='ε*', 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='ε<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')
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='α', 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='τ<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='τ<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>[-τ<sub>1</sub>, 0]</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>[-τ<sub>1</sub>, 0]</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>[-τ<sub>2</sub>, 0]</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>[-τ<sub>2</sub>, 0]</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')
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)
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
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='γ', 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