RayDraping
- class PlasmaCalcs.tools.sci_tools.ray_draping.RayDraping(*, scene, anchor, fov=None, ray_s=None)
Bases:
RayDrapingCorerepresentation of the entire ray draping problem, including mapping calculations.
Consider using self.wbox(), to get “the answer”, i.e. ray points mapped into box system.scene: dict or RayDrapeScenescene conditions for ray draping problem.dict –> convert to RayDrapeScene.Should have keys: R0, XEXT, YEXT, ZEXT, T.anchor: dict or RayDrapeAnchoranchor point for ray draping problem.dict –> convert to RayDrapeAnchor.May have any of these keys: Asph_theta, Asph_phi, Abox_x, Abox_y.(Missing keys use RayDrapeAnchor defaults.)fov: 3-tuple of (“standard”, Nx, Ny), None, xr.DataArray, or RayDrapeFOVfield-of-view grid for ray draping problem.None –> specify it later, by setting self.fov = value.xr.DataArray –> convert to RayDrapeFOV.Should have ‘component’ dimension associated with x, y, z coords of each point,in sph system cartesian coords centered at r=0.(“standard”, Nx, Ny) –> use self.standard_fov(Nx, Ny) to create reasonable FOV,chosen such as the rectangle at zsph=R0+ZEXT) which fully covers entire box(without any smart rotations yet; edges parallel to x sph and y sph axes).ray_s: None, int, dict, or xr.DataArray including ‘ray_s’ or ‘ray_s_dim’ dimension.Distance along each ray, from FOV. Rays are parametrized (in sph system) as:w(s) = F + rayhat * s, where:rayhat = (F - T)/|F - T|,F is the point in FOV corresponding to this ray (there is one ray per FOV point),T is the telescope/observer position.Must include the ‘ray_s’ or ‘ray_s_dim’ dimension. Can be 1D if all rays have same spacing,but might also have same dims as FOV, to specify different spacing for each ray.None –> specify later (getting self.ray_s before specifying will just cause crash).int –> number of points along each ray, choosing self.standard_ray_s_limits() for min and max s,while using inclusive=(False,False) when generating the grid (to avoid including edge points).standard_ray_s_limits() picks s limits to precisely cover full paths through the draped box region.dict –> kwargs for pc.xarray_grid(). Uses self.standard_ray_s_limits() for min and max, unless provided.Also uses name=’ray_s’ unless provided, and inclusive=(False,False) unless provided.[TODO] add “maxstep” option to xarray_grid(), to enable “maxstep = simulation dx”.Workaround to solve that problem for now: specify ray_s=None when making drape, then later do:smin, smax = drape.standard_ray_s_limits()ray_s=pc.xarray_grid(smin, smax, N=1+int(np.max((smax-smin)/dx)))Examples: 100; dict(N=100); pc.xr1d([100, 200, 300, 400], name=’ray_s’).(Use self.ray_s to see ray_s value, and self.ray_s_array to see the actual ray_s xr.DataArray.)EXAMPLE——-# Below is a somewhat exaggerated example for visualization purposes;# if the 3D simulation box is really that large compared to the Sun,# then curvature effects might be physically significant within the plasma,# so maybe a plane-parallel simulation isn’t the best idea on that scale.import PlasmaCalcs as pcimport numpy as npRsun = 6.957e8 # [m]AU = pc.DEFAULTS.PHYSICAL.CONSTANTS_SI[‘AU’] # 1.495978707e11 [m]scene = pc.RayDrapeScene(R0=Rsun,XEXT=1.0*Rsun,YEXT=0.7*Rsun,ZEXT=1.0*Rsun,T=1*AU)anchor = pc.RayDrapeAnchor(Asph_theta=np.pi*3/8,Asph_phi=np.pi/4)drape = pc.RayDraping(scene=scene, anchor=anchor,fov=(“standard”, 7, 4),ray_s=30)drape.plot(‘both’, periodic=False)Methods
box_to_sph(wbox)return wsph corresponding to any wbox point or points.
from_dict(d)create RayDraping instance from dict, with keys corresponding to __init__ kwargs,
get_post(x, y[, system, dim, N])returns this post, i.e. points corresponding to line from (x,y,0) to (x,y,ZEXT) in box system.
keep_in_box(wsph, *[, in_box])return wsph points masked to only those inside the draped box region.
periodic_wrap(wbox)return wbox points wrapped periodically into x and y box extents.
plot([system, box, fov, rays, max_n_rays, ...])visualize self by plotting.
plot_post(x, y[, ax_sph, ax_box])plot a post (i.e. line from z=0 to z=ZEXT in box system) on the indicated ax(es).
self.ray_s as an xr.DataArray including 'ray_s' or 'ray_s_dim' dimension.
ray_tangents([system, unit_vector])return array of vectors pointing in ray directions (i.e. tangent to ray path).
rayhat()rayhat, i.e. unit vector along each ray in sph system cartesian coords.
rays([system, in_box, periodic])return rays, i.e. points along each ray, in desired coordinate system.
sph_to_box(wsph, *[, in_box, periodic])return wbox corresponding to any wsph point or points.
standard_FOV(Nx, Ny, *[, xdim, ydim])return standard FOV (array) with (Nx, Ny) points.
standard_fov(Nx, Ny, *[, xdim, ydim])return standard fov (RayDrapeFOV) with (Nx, Ny) points.
return (xmin, xmax, ymin, ymax) for standard FOV.
return standard ray_s with N points along each ray.
return (min, max) s to use for self.ray_s, corresponding to full overlap with the box.
wbox(*[, in_box, periodic])return wbox, i.e. the points along each ray, in box system cartesian coords.
wsph(*[, in_box])return wsph, i.e. the points along each ray in sph system cartesian coords centered at r=0.
_get_box_corners([system])return all 8 corners of the box, as xr.DataArray with 'corner' and 'component' dims.
_get_box_plot_values(*[, system, include])return dict of values related to box, for self.plot(box=True).
_get_box_top([system, Nu, Nv])return top surface of box, with Nu x Nv points,
_get_fov_value(value)convert value to RayDrapeFOV (unless None) appropriate for storage in self.fov.
list of contents for self.__repr__
Attributes
alias to self.anchor.Abox_x
alias to self.anchor.Abox_y
alias to self.anchor.Asph
alias to self.fov.FOV
PLOT_DEFAULTSalias to self.scene.R0
alias to self.scene.T
alias to self.scene.X0
x-coordinate of right edge of box in box system.
alias to self.scene.XEXT
alias to self.scene.Y0
y-coordinate of top edge of box in box system.
alias to self.scene.YEXT
alias to self.scene.ZEXT
field-of-view grid for ray draping problem.
number of rays, i.e. number of points in self.FOV.
return name of ray_s dimension, i.e. 'ray_s' or 'ray_s_dim', depending on which one self.ray_s_array() has.
- property Abox_x
alias to self.anchor.Abox_x
- property Abox_y
alias to self.anchor.Abox_y
- property Asph
alias to self.anchor.Asph
- property FOV
alias to self.fov.FOV
- property R0
alias to self.scene.R0
- property T
alias to self.scene.T
- property X0
alias to self.scene.X0
- property X1
x-coordinate of right edge of box in box system. == X0 + XEXT.
- property XEXT
alias to self.scene.XEXT
- property Y0
alias to self.scene.Y0
- property Y1
y-coordinate of top edge of box in box system. == Y0 + YEXT.
- property YEXT
alias to self.scene.YEXT
- property ZEXT
alias to self.scene.ZEXT
- _get_box_corners(system='box')
return all 8 corners of the box, as xr.DataArray with ‘corner’ and ‘component’ dims.
Corners are in box system unless system==’sph’, in which case converted via self.box_to_sph().
- _get_box_plot_values(*, system='box', include=['o', 'x', 'A', 'posts', 'bottom', 'top'])
return dict of values related to box, for self.plot(box=True).
Results are xr.DataArrays with ‘component’ dim telling x,y,z coords.system: ‘box’ or ‘sph’which system to get box values for.‘box’ –> returns values in box system cartesian coords. No conversion necessary.‘sph’ –> convert to sph system cartesian coords centered at r=0, via self.box_to_sph().include: list of strs, tells which keys to include. (Use ‘posts’ to include all posts):‘o’: point at xbox=X0, ybox=Y0, zbox=0. This is the lower-left point in the box.‘x’: point at xbox=X1, ybox=Y0, zbox=0‘A’: the anchor point‘post00’: (xbox=X0,ybox=Y0), zbox from 0 to ZEXT, with dim ‘_pc_post_i_’‘post10’: (xbox=X1,ybox=Y0), zbox from 0 to ZEXT, with dim ‘_pc_post_i_’‘post01’: (xbox=X0,ybox=Y1), zbox from 0 to ZEXT, with dim ‘_pc_post_i_’‘post11’: (xbox=X1,ybox=Y1), zbox from 0 to ZEXT, with dim ‘_pc_post_i_’‘bottom’: zbox=0 surface, with dims ‘_pc_surface_u_’, and ‘_pc_surface_v_’‘top’: zbox=ZEXT surface, with dims ‘_pc_surface_u_’, and ‘_pc_surface_v_’(above, X1=X0+XEXT; Y1=Y0+YEXT)The number of points along the posts and surface dims are determined byself.PLOT_DEFAULTS[‘post_points’] and self.PLOT_DEFAULTS[‘surface_points’].
- _get_box_top(system='box', *, Nu=21, Nv=21)
return top surface of box, with Nu x Nv points,
along dims _pc_surface_u_ and _pc_surface_v_.Points are in box system unless system==’sph’, in which case converted via self.box_to_sph().
- _get_fov_value(value)
convert value to RayDrapeFOV (unless None) appropriate for storage in self.fov.
- _repr_contents()
list of contents for self.__repr__
- anchor_cls
alias of
RayDrapeAnchor
- box_to_sph(wbox)
return wsph corresponding to any wbox point or points.
i.e., returns w expressed in sph system cartesian coords centered at r=0.wbox: xarray object (e.g. DataArray)points in box system cartesian coords,with ‘component’ dimension associated with x, y, z coords of each point.(Possibly useful: wbox=xr.concat([xbox, ybox, zbox], dim=’component’))
- property fov
field-of-view grid for ray draping problem.
For efficiency, RayDrapeFOV is created immediately when setting self.fov (unless None).(E.g., self.fov=arr; self.fov # == RayDrapeFOV(arr))See help(type(self)) for more details about possible values.
- fov_cls
alias of
RayDrapeFOV
- classmethod from_dict(d)
create RayDraping instance from dict, with keys corresponding to __init__ kwargs,
or to kwargs used to initialize scene, anchor, and fov, e.g. can provide “T” here.Cannot overlap __init__ and scene/anchor/fov kwargs;e.g. cannot provide both “T” and “scene”.Keys allowed are:‘scene’ or scene kwargs: {‘ZEXT’, ‘XEXT’, ‘R0’, ‘Y0’, ‘X0’, ‘T’, ‘YEXT’}‘anchor’ or anchor kwargs: {‘Abox_y’, ‘Asph_phi’, ‘Asph_theta’, ‘Abox_x’}‘fov’ or fov kwargs: {‘FOV’}‘ray_s’
- get_post(x, y, system='box', *, dim='_pc_post_i_', N=2)
returns this post, i.e. points corresponding to line from (x,y,0) to (x,y,ZEXT) in box system.
Result is an xarray.DataArray with ‘component’ dimension, converted to the indicated system.x, y: scalarscoordinates of post in box system.In box system, the post is a line from (x,y,0) to (x,y,ZEXT).dim: strname of dimension for points along post.N: intnumber of points along post (including endpoints).
- keep_in_box(wsph, *, in_box=True)
return wsph points masked to only those inside the draped box region.
i.e., only keep points where R0 <= |wsph| <= R0 + ZEXT.wsph: xarray object (e.g. DataArray)points in sph system cartesian coords centered at r=0,with ‘component’ dimension associated with x, y, z coords of each point.(Possibly useful: wsph=xr.concat([xsph, ysph, zsph], dim=’component’))in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.
- property n_rays
number of rays, i.e. number of points in self.FOV
- periodic_wrap(wbox)
return wbox points wrapped periodically into x and y box extents.
The wrapping is done using modulus operation, accounting for X0 and Y0 if nonzero:xbox = (xbox - X0) % XEXT + X0ybox = (ybox - Y0) % YEXT + Y0wbox: xarray object (e.g. DataArray)points in box system cartesian coords,with ‘component’ dimension associated with x, y, z coords of each point.(Possibly useful: wbox=xr.concat([xbox, ybox, zbox], dim=’component’))
- plot(system='both', *, box=True, fov=True, rays=True, max_n_rays=100, in_box='lower', periodic=True, ax=None, axsize=(6, 6), aspect=True, view_init=True, extra_points=None, extra_lines=None)
visualize self by plotting. Useful for sanity checks!
Returns matplotlib ax (or tuple of (ax_sph, ax_box) if system=’both’).If using Jupyter, for easier 3D visualization consider running a cell with command:%matplotlib notebook(Below, False-ness checked via “is False”, to avoid ambiguity with empty dicts)system: ‘both’, ‘sph’ or ‘box’which system(s) to visualize.‘both’ –> make a figure with two plots, one for each system.‘sph’ –> ‘sph’ system, where rays are straight, and box top and bottom are curved.‘box’ –> ‘box’ system, where rays are curved, and box top and bottom are flat.box: bool or dict of dictswhether to plot the box boundaries.True –> use default box plotting parameters (self.PLOT_DEFAULTS[‘box’]).dict of dicts –> customize box plotting parameters. vals are dict or False.Use False to indicate “don’t plot this part”.Skip key to indicate “use default kwargs for this part”.‘bottom’: kwargs for ax.plot_surface() for bottom of box (zbox=0 plane)‘top’: kwargs for ax.plot_surface() for top of box (zbox=ZEXT plane)‘posts’: kwargs for ax.plot() for vertical posts connecting bottom/top corners‘A’: kwargs for ax.scatter() for anchor point‘o’: kwargs for ax.scatter() for point at xbox=X0, ybox=Y0, zbox=0‘x’: kwargs for ax.scatter() for point at xbox=XEXT, ybox=Y0, zbox=0fov: bool or dictwhether to plot the FOV points.True –> use default FOV plotting parameters (self.PLOT_DEFAULTS[‘fov’]).dict –> customize FOV plotting parameters. Can provide any kwargs for ax.scatter().rays: bool or dictwhether to plot the rays.True –> use default ray plotting parameters (self.PLOT_DEFAULTS[‘box’]).dict –> customize ray plotting parameters. Can provide any kwargs for ax.plot().Some kwargs are treated specially: ‘colors’ and ‘cmap’if ‘colors’ is provided, cycle these colors if there are more colors than rays,else use ‘cmap’, or self.PLOT_DEFAULTS[‘rays_cmap’] if ‘cmap’ not provided.max_n_rays: int or Nonemaximum number of rays to plot, else crash (if doing fov and/or rays).prevents accidentally plotting way too much if doing production-grade RayDraping.None –> no limit.in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.(The check here applies only to plotted rays)periodic: boolwhether to wrap points periodically into x and y box extents.True –> like draping the box periodically around the sphere.False –> mainly useful for debugging… are there other use cases?(The wrapping here applies only to plotted rays and FOV points when system==’box’)(If periodic wrapping leads to weird-looking lines crossing the box,consider using rays={‘linestyle’:’none’, ‘marker’:’.’} to just plot points.)ax: None or matplotlib Axes3D objectAxes to plot on. None –> create new figure and axes.Incompatible with system=’both’.axsize: tuple of two ints(x,y) size of new figure, per axes (only if making new axes because ax is None).figsize = (2x, y) if system=’both’, else (x,y).aspect: bool or 3-tuple of numberswhether to set aspect ratio for 3D axes.True –> set aspect based on self.PLOT_DEFAULTS[‘view_init’]. (default: (1,1,1))3-tuple –> (x,y,z) scaling to use.(Matplotlib is annoying about this, so we have to do:sizes=[xmax-xmin, ymax-ymin, zmax-zmin] from get_xlim(), get_ylim(), get_zlim(),ax.set_box_aspect(sizes[0]*aspect[0], sizes[1]*aspect[1], sizes[2]*aspect[2]))view_init: bool or dictwhether to ax.view_init().True –> use self.PLOT_DEFAULTS[‘view_init’].dict –> dict of kwargs for ax.view_init(). (Consider: ‘elev’, ‘azim’, ‘roll’.)
- plot_post(x, y, ax_sph=None, ax_box=None, **kw_plot)
plot a post (i.e. line from z=0 to z=ZEXT in box system) on the indicated ax(es).
x, y: scalars
coordinates of post in box system.In box system, the post is a line from (x,y,0) to (x,y,ZEXT).ax_sph, ax_box: None or matplotlib axes objectsplots post in sph system on ax_sph, in box system on ax_box.None –> don’t plot on that system.At least one of these two inputs must be provided, else crash.Additional kwargs go to matplotlib ax.plot() calls.Example (plots post at x=5, y=7 in both systems):draper = RayDraping(…)axes = draper.plot(system=’both’)draper.plot_post(5, 7, *axes)# equivalent: draper.plot_post(5, 7, ax_sph=axes[0], ax_box=axes[1])
- ray_s_array()
self.ray_s as an xr.DataArray including ‘ray_s’ or ‘ray_s_dim’ dimension.
Behavior depends on self.ray_s:xr.DataArray –> if has ‘ray_s’ or ‘ray_s_dim’ dim, return as-is, else crash (DimensionalityError)None –> crash (InputMissingError)int –> use this many points along each ray, with s_min, s_max = self.standard_ray_s_limits()dict –> pass kwargs to pc.xarray_grid(), with min, max = self.standard_ray_s_limits() unless provided.
- property ray_s_dim
return name of ray_s dimension, i.e. ‘ray_s’ or ‘ray_s_dim’, depending on which one self.ray_s_array() has.
[EFF] for now this just checks dims of self.ray_s_array() (i.e. it recomputes that array every time),rather than guessing properly before the array is computed.
- ray_tangents(system='box', *, unit_vector=False)
return array of vectors pointing in ray directions (i.e. tangent to ray path).
The implementation here takes derivatives along the ‘ray_s’ or ‘ray_s_dim’ dimension,which may produce artifacts at edges of ray_s.system: ‘box’ or ‘sph’‘box’ –> return directions along rays in box system‘sph’ –> equivalent to self.rayhat() (which is a constant for each ray)unit_vector: boolwhether to convert to unit vector.(‘sph’ result will always be unit vector, regardless.)False –> ‘box’ result will just be derivative of ray with respect to ray_s.
- rayhat()
rayhat, i.e. unit vector along each ray in sph system cartesian coords.
rayhat has dimensions of self.FOV,
as well as ‘component’ dimension associated with x, y, z coords of each point.rayhat = (F - T)/|F - T|, where:F is the point in FOV corresponding to this ray (there is one ray per FOV point),T is the telescope/observer position.
- rays(system='box', *, in_box=True, periodic=True)
return rays, i.e. points along each ray, in desired coordinate system.
Result is an xr.DataArray with dims from self.FOV, ‘ray_s’ or ‘ray_s_dim’,and ‘component’ dim associated with x, y, z coords of each point.system: ‘box’ or ‘sph’‘box’ –> return points in box system cartesian coords.‘sph’ –> return points in sph system cartesian coords centered at r=0.in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.periodic: boolwhether to wrap points periodically into x and y box extents.True –> like draping the box periodically around the sphere.False –> mainly useful for debugging… are there other use cases?(only used if system==’box’)Equivalent to self.wbox() or self.wsph(), depending on system.
- scene_cls
alias of
RayDrapeScene
- sph_to_box(wsph, *, in_box=False, periodic=True)
return wbox corresponding to any wsph point or points.
i.e., returns w expressed in box system cartesian coords.wsph: xarray object (e.g. DataArray)points in sph system cartesian coords centered at r=0,with ‘component’ dimension associated with x, y, z coords of each point.(Possibly useful: wsph=xr.concat([xsph, ysph, zsph], dim=’component’))in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.(Use False for efficiency if this was already checked elsewhere!)periodic: boolwhether to wrap points periodically into x and y box extents.True –> like draping the box periodically around the sphere.False –> mainly useful for debugging… are there other use cases?
- standard_FOV(Nx, Ny, *, xdim='FOVx', ydim='FOVy')
return standard FOV (array) with (Nx, Ny) points.
This is chosen from scene and anchor params,as rectangle (at zsph=R0+ZEXT) with size chosen to cover entire box,and edges parallel to x sph and y sph axes.It assumes that T is along sph z axis (else crash with NotImplementedError)See help(PlasmaCalcs.ray_draping) FOV POSITION AND SIZE for more details.See also: self.standard_fov(), self.standard_fov_limits()
- standard_fov(Nx, Ny, *, xdim='FOVx', ydim='FOVy')
return standard fov (RayDrapeFOV) with (Nx, Ny) points.
This is chosen from scene and anchor params,as rectangle (at zsph=R0+ZEXT) with size chosen to cover entire box,and edges parallel to x sph and y sph axes.It assumes that T is along sph z axis (else crash with NotImplementedError)See help(PlasmaCalcs.ray_draping) FOV POSITION AND SIZE for more details.See also: self.standard_FOV(), self.standard_fov_limits()
- standard_fov_limits()
return (xmin, xmax, ymin, ymax) for standard FOV.
This is chosen from scene and anchor params,as rectangle (at zsph=R0+ZEXT) with size chosen to cover entire box,and edges parallel to x sph and y sph axes.It assumes that T is along sph z axis (else crash with NotImplementedError)See help(PlasmaCalcs.ray_draping) FOV POSITION AND SIZE for more details.See also: self.standard_FOV(), self.standard_fov()
- standard_ray_s(N)
return standard ray_s with N points along each ray.
Equivalent: self.ray_s_array() when self.ray_s == N.Equivalent: xarray_grid(*self.standard_ray_s_limits(), N=N, **self._RAY_S_GRID_DEFAULTS)(self._RAY_S_GRID_DEFAULTS is by default equivalent to: name=’ray_s’, inclusive=(False, False))
- standard_ray_s_limits()
return (min, max) s to use for self.ray_s, corresponding to full overlap with the box.
Each ray may have its own (min, max) pair, so each is an xarray with same dims as self.FOV.See help(PlasmaCalcs.ray_draping) RAY BOUNDARIES section for more details.Value will be NaN for rays which never enter the draped box region.
- wbox(*, in_box=True, periodic=True)
return wbox, i.e. the points along each ray, in box system cartesian coords.
These are the curved paths which are the “final answer” for the ray draping problem.wbox has dimensions of self.FOV plus ‘ray_s’ or ‘ray_s_dim’ dimension,as well as ‘component’ dimension associated with x, y, z coords of each point.in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.periodic: boolwhether to wrap points periodically into x and y box extents.True –> like draping the box periodically around the sphere.False –> mainly useful for debugging… are there other use cases?
- wsph(*, in_box=True)
return wsph, i.e. the points along each ray in sph system cartesian coords centered at r=0.
wsph has dimensions of self.FOV plus ‘ray_s’ or ‘ray_s_dim’ dimension,
as well as ‘component’ dimension associated with x, y, z coords of each point.wsph = F + rayhat * s, where:rayhat = (F - T)/|F - T|,F is the point in FOV corresponding to this ray (there is one ray per FOV point),T is the telescope/observer position.in_box: bool, ‘lower’, or ‘upper’whether to check that points will fall inside the draped box region,masking all other points using NaNs.‘lower’ –> only check lower bound: R0 <= |wsph|.‘upper’ –> only check upper bound: |wsph| <= R0 + ZEXT.