def make_dzdx_poly( dzdx_Ci_polylike_eqn_: Eq, sub_: Dict, ) -> Poly: """ TODO. Args: TODO """ eta_ = eta.subs(sub_) # Bit of a hack - assumes the dzdx ODE has only two "arg" terms # for $\eta=1/4$ if eta_ == Rational(1, 4): dzdx_eqn_ = dzdx_Ci_polylike_eqn_.subs({eta: Rational(1, 4)}) dzdx_eqn_ = Eq(dzdx_eqn_.lhs.args[0]**2 - dzdx_eqn_.lhs.args[1]**2, 0) else: dzdx_eqn_ = dzdx_Ci_polylike_eqn_ return poly(N(dzdx_eqn_.lhs.subs(sub_)), dzdx)
def integrate_dzdx( gmeq: Eq, sub_: Dict, n_pts: int = 200, xivhat0_: float = 1, x_end: float = 0.999, ) -> Tuple[np.ndarray, np.ndarray]: r""" Generate a topographic profile $h(x)$. Achieved by numerically integrating a sequence of $\mathrm{d}z/\mathrm{d}x$ values at regular $x$ values. """ sub_copy = sub_.copy() sub_copy[xivhat_0] = xivhat0_ eta_ = eta.subs(sub_) dzdx_poly_ = make_dzdx_poly(gmeq.dzdx_Ci_polylike_eqn, sub_copy) xhat_array = np.linspace(0, x_end, n_pts, endpoint=True) dzdxhat_array = [ find_dzdx_poly_root(dzdx_poly_, xhat_, xivhat0_, eta_=eta_) for xhat_ in xhat_array ] zhat_array = cumtrapz(dzdxhat_array, xhat_array, initial=0) return (xhat_array, zhat_array)
def plot_Hetc_contours( self, sm: SlicingMath, grids_: Tuple[Any, Any], sub_: Dict, do_Ci: bool, do_modv: bool = False, do_fmt_labels: bool = False, do_aspect: bool = True, do_rxpx: bool = False, pxpz_points=None, do_log2H: bool = False, do_siggrid: bool = True, do_black_contours: bool = False, do_grid: bool = True, do_at_rxcrit: bool = False, contour_nlevels: Optional[Union[int, List, Tuple]] = None, contour_range: Tuple[float, float] = (0, 1), v_contour_range: Tuple[float, float] = (0, 1), contour_values: Optional[List[float]] = None, contour_label_locs: Optional[List] = None, ) -> str: r"""Plot Hamiltonian contours.""" # Create figure rxhat_: float = 0 if do_rxpx else round(float(rxhat.subs(sub_).n()), 4) fig_name_elements: Tuple = ( "Ci" if do_Ci else ("v" if do_modv else "H"), "_rslice" if do_rxpx else "_pslice", f"_eta{float(eta.subs(sub_).n()):g}", f"_Ci{deg(Ci.subs(sub_))}" if do_rxpx else f"_rxhat{rxhat_:g}", ) fig_name: str = ("".join(fig_name_elements)).replace(".", "p") fig: Figure = self.create_figure(fig_name, fig_size=(6, 6)) axes: Axes = plt.gca() labels: Tuple[str, str] = ((r"\hat{r}^x", r"\hat{p}_x") if do_rxpx else (r"\hat{p}_x", r"\hat{p}_z")) xlabel, ylabel = [rf"${label_}$" for label_ in labels] vars_label = rf"$\left({labels[0]},{labels[1]}\right)$" plt.xlabel(xlabel) plt.ylabel(ylabel) if do_grid: plt.grid(":") # Generate a grid of H or Ci for a meshgrid of (px,pz) or (rx,px) H_grid_ = sm.Ci_lambda(*grids_) if do_Ci else sm.H_lambda(*grids_) modv_grid_ = (sm.modv_pxpzhat_lambda(*grids_) if (do_modv and not do_rxpx) else None) if do_siggrid: gstar_signature_grid_ = np.array( grids_[0].shape) # for i_ in [1,2]] gstar_signature_grid_ = np.array([ sm.gstar_signature_lambda(x_, y_) for x_, y_ in zip(grids_[0].flatten(), grids_[1].flatten()) ]).reshape((grids_[0]).shape) gstar_signature_grid_[np.isnan(gstar_signature_grid_)] = 0 # Axis labeling if do_fmt_labels: for axis_ in [axes.xaxis, axes.yaxis]: axis_.set_major_formatter(ticker.FormatStrFormatter("%0.0e")) # Metric signature colour background cmap_: LinearSegmentedColormap = plt.get_cmap("PiYG") if do_siggrid: cf = axes.contourf(*grids_, gstar_signature_grid_, levels=1, cmap=cmap_) divider = make_axes_locatable(axes) cax = divider.append_axes("top", size="6%", pad=0.4) label_levels = np.array([0.25, 0.75]) # mypy: Incompatible types in assignment # (expression has type "List[str]", # variable has type "Tuple[str, str]") tick_labels: Tuple[str, str] = ("mixed: -,+", "positive: +,+") cbar = fig.colorbar( cf, cax=cax, orientation="horizontal", ticks=label_levels, label="metric signature", ) cbar.ax.set_xticklabels(tick_labels) cbar.ax.xaxis.set_ticks_position("top") if do_aspect: axes.set_aspect(1) fig.tight_layout() y_limit: Tuple[float, float] = axes.get_ylim() # beta_crit line axes.set_autoscale_on(False) tan_beta_crit_: float = np.sqrt(float(eta.subs(sub_))) beta_crit_: float = np.round(np.rad2deg(np.arctan(tan_beta_crit_)), 1) x_array: Optional[np.ndarray] = None y_array: Optional[np.ndarray] = None if do_rxpx: # rx (+ve) x_array = grids_[1][0] y_array = (grids_[1][0] * 0 - float(pzhat.subs(sub_)) * tan_beta_crit_) # px (+ve) else: x_array = -grids_[1][0] * tan_beta_crit_ # px (+ve) y_array = grids_[1][0] # pz (-ve) axes.plot( x_array, y_array, "Red", lw=3, ls="-", label=r"$\beta_\mathrm{c} = $" + rf"{beta_crit_}$\degree$", ) # px,pz on-shell point beta_: float = 0 if pxpz_points is not None and not do_rxpx: for i_, (px_, pz_) in enumerate(pxpz_points): axes.scatter(px_, pz_, marker="o", s=70, color="k", label=None) beta_ = np.round(np.rad2deg(np.arctan(float(-px_ / pz_))), 1) beta_label: str = (r"$\beta_0$" if rxhat.subs(sub_) == 0 else r"$\beta$") axes.plot( np.array([0, px_ * 10]), np.array([0, pz_ * 10]), "-.", color="b", label=beta_label + r"$ = $" + rf"{beta_:g}$\degree$" if i_ == 0 and not do_Ci else None, ) # pz=pz_0 constant line if pxpz_points is not None: for i_, (px_, pz_) in enumerate(pxpz_points): axes.plot( np.array([0, px_ * 100]), np.array([pz_, pz_]), ":", lw=2, color="grey", label=r"$\hat{p}_{z} = \hat{p}_{z_0}$" if i_ == 0 else None, ) beta_ = np.round(np.rad2deg(np.arctan(float(-px_ / pz_))), 0) cmap_ = plt.get_cmap("Greys_r") colors_: Tuple[str] = ("k", ) # |v| contours levels_: Optional[np.ndarray] = None if do_modv: fmt_modv: Callable = lambda modv_: f"{modv_:g}" # levels_ = np.linspace(0,0.5, 51, endpoint=True) n_levels_ = ( contour_nlevels if isinstance(contour_nlevels, int) else contour_nlevels[0] if contour_nlevels is not None else 1) levels_ = np.linspace(v_contour_range[0], v_contour_range[1], n_levels_, endpoint=True) modv_contours_ = axes.contour(*grids_, modv_grid_, levels_, cmap=cmap_) # levels_[levels_!=levels_H0p5[0]], linestyles=['solid'], # cmap=cmap_ if not do_black_contours else None, # colors=colors_ if do_black_contours else None) axes.clabel( modv_contours_, fmt=fmt_modv, inline=True, colors="0.3", fontsize=9, ) # H, Ci contours # If we provide specific contour values, assume they are Ci values, # - otherwise, assume we want to contour H if contour_values is None: # H contours levels_H0p5: Optional[np.ndarray] = None if not do_log2H: n_levels_ = ( contour_nlevels if isinstance(contour_nlevels, int) else contour_nlevels if contour_nlevels is not None else 1) logging.debug(f"contour_nlevels={contour_nlevels}") logging.debug(f"n_levels_={contour_nlevels}") levels_ = np.concatenate([ np.linspace(0.0, 0.5, n_levels_[0], endpoint=False), np.flip( np.linspace( contour_range[1], 0.5, n_levels_[1], endpoint=False, )), ]) levels_H0p5 = np.array([0.5]) def fmt_H(H_): return rf"{H_:g}" def fmt_H0p5(H_): return rf"H={H_:g}" manual_location = (np.array([0.6, -0.25])) * np.abs(y_limit[0]) else: n_levels_ = int(contour_range[1] - contour_range[0] + 1) n_levels_ = n_levels_ * 2 - 1 if do_rxpx else n_levels_ levels_ = np.linspace(contour_range[0], contour_range[1], n_levels_, endpoint=True) levels_H0p5 = np.array([0]) def fmt_H_rxpx(H_): H__ = np.round( 10**H_ / 2, 2 if 10**H_ < 0.5 else (1 if 10**H_ < 5 else 0), ) return rf"$H={H__:g}$" def fmt_H_pxpz(H_): return rf"$2H=10^{H_:g}$" fmt_H = fmt_H_rxpx if do_rxpx else fmt_H_pxpz def fmt_H0p5(H): # type: ignore return r"$H=0.5$" manual_location = (0.1, -7) levels__ = (levels_H0p5[0] if levels_ is None else levels_[levels_ != levels_H0p5[0]]) contours_ = axes.contour( *grids_, np.log10(2 * H_grid_) if do_log2H else H_grid_, levels__, linestyles=["solid"], cmap=cmap_ if not do_black_contours else None, colors=colors_ if do_black_contours else None, ) axes.clabel(contours_, inline=True, fmt=fmt_H, fontsize=9) contour_ = axes.contour( *grids_, np.log10(2 * H_grid_) if do_log2H else H_grid_, levels_H0p5, linewidths=[3], cmap=cmap_ if not do_black_contours else None, colors=colors_ if do_black_contours else None, ) axes.clabel( contour_, inline=True, fmt=fmt_H0p5, fontsize=14, manual=[(manual_location[0], manual_location[1])] if manual_location is not None else None, ) else: # Ci contours def fmt_Ci(Ci_): return r"$\mathsf{Ci}=$" + f"{Ci_:g}" + r"$\degree$" contour_values_ = (np.log10(2 * np.array(contour_values)) if do_log2H else np.array(contour_values)) contours_ = axes.contour( *grids_, np.log10(2 * H_grid_) if do_log2H else H_grid_, contour_values_, cmap=cmap_ if not do_black_contours else None, colors=colors_ if do_black_contours else None, ) axes.clabel( contours_, inline=True, fmt=fmt_Ci, fontsize=12, manual=contour_label_locs, ) axes.set_autoscale_on(False) # H() or Ci() or v() annotation x_: float = 1.25 if not do_Ci: axes.text( *[x_, 1.1], (r"$|\mathbf{\hat{v}}|$" if do_modv else r"$\mathcal{H}$") + vars_label, horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, fontsize=18, color="k", ) Ci_: float = Ci.subs(sub_) axes.text( *[x_, 0.91], r"$\mathsf{Ci}=$" + rf"${deg(Ci_)}\degree$", horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, fontsize=16, color="k", ) else: axes.text( *[x_, 1.0], r"$\mathsf{Ci}$" + vars_label, horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, fontsize=18, color="k", ) # eta annotation eta_: float = eta.subs(sub_) axes.text( *[x_, 0.8], rf"$\eta={eta_}$", horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, fontsize=16, color="k", ) # pz or rx annotation label_: Optional[str] = None val_: Optional[float] = None if do_rxpx: label_ = r"$\hat{p}_{z_0}=$" val_ = round(pzhat.subs(sub_), 1) else: label_ = (r"$\hat{r}^x_{\mathrm{crit}}=$" if do_at_rxcrit else r"$\hat{r}^x=$") val_ = round(rxhat.subs(sub_), 4 if do_at_rxcrit else 4) x_ += 0.01 if do_at_rxcrit else 0.0 axes.text( *[x_, 0.68], label_ + rf"${val_}$", transform=axes.transAxes, horizontalalignment="center", verticalalignment="center", fontsize=16, color="k", ) axes.legend(loc=[1.07, 0.29], fontsize=15, framealpha=0) return fig_name
def plot_modv_slice( self, sm: SlicingMath, sub_: Dict, psub_: Dict, do_at_rxcrit: bool = False, ) -> str: r"""Plot :math`|v|` slice.""" rxhat_: float = round(float(rxhat.subs(psub_).n()), 4 if do_at_rxcrit else 4) fig_name_elements: Tuple = ( "v_pz_H0p5", f"_eta{float(eta.subs(sub_).n()):g}", f"_Ci{deg(Ci.subs(sub_))}", f"_rxhat{rxhat_:g}", ) fig_name: str = ("".join(fig_name_elements)).replace(".", "p") _ = self.create_figure(fig_name, fig_size=(6, 5)) axes: Axes = plt.gca() pxhat_eqn_: Eq = sm.pxhatsqrd_Ci_polylike_eqn(sub_, pzhat) # .subs(sub_) pxhat_poly_: Poly = poly(pxhat_eqn_.lhs.subs(psub_).n(), pxhat) pzhat0_: float = float(sm.pzhat_lambda(sub_, 0, 1).n()) # For H=1/2 pzhat_array: np.ndarray = np.flipud( np.linspace( -30, 0, 31, endpoint=bool(rxhat.subs(psub_) < 0.95 and eta.subs(sub_) < 1), )) pxhat_array: np.ndarray = np.array([ float( px_value( rxhat.subs(psub_), pzhat_, pxhat_poly_, px_var_=pxhat, pz_var_=pzhat, )) for pzhat_ in pzhat_array ]) modp_array: np.ndarray = np.sqrt(pxhat_array**2 + pzhat_array**2) modv_array: np.ndarray = np.array([ sm.modv_pxpzhat_lambda(pxhat_, pzhat_) for pxhat_, pzhat_ in zip(pxhat_array, pzhat_array) ]) projv_array: np.ndarray = modv_array * np.cos( np.arctan(-pxhat_array / pzhat_array)) plt.xlim(min(pzhat_array), max(pzhat_array)) plt.ylim(0, max(modv_array) * 1.05) axes.set_autoscale_on(False) plt.plot( pzhat_array, modv_array, "o-", color="k", ms=3, label=r"$|\mathbf{\hat{v}}|$", ) plt.plot( pzhat_array, projv_array, "-", color="r", ms=3, label=r"$|\mathbf{\hat{v}}|\cos\beta$", ) plt.plot( pzhat_array, (1 / modp_array), "-", color="b", ms=3, label=r"$1/|\mathbf{\hat{p}}|$", ) plt.plot( [pzhat0_, pzhat0_], [0, max(modv_array) * 1.05], ":", color="k", label=r"$\hat{p}_z = \hat{p}_{z_0}$", ) plt.legend(loc="lower left") plt.grid("on") plt.ylabel(r"$|\mathbf{\hat{v}}|$ " + r"or $|\mathbf{\hat{v}}|\cos\beta$ " + r"or $1/|\mathbf{\hat{p}}|$") plt.xlabel(r"$\hat{p}_z\left(H=\frac{1}{2}\right)$") # Annotations x_: float = 1.19 r_label_: str = (r"$\hat{r}^x_{\mathrm{crit}}=$" if do_at_rxcrit else r"$\hat{r}^x=$") r_value_: float = round(rxhat.subs(psub_), 4 if do_at_rxcrit else 4) labels: Tuple = ( r"$\mathcal{H}=\frac{1}{2}$", r"$\mathbf{\hat{p}}(\mathbf{\hat{v}})=1$", rf"$\eta={eta.subs(sub_)}$", r"$\mathsf{Ci}=$" + rf"${deg(Ci.subs(sub_))}\degree$", r_label_ + rf"${r_value_}$", ) for i_, label_ in enumerate(labels): plt.text( *(x_, 0.9 - i_ * 0.15), label_, fontsize=16, color="k", horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, ) return fig_name
def plot_dHdp_slice( self, sm: SlicingMath, sub_: Dict, psub_: Dict, pxhat_: float, do_detHessian: bool = False, do_at_rxcrit: bool = False, ) -> str: r"""Plot :math`dH/dp` slice.""" rxhat_: float = round(float(rxhat.subs(psub_).n()), 4 if do_at_rxcrit else 4) fig_name_elements: Tuple = ( "detHessian" if do_detHessian else "d2Hdpz2" f"_eta{float(eta.subs(sub_).n()):g}", f"_Ci{deg(Ci.subs(sub_))}", f"_rxhat{rxhat_:g}", ) fig_name: str = ("".join(fig_name_elements)).replace(".", "p") _ = self.create_figure(fig_name, fig_size=(6, 5)) axes: Axes = plt.gca() pzhat0_ = float(sm.pzhat_lambda(sub_, 0, 1).n()) x_array: np.ndarray = np.flipud( np.linspace( -30, 0, 301, endpoint=bool(rxhat.subs(psub_) < 0.95 and eta.subs(sub_) < 1), )) y_array: np.ndarray = np.array(None) if do_detHessian: y_array = np.array([ sm.detHessianSqrd_lambda(pxhat_, pzhat_) for pzhat_ in x_array ]) else: y_array = np.array( [sm.d2Hdpzhat2_lambda(pxhat_, pzhat_) for pzhat_ in x_array]) cmap_: LinearSegmentedColormap = plt.get_cmap("PiYG") y_label_: str = (r"$\det\left(\mathrm{Hessian}\right)$" if do_detHessian else r"${\partial^2\mathcal{H}}/{\partial\hat{p}_z^2}$") # l_label_ = r'$\det\left(\text{Hessian}\right)$' if do_detH \ # else r'$\frac{\partial^2\mathcal{H}}{\partial\hat{p}_z^2}$' # font_size_ = 16 if not do_detH else None plt.plot(x_array, y_array, "-", color="k", ms=3) # , label=l_label_) axes.fill_between( x_array, y_array, y2=0, where=y_array >= 0, interpolate=True, color=cmap_(0.75), ) axes.fill_between( x_array, y_array, y2=0, where=y_array <= 0, interpolate=True, color=cmap_(0.25), ) axes.scatter(pzhat0_, 0, marker="o", s=40, color="k", label=None) # plt.legend(loc='center left', fontsize=font_size_) plt.grid("on") plt.ylabel(y_label_) plt.xlabel(r"$\hat{p}_z$") # plt.xlabel(r'$\hat{p}_z'+rf'\,\,|\,\,p_x={round(pxhat_,2)}$') # Annotations x_: float = 1.19 r_label_: str = (r"$\hat{r}^x_{\mathrm{crit}}=$" if do_at_rxcrit else r"$\hat{r}^x=$") r_value_: float = round(rxhat.subs(psub_), 4 if do_at_rxcrit else 4) labels: Tuple = ( rf"$\eta={eta.subs(sub_)}$", r"$\mathsf{Ci}=$" + rf"${deg(Ci.subs(sub_))}\degree$", r"$\hat{p}_x=$" + rf"${round(pxhat_,2)}$", r_label_ + rf"${r_value_}$", ) for i_, label_ in enumerate(labels): plt.text( *(x_, 0.9 - i_ * 0.15), label_, fontsize=16, color="k", horizontalalignment="center", verticalalignment="center", transform=axes.transAxes, ) return fig_name