patch_shape_comparison.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. from charged_shells import expansion, functions as fn, potentials, patch_size
  2. import numpy as np
  3. from charged_shells.parameters import ModelParams
  4. import matplotlib.pyplot as plt
  5. import scipy.special as sps
  6. from pathlib import Path
  7. from functools import partial
  8. from matplotlib.lines import Line2D
  9. def point_to_gauss_map(sigma_m, a_bar, lbd, params: ModelParams):
  10. return (sigma_m * fn.coefficient_Cim(2, params.kappaR) / fn.coefficient_Cpm(2, params.kappaR)
  11. * np.sinh(lbd) / (lbd * fn.sph_bessel_i(2, lbd)) * a_bar ** 2)
  12. def point_to_cap_map(sigma_m, a_bar, theta0, params: ModelParams):
  13. return (sigma_m * 10 * fn.coefficient_Cim(2, params.kappaR) / fn.coefficient_Cpm(2, params.kappaR) *
  14. a_bar ** 2 / (sps.eval_legendre(1, np.cos(theta0)) - sps.eval_legendre(3, np.cos(theta0))))
  15. def ic_cs_comparison():
  16. kappaR = 15
  17. params = ModelParams(R=150, kappaR=kappaR)
  18. sigma_m = 0.001
  19. sigma0 = 0.0001
  20. a_bar = 0.3
  21. theta = np.linspace(0, np.pi, 1001)
  22. phi = 0.
  23. dist = 1
  24. ex_cp = expansion.MappedExpansionQuad(a_bar=a_bar, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30,
  25. sigma0=sigma0)
  26. potential_cp = potentials.charged_shell_potential(theta, phi, dist, ex_cp, params)
  27. potential_ic = potentials.inverse_patchy_particle_potential(theta, dist, a_bar, -2 * sigma_m + sigma0,
  28. (sigma_m, sigma_m), params, 30)
  29. fig, ax = plt.subplots()
  30. ax.scatter(theta[::50], 1000 * potential_ic.T[::50], marker='o', label='ICi', facecolors='none',
  31. edgecolors='tab:red')
  32. ax.plot(theta, 1000 * potential_cp.T, label='CSp - mapped', linewidth=2)
  33. # ax.plot(1000 * potential_ic.T - 1000 * potential_cp.T)
  34. ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  35. ax.set_xlabel(r'$\theta$', fontsize=15)
  36. ax.set_ylabel(r'$\phi$ [mV]', fontsize=15)
  37. custom_ticks = [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4, np.pi]
  38. custom_labels = ['0', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$']
  39. plt.axhline(y=0, color='black', linestyle=':')
  40. plt.xticks(custom_ticks, custom_labels, fontsize=13)
  41. plt.legend(fontsize=12)
  42. plt.tight_layout()
  43. # plt.savefig(Path("/home/andraz/ChargedShells/Figures/potential_shape_comparison_overcharged05.pdf"), dpi=300)
  44. plt.show()
  45. def models_comparison():
  46. target_patch_size = 0.92
  47. kappaR = 3
  48. params = ModelParams(R=150, kappaR=kappaR)
  49. sigma_m = 0.001
  50. sigma0 = 0 # taking this total charge parameter nonzero causes cap model to fail in finding the appropriate theta0
  51. sigma0_mapped = expansion.net_charge_map(sigma0, kappaR)
  52. def fn1(x):
  53. return expansion.MappedExpansionQuad(a_bar=x, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30, sigma0=sigma0)
  54. def fn2(x):
  55. return expansion.GaussianCharges(lambda_k=x, omega_k=np.array([[0, 0], [np.pi, 0]]), sigma1=0.001, l_max=30, sigma0=sigma0_mapped)
  56. def fn3(x):
  57. return expansion.SphericalCap(theta0_k=x, sigma1=0.001, l_max=50, omega_k=np.array([[0, 0], [np.pi, 0]]), sigma0=sigma0_mapped)
  58. a_bar = patch_size.inverse_potential_patch_size(target_patch_size, fn1, 0.5, params)
  59. lbd = patch_size.inverse_potential_patch_size(target_patch_size, fn2, 5, params)
  60. theta0 = patch_size.inverse_potential_patch_size(target_patch_size, fn3, 0.5, params)
  61. ex_point = expansion.MappedExpansionQuad(a_bar=a_bar, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30, sigma0=sigma0)
  62. gauss_sigma = point_to_gauss_map(sigma_m, a_bar, lbd, params)
  63. ex_gauss = expansion.GaussianCharges(lambda_k=lbd, omega_k=np.array([[0, 0], [np.pi, 0]]), sigma1=gauss_sigma,
  64. l_max=30, sigma0=sigma0_mapped)
  65. cap_sigma = point_to_cap_map(sigma_m, a_bar, theta0, params)
  66. ex_cap = expansion.SphericalCap(theta0_k=theta0, sigma1=cap_sigma, omega_k=np.array([[0, 0], [np.pi, 0]]), l_max=30, sigma0=sigma0_mapped)
  67. theta = np.linspace(0, np.pi, 1001)
  68. phi = 0.
  69. dist = 1
  70. potential_ic = potentials.inverse_patchy_particle_potential(theta, dist, a_bar, -2 * sigma_m + sigma0,
  71. (sigma_m, sigma_m), params, 30)
  72. potential1 = potentials.charged_shell_potential(theta, phi, dist, ex_point, params)
  73. potential2 = potentials.charged_shell_potential(theta, phi, dist, ex_gauss, params)
  74. potential3 = potentials.charged_shell_potential(theta, phi, dist, ex_cap, params)
  75. # print(potential.shape)
  76. # print(potential)
  77. # expansion.plot_theta_profile_multiple([ex_point, ex_gauss, ex_cap], ['IC', 'Gauss', 'cap'], num=1000)
  78. fig, ax = plt.subplots()
  79. ax.scatter(theta[::50], 1000 * potential_ic.T[::50], marker='o', label='ICi', facecolors='none',
  80. edgecolors='tab:red')
  81. ax.plot(theta, 1000 * potential1.T, label='CSp - mapped', linewidth=2)
  82. # ax.plot(theta, potential_ic.T, label='IC', ls=':', linewidth=2, marker='o', markevery=50, mfc='none')
  83. ax.plot(theta, 1000 * potential2.T, label='CSp - Gauss', linewidth=2, ls='--')
  84. ax.plot(theta, 1000 * potential3.T, label='CSp - caps', linewidth=2, ls='--')
  85. ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  86. ax.set_xlabel(r'$\theta$', fontsize=15)
  87. ax.set_ylabel(r'$\phi$ [mV]', fontsize=15)
  88. custom_ticks = [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4, np.pi]
  89. custom_labels = ['0', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$']
  90. plt.axhline(y=0, color='black', linestyle=':')
  91. plt.axvline(x=target_patch_size, color='black', linestyle=':')
  92. plt.xticks(custom_ticks, custom_labels, fontsize=13)
  93. plt.legend(fontsize=12)
  94. plt.tight_layout()
  95. plt.savefig(Path("/home/andraz/ChargedShells/Figures/potential_shape_comparison.pdf"), dpi=300)
  96. plt.show()
  97. def abar_comparison():
  98. target_patch_sizes = [0.8, 0.85, 0.92]
  99. params = ModelParams(R=150, kappaR=3)
  100. sigma_m = 0.001
  101. theta = np.linspace(0, np.pi, 1001)
  102. phi = 0.
  103. dist = 1
  104. def fn1(x):
  105. return expansion.MappedExpansionQuad(a_bar=x, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30)
  106. pots = []
  107. for ps in target_patch_sizes:
  108. a_bar = patch_size.inverse_potential_patch_size(ps, fn1, 0.5, params)
  109. ex_point = expansion.MappedExpansionQuad(a_bar=a_bar, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30)
  110. pots.append(potentials.charged_shell_potential(theta, phi, dist, ex_point, params))
  111. fig, ax = plt.subplots()
  112. for pot, ps in zip(pots, target_patch_sizes):
  113. ax.plot(theta, 1000 * pot, label=fr'$\theta_0={180 / np.pi * ps:.1f}^o$', linewidth=2)
  114. ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  115. ax.set_xlabel(r'$\theta$', fontsize=15)
  116. ax.set_ylabel(r'$\phi$ [mV]', fontsize=15)
  117. custom_ticks = [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4, np.pi]
  118. custom_labels = ['0', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$']
  119. plt.axhline(y=0, color='black', linestyle=':')
  120. plt.xticks(custom_ticks, custom_labels, fontsize=13)
  121. plt.legend(fontsize=12)
  122. plt.tight_layout()
  123. plt.savefig(Path("/home/andraz/ChargedShells/Figures/potential_amplitude_comparison.pdf"), dpi=300)
  124. plt.show()
  125. def charge_comparsion():
  126. charges = np.array([-0.001, 0, 0.001, 0.002])
  127. a_bar = 0.6
  128. params = ModelParams(R=150, kappaR=10)
  129. sigma_m = 0.001
  130. theta = np.linspace(0, np.pi, 1001)
  131. phi = 0.
  132. dist = 1
  133. ex_point = expansion.MappedExpansionQuad(a_bar=a_bar, kappaR=params.kappaR, sigma_tilde=sigma_m,
  134. l_max=30, sigma0=charges)
  135. pot = potentials.charged_shell_potential(theta, phi, dist, ex_point, params)
  136. fig, ax = plt.subplots()
  137. for p, lbl in zip(pot, [fr'$\sigma_0={c}$' for c in charges]):
  138. ax.plot(theta, 1000 * p, linewidth=2, label=lbl)
  139. ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  140. ax.set_xlabel(r'$\theta$', fontsize=15)
  141. ax.set_ylabel(r'$\phi$ [mV]', fontsize=15)
  142. custom_ticks = [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4, np.pi]
  143. custom_labels = ['0', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$']
  144. plt.axhline(y=0, color='black', linestyle=':')
  145. plt.xticks(custom_ticks, custom_labels, fontsize=13)
  146. plt.legend(fontsize=12)
  147. plt.tight_layout()
  148. # plt.savefig(Path("/home/andraz/ChargedShells/Figures/potential_charge_comparison.pdf"), dpi=300)
  149. plt.show()
  150. # TODO: comparison of patch shape at different kappaR and a neutral particle, with fixed patch size
  151. def IC_CS_comparison():
  152. target_patch_size = 0.92
  153. kappaR = 3
  154. params = ModelParams(R=150, kappaR=kappaR)
  155. sigma_m = 0.001
  156. sigma0_array = np.array([-0.0002, 0, 0.0002])
  157. theta = np.linspace(0, np.pi, 1001)
  158. phi = 0.
  159. dist = 1
  160. def fn1(x):
  161. return expansion.MappedExpansionQuad(a_bar=x, kappaR=params.kappaR, sigma_tilde=sigma_m, l_max=30, sigma0=0)
  162. # a_bar is determined only for a neutral particle (patch size only well-defined in this case)
  163. a_bar = patch_size.inverse_potential_patch_size(target_patch_size, fn1, 0.5, params)
  164. potential_ic = []
  165. potential_cs = []
  166. for sigma0 in sigma0_array:
  167. ex_point = expansion.MappedExpansionQuad(a_bar=a_bar, kappaR=params.kappaR,
  168. sigma_tilde=sigma_m, l_max=30, sigma0=sigma0)
  169. potential_ic.append(potentials.inverse_patchy_particle_potential(theta, dist, a_bar, -2 * sigma_m + sigma0,
  170. (sigma_m, sigma_m), params, 30))
  171. potential_cs.append(potentials.charged_shell_potential(theta, phi, dist, ex_point, params))
  172. fig, ax = plt.subplots()
  173. lines = []
  174. for p_ic, p_cs, charge in zip(potential_ic, potential_cs, sigma0_array):
  175. ax.scatter(theta[::50], 1000 * p_ic.T[::50], marker='o', facecolors='none',
  176. edgecolors='tab:red')
  177. l, = ax.plot(theta, 1000 * p_cs.T, label=rf'$\tilde \sigma_0 = {charge}$', linewidth=2)
  178. lines.append(l)
  179. # ax.plot(theta, potential_ic.T, label='IC', ls=':', linewidth=2, marker='o', markevery=50, mfc='none')
  180. ax.tick_params(which='both', direction='in', top=True, right=True, labelsize=12)
  181. ax.set_xlabel(r'$\theta$', fontsize=15)
  182. ax.set_ylabel(r'$\phi$ [mV]', fontsize=15)
  183. custom_ticks = [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4, np.pi]
  184. custom_labels = ['0', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$']
  185. plt.axhline(y=0, color='black', linestyle=':')
  186. plt.axvline(x=target_patch_size, color='black', linestyle=':')
  187. plt.xticks(custom_ticks, custom_labels, fontsize=13)
  188. lines.append(Line2D([0], [0], color='k', label='CSp'))
  189. lines.append(plt.scatter([], [], marker='o', facecolor='none', edgecolor='red', label='ICi'))
  190. plt.legend(handles=lines, fontsize=12)
  191. plt.tight_layout()
  192. plt.savefig(Path("/home/andraz/ChargedShells/Figures/potential_ic_cs_comparison_new.pdf"), dpi=300)
  193. plt.show()
  194. def main():
  195. # models_comparison()
  196. # ic_cs_comparison()
  197. IC_CS_comparison()
  198. # abar_comparison()
  199. # charge_comparsion()
  200. if __name__ == '__main__':
  201. main()