patch_size.py 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import numpy as np
  2. from scipy.optimize import bisect, root_scalar
  3. import expansion
  4. from matplotlib import pyplot as plt
  5. import parameters
  6. import potentials
  7. from pathlib import Path
  8. from typing import Callable
  9. Expansion = expansion.Expansion
  10. Array = np.ndarray
  11. ModelParams = parameters.ModelParams
  12. @expansion.map_over_expansion
  13. def charge_patch_size(ex: Expansion, phi: float = 0, theta0: Array | float = 0, theta1: Array | float = np.pi / 2):
  14. return bisect(lambda theta: ex.charge_value(theta, phi), theta0, theta1)
  15. def potential_patch_size(ex: Expansion, params: ModelParams,
  16. phi: float = 0, theta0: Array | float = 0, theta1: Array | float = np.pi / 2,
  17. match_expansion_axis_to_params: int = None):
  18. # this is more complicate to map over leading axes of the expansion as potential also depends on model parameters,
  19. # with some, such as kappaR, also being the parameters of the expansion in the first place. When mapping,
  20. # we must therefore provide the expansion axis that should match the collection of parameters in params.
  21. meap = match_expansion_axis_to_params # just a shorter variable name
  22. @expansion.map_over_expansion
  23. def potential_zero(exp: Expansion, prms: ModelParams):
  24. return bisect(lambda theta: potentials.charged_shell_potential(theta, phi, 1, exp, prms), theta0, theta1)
  25. params_list = params.unravel()
  26. if meap is not None:
  27. expansion_list = [Expansion(ex.l_array, np.take(ex.coefs, i, axis=meap)) for i in range(ex.shape[meap])]
  28. else:
  29. expansion_list = [ex for _ in params_list]
  30. if not len(expansion_list) == len(params_list):
  31. raise ValueError(f'Axis of expansion that is supposed to match params does not have the same length, got '
  32. f'len(params.unravel()) = {len(params_list)} and '
  33. f'expansion.shape[{meap}] = {len(expansion_list)}')
  34. results = []
  35. for exp, prms in zip(expansion_list, params_list):
  36. results.append(potential_zero(exp, prms))
  37. if meap is not None:
  38. return np.array(results).swapaxes(0, meap) # return the params-matched axis to where it belongs
  39. return np.squeeze(np.array(results))
  40. def inverse_potential_patch_size(target_patch_size: float,
  41. ex_generator: Callable[[float], Expansion],
  42. x0: float,
  43. params: ModelParams, **ps_kwargs):
  44. def patch_size_dif(x):
  45. ex = ex_generator(x)
  46. return potential_patch_size(ex, params, **ps_kwargs) - target_patch_size
  47. root_result = root_scalar(patch_size_dif, x0=x0)
  48. if not root_result.converged:
  49. raise ValueError('No convergence. Patches of desired size might not be achievable in the given model. '
  50. 'Conversely, a common mistake might be target patch size input in degrees.')
  51. return root_result.root
  52. if __name__ == '__main__':
  53. a_bar = np.linspace(0.2, 0.8, 100)
  54. kappaR = np.array([0.26, 1, 3, 10, 26])
  55. params = ModelParams(R=150, kappaR=10)
  56. # ex = expansion.MappedExpansionQuad(a_bar=a_bar[:, None], sigma_m=0.001, l_max=30, kappaR=kappaR[None, :])
  57. fn = lambda x: expansion.SphericalCap(theta0_k=x, sigma1=0.001, l_max=30, omega_k=np.array([[0, 0], [np.pi, 0]]))
  58. print(inverse_potential_patch_size(48.8 * np.pi / 180, fn, 0.4, params))
  59. # # patch_size = charge_patch_size(ex)
  60. # patch_size = potential_patch_size(ex, params, match_expansion_axis_to_params=1)
  61. #
  62. # fig, ax = plt.subplots()
  63. # for patch, kR in zip(patch_size.T, kappaR):
  64. # ax.plot(a_bar, patch * 180 / np.pi, label=rf'$\kappa$ = {kR}')
  65. # ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  66. # ax.set_xlabel(r'$\bar a$', fontsize=13)
  67. # ax.set_ylabel(r'$\theta$', fontsize=13)
  68. # plt.legend(fontsize=12)
  69. # # plt.savefig(Path("/home/andraz/ChargedShells/Figures/patch_size_potential.png"), dpi=600)
  70. # plt.show()