Update_parameters.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. import ivp
  2. import solveMatrix
  3. import os
  4. import 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")
  79. setup_file = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'setup', 'setupMinute.json')
  80. model_file = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam.json')
  81. parameter_file1 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam_parameters.json')
  82. # Prvi model s prvim parameter file
  83. model1 = cModel.model()
  84. model1.parse(model_file, parameter_file1)
  85. setup1 = runSolver.parseSetup(setup_file)
  86. name_value_dict1 = create_name_value_dict(model1.parSetup['parameters'])
  87. # Lahko zdaj uporabiš name_value_dict1 in name_value_dict2 ločeno
  88. # Excluded parameters
  89. excluded_params1 = {'venousInput',"heartPC","kidneyPC","remainderPC","skinPC","splanchnicPC","stomachPC","testesPC","one","venousVolume","heartVolume","brainVolume","adiposeVolume","remainderFlow"}
  90. # Create initial guesses without excluded parameters
  91. initial_guesses = np.array(
  92. [val for par, val in name_value_dict1.items() if par not in excluded_params1],
  93. dtype=np.float64
  94. )
  95. # Create list of parameter names without excluded
  96. param_names = [par for par in name_value_dict1.keys() if par not in excluded_params1]
  97. initial_pars = np.array([x for x in initial_guesses])
  98. #initial_pars[3]*=1.1
  99. clean_dir(jobDir)
  100. #print("kolicnik")
  101. #print(initial_guesses/initial_pars)
  102. #print(param_names)
  103. # TO NAREDI REŠITVE Z ZAČETNIMI PARAMETRI
  104. start_point= runSolver.findStartPoint("NONE",setup1)
  105. model1.setValues(param_names,initial_pars)
  106. t,sol,se,qt,sOut,full_t,full_sol = runSolver.solve(model1,setup1,start_point,jobDir)
  107. clean_dir(jobDir)
  108. # Step 4: Create a new dictionary for the optimized parameters
  109. # Map the optimized parameters back to the correct order in the original parameter dictionary
  110. optimized_params_dict1 = {par: initial_guesses[i] for i, par in enumerate(param_names)}
  111. # Step 5: Include the excluded parameters with their original values
  112. for par in excluded_params1:
  113. optimized_params_dict1[par] = name_value_dict1[par]
  114. # Step 6: Ensure that everything stays in order in the final dictionary
  115. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  116. final_dict1 = {par: optimized_params_dict1.get(par, name_value_dict1[par]) for par in name_value_dict1}
  117. #################################################################################################################333
  118. # Z DRUGIMI PARAMETRI
  119. ##########################################################################################################################
  120. # Drugi model z drugim parameter file
  121. parameter_file2 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam_parameters1.json')
  122. model2 = cModel.model()
  123. model2.parse(model_file, parameter_file2)
  124. setup2 = runSolver.parseSetup(setup_file)
  125. name_value_dict2 = create_name_value_dict(model2.parSetup['parameters'])
  126. # Excluded parameters
  127. excluded_params = {'venousInput',"heartPC","kidneyPC","remainderPC","skinPC","splanchnicPC","stomachPC","testesPC","one","venousVolume","heartVolume","brainVolume","adiposeVolume","remainderFlow"}
  128. # Step 1: Filter out excluded parameters for initial guesses
  129. initial_guesses2 = np.array(
  130. [val for par, val in name_value_dict2.items() if par not in excluded_params],
  131. dtype=np.float64
  132. )
  133. param_names2 = [par for par in name_value_dict2.keys() if par not in excluded_params]
  134. # Step 4: Create a new dictionary for the optimized parameters
  135. # Map the optimized parameters back to the correct order in the original parameter dictionary
  136. optimized_params_dict22 = {par: initial_guesses2[i] for i, par in enumerate(param_names2)}
  137. # Step 5: Include the excluded parameters with their original values
  138. for par in excluded_params1:
  139. optimized_params_dict22[par] = name_value_dict2[par]
  140. # Step 6: Ensure that everything stays in order in the final dictionary
  141. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  142. final_dict22 = {par: optimized_params_dict22.get(par, name_value_dict1[par]) for par in name_value_dict2}
  143. # Step 2: Run optimization
  144. result = least_squares(
  145. cost_function, initial_guesses2,
  146. args=(param_names2, full_sol, model2, start_point, setup2, jobDir)
  147. )
  148. # Step 3: Retrieve optimized parameters
  149. optimized_params2 = result.x
  150. # Step 4: Create a new dictionary for the optimized parameters
  151. # Map the optimized parameters back to the correct order in the original parameter dictionary
  152. optimized_params_dict2 = {par: optimized_params2[i] for i, par in enumerate(param_names2)}
  153. # Step 5: Include the excluded parameters with their original values
  154. for par in excluded_params:
  155. optimized_params_dict2[par] = name_value_dict2[par]
  156. # Step 6: Ensure that everything stays in order in the final dictionary
  157. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  158. final_optimized_dict = {par: optimized_params_dict2.get(par, name_value_dict2[par]) for par in name_value_dict2}
  159. # Now, final_optimized_dict contains the optimized values in the same order as in `name_value_dict2`
  160. print(name_value_dict2)
  161. print(final_optimized_dict)
  162. vrednosti3 = np.array(
  163. [val for par, val in final_optimized_dict.items()],
  164. dtype=np.float64
  165. )
  166. param_names3 = [par for par in final_optimized_dict.keys()]
  167. #model2.setValues(param_names3,vrednosti3)
  168. #################################################################################################################################
  169. # PREVRBA ČE SO 3 različne rešitve
  170. clean_dir(jobDir)
  171. t,sol,se,qt,sOut,full_t,full_sol1 = runSolver.solve(model1,setup1,start_point,jobDir)
  172. clean_dir(jobDir)
  173. t,sol,se,qt,sOut,full_t,full_sol2 = runSolver.solve(model2,setup2,start_point,jobDir)
  174. model2.setValues(param_names3,vrednosti3)
  175. clean_dir(jobDir)
  176. t,sol,se,qt,sOut,full_t,full_sol3 = runSolver.solve(model2,setup2,start_point,jobDir)
  177. print(np.array(full_sol2)/np.array(full_sol1))
  178. print(np.array(full_sol3)/np.array(full_sol1))
  179. print(np.array(full_sol3)/np.array(full_sol2))
  180. print(initial_guesses2/initial_guesses)
  181. print(optimized_params2/initial_guesses2)
  182. print(optimized_params2/initial_guesses)
  183. ##################################################################################################################################
  184. # SHRANIMO REŠITVE ZA PARAMETRE
  185. def create_or_clean_dir(directory):
  186. """Create the directory if it doesn't exist, otherwise clean it."""
  187. if os.path.exists(directory):
  188. shutil.rmtree(directory) # Remove the existing directory and its contents
  189. os.makedirs(directory) # Create a fresh directory
  190. def save_parameters(file_path, data):
  191. """Save dictionary data to a JSON file."""
  192. with open(file_path, 'w') as f:
  193. json.dump(data, f, indent=4)
  194. return file_path # Return the path for immediate use
  195. # Define unique subdirectories
  196. jobDir1 = os.path.join(jobDir, "run1")
  197. jobDir2 = os.path.join(jobDir, "run2")
  198. jobDir3 = os.path.join(jobDir, "run3")
  199. # Ensure directories exist and are clean
  200. create_or_clean_dir(jobDir1)
  201. create_or_clean_dir(jobDir2)
  202. create_or_clean_dir(jobDir3)
  203. # Solve and save results in respective directories
  204. t, sol, se, qt, sOut, full_t, full_sol1 = runSolver.solve(model1, setup1, start_point, jobDir1)
  205. save_parameters(os.path.join(jobDir1, "parameters.json"), final_dict1)
  206. t, sol, se, qt, sOut, full_t, full_sol2 = runSolver.solve(model2, setup2, start_point, jobDir2)
  207. save_parameters(os.path.join(jobDir2, "parameters.json"), final_dict22)
  208. model2.setValues(param_names3, vrednosti3)
  209. t, sol, se, qt, sOut, full_t, full_sol3 = runSolver.solve(model2, setup2, start_point, jobDir3)
  210. # Save parameters and immediately store the path for further use
  211. param_file3 = save_parameters(os.path.join(jobDir3, "parameters.json"), final_optimized_dict)
  212. # Now you can directly use param_file3 in further processing
  213. print(f"Parameters for run3 saved at: {param_file3}")
  214. ########################################################################################################################
  215. #ZGRADIMO 3 MODEL (da bo lažje pol risat)
  216. ##############################################################################################################################################
  217. # param_file3 already contains the full path to "parameters.json"
  218. directory = os.path.dirname(param_file3)
  219. print(directory)
  220. model3 = cModel.model()
  221. parameter_file3 = os.path.join(directory) # Use it as a path
  222. model3.parse(model_file, parameter_file3)
  223. # Load the model using the saved parameter file
  224. #model3.parse(model_file, parameter_file3) # Use param_file3 here
  225. # Parse the setup
  226. setup3 = runSolver.parseSetup(setup_file)
  227. # Create the name-value dictionary
  228. name_value_dict3 = create_name_value_dict(model3.parSetup['parameters'])
  229. ########################################################################################################3333
  230. runSolver.main([setup_file,model3,parameter_file3,jobDir])
  231. #RISANJE
  232. ########################################################################################################################
  233. job_configs = {
  234. 'cDiazepam_IVP': {
  235. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run1')
  236. },
  237. 'cDiazepam1_IVP': {
  238. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run2')
  239. },
  240. 'cDiazepamF_IVP': {
  241. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run3')
  242. }
  243. }
  244. def mergeSolutions(seq):
  245. """
  246. Merge multiple solution dictionaries into a single dictionary.
  247. """
  248. out = {}
  249. for v in ['t', 'sol', 'se', 'qt', 'sOut']: # Merge arrays from each solution
  250. out[v] = np.concatenate([x[v] for x in seq])
  251. for v in ['lut', 'lutSE', 'setup', 'model', 'parameters', 'qt', 'sOut']: # Use data from the last solution for these keys
  252. out[v] = seq[-1][v]
  253. return out # Return the merged dictionary