Update_parameters.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. #print("kolicnik")
  100. #print(initial_guesses/initial_pars)
  101. #print(param_names)
  102. # TO NAREDI REŠITVE Z ZAČETNIMI PARAMETRI
  103. start_point= runSolver.findStartPoint("NONE",setup1)
  104. #model1.setValues(param_names,initial_pars)
  105. clean_dir(jobDir)
  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. fh = os.path.expanduser("~")
  121. # Drugi model z drugim parameter file
  122. parameter_file2 = os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'models', 'cDiazepam_parameters1.json')
  123. model2 = cModel.model()
  124. model2.parse(model_file, parameter_file2)
  125. setup2 = runSolver.parseSetup(setup_file)
  126. name_value_dict2 = create_name_value_dict(model2.parSetup['parameters'])
  127. # Excluded parameters
  128. excluded_params2 = {'venousInput',"heartPC","kidneyPC","remainderPC","skinPC","splanchnicPC","stomachPC","testesPC","one","venousVolume","heartVolume","brainVolume","adiposeVolume","remainderFlow"}
  129. # Step 1: Filter out excluded parameters for initial guesses
  130. initial_guesses2 = np.array(
  131. [val for par, val in name_value_dict2.items() if par not in excluded_params2],
  132. dtype=np.float64
  133. )
  134. param_names2 = [par for par in name_value_dict2.keys() if par not in excluded_params2]
  135. initial_pars2 = np.array([x for x in initial_guesses2])
  136. # Step 4: Create a new dictionary for the optimized parameters
  137. # Map the optimized parameters back to the correct order in the original parameter dictionary
  138. optimized_params_dict2 = {par: initial_guesses2[i] for i, par in enumerate(param_names2)}
  139. # Step 5: Include the excluded parameters with their original values
  140. for par in excluded_params2:
  141. optimized_params_dict2[par] = name_value_dict2[par]
  142. # Step 6: Ensure that everything stays in order in the final dictionary
  143. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  144. final_dict2 = {par: optimized_params_dict2.get(par, name_value_dict2[par]) for par in name_value_dict2}
  145. # Step 2: Run optimization
  146. clean_dir(jobDir)
  147. start_point2= runSolver.findStartPoint("NONE",setup2)
  148. t,sol,se,qt,sOut,full_t,full_sol2 = runSolver.solve(model2,setup2,start_point2,jobDir)
  149. result = least_squares(
  150. cost_function, initial_guesses2,
  151. args=(param_names2, full_sol, model2, start_point2, setup2, jobDir)
  152. )
  153. # Step 3: Retrieve optimized parameters
  154. optimized_params3 = result.x
  155. print(result.x)
  156. # Step 4: Create a new dictionary for the optimized parameters
  157. # Map the optimized parameters back to the correct order in the original parameter dictionary
  158. optimized_params_dict3 = {par: optimized_params3[i] for i, par in enumerate(param_names2)}
  159. # Step 5: Include the excluded parameters with their original values
  160. for par in excluded_params2:
  161. optimized_params_dict3[par] = name_value_dict2[par]
  162. # Step 6: Ensure that everything stays in order in the final dictionary
  163. # This will maintain the order of parameters as they appear in the original `name_value_dict2`
  164. final_optimized_dict3 = {par: optimized_params_dict3.get(par, name_value_dict2[par]) for par in name_value_dict2}
  165. # Now, final_optimized_dict contains the optimized values in the same order as in `name_value_dict2`
  166. print(name_value_dict2)
  167. print(final_optimized_dict3)
  168. vrednosti3 = np.array(
  169. [val for par, val in final_optimized_dict3.items()],
  170. dtype=np.float64
  171. )
  172. param_names3 = [par for par in final_optimized_dict3.keys()]
  173. #model2.setValues(param_names3,vrednosti3)
  174. #################################################################################################################################
  175. # PREVRBA ČE SO 3 različne rešitve
  176. clean_dir(jobDir)
  177. t,sol,se,qt,sOut,full_t,full_sol1 = runSolver.solve(model1,setup1,start_point,jobDir)
  178. clean_dir(jobDir)
  179. t,sol,se,qt,sOut,full_t,full_sol2 = runSolver.solve(model2,setup2,start_point2,jobDir)
  180. model2.setValues(param_names3,vrednosti3)
  181. clean_dir(jobDir)
  182. t,sol,se,qt,sOut,full_t,full_sol3 = runSolver.solve(model2,setup2,start_point,jobDir)
  183. print(np.array(full_sol2)/np.array(full_sol1))
  184. print(np.array(full_sol3)/np.array(full_sol1))
  185. print(np.array(full_sol3)/np.array(full_sol2))
  186. print(initial_guesses2/initial_guesses)
  187. print(optimized_params3/initial_guesses2)
  188. print(optimized_params3/initial_guesses)
  189. ##################################################################################################################################
  190. # SHRANIMO REŠITVE ZA PARAMETRE
  191. def create_or_clean_dir(directory):
  192. """Create the directory if it doesn't exist, otherwise clean it."""
  193. if os.path.exists(directory):
  194. shutil.rmtree(directory) # Remove the existing directory and its contents
  195. os.makedirs(directory) # Create a fresh directory
  196. # Example structure to match your requested output format
  197. def save_parameters(file_path, param_dict):
  198. """
  199. Overwrites the original file with the updated parameters.
  200. Parameters:
  201. file_path (str): The path where the updated parameters will be saved.
  202. param_dict (dict): The updated parameters to save.
  203. """
  204. # Open the original file and load its content to preserve its structure
  205. with open(file_path, 'r') as f:
  206. data = json.load(f)
  207. # Update the 'parameters' field with the new parameters
  208. data['parameters'] = param_dict
  209. # Save the updated structure back to the same file
  210. with open(file_path, 'w') as f:
  211. json.dump(data, f, indent=4)
  212. print(f"Updated parameters have been written to {file_path}")
  213. # Define unique subdirectories
  214. jobDir1 = os.path.join(jobDir, "run1")
  215. jobDir2 = os.path.join(jobDir, "run2")
  216. jobDir3 = os.path.join(jobDir, "run3")
  217. # Ensure directories exist and are clean
  218. create_or_clean_dir(jobDir1)
  219. create_or_clean_dir(jobDir2)
  220. create_or_clean_dir(jobDir3)
  221. #ZA ORIGNAL
  222. # Solve and save results in respective directories
  223. t, sol, se, qt, sOut, full_t, full_sol1 = runSolver.solve(model1, setup1, start_point, jobDir1)
  224. # Define file paths for the new parameter file
  225. new_param_file1 = os.path.join(jobDir1, "parameters.json")
  226. # Update parameters and save them to the new file
  227. model1.updateParameters(final_dict1, parameter_file1, new_param_file1)
  228. # Save updated parameters to the respective directory
  229. save_parameters(os.path.join(jobDir1, "parameters.json"), model1.parSetup['parameters'])
  230. #ZA DRUGI ORIGINAL
  231. new_param_file2 = os.path.join(jobDir2, "parameters.json")
  232. t, sol, se, qt, sOut, full_t, full_sol2 = runSolver.solve(model2, setup2, start_point, jobDir2)
  233. model2.updateParameters(final_dict2, parameter_file2, new_param_file2)
  234. save_parameters(os.path.join(jobDir2, "parameters.json"), model2.parSetup['parameters'])
  235. new_param_file3 = os.path.join(jobDir3, "parameters.json")
  236. model2.setValues(param_names3, vrednosti3)
  237. t, sol, se, qt, sOut, full_t, full_sol3 = runSolver.solve(model2, setup2, start_point, jobDir3)
  238. model2.updateParameters(final_optimized_dict3, parameter_file2, new_param_file3)
  239. # Save parameters and immediately store the path for further use
  240. param_file3 = save_parameters(os.path.join(jobDir3, "parameters.json"), model2.parSetup['parameters'])
  241. # Now you can directly use param_file3 in further processing
  242. print(f"Parameters for run3 saved at: {param_file3}")
  243. ########################################################################################################################
  244. #ZGRADIMO 3 MODEL (da bo lažje pol risat)
  245. ##############################################################################################################################################
  246. # param_file3 already contains the full path to "parameters.json"
  247. import os
  248. directory = os.path.dirname(param_file3)
  249. print(directory)
  250. model3 = cModel.model()
  251. import os
  252. # Make sure param_file3 contains the correct file path, including file name.
  253. # If param_file3 only has the directory, append the file name
  254. parameter_file3 = os.path.join(directory, "parameters.json") # Specify the file name
  255. # Check if it's a valid file
  256. if os.path.isfile(parameter_file3):
  257. with open(parameter_file3, 'r') as f:
  258. # Your code to process the file
  259. pass
  260. else:
  261. print(f"Error: {parameter_file3} is not a valid file.")
  262. # Load the model using the saved parameter file
  263. model3 = cModel.model()
  264. model3.parse(model_file, parameter_file3)
  265. # Parse the setup
  266. setup3 = runSolver.parseSetup(setup_file)
  267. # Create the name-value dictionary
  268. name_value_dict3 = create_name_value_dict(model3.parSetup['parameters'])
  269. ########################################################################################################3333
  270. runSolver.main([setup_file,model3,parameter_file3,jobDir])
  271. #RISANJE
  272. ########################################################################################################################
  273. job_configs = {
  274. 'cDiazepam_IVP': {
  275. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run1')
  276. },
  277. 'cDiazepam1_IVP': {
  278. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run2')
  279. },
  280. 'cDiazepamF_IVP': {
  281. 'jobDir': os.path.join(fh, 'Documents', 'Sola', 'IJS', 'PBPK_ociscen', 'rezultati','run3')
  282. }
  283. }
  284. def mergeSolutions(seq):
  285. """
  286. Merge multiple solution dictionaries into a single dictionary.
  287. """
  288. out = {}
  289. for v in ['t', 'sol', 'se', 'qt', 'sOut']: # Merge arrays from each solution
  290. out[v] = np.concatenate([x[v] for x in seq])
  291. for v in ['lut', 'lutSE', 'setup', 'model', 'parameters', 'qt', 'sOut']: # Use data from the last solution for these keys
  292. out[v] = seq[-1][v]
  293. return out # Return the merged dictionary