Update_parameters.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. import ivp
  2. import solveMatrix
  3. import os
  4. import cModel_posodabljanje as cModel
  5. import sys
  6. import json
  7. from contextlib import contextmanager
  8. import numpy as np
  9. import time
  10. import scipy.interpolate
  11. import shutil
  12. import importlib
  13. from scipy.optimize import least_squares
  14. importlib.reload(solveMatrix)
  15. import runSolver
  16. importlib.reload(runSolver)
  17. def updateSetup(job):
  18. setupFileSrc = job['setupFile']
  19. setupFile = os.path.join(job['jobDir'], 'setupInput.json')
  20. with open(setupFileSrc, 'r') as f:
  21. setup = json.load(f)
  22. try:
  23. setup.update(job['setupUpdates'])
  24. except KeyError:
  25. pass
  26. with open(setupFile, 'w+') as f:
  27. f.write(json.dumps(setup))
  28. return setupFile
  29. def generate_noisy_data(full_sol, noise_std=20.5):
  30. full_sol = np.asarray(full_sol) # Ensure input is a NumPy array
  31. random_state = np.random.RandomState(seed=None)
  32. # Create highly volatile noise
  33. noise = random_state.normal(loc=0, scale=noise_std, size=full_sol.shape) ** 2 # Squared to amplify large deviations
  34. noise2 = np.random.laplace(loc=0, scale=noise_std * 10, size=full_sol.shape) # Increased scale for even more extreme spikes
  35. # Introduce highly chaotic scaling factors
  36. random_scaling = random_state.uniform(-200, 400, size=full_sol.shape) # Further extended range for more variation
  37. random_exponent = random_state.uniform(4, 12, size=full_sol.shape) # Increased exponentiation for more instability
  38. # Apply extreme, chaotic transformations
  39. noisy_data = np.zeros_like(full_sol)
  40. for i in range(len(full_sol)):
  41. perturbation = random_scaling[i] * (abs(noise[i]) ** random_exponent[i]) - noise2[i] * np.sin(full_sol[i])
  42. noisy_data[i] = (1 + np.tanh(perturbation)) * full_sol[i] * np.cosh(noise[i])
  43. # Introduce frequent large perturbations to increase instability
  44. if random_state.rand() < 0.75: # 30% chance of a drastic shift
  45. noisy_data[i] *= random_state.uniform(2, 5)
  46. return noisy_data
  47. def calculate_residuals(full_sol, noisy_data):
  48. """
  49. Calculates residuals based on the solution and noisy data.
  50. """
  51. residuals = np.ravel((noisy_data - full_sol))
  52. #print(residuals)
  53. return residuals
  54. # Updated cost function
  55. def cost_function(params,parnames,noisy_data,model,startPoint,setup,jobDir):
  56. """
  57. Cost function that calculates residuals based on the model.
  58. """
  59. #print(params)
  60. model.setValues(parnames,params)
  61. clean_dir(jobDir)
  62. t,sol,se,qt,sOut,full_t,full_sol=runSolver.solve(model,setup,startPoint,jobDir)
  63. residuals = calculate_residuals(np.array(full_sol), noisy_data)
  64. return residuals
  65. def create_name_value_dict(original_dict):
  66. return {
  67. val['name']: val['value']
  68. for key, val in original_dict.items()
  69. if isinstance(val, dict) and 'name' in val and 'value' in val
  70. }
  71. # Create parameter dictionary
  72. def clean_dir(jobDir):
  73. shutil.rmtree(jobDir)
  74. os.mkdir(jobDir)
  75. #PRENOS ZAČETNIH PODATKOV
  76. ##############################################################################################################################################
  77. fh = os.path.expanduser("~")
  78. jobDir = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen',"rezultati","least_squares")
  79. srcDir = "NONE"
  80. setup_file = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'setup', 'setupMinute.json')
  81. model_file = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam.json')
  82. parameter_file1 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam_parameters.json')
  83. # Prvi model s prvim parameter file
  84. model1 = cModel.model()
  85. model1.parse(model_file, parameter_file1)
  86. setup1 = runSolver.parseSetup(setup_file)
  87. name_value_dict1 = create_name_value_dict(model1.parSetup['parameters'])
  88. # Lahko zdaj uporabiš name_value_dict1 in name_value_dict2 ločeno
  89. # Excluded parameters
  90. vse_parametri = {
  91. 'commentsInput', 'venousInput', '_venousInput', 'inputA', 'inputTau', 'commentPC', 'adiposePC', 'brainPC',
  92. 'heartPC', 'kidneyPC', 'liverPC', 'lungPC', 'musclePC', 'remainderPC', 'skinPC', 'splanchnicPC',
  93. 'stomachPC', 'testesPC', 'commentFlows', 'flowNotes', 'adiposeFlow', 'brainFlow', 'heartFlow',
  94. 'kidneyFlow', 'liverInFlow', 'liverOutFlow', 'gutOutFlow', 'totalFlow', 'muscleFlow', 'skinFlow',
  95. 'splanchnicFlow', 'stomachFlow', 'testesFlow', 'remainderFlow', 'adiposeVolume', 'brainVolume',
  96. 'heartVolume', 'kidneyVolume', 'liverVolume', 'lungVolume', 'muscleVolume', 'skinVolume',
  97. 'splanchnicVolume', 'stomachVolume', 'testesVolume', 'remainderVolume', 'venousVolume',
  98. 'arterialVolume', 'liverToExcrementNotes', 'k1', 'one', 'zero', 'two'
  99. }
  100. excluded_params1 = {'venousInput',"heartPC","kidneyPC","remainderPC","skinPC","splanchnicPC","stomachPC","testesPC","one","venousVolume","heartVolume","brainVolume","adiposeVolume"}
  101. #excluded_params1={}
  102. # Create initial guesses without excluded parameters
  103. initial_guesses = np.array(
  104. [val for par, val in name_value_dict1.items() if par not in excluded_params1],
  105. dtype=np.float64
  106. )
  107. # Create list of parameter names without excluded
  108. param_names = [par for par in name_value_dict1.keys() if par not in excluded_params1]
  109. initial_pars = np.array([x for x in initial_guesses])
  110. #initial_pars[3]*=1.1
  111. #print("kolicnik")
  112. #print(initial_guesses/initial_pars)
  113. #print(param_names)
  114. # TO NAREDI REŠITVE Z ZAČETNIMI PARAMETRI
  115. start_point= runSolver.findStartPoint("NONE",setup1)
  116. #model1.setValues(param_names,initial_pars)
  117. clean_dir(jobDir)
  118. t,sol,se,qt,sOut,full_t,full_sol = runSolver.solve(model1,setup1,start_point,jobDir)
  119. clean_dir(jobDir)
  120. # Step 4: Create a new dictionary for the optimized parameters
  121. # Map the optimized parameters back to the correct order in the original parameter dictionary
  122. optimized_params_dict1 = {par: initial_guesses[i] for i, par in enumerate(param_names)}
  123. # Step 5: Include the excluded parameters with their original values
  124. for par in excluded_params1:
  125. optimized_params_dict1[par] = name_value_dict1[par]
  126. # Step 6: Ensure that everything stays in order in the final dictionary
  127. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  128. final_dict1 = {par: optimized_params_dict1.get(par, name_value_dict1[par]) for par in name_value_dict1}
  129. #################################################################################################################333
  130. # Z DRUGIMI PARAMETRI
  131. ##########################################################################################################################
  132. fh = os.path.expanduser("~")
  133. # Drugi model z drugim parameter file
  134. parameter_file2 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam_parameters1.json')
  135. model2 = cModel.model()
  136. model2.parse(model_file, parameter_file2)
  137. setup2 = runSolver.parseSetup(setup_file)
  138. name_value_dict2 = create_name_value_dict(model2.parSetup['parameters'])
  139. # Excluded parameters
  140. excluded_params2 = {'venousInput',"heartPC","kidneyPC","remainderPC","skinPC","splanchnicPC","stomachPC","testesPC","one","venousVolume","heartVolume","brainVolume","adiposeVolume"}
  141. #excluded_params2={}
  142. # Step 1: Filter out excluded parameters for initial guesses
  143. initial_guesses2 = np.array(
  144. [val for par, val in name_value_dict2.items() if par not in excluded_params2],
  145. dtype=np.float64
  146. )
  147. param_names2 = [par for par in name_value_dict2.keys() if par not in excluded_params2]
  148. initial_pars2 = np.array([x for x in initial_guesses2])
  149. # Step 4: Create a new dictionary for the optimized parameters
  150. # Map the optimized parameters back to the correct order in the original parameter dictionary
  151. optimized_params_dict2 = {par: initial_guesses2[i] for i, par in enumerate(param_names2)}
  152. # Step 5: Include the excluded parameters with their original values
  153. for par in excluded_params2:
  154. optimized_params_dict2[par] = name_value_dict2[par]
  155. # Step 6: Ensure that everything stays in order in the final dictionary
  156. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  157. final_dict2 = {par: optimized_params_dict2.get(par, name_value_dict2[par]) for par in name_value_dict2}
  158. # Step 2: Run optimization
  159. clean_dir(jobDir)
  160. lower_bound_value = 0 # Example: all parameters must be ≥ 0
  161. upper_bound_value = 1000 # Example: all parameters must be ≤ 10
  162. # Create bounds arrays of the same length as initial_guesses2
  163. lower_bounds = np.full_like(initial_guesses2, lower_bound_value)
  164. upper_bounds = np.full_like(initial_guesses2, upper_bound_value)
  165. start_point2= runSolver.findStartPoint("NONE",setup2)
  166. #t,sol,se,qt,sOut,full_t,full_sol2 = runSolver.solve(model2,setup2,start_point2,jobDir)
  167. result = least_squares(
  168. cost_function, initial_guesses2,
  169. args=(param_names2, full_sol, model2, start_point2, setup2, jobDir),
  170. bounds=(lower_bounds, upper_bounds)
  171. )
  172. num_iterations = result.nfev
  173. print(f"Number of function evaluations: {num_iterations}")
  174. print(f"Exit status: {result.status}")
  175. # Step 3: Retrieve optimized parameters
  176. optimized_params3 = result.x
  177. print(result.x)
  178. # Step 4: Create a new dictionary for the optimized parameters
  179. # Map the optimized parameters back to the correct order in the original parameter dictionary
  180. optimized_params_dict3 = {par: optimized_params3[i] for i, par in enumerate(param_names2)}
  181. # Step 5: Include the excluded parameters with their original values
  182. for par in excluded_params2:
  183. optimized_params_dict3[par] = name_value_dict2[par]
  184. # Step 6: Ensure that everything stays in order in the final dictionary
  185. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  186. final_optimized_dict3 = {par: optimized_params_dict3.get(par, name_value_dict2[par]) for par in name_value_dict2}
  187. # Now, final_optimized_dict contains the optimized values in the same order as in `name_value_dict2`
  188. print(name_value_dict2)
  189. print(final_optimized_dict3)
  190. vrednosti3 = np.array(
  191. [val for par, val in final_optimized_dict3.items()],
  192. dtype=np.float64
  193. )
  194. param_names3 = [par for par in final_optimized_dict3.keys()]
  195. #model2.setValues(param_names3,vrednosti3)
  196. #################################################################################################################################
  197. # PREVRBA ČE SO 3 različne rešitve
  198. #clean_dir(jobDir)
  199. #t,sol,se,qt,sOut,full_t,full_sol1 = runSolver.solve(model1,setup1,start_point,jobDir)
  200. #clean_dir(jobDir)
  201. #t,sol,se,qt,sOut,full_t,full_sol2 = runSolver.solve(model2,setup2,start_point2,jobDir)
  202. #model2.setValues(param_names3,vrednosti3)
  203. #clean_dir(jobDir)
  204. #t,sol,se,qt,sOut,full_t,full_sol3 = runSolver.solve(model2,setup2,start_point,jobDir)
  205. #print(np.array(full_sol2)/np.array(full_sol1))
  206. #print(np.array(full_sol3)/np.array(full_sol1))
  207. #print(np.array(full_sol3)/np.array(full_sol2))
  208. #print(initial_guesses2/initial_guesses)
  209. #print(optimized_params3/initial_guesses2)
  210. #print(optimized_params3/initial_guesses)
  211. ##################################################################################################################################
  212. # SHRANIMO REŠITVE ZA PARAMETRE
  213. def create_or_clean_dir(directory):
  214. """Create the directory if it doesn't exist, otherwise clean it."""
  215. if os.path.exists(directory):
  216. shutil.rmtree(directory) # Remove the existing directory and its contents
  217. os.makedirs(directory) # Create a fresh directory
  218. # Example structure to match your requested output format
  219. def save_parameters(file_path, param_dict):
  220. """
  221. Overwrites the original file with the updated parameters.
  222. Parameters:
  223. file_path (str): The path where the updated parameters will be saved.
  224. param_dict (dict): The updated parameters to save.
  225. """
  226. # Ensure the directory exists
  227. os.makedirs(os.path.dirname(file_path), exist_ok=True)
  228. # Open the original file and load its content to preserve its structure
  229. with open(file_path, 'r') as f:
  230. data = json.load(f)
  231. # Update the 'parameters' field with the new parameters
  232. data['parameters'] = param_dict
  233. # Save the updated structure back to the same file
  234. with open(file_path, 'w') as f:
  235. json.dump(data, f, indent=4)
  236. print(f"Updated parameters have been written to {file_path}")
  237. return file_path # Make sure the file path is returned
  238. # Define unique subdirectories
  239. jobDir1 = os.path.join(jobDir, "run1")
  240. jobDir2 = os.path.join(jobDir, "run2")
  241. jobDir3 = os.path.join(jobDir, "run3")
  242. # Ensure directories exist and are clean
  243. create_or_clean_dir(jobDir1)
  244. create_or_clean_dir(jobDir2)
  245. create_or_clean_dir(jobDir3)
  246. #ZA ORIGNAL
  247. # Solve and save results in respective directories
  248. t, sol, se, qt, sOut, full_t, full_sol1 = runSolver.solve(model1, setup1, start_point, jobDir1)
  249. # Define file paths for the new parameter file
  250. new_param_file1 = os.path.join(jobDir1, "parameters.json")
  251. # Update parameters and save them to the new file
  252. model1.updateParameters(final_dict1, parameter_file1, new_param_file1)
  253. # Save updated parameters to the respective directory
  254. save_parameters(os.path.join(jobDir1, "parameters.json"), model1.parSetup['parameters'])
  255. #ZA DRUGI ORIGINAL
  256. new_param_file2 = os.path.join(jobDir2, "parameters.json")
  257. t, sol, se, qt, sOut, full_t, full_sol2 = runSolver.solve(model2, setup2, start_point, jobDir2)
  258. model2.updateParameters(final_dict2, parameter_file2, new_param_file2)
  259. save_parameters(os.path.join(jobDir2, "parameters.json"), model2.parSetup['parameters'])
  260. # Posodobljeni parametri in rešitev
  261. new_param_file3 = os.path.join(jobDir3, "updated_parameters.json")
  262. model2.setValues(param_names3, vrednosti3)
  263. t, sol, se, qt, sOut, full_t, full_sol3 = runSolver.solve(model2, setup2, start_point, jobDir3)
  264. model2.updateParameters(final_optimized_dict3, parameter_file2, new_param_file3)
  265. # Save parameters and immediately store the path for further use
  266. param_file3 = save_parameters(os.path.join(jobDir3, "updated_parameters.json"), model2.parSetup['parameters'])
  267. # Now you can directly use param_file3 in further processing
  268. print(f"Parameters for run3 saved at: {param_file3}")
  269. ########################################################################################################################
  270. #ZGRADIMO 3 MODEL (da bo lažje pol risat)
  271. ##############################################################################################################################################
  272. # param_file3 already contains the full path to "parameters.json"
  273. import os
  274. import glob
  275. directory = os.path.dirname(param_file3)
  276. jobDir3 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen',"rezultati","least_squares","run3")
  277. # Make sure param_file3 contains the correct file path, including file name.
  278. # If param_file3 only has the directory, append the file name
  279. parameter_file3 = os.path.join(directory, "updated_parameters.json") # Specify the file name
  280. # Check if it's a valid file
  281. if os.path.isfile(parameter_file3):
  282. with open(parameter_file3, 'r') as f:
  283. # Your code to process the file
  284. pass
  285. else:
  286. print(f"Error: {parameter_file3} is not a valid file.")
  287. import os
  288. import glob
  289. def clean_files(directory):
  290. """Deletes all .txt and .csv files in the given directory."""
  291. # Use glob to find all .txt and .csv files in the directory
  292. txt_files = glob.glob(os.path.join(directory, "*.txt"))
  293. csv_files = glob.glob(os.path.join(directory, "*.csv"))
  294. # Combine both lists of files
  295. all_files = txt_files + csv_files
  296. # Loop through the list of files and delete each one
  297. for file in all_files:
  298. try:
  299. os.remove(file)
  300. print(f"Deleted: {file}")
  301. except Exception as e:
  302. print(f"Error deleting {file}: {e}")
  303. clean_files(jobDir3)
  304. clean_files(jobDir)
  305. clean_files(jobDir1)
  306. clean_files(jobDir2)
  307. #Saves alll the necessary information for drawing in the right files
  308. runSolver.main([setup_file,model_file,parameter_file2,srcDir],jobDir2)
  309. runSolver.main([setup_file,model_file,parameter_file1,srcDir],jobDir1)
  310. runSolver.main([setup_file,model_file,parameter_file3,srcDir],jobDir3)
  311. ########################################################################################################3333
  312. #RISANJE
  313. ########################################################################################################################
  314. import matplotlib.pyplot as plt
  315. job_configs = {
  316. 'Osnovni': {
  317. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','least_squares','run1')
  318. },
  319. 'Osnovni2': {
  320. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','least_squares','run2')
  321. },
  322. 'Posodobljeni_parametri': {
  323. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','least_squares','run3')
  324. }
  325. }
  326. def getModel(solution, modelName):
  327. """
  328. Load and parse the model from the given solution dictionary using the modelName.
  329. """
  330. Q = solution[modelName] # Retrieve the solution dictionary for the specified model
  331. model = cModel.model() # Create an instance of the cModel class
  332. setupFile = Q['setup'] # Get the setup file path from the solution
  333. modelFile = Q['model'] # Get the model file path from the solution
  334. parameterFile = Q['parameters'] # Get the parameter file path from the solution
  335. model.parse(modelFile, parameterFile) # Parse the model file with the given parameters
  336. return model # Return the loaded model
  337. def mergeSolutions(seq):
  338. """
  339. Merge multiple solution dictionaries into a single dictionary.
  340. """
  341. out = {}
  342. for v in ['t', 'sol', 'se', 'qt', 'sOut']: # Merge arrays from each solution
  343. out[v] = np.concatenate([x[v] for x in seq])
  344. for v in ['lut', 'lutSE', 'setup', 'model', 'parameters', 'qt', 'sOut']: # Use data from the last solution for these keys
  345. out[v] = seq[-1][v]
  346. return out # Return the merged dictionary
  347. # Load and merge solutions
  348. solution = {}
  349. for modelName, job in job_configs.items():
  350. seq = [runSolver.loadSolutionFromDir(job['jobDir'], True)]
  351. solution[modelName] = mergeSolutions(seq)
  352. def analyze_model(model, setup):
  353. """
  354. Perform matrix operations and print results.
  355. """
  356. tscale = runSolver.getScale(setup) # Get the time scale from the setup
  357. model.inspect() # Inspect the model
  358. nt = setup['nt'] # Number of time points
  359. qtmax = 1 # Maximum time (minute)
  360. qt = np.linspace(0, qtmax, nt) # Generate time points
  361. par = 'venousInput' # Parameter to plot
  362. # Plot parameters
  363. try:
  364. hw = model.get(par) # Get the parameter from the model
  365. ht = [10 * hw['value'](x) for x in qt] # Calculate parameter values over time
  366. plt.plot(qt / tscale, ht) # Plot the parameter values
  367. except (KeyError, TypeError): # Handle errors if the parameter is not found
  368. pass
  369. # Measure performance of matrix operations
  370. start_time = time.time() # Record start time
  371. for i in range(100000): # Perform matrix operations 100,000 times
  372. model.M(1e7) # Call the matrix operation
  373. end_time = time.time() # Record end time
  374. fM = model.M(0) # Get the matrix from the model
  375. np.set_printoptions(suppress=True, precision=2, linewidth=150) # Set NumPy print options
  376. np.set_printoptions(suppress=False) # Reset NumPy print options
  377. v, Q = np.linalg.eig(fM) # Perform eigenvalue decomposition
  378. Q1 = np.linalg.inv(Q) # Calculate the inverse of the eigenvector matrix
  379. D = np.diag(v) # Create a diagonal matrix of eigenvalues
  380. t = np.linspace(0, 100, 101) # Generate time points for plotting
  381. fy = [model.u(x)[14] for x in t] # Calculate model output over time
  382. plt.figure() # Create a new figure
  383. plt.plot(fy) # Plot the model output
  384. fu = model.u(0) # Get the model output at time 0
  385. plt.show() # Display the plot
  386. # Restore stdout
  387. def plot_results(solution, modelName):
  388. """
  389. Plot results for the specified model from the solution.
  390. """
  391. model = getModel(solution, modelName) # Load the model
  392. setup = solution[modelName]['setup'] # Get the setup from the solution
  393. tscale = runSolver.getScale(setup) # Get the time scale
  394. name = ['venous', 'adipose', 'brain', 'heart', 'kidney', 'liver', 'lung', 'muscle', 'skin', 'stomach', 'splanchnic', "arterial","remainder","excrement"] # Compartment names
  395. tmax = solution[modelName]['t'][-1] # Get the maximum time from the solution
  396. # Define colors and shading for models
  397. models = {
  398. 'Osnovni': {'color': 'orange', 'shadeColor': 'red'},
  399. 'Osnovni2': {'color': 'blue', 'shadeColor': 'green'},
  400. 'Posodobljeni_parametri': {'color': 'black', 'shadeColor': 'yellow'}
  401. }
  402. fig, axs = plt.subplots(5, 3, figsize=(15, 20)) # Create a grid of subplots
  403. for i in range(len(name)): # Loop over each compartment
  404. row = i // 3 # Determine row index
  405. col = i % 3 # Determine column index
  406. ax = axs[row, col] # Get the subplot
  407. for m in models: # Loop over each model
  408. fM = models[m] # Get model configuration
  409. Q = solution[m] # Get solution for the model
  410. v = name[i] # Get the compartment name
  411. try:
  412. j = Q['lut'][v] # Get the index for the compartment
  413. except KeyError:
  414. try:
  415. v1 = alias[v] # Handle alias if needed
  416. j = Q['lut'][v1] # Get the index for the alias
  417. except KeyError:
  418. continue
  419. fy = Q['sol'][:, j] # Get the solution for the compartment
  420. fe = Q['se'][:, j] # Get the standard error for the compartment
  421. t = Q['t'] # Get the time points
  422. # Plot the mean values and confidence intervals
  423. ax.plot(t / tscale, fy, color=fM['color'], label=f'{m} sol')
  424. ax.fill_between(t / tscale, fy - fe, fy + fe, color=fM['shadeColor'], alpha=0.1) # Shaded area for confidence intervals
  425. ax.plot(t / tscale, fy - fe, color=fM['shadeColor'], linewidth=1, alpha=0.2) # Lower bound
  426. ax.plot(t / tscale, fy + fe, color=fM['shadeColor'], linewidth=1, alpha=0.2) # Upper bound
  427. # Find the maximum y-value including confidence intervals
  428. max_y_value = max(np.max(fy + fe), np.max(fy - fe))
  429. ax.set_ylim([0, min(max_y_value, 10000)]) # Set y-axis limit to max value or 10000, whichever is smaller
  430. ax.set_xlim([0, 1.1 * tmax / tscale]) # Set x-axis limits
  431. ax.set_xlabel(setup['tUnit']) # Set x-axis label
  432. ax.set_title(name[i]) # Set plot title
  433. ax.legend() # Add legend
  434. # output_file = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', f'{modelName}_results.pdf')
  435. plt.tight_layout()
  436. # plt.savefig(output_file) # Save the figure
  437. plt.show() # Display the plot
  438. # Extract the number of iterations from the result dictionary
  439. num_iterations = result.nfev
  440. print(f"Number of function evaluations: {num_iterations}")
  441. print(f"Exit status: {result.status}")
  442. # Analyze and plot results for the specified models
  443. for modelName in job_configs.keys():
  444. if modelName == 'Osnovni': # Analyze only the specified model
  445. analyze_model(getModel(solution, modelName), solution[modelName]['setup'])
  446. plot_results(solution, modelName)