Skip to content
Snippets Groups Projects
Commit 4f13dda4 authored by Adam Paquette's avatar Adam Paquette
Browse files
parents b33ed314 94c02baf
Branches
Tags
No related merge requests found
......@@ -30,7 +30,7 @@ before_install:
- conda env update -n test -f environment.yml
script:
- pytest tests
- PYTHONPATH=. pytest tests
after_success:
- coveralls
......
......@@ -2,16 +2,26 @@ name: knoten
channels:
- conda-forge
- usgs-astrogeology
- plotly
dependencies:
- python >= 3
- coveralls
- csmapi
- gdal
- holoviews
- jinja2
- jupyter
- matplotlib
- numpy
- pytest
- plio
- plotly
- plotly-orca
- psutil
- pvl
- pyproj
- pysis
- pytest
- python>=3
- requests
- scipy
- matplotlib
- shapely
- usgscsm
%% Cell type:markdown id: tags:
# Comparing a USGSCSM and ISIS camera for Cassini ISS
%% Cell type:code id: tags:
``` python
import pvl
import numpy as np
import os
import pandas as pd
import knoten
import csmapi
os.environ['ISISROOT'] = '/usgs/pkgs/isis3.8.0_RC1/install'
from pysis import isis
from pysis.exceptions import ProcessError
```
%% Cell type:markdown id: tags:
## Make a CSM sensor model
Requires N1702360370_1.LBL and N1702360370_1.IMG in data directory
%% Cell type:code id: tags:
``` python
fileName = 'data/N1702360370_1.LBL'
camera = knoten.csm.create_csm(fileName)
```
%% Cell type:markdown id: tags:
## Ingest the image and spiceinit
%% Cell type:code id: tags:
``` python
# Set the output location of the resulting .cub
cub_loc = os.path.splitext(fileName)[0] + '.cub'
try:
isis.ciss2isis(from_=fileName, to=cub_loc)
except ProcessError as e:
print(e.stderr)
try:
isis.spiceinit(from_=cub_loc, shape='ellipsoid')
except ProcessError as e:
print(e.stderr)
```
%% Cell type:markdown id: tags:
## Define a function that compares ISIS and USGSCSM pixels
%% Cell type:code id: tags:
``` python
def check_pixel(camera, cub, line, sample):
"""Compares ISIS and USGSCSM pixel.
Takes an image coordinate, projects it to a ground point using ISIS, then projects
the result back into an image coordinate using USGSCSM and computes the difference
between image coordinates.
"""
output = isis.campt(from_=cub, line=line, sample=sample)
pvl_output = pvl.loads(output)
bodyfixed = pvl_output['GroundPoint']['BodyFixedCoordinate']
bodyfixed = np.asarray(bodyfixed.value) * 1000
image_coord = camera.groundToImage(csmapi.EcefCoord(*bodyfixed))
# (.5,.5) in CSM == (1,1) in ISIS, so we have to subtract (.5,.5) from the ISIS pixels
line_diff = line - image_coord.line - .5
sample_diff = sample - image_coord.samp - .5
return line_diff, sample_diff
```
%% Cell type:markdown id: tags:
## Get the total number of lines / samples
%% Cell type:code id: tags:
``` python
isis_label = pvl.load(cub_loc)
n_samples = isis_label['IsisCube']['Core']['Dimensions']['Samples']
n_lines = isis_label['IsisCube']['Core']['Dimensions']['Lines']
```
%% Cell type:markdown id: tags:
## Compare top left, top right, bottom left, bottom right, and center pixels using check_pixel
%% Cell type:code id: tags:
``` python
pixels_dict = {'line' : [1,1,n_lines, n_lines, n_lines/2],
'sample' : [1, n_samples, 1, n_samples, n_samples/2]}
pixels_df = pd.DataFrame.from_dict(pixels_dict)
pixels_df['line_diff'] = np.NaN
pixels_df['sample_diff'] = np.NaN
for idx, row in pixels_df.iterrows():
pixels_df.iloc[idx]['line_diff'], pixels_df.iloc[idx]['sample_diff'] = check_pixel(camera, cub_loc, row['line'], row['sample'])
pixels_df
```
%% Output
line sample line_diff sample_diff
0 1.0 1.0 0.153039 0.906085
1 1.0 1024.0 0.142231 0.326977
2 1024.0 1.0 -0.425122 0.915083
3 1024.0 1024.0 -0.435769 0.335980
4 512.0 512.0 -0.142021 0.620648
This diff is collapsed.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
File added
PDS_VERSION_ID = PDS3
/* FILE CHARACTERISTICS */
RECORD_TYPE = FIXED_LENGTH
RECORD_BYTES = 1048
FILE_RECORDS = 1028
/* POINTERS TO DATA OBJECTS */
^IMAGE_HEADER = ("N1702360370_1.IMG",1)
^TELEMETRY_TABLE = ("N1702360370_1.IMG",4)
^LINE_PREFIX_TABLE = ("N1702360370_1.IMG",5)
^IMAGE = ("N1702360370_1.IMG",5)
/* IDENTIFICATION DATA ELEMENTS */
ANTIBLOOMING_STATE_FLAG = "OFF"
BIAS_STRIP_MEAN = 8.850293
CALIBRATION_LAMP_STATE_FLAG = "N/A"
COMMAND_FILE_NAME = "trigger_3618_1.ioi"
COMMAND_SEQUENCE_NUMBER = 3618
DARK_STRIP_MEAN = 0.269221
DATA_CONVERSION_TYPE = "TABLE"
DATA_SET_ID = "CO-S-ISSNA/ISSWA-2-EDR-V1.0"
DELAYED_READOUT_FLAG = "NO"
DESCRIPTION = "Incomplete product finalized due to truncated lines."
DETECTOR_TEMPERATURE = -89.243546 <DEGC>
EARTH_RECEIVED_START_TIME = 2011-346T22:30:08.981
EARTH_RECEIVED_STOP_TIME = 2011-346T22:30:49.765
ELECTRONICS_BIAS = 112
EXPECTED_MAXIMUM = (62.996498,69.454498)
EXPECTED_PACKETS = 576
EXPOSURE_DURATION = 4600.000000
FILTER_NAME = ("CL1","UV3")
FILTER_TEMPERATURE = 0.248629
FLIGHT_SOFTWARE_VERSION_ID = "1.4"
GAIN_MODE_ID = "29 ELECTRONS PER DN"
IMAGE_MID_TIME = 2011-346T05:02:22.073
IMAGE_NUMBER = "1702360370"
IMAGE_OBSERVATION_TYPE = {"SCIENCE"}
IMAGE_TIME = 2011-346T05:02:24.373
INSTRUMENT_DATA_RATE = 182.783997
INSTRUMENT_HOST_NAME = "CASSINI ORBITER"
INSTRUMENT_ID = "ISSNA"
INSTRUMENT_MODE_ID = "FULL"
INSTRUMENT_NAME = "IMAGING SCIENCE SUBSYSTEM - NARROW ANGLE"
INST_CMPRS_PARAM = ("N/A","N/A","N/A","N/A")
INST_CMPRS_RATE = (5.333330,3.631307)
INST_CMPRS_RATIO = 2.203063
INST_CMPRS_TYPE = "LOSSLESS"
LIGHT_FLOOD_STATE_FLAG = "ON"
METHOD_DESC = "ISSPT2.7;Enceladus;ISS_158EN_ENCEL001_PRIME"
MISSING_LINES = 31
MISSING_PACKET_FLAG = "NO"
MISSION_NAME = "CASSINI-HUYGENS"
MISSION_PHASE_NAME = "EXTENDED-EXTENDED MISSION"
OBSERVATION_ID = "ISS_158EN_ENCEL001_PRIME"
OPTICS_TEMPERATURE = (0.627499,1.905708)
ORDER_NUMBER = 16
PARALLEL_CLOCK_VOLTAGE_INDEX = 9
PREPARE_CYCLE_INDEX = 4
PRODUCT_CREATION_TIME = 2011-346T15:34:07.000
PRODUCT_ID = "1_N1702360370.120"
PRODUCT_VERSION_TYPE = "FINAL"
READOUT_CYCLE_INDEX = 6
RECEIVED_PACKETS = 523
SENSOR_HEAD_ELEC_TEMPERATURE = 1.633024
SEQUENCE_ID = "S71"
SEQUENCE_NUMBER = 16
SEQUENCE_TITLE = "ISS_158EN_ENCEL001_PRIME"
SHUTTER_MODE_ID = "NACONLY"
SHUTTER_STATE_ID = "ENABLED"
SOFTWARE_VERSION_ID = "ISS 11.00 05-24-2006"
SPACECRAFT_CLOCK_CNT_PARTITION = 1
SPACECRAFT_CLOCK_START_COUNT = "1702360365.220"
SPACECRAFT_CLOCK_STOP_COUNT = "1702360370.120"
START_TIME = 2011-346T05:02:19.773
STOP_TIME = 2011-346T05:02:24.373
TARGET_DESC = "Enceladus"
TARGET_LIST = "N/A"
TARGET_NAME = "ENCELADUS"
TELEMETRY_FORMAT_ID = "S&ER3"
VALID_MAXIMUM = (4095,4095)
OBJECT = IMAGE_HEADER
INTERCHANGE_FORMAT = ASCII
HEADER_TYPE = VICAR2
BYTES = 3144
RECORDS = 1
^DESCRIPTION = "../../label/vicar2.txt"
END_OBJECT = IMAGE_HEADER
OBJECT = TELEMETRY_TABLE
INTERCHANGE_FORMAT = BINARY
ROWS = 1
COLUMNS = 2
ROW_BYTES = 1048
^STRUCTURE = "../../label/tlmtab.fmt"
OBJECT = COLUMN
NAME = NULL_PADDING
DATA_TYPE = MSB_UNSIGNED_INTEGER
START_BYTE = 61
BYTES = 987
END_OBJECT = COLUMN
END_OBJECT = TELEMETRY_TABLE
OBJECT = LINE_PREFIX_TABLE
INTERCHANGE_FORMAT = BINARY
ROWS = 1024
COLUMNS = 7
ROW_BYTES = 24
ROW_SUFFIX_BYTES = 1024
^LINE_PREFIX_STRUCTURE = "../../label/prefix3.fmt"
END_OBJECT = LINE_PREFIX_TABLE
OBJECT = IMAGE
LINES = 1024
LINE_SAMPLES = 1024
SAMPLE_BITS = 8
SAMPLE_TYPE = SUN_INTEGER
LINE_PREFIX_BYTES = 24
END_OBJECT = IMAGE
END
import pyproj
def reproject(record, semi_major, semi_minor, source_proj, dest_proj, **kwargs):
"""
Thin wrapper around PyProj's Transform() function to transform 1 or more three-dimensional
point from one coordinate system to another. If converting between Cartesian
body-centered body-fixed (BCBF) coordinates and Longitude/Latitude/Altitude coordinates,
the values input for semi-major and semi-minor axes determine whether latitudes are
planetographic or planetocentric and determine the shape of the datum for altitudes.
If semi_major == semi_minor, then latitudes are interpreted/created as planetocentric
and altitudes are interpreted/created as referenced to a spherical datum.
If semi_major != semi_minor, then latitudes are interpreted/created as planetographic
and altitudes are interpreted/created as referenced to an ellipsoidal datum.
Parameters
----------
record : object
Pandas series object
semi_major : float
Radius from the center of the body to the equater
semi_minor : float
Radius from the pole to the center of mass
source_proj : str
Pyproj string that defines a projection space ie. 'geocent'
dest_proj : str
Pyproj string that defines a project space ie. 'latlon'
Returns
-------
: list
Transformed coordinates as y, x, z
"""
source_pyproj = pyproj.Proj(proj = source_proj, a = semi_major, b = semi_minor)
dest_pyproj = pyproj.Proj(proj = dest_proj, a = semi_major, b = semi_minor)
y, x, z = pyproj.transform(source_pyproj, dest_pyproj, record[0], record[1], record[2], **kwargs)
return y, x, z
import tempfile
import json
import pvl
import pyproj
import csmapi
from knoten import csm
from numbers import Number
import numpy as np
import pandas as pd
from pysis import isis
from pysis.exceptions import ProcessError
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
def reproject(record, semi_major, semi_minor, source_proj, dest_proj, **kwargs):
"""
Thin wrapper around PyProj's Transform() function to transform 1 or more three-dimensional
point from one coordinate system to another. If converting between Cartesian
body-centered body-fixed (BCBF) coordinates and Longitude/Latitude/Altitude coordinates,
the values input for semi-major and semi-minor axes determine whether latitudes are
planetographic or planetocentric and determine the shape of the datum for altitudes.
If semi_major == semi_minor, then latitudes are interpreted/created as planetocentric
and altitudes are interpreted/created as referenced to a spherical datum.
If semi_major != semi_minor, then latitudes are interpreted/created as planetographic
and altitudes are interpreted/created as referenced to an ellipsoidal datum.
Parameters
----------
record : object
Pandas series object
semi_major : float
Radius from the center of the body to the equater
semi_minor : float
Radius from the pole to the center of mass
source_proj : str
Pyproj string that defines a projection space ie. 'geocent'
dest_proj : str
Pyproj string that defines a project space ie. 'latlon'
Returns
-------
: list
Transformed coordinates as y, x, z
"""
source_pyproj = pyproj.Proj(proj = source_proj, a = semi_major, b = semi_minor)
dest_pyproj = pyproj.Proj(proj = dest_proj, a = semi_major, b = semi_minor)
y, x, z = pyproj.transform(source_pyproj, dest_pyproj, record[0], record[1], record[2], **kwargs)
return y, x, z
def point_info(cube_path, x, y, point_type, allow_outside=False):
"""
Use Isis's campt to get image/ground point info from an image
Parameters
----------
cube_path : str
path to the input cube
x : float
point in the x direction. Either a sample or a longitude value
depending on the point_type flag
y : float
point in the y direction. Either a line or a latitude value
depending on the point_type flag
point_type : str
Options: {"image", "ground"}
Pass "image" if x,y are in image space (sample, line) or
"ground" if in ground space (longitude, lattiude)
Returns
-------
: PvlObject
Pvl object containing campt returns
"""
point_type = point_type.lower()
if point_type not in {"image", "ground"}:
raise Exception(f'{point_type} is not a valid point type, valid types are ["image", "ground"]')
if isinstance(x, Number) and isinstance(y, Number):
x, y = [x], [y]
with tempfile.NamedTemporaryFile("w+") as f:
# ISIS wants points in a file, so write to a temp file
if point_type == "ground":
# campt uses lat, lon for ground but sample, line for image.
# So swap x,y for ground-to-image calls
x,y = y,x
elif point_type == "image":
# convert to ISIS pixels
x = np.add(x, .5)
y = np.add(y, .5)
f.write("\n".join(["{}, {}".format(xval,yval) for xval,yval in zip(x, y)]))
f.flush()
with tempfile.NamedTemporaryFile("r+") as campt_output:
try:
isis.campt(from_=cube_path, coordlist=f.name, allowoutside=allow_outside, usecoordlist=True, coordtype=point_type, to=campt_output.name)
except ProcessError as e:
warn(f"CAMPT call failed, image: {cube_path}\n{e.stderr}")
return
pvlres = pvl.load(campt_output.name)
if len(x) > 1 and len(y) > 1:
for r in pvlres:
# convert all pixels to PLIO pixels from ISIS
r[1]["Sample"] -= .5
r[1]["Line"] -= .5
else:
pvlres["GroundPoint"]["Sample"] -= .5
pvlres["GroundPoint"]["Line"] -= .5
return pvlres
def plot_diff(data, title='diff plot', colx='x', coly='y', coldx='diffx', coldy='diffy', colmag='magnitude', width=500, height=500):
import matplotlib.cm as cm
from matplotlib.colors import Normalize
fig = make_subplots(rows=2, cols=2, column_widths=[0.9, .1], row_width=[.9, .1],
shared_xaxes=True, shared_yaxes=True, horizontal_spacing = 0.01, vertical_spacing = 0.01)
quiver_plot = ff.create_quiver(data[colx],
data[coly],
data[coldx],
data[coldy],
scale=1,
line_color='#e3838e',
name='offset direction',
arrow_scale=0.1)
for i in range(len(quiver_plot.data)):
quiver_plot.data[i].xaxis='x1'
quiver_plot.data[i].yaxis='y1'
quiver_plot.layout.xaxis1.update({'anchor': 'y1'})
quiver_plot.layout.yaxis1.update({'anchor': 'x1', 'domain': [.55, 1]})
fig.add_trace(quiver_plot.data[0], row=2, col=1)
text = [f'{coldx}: {r[coldx]}<br>{coldy}: {r[coldy]}<br>{colmag}: {r[colmag]}' for i,r in data.iterrows()]
fig.add_trace(go.Scatter(x=data[colx], y=data[coly],
customdata=data,
mode='markers',
name=f'{colx},{coly}',
hovertext=text,
marker=dict(
color=data[colmag],
colorbar=dict(
thickness = 5,
outlinewidth = 0,
ypad=0,
title=f'{colmag}'
),
colorscale="viridis",
)), row=2, col=1)
xavg = data.groupby(colx).apply(np.mean)
fig.add_trace(go.Scatter(x=xavg.index, y=xavg[colmag],
customdata=xavg,
name=f'{colx} mean error',
mode='lines+markers',
line_shape='spline',
line_color='seagreen',
marker=dict(
color=xavg[colmag],
colorscale="viridis",
)), row=1, col=1)
yavg = data.groupby(coly).apply(np.mean)
fig.add_trace(go.Scatter(x=yavg[colmag],y=yavg.index,
customdata=yavg,
name=f'{coly} mean error',
mode='lines+markers',
line_shape='spline',
line_color='purple',
marker=dict(
color=yavg[colmag],
colorscale="viridis",
)), row=2, col=2)
fig.update_layout(width=width, height=height, showlegend=True,legend_orientation="h", title_text=title)
fig.update_yaxes(autorange="reversed", title_text=coly, row=2, col=1)
fig.update_xaxes(title_text=colx, row=2, col=1)
fig.update_xaxes(title_text=f'mean error', row=2, col=2)
return fig
def plot_diff_3d(data, title='3D diff plot', colx='x', coly='y', colz='z', coldx='diffx', coldy='diffy', coldz='diffz', colmag='magnitude', width=500, height=500):
text = [f'{coldx}: {r[coldx]}<br>{coldy}: {r[coldy]}<br>{coldz}: {r[coldz]}<br>{colmag}: {r[colmag]}' for i,r in data.iterrows()]
plot_data = {
"type": "scatter3d",
"mode": "markers",
"name": "original",
"text": text,
"x": data[colx],
"y": data[coly],
"z": data[colz],
"marker": { "colorscale": 'viridis',
"opacity": .8,
"size": 5,
"color": data[colmag],
"colorbar":{
"thickness": 5,
"outlinewidth": 0,
"ypad": 0,
"title":f'{colmag}'
}
}
}
layout = {
"title": title,
"width": width,
"height": height,
"scene": {
"aspectratio": {"x": 1, "y": 1, "z": 0.8},
}
}
fig = go.Figure(data=[plot_data], layout=layout)
return fig
def plot_diff_3d_cone(data, title='3D diff plot', colx='x', coly='y', colz='z',
colu='u', colv='v',colw='w',
coldx='diffx', coldy='diffy', coldz='diffz',
coldv = 'diffu', coldu='diffv', coldw='diffw',
colxyz_mag='xyz_magnitude', coluvw_mag='uvw_magnitude',
width=500, height=500):
text = [f'{coldx}: {r[coldx]}<br>\
{coldy}: {r[coldy]}<br>\
{coldz}: {r[coldz]}<br>\
{coldu}: {r[coldu]}<br>\
{coldv}: {r[coldv]}<br>\
{coldw}: {r[coldw]}<br>\
{colxyz_mag}: {r[colxyz_mag]}<br>\
{coluvw_mag}: {r[coluvw_mag]}' for i,r in data.iterrows()]
plot_data = {
"type": "cone",
"text":text,
"x": data[colx],
"y": data[coly],
"z": data[colz],
"u": data[colu],
"v": data[colv],
"w": data[colw],
"sizeref": 5,
"colorscale": 'viridis',
"colorbar":{
"thickness": 5,
"outlinewidth": 0,
"ypad": 0,
"title": f'mean({colxyz_mag},{coluvw_mag})'
}
}
layout = {
"title": title,
"width": width,
"height": height,
"scene": {
"aspectratio": {"x": 1, "y": 1, "z": 0.8},
}
}
fig = go.Figure(data=[plot_data], layout=layout)
return fig
def reprojection_diff(isd, cube, nx=10, ny=50, width=500, height=500):
"""
"""
isdjson = json.load(open(isd))
nlines = isdjson['image_lines']
nsamples = isdjson['image_samples']
# generate meshgrid
xs, ys = np.mgrid[0:nsamples:nsamples/nx, 0:nlines:nlines/ny]
xs, ys = xs.flatten(), ys.flatten()
csmcam = csm.create_csm(isd)
# get data for isis image to ground, csm ground to image
isis_pts = point_info(cube, xs, ys, 'image')
isisgnds = np.asarray([np.asarray(g[1]['BodyFixedCoordinate'].value)*1000 for g in isis_pts])
csm_pts = np.asarray([[p.samp, p.line] for p in [csmcam.groundToImage(csmapi.EcefCoord(*bf)) for bf in isisgnds]])
isis2csm_diff = np.asarray([xs,ys]).T - csm_pts
isis2csm_diffmag = np.linalg.norm(isis2csm_diff, axis=1)
isis2csm_angles = np.arctan2(*isis2csm_diff.T[::-1])
isis2csm_data = np.asarray([csm_pts.T[0], csm_pts.T[1], xs, ys, isis2csm_diff.T[0], isis2csm_diff.T[1], isis2csm_diffmag, isis2csm_angles]).T
isis2csm_data = pd.DataFrame(isis2csm_data, columns=['csm sample', 'csm line', 'isis sample','isis line', 'diff sample', 'diff line', 'magnitude', 'angles'])
isis2csm_plot = plot_diff(isis2csm_data, colx='isis sample', coly='isis line',
coldx='diff sample', coldy='diff line',
title="ISIS2Ground->CSM2Image", width=width, height=height)
# get data for csm image to ground, isis ground to image
csmgnds = np.asarray([[p.x, p.y, p.z] for p in [csmcam.imageToGround(csmapi.ImageCoord(y,x), 0) for x,y in zip(xs,ys)]])
csmlon, csmlat, _ = reproject(csmgnds.T, isdjson['radii']['semimajor'], isdjson['radii']['semimajor'], 'geocent', 'latlong')
isis_imgpts = point_info(cube, (csmlon+360)%360, csmlat, 'ground')
isis_imgpts = np.asarray([(p[1]['Sample'], p[1]['Line']) for p in isis_imgpts])
csm2isis_diff = np.asarray([xs,ys]).T - isis_imgpts
csm2isis_diffmag = np.linalg.norm(csm2isis_diff, axis=1)
csm2isis_angles = np.arctan2(*(csm2isis_diff/csm2isis_diffmag[:,np.newaxis]).T[::-1])
csm2isis_data = np.asarray([xs, ys, isis_imgpts.T[0], isis_imgpts.T[1], csm2isis_diff.T[0], csm2isis_diff.T[1], csm2isis_diffmag, csm2isis_angles]).T
csm2isis_data = pd.DataFrame(csm2isis_data, columns=['csm sample', 'csm line', 'isis sample','isis line', 'diff sample', 'diff line', 'magnitude', 'angles'])
csm2isis_plot = plot_diff(csm2isis_data, colx='csm sample', coly='csm line',
coldx='diff sample', coldy='diff line',
title="CSM2Ground->ISIS2Image", width=width, height=height)
# get data for footprint comparison
isis_lonlat = np.asarray([[p[1]['PositiveEast360Longitude'].value, p[1]['PlanetocentricLatitude'].value] for p in isis_pts])
csm_lonlat = np.asarray([(csmlon+360)%360, csmlat]).T
isiscsm_difflatlon = csm_lonlat - isis_lonlat
isiscsm_difflatlonmag = np.linalg.norm(isiscsm_difflatlon, axis=1)
isiscsm_angleslatlon = np.arctan2(*isiscsm_difflatlon.T[::-1])
isiscsm_latlondata = np.asarray([isis_lonlat.T[0], isis_lonlat.T[1], csm_lonlat.T[0], csm_lonlat.T[1], isiscsm_difflatlon.T[0], isiscsm_difflatlon.T[1], isiscsm_difflatlonmag, isiscsm_angleslatlon]).T
isiscsm_latlondata = pd.DataFrame(isiscsm_latlondata, columns=['isis lon', 'isis lat', 'csm lon','csm lat', 'diff lon', 'diff lat', 'magnitude', 'angles'])
isiscsm_latlonplot = plot_diff(isiscsm_latlondata, colx='isis lon', coly='isis lat',
coldx='diff lon', coldy='diff lat',
title="ISIS Lat/Lon vs CSM Lat/Lon", width=width, height=height)
isiscsm_diffbf = isisgnds - csmgnds
isiscsm_diffbfmag = np.linalg.norm(isiscsm_diffbf, axis=1)
isiscsm_anglesbf = np.arctan2(*isiscsm_diffbf.T[::-1])
isiscsm_bfdata = np.asarray([isisgnds.T[0], isisgnds.T[1], isisgnds.T[2], csmgnds.T[0], csmgnds.T[1], csmgnds.T[2], isiscsm_diffbf.T[0], isiscsm_diffbf.T[1], isiscsm_diffbf.T[2], isiscsm_diffbfmag, isiscsm_anglesbf]).T
isiscsm_bfdata = pd.DataFrame(isiscsm_bfdata, columns=['isisx', 'isisy', 'isisz', 'csmx','csmy', 'csmz', 'diffx', 'diffy', 'diffz', 'magnitude', 'angles'])
isiscsm_bfplot = plot_diff_3d(isiscsm_bfdata, colx='isisx', coly='isisy', colz='isisz',
title='ISIS Body-Fixed vs CSM Body-Fixed', width=width, height=height)
return isis2csm_plot, csm2isis_plot, isiscsm_latlonplot, isiscsm_bfplot, isis2csm_data, csm2isis_data, isiscsm_latlondata, isiscsm_bfdata
def external_orientation_diff(isd, cube, nx=4, ny=4, width=500, height=500):
csmcam = csm.create_csm(isd)
isdjson = json.load(open(isd))
nlines, nsamples = isdjson['image_lines'], isdjson['image_samples']
xs, ys = np.mgrid[0:nsamples:nsamples/nx, 0:nlines:nlines/ny]
xs, ys = xs.flatten(), ys.flatten()
isis_pts = point_info(cube, xs, ys, "image")
isis_lv_bf = np.asarray([p[1]['LookDirectionBodyFixed'] for p in isis_pts])
isis_pos_bf = np.asarray([p[1]['SpacecraftPosition'].value for p in isis_pts])*1000
isis_ephem_times = np.asarray([p[1]['EphemerisTime'].value for p in isis_pts])
csm_locus = [csmcam.imageToRemoteImagingLocus(csmapi.ImageCoord(y, x)) for x,y in zip(xs,ys)]
csm_lv_bf = np.asarray([[lv.direction.x, lv.direction.y, lv.direction.z] for lv in csm_locus])
csm_pos_bf = np.asarray([[lv.point.x, lv.point.y, lv.point.z] for lv in csm_locus])
csm_ephem_times = np.asarray([csmcam.getImageTime(csmapi.ImageCoord(y, x)) for x,y in zip(xs,ys)])
csm_ephem_times += isdjson['center_ephemeris_time']
csmisis_diff_pos = csm_pos_bf - isis_pos_bf
csmisis_diff_lv = csm_lv_bf - isis_lv_bf
csmisis_diff_ephem = csm_ephem_times - isis_ephem_times
csmisis_diff_pos_mag = np.linalg.norm(csmisis_diff_pos, axis=1)
csmisis_diff_lv_mag = np.linalg.norm(csmisis_diff_lv, axis=1)
csmisis_diff_pos_data = np.asarray([csm_pos_bf.T[0], csm_pos_bf.T[1], csm_pos_bf.T[2],
isis_pos_bf.T[0], isis_pos_bf.T[1], isis_pos_bf.T[2],
csmisis_diff_pos.T[0], csmisis_diff_pos.T[1], csmisis_diff_pos.T[2],
csmisis_diff_pos_mag])
csmisis_diff_pos_data = pd.DataFrame(csmisis_diff_pos_data.T, columns=['csm pos x', 'csm pos y', 'csm pos z',
'isis pos x', 'isis pos y', 'isis pos z',
'diffx', 'diffy', 'diffz',
'magnitude'])
csmisis_diff_pos_plot = plot_diff_3d(csmisis_diff_pos_data, colx='isis pos x', coly='isis pos y', colz='isis pos z',
title='ISIS CSM Position Difference')
csmisis_diff_lv_data = np.asarray([isis_pos_bf.T[0], isis_pos_bf.T[1], isis_pos_bf.T[2],
csm_lv_bf.T[0], csm_lv_bf.T[1], csm_lv_bf.T[2],
isis_lv_bf.T[0], isis_lv_bf.T[1], isis_lv_bf.T[2],
csmisis_diff_pos.T[0], csmisis_diff_pos.T[1], csmisis_diff_pos.T[2],
csmisis_diff_lv.T[0], csmisis_diff_lv.T[1], csmisis_diff_lv.T[2],
csmisis_diff_pos_mag, csmisis_diff_lv_mag, isis_ephem_times, csm_ephem_times, csmisis_diff_ephem])
csmisis_diff_lv_data = pd.DataFrame(csmisis_diff_lv_data.T, columns=['isis pos x', 'isis pos y', 'isis pos z',
'csm lv x', 'csm lv y', 'csm lv z',
'isis lv x', 'isis lv y', 'isis lv z',
'diffx', 'diffy', 'diffz',
'diffu', 'diffv', 'diffw',
'xyz_magnitude', 'uvw_magnitude', 'isis ephem time', 'csm ephem time', 'diff ephem'])
csmisis_diff_lv_plot = plot_diff_3d_cone(csmisis_diff_lv_data, colx='isis pos x', coly='isis pos y', colz='isis pos z',
colu='isis lv x', colv='isis lv y', colw='isis lv z',
title='ISIS CSM Position and Look Vector Difference', width=width, height=height)
csmisis_diff_ephem_plot = go.Figure(go.Scatter(x=np.linspace(0, nlines, ny), y=csmisis_diff_ephem, line_shape='spline')).update_layout(title='ISIS CSM Ephem Time Difference', width=width, height=height/2).update_xaxes(title_text='Line').update_yaxes(title_text='Time Delta Seconds')
return csmisis_diff_lv_plot, csmisis_diff_ephem_plot, csmisis_diff_lv_data
from unittest import mock
import pytest
from knoten import utils
def test_reproject():
with mock.patch('pyproj.transform', return_value=[1,1,1]) as mock_pyproj:
res = utils.reproject([1,1,1], 10, 10, 'geocent', 'latlon')
mock_pyproj.assert_called_once()
assert res == (1,1,1)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment