Skip to content

Commit b3f6391

Browse files
author
Katzberg
committed
added ODE Solver and Nebenrechnungen
1 parent 561d2ca commit b3f6391

4 files changed

Lines changed: 89 additions & 12 deletions

File tree

src/DataModels/input_definition.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ class InputKeys(str, Enum):
1818
density = "Dichte",
1919
c_x0 = "c_x0",
2020
q_in = "Q_in",
21-
q_out = "Q_Out"
21+
q_out = "Q_Out",
22+
c_o2_sat ="c_O2_sat"

src/calc_bioreactor.py

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,105 @@
11
import pandas as pd
22
import json
3+
import numpy as np
4+
from scipy.integrate import solve_ivp #solve odes
35
from DataModels.input_definition import InputKeys
6+
from DataModels.model_definition import ModelKeys
7+
from Nebenrechnungen import Nebenrechnungen
8+
from Fx_ODE_Bioreaktor import Bioreaktor_ODE #hier wird das Differentialgleichungssystem definiert
49

510
MODEL_PATH = "./src/DataModels/model_db.json"
611

712

8-
def calculate(df: pd.DataFrame) -> pd.DataFrame:
13+
def calculate(ferm_param_in_df: pd.DataFrame) -> pd.DataFrame:
914
try:
10-
model_name = df[InputKeys.model][0]
15+
model_number = int(ferm_param_in_df[InputKeys.model][0]-1) #"-1" as indices start with 0 and model numbers start with 1
16+
print("Genutztes Model hat die Nummer: ", model_number+1)
1117
with open(MODEL_PATH) as f:
1218
model = json.load(f)
13-
model = model[model_name]
19+
model_param_in= model[model_number] #dictionary
20+
#print (model_param_in[ModelKeys.YPS1])
1421

1522
except json.JSONDecodeError:
1623
print("Invalid JSON input.")
1724
pass
1825

19-
result_df = pd.DataFrame([])
20-
21-
# nebenberechnung
22-
# vorberechnung
23-
26+
# Nebenberechnung
27+
[model_param,ferm_param_df]=Nebenrechnungen(model_param_in,ferm_param_in_df)
28+
29+
#global constants
30+
data_rate=60 #data rate per hour
31+
Vm_norm=22.41396954 #molares Volumen in NL/mol bei Normbedingungen (0°C und 101,325 kPa)
32+
c_O2_Luft = 0.2095 #Sauerstoffgehalt Luft in mol(O2)/mol(Luft)
33+
c_CO2_Luft =0.0004147 #CO2 Gehalt der Luft in mol(CO2)/mol(Luft)
34+
35+
2436
# nachfolgend Hauptberechnung
25-
for index, row in df.iterrows():
37+
for index, row in ferm_param_df.iterrows():
2638
# result_df hier befüllen
27-
pass
39+
print("Phase:", row[InputKeys.phase])
40+
41+
if index==0:
42+
c_x_0=row[InputKeys.c_x0]
43+
c_S1_0=row[InputKeys.bolus_c]
44+
c_S2_0=row[InputKeys.bolus_n]
45+
c_P_0=0
46+
c_DO_0=row[InputKeys.c_o2_sat]*row[InputKeys.do]/100
47+
48+
y0=[c_x_0,c_S1_0,c_S2_0, c_P_0, c_DO_0, c_O2_Luft, c_CO2_Luft] #Startparameter in Vektor
49+
t_start=0
50+
t_ende=row[InputKeys.duration]
51+
52+
else:
53+
c_x_0=y[-1,0] #"-1" means the last element of the array
54+
c_S1_0=y[-1,1]+row[InputKeys.bolus_c]
55+
c_S2_0=y[-1,2]+row[InputKeys.bolus_n]
56+
c_P_0=y[-1,3]
57+
#print("c_P0",c_P_0)
58+
c_DO_0=y[-1,4]
59+
O2_Out=y[-1,5] #Konz. O2 in Abluft
60+
CO2_Out=y[-1,6] #Konz. CO2 in Abluft
61+
y0=[c_x_0,c_S1_0,c_S2_0, c_P_0, c_DO_0, O2_Out, CO2_Out] #Startparameter in Vektor
62+
t_start=result.t[-1]
63+
t_ende=t_start+row[InputKeys.duration]
64+
#print("Calc Phase: ",i," from ",t_start," - ",t_ende,"h")
2865

66+
if row[InputKeys.duration]!=0:
67+
print("Calc Phase: ",index," from ",t_start," - ",t_ende,"h")
68+
datapoints=row[InputKeys.duration]*data_rate
69+
t_span=np.linspace(t_start,t_ende,datapoints)
70+
if datapoints < 50:datapoints=50 #this is needed in case a Phase is really short so the minimal number of datapoint per phase=50
71+
Fpar_d=row.to_dict() #extract Fermentation parameters for current phase and convert to dictionary as this is faster in solve_ivp
72+
73+
74+
result=solve_ivp(Bioreaktor_ODE,(t_start,t_ende),y0,args=(model_param,Fpar_d), t_eval=t_span, max_step=0.0005, atol=1e-6, rtol=1e-7)
75+
#solve_IVP Explanations
76+
#args are passed as a tupel - a single element in a tupel is single_element_tuple = (5,)
77+
#via small atol and rtol practical "non-negative" is achieved
78+
# #Results of Solve_ivp stores y values in result.y which is an array of one row per parameter
79+
#and n-datapoints in n columns
80+
if index==0:
81+
y=result.y.T
82+
y_ges=y #transform array
83+
#print("dim y_ges", y_ges.shape)
84+
t_ges=np.atleast_2d(result.t).T
85+
#print("dim t_ges", t_ges.shape)
86+
# sum_feeding = t_span*Fpar["Feed_C"][0]
87+
# len_t_span=len(t_span)
88+
# Drehzahl = np.zeros(len_t_span)+Fpar["Drehzahl"][0]
89+
# Begasungsrate = np.zeros(len_t_span)+Fpar["Q_Air"][0]
90+
# Druck = np.zeros(len_t_span)+Fpar["Druck"][0]
91+
else:
92+
y=result.y.T #transform array
93+
y_ges=np.vstack((y_ges, y))
94+
t=np.atleast_2d(result.t).T
95+
t_ges=np.vstack((t_ges, t))
96+
# already_fed=sum_feeding[-1]
97+
# t_span_temp=np.subtract(t_span,t_span[0])
98+
# temp_feed=already_fed+t_span_temp*Fpar["Feed_C"][i-1]
99+
# sum_feeding = np.hstack((sum_feeding, temp_feed))
100+
# len_t_span=len(t_span)
101+
# Drehzahl = np.hstack((Drehzahl, np.zeros(len_t_span)+Fpar["Drehzahl"][i-1]))
102+
# Begasungsrate = np.hstack((Begasungsrate, np.zeros(len_t_span)+Fpar["Q_Air"][i-1]))
103+
# Druck = np.hstack((Druck,np.zeros(len_t_span)+Fpar["Druck"][i-1]))
104+
result_df=pd.DataFrame([0,0])
29105
return result_df

src/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def main() -> Tuple[pd.DataFrame, IOAdapter]:
2929

3030
arg = sys.argv[1]
3131
input_df = input_adapter.transform_data(arg)
32-
32+
print(input_df)
3333
"""
3434
TODO: Selection logic (cli-parameters) to select OutputAdapter if required.
3535
Default is ChartJSAdapter

0 commit comments

Comments
 (0)