Initial commit
This commit is contained in:
commit
3d4eb2b4a6
7
.babelrc
Normal file
7
.babelrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/react",
|
||||
"@babel/preset-env",
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-export-default-from"]
|
||||
}
|
||||
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
venv
|
||||
7
.eslintrc.js
Normal file
7
.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
"extends": "airbnb-base",
|
||||
"plugins": [
|
||||
"import",
|
||||
"react",
|
||||
]
|
||||
};
|
||||
131
.gitignore
vendored
Normal file
131
.gitignore
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
venv
|
||||
db.sqlite3
|
||||
data/rawdata
|
||||
node_modules
|
||||
|
||||
### Vim ###
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
|
||||
### OSX ###
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM python:3-alpine3.12
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Postgres and python deps
|
||||
RUN apk update && \
|
||||
apk add --virtual build-deps gcc python-dev musl-dev && \
|
||||
apk add postgresql-dev curl bash
|
||||
|
||||
# Install python deps
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY spacedb spacedb
|
||||
COPY spaceobjects spaceobjects
|
||||
COPY static static
|
||||
COPY templates templates
|
||||
COPY data data
|
||||
COPY manage.py manage.py
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD python /app/manage.py runserver 0.0.0.0:8000
|
||||
4
README
Normal file
4
README
Normal file
@ -0,0 +1,4 @@
|
||||
when setting up a new instance, also don't forget to populate
|
||||
|
||||
/var/spacedb/manual - manual copy
|
||||
(/var/spacedb/raw - raw data) -- should persist
|
||||
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
||||
# spacedb
|
||||
|
||||
To get started:
|
||||
|
||||
```
|
||||
virtualenv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
First time:
|
||||
|
||||
```
|
||||
# Python backend
|
||||
pip install -r requirements.txt
|
||||
./manage.py migrate
|
||||
./manage.py loaddata orbit_class
|
||||
|
||||
# Webpack frontend
|
||||
yarn install
|
||||
```
|
||||
|
||||
Now run it:
|
||||
|
||||
```
|
||||
# Terminal 1: run the web server
|
||||
./manage.py runserver
|
||||
|
||||
# Terminal 2: build the js assets continuously
|
||||
yarn build:watch
|
||||
```
|
||||
55
client/components/Search.jsx
Normal file
55
client/components/Search.jsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'react-proptypes';
|
||||
|
||||
import AsyncSelect from 'react-select/lib/Async';
|
||||
|
||||
const loadOptions = (inputValue, callback) => {
|
||||
return new Promise(resolve => {
|
||||
if (inputValue.length < 3) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
fetch(`/api/objects/search?q=${inputValue}`).then(resp => {
|
||||
return resp.json()
|
||||
}).then(respJson => {
|
||||
resolve(respJson.results.map(result => {
|
||||
return {
|
||||
label: result.fullname,
|
||||
value: result.slug,
|
||||
};
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
class Search extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
inputValue: '',
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(inputValue) {
|
||||
this.setState({ inputValue })
|
||||
window.location.href = `/asteroid/${inputValue.value}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<AsyncSelect
|
||||
cacheOptions
|
||||
loadOptions={loadOptions}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
placeholder="Search for an asteroid or comet..."
|
||||
className="topnav__react-search__control"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Search.propTypes = {
|
||||
blah: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Search;
|
||||
200
client/components/SearchAndVisualize.jsx
Normal file
200
client/components/SearchAndVisualize.jsx
Normal file
@ -0,0 +1,200 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'react-proptypes';
|
||||
|
||||
import AsyncSelect from 'react-select/lib/Async';
|
||||
|
||||
import { parseQuery } from '../util';
|
||||
|
||||
const INPUT_LENGTH_MIN = 3;
|
||||
|
||||
const loadOptions = (inputValue, callback) => {
|
||||
return new Promise(resolve => {
|
||||
if (inputValue.length < INPUT_LENGTH_MIN) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
fetch(`/api/objects/search?q=${inputValue}`).then(resp => {
|
||||
return resp.json()
|
||||
}).then(respJson => {
|
||||
resolve(respJson.results.map(result => {
|
||||
return {
|
||||
label: result.fullname,
|
||||
vizLabel: result.name,
|
||||
value: result.slug,
|
||||
ephem: result.ephem,
|
||||
};
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
class SearchAndVisualize extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._objCount = 0;
|
||||
this.state = {
|
||||
inputValue: '',
|
||||
savedDate: undefined,
|
||||
selectedObjects: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const hash = parseQuery(window.location.hash);
|
||||
if (hash.ob) {
|
||||
fetch(`/api/objects?slugs=${hash.ob}`).then(resp => {
|
||||
return resp.json()
|
||||
}).then(respJson => {
|
||||
this.addMany(respJson.results.map(result => {
|
||||
return {
|
||||
label: result.fullname,
|
||||
vizLabel: result.name,
|
||||
value: result.slug,
|
||||
ephem: result.ephem,
|
||||
};
|
||||
}), {
|
||||
showLabel: true,
|
||||
showOrbit: true,
|
||||
updateHash: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
if (hash.cat) {
|
||||
const query = parseQuery(window.location.search);
|
||||
const limit = query.limit || 3000;
|
||||
fetch(`/api/category/${hash.cat}?limit=${limit}`).then(resp => {
|
||||
return resp.json()
|
||||
}).then(respJson => {
|
||||
this.addMany(respJson.data.map(result => {
|
||||
return {
|
||||
label: result.fullname,
|
||||
vizLabel: result.name,
|
||||
value: result.slug,
|
||||
ephem: result.ephem,
|
||||
};
|
||||
}), {
|
||||
showLabel: false,
|
||||
showOrbit: false,
|
||||
updateHash: false,
|
||||
displayEclipticLines: false,
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
if (hash.date) {
|
||||
const dateObj = new Date(Date.parse(`${hash.date}T00:00:00Z`));
|
||||
window.viz.setDate(dateObj);
|
||||
this.setState({
|
||||
savedDate: hash.date,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addMany(objs, opts) {
|
||||
opts = opts || {};
|
||||
objs.forEach(obj => {
|
||||
const key = `spaceobject${this._objCount++}`;
|
||||
window.viz.createObject(key, Object.assign(window.VIZ_OBJECT_OPTS, {
|
||||
ephem: new Spacekit.Ephem(obj.ephem, 'deg'),
|
||||
// Show short name
|
||||
labelText: opts.showLabel ? obj.vizLabel : undefined,
|
||||
hideOrbit: !opts.showOrbit,
|
||||
particleSize: opts.particleSize,
|
||||
ecliptic: {
|
||||
displayLines: opts.displayEclipticLines,
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
if (opts.updateHash) {
|
||||
this.setState(prevState => ({ selectedObjects: prevState.selectedObjects.concat(objs) }), () => {
|
||||
let hashStr = '#ob=' + this.state.selectedObjects.map(object => object.value).join(',');
|
||||
if (this.state.savedDate) {
|
||||
hashStr += `&date=${this.state.savedDate}`;
|
||||
}
|
||||
window.location.hash = hashStr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(inputValue) {
|
||||
this.addMany([inputValue], {
|
||||
showLabel: true,
|
||||
showOrbit: true,
|
||||
updateHash: true,
|
||||
});
|
||||
}
|
||||
|
||||
getObjectList() {
|
||||
return this.state.selectedObjects.map(object => {
|
||||
return (
|
||||
<div className="tile" key={`selectedObject-${object.value}`}>
|
||||
<a target="_blank" href={`/asteroid/${object.value}`}>
|
||||
<h5>{object.label}</h5>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<AsyncSelect
|
||||
cacheOptions
|
||||
loadOptions={loadOptions}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
value={null}
|
||||
placeholder="Search for an asteroid or comet..."
|
||||
className="topnav__react-search__control"
|
||||
noOptionsMessage={() => {
|
||||
if (this.state.inputValue.length < INPUT_LENGTH_MIN) {
|
||||
return null;
|
||||
}
|
||||
return "No matching objects"
|
||||
}}
|
||||
styles={{
|
||||
input: base => ({
|
||||
...base,
|
||||
color: "#fff"
|
||||
}),
|
||||
noOptionsMessage: base => ({
|
||||
...base,
|
||||
color: "#ccc"
|
||||
}),
|
||||
loadingMessage: base => ({
|
||||
...base,
|
||||
color: "#ccc"
|
||||
}),
|
||||
}}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
borderRadius: 0,
|
||||
colors: {
|
||||
...theme.colors,
|
||||
primary25: '#404040',
|
||||
primary: 'black',
|
||||
neutral0: '#1d1d1d',
|
||||
neutral5: '#000a',
|
||||
neutral10: '#000b',
|
||||
neutral20: '#666',
|
||||
neutral30: '#000d',
|
||||
neutral40: '#000e',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
{this.state.selectedObjects.length > 0 ? (
|
||||
<div className="item-container tile-list">
|
||||
{this.getObjectList()}
|
||||
</div>
|
||||
): null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchAndVisualize.propTypes = {
|
||||
blah: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SearchAndVisualize;
|
||||
13
client/index.js
Normal file
13
client/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import Search from './components/Search.jsx';
|
||||
import SearchAndVisualize from './components/SearchAndVisualize.jsx';
|
||||
|
||||
Array.from(document.getElementsByClassName('react-search')).forEach(elt => {
|
||||
ReactDOM.render(<Search/>, elt);
|
||||
});
|
||||
|
||||
Array.from(document.getElementsByClassName('react-search-and-visualize')).forEach(elt => {
|
||||
ReactDOM.render(<SearchAndVisualize/>, elt);
|
||||
});
|
||||
15
client/util.js
Normal file
15
client/util.js
Normal file
@ -0,0 +1,15 @@
|
||||
export function parseQuery(queryString) {
|
||||
const query = {};
|
||||
if (!queryString) {
|
||||
return query;
|
||||
}
|
||||
const firstChar = queryString[0];
|
||||
const cleanedString = firstChar === '?' || firstChar === '#' ?
|
||||
queryString.substr(1) : queryString;
|
||||
const pairs = cleanedString.split('&');
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
const pair = pairs[i].split('=');
|
||||
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
|
||||
}
|
||||
return query;
|
||||
}
|
||||
25
config/nginx/conf.d/local.conf
Normal file
25
config/nginx/conf.d/local.conf
Normal file
@ -0,0 +1,25 @@
|
||||
upstream appserver {
|
||||
server app:8000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name spacereference.org;
|
||||
return 301 $scheme://www.spacereference.org$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost www.spacereference.org;
|
||||
|
||||
location / {
|
||||
proxy_pass http://appserver;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect off;
|
||||
}
|
||||
|
||||
location /static/ {
|
||||
alias /var/www/static/;
|
||||
}
|
||||
}
|
||||
0
data/__init__.py
Normal file
0
data/__init__.py
Normal file
24
data/download.sh
Executable file
24
data/download.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
mkdir -p rawdata
|
||||
|
||||
echo 'Downloading SBDB...'
|
||||
./download_sbdb.sh
|
||||
|
||||
echo 'Downloading close approaches...'
|
||||
./download_close_approaches.sh
|
||||
|
||||
echo 'Downloading sentry...'
|
||||
./download_sentry.sh
|
||||
|
||||
echo 'Downloading nhats...'
|
||||
./download_nhats.sh
|
||||
|
||||
echo 'Downloading damit...'
|
||||
./download_damit.sh
|
||||
|
||||
echo 'Done.'
|
||||
|
||||
popd &>/dev/null
|
||||
7
data/download_close_approaches.sh
Executable file
7
data/download_close_approaches.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
curl 'https://ssd-api.jpl.nasa.gov/cad.api?date-min=2019-01-01&date-max=2200-01-01&dist-max=0.2&fullname=true' -o rawdata/close_approach.json
|
||||
|
||||
popd &>/dev/null
|
||||
20
data/download_damit.sh
Executable file
20
data/download_damit.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
mkdir -p rawdata/shapes
|
||||
rm -rf rawdata/shapes/*
|
||||
cd rawdata/shapes
|
||||
|
||||
# Download complete flush from
|
||||
# http://astro.troja.mff.cuni.cz/projects/asteroids3D/web.php?page=db_export
|
||||
#curl -o damit.tar.gz 'https://astro.troja.mff.cuni.cz/projects/damit/exports/complete/damit-20210401T000301Z.tar.gz'
|
||||
curl -o damit.tar.gz 'https://www.ianww.com/damit_old.tar.gz'
|
||||
|
||||
# Decompress
|
||||
tar xzvf damit.tar.gz
|
||||
# Put everything into one directory instead of breaking it up every thousand
|
||||
# Use find instead of mv because on mac mv limits the number of arguments.
|
||||
find archive/ -name '*.*' -exec mv {} archive/. \;
|
||||
|
||||
popd &>/dev/null
|
||||
7
data/download_nhats.sh
Executable file
7
data/download_nhats.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
curl -o rawdata/nhats.json https://ssd-api.jpl.nasa.gov/nhats.api
|
||||
|
||||
popd &>/dev/null
|
||||
8
data/download_sbdb.sh
Executable file
8
data/download_sbdb.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
curl -v 'https://ssd-api.jpl.nasa.gov/sbdb_query.api?fields=full_name,pdes,name,class,neo,pha,moid,moid_jup,epoch,e,a,q,i,om,w,ma,tp,per,n,ad,first_obs,last_obs,n_obs_used,H,M1,diameter,density,extent,rot_per,GM,pole,albedo,BV,UB,IR,spec_T,spec_B' -o rawdata/sbdb.json
|
||||
gzip -f rawdata/sbdb.json
|
||||
|
||||
popd &>/dev/null
|
||||
7
data/download_sentry.sh
Executable file
7
data/download_sentry.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
curl -o rawdata/sentry.json https://ssd-api.jpl.nasa.gov/sentry.api?all=1
|
||||
|
||||
popd &>/dev/null
|
||||
2998
data/manual/shapes/2014_mu69.obj
Normal file
2998
data/manual/shapes/2014_mu69.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/manual/shapes/2014_mu69.png
Normal file
BIN
data/manual/shapes/2014_mu69.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
4802
data/manual/shapes/Pallas_ADAM.obj
Normal file
4802
data/manual/shapes/Pallas_ADAM.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/manual/shapes/bennu.gif
Normal file
BIN
data/manual/shapes/bennu.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 MiB |
296454
data/manual/shapes/bennu.obj
Normal file
296454
data/manual/shapes/bennu.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/manual/shapes/pallas.png
Normal file
BIN
data/manual/shapes/pallas.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 257 KiB |
12
data/process.sh
Executable file
12
data/process.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
./process_sbdb.py
|
||||
./process_close_approach.py
|
||||
./process_sentry.py
|
||||
./process_nhats.py
|
||||
./process_damit.py
|
||||
./process_manual_shapes.py
|
||||
|
||||
popd &>/dev/null
|
||||
83
data/process_close_approach.py
Executable file
83
data/process_close_approach.py
Executable file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import csv
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import django
|
||||
from django.db import transaction
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import SpaceObject, CloseApproach
|
||||
from data.util import get_normalized_full_name
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@transaction.atomic
|
||||
def insert_all(newobjects, delete=False):
|
||||
if delete:
|
||||
CloseApproach.objects.all().only('pk').delete()
|
||||
CloseApproach.objects.bulk_create(newobjects, batch_size=499)
|
||||
|
||||
def process(fields, data):
|
||||
CloseApproach.objects.all().delete()
|
||||
newobjects = []
|
||||
inserted_once = False
|
||||
for count, row in enumerate(data, 1):
|
||||
if count % 100 == 0:
|
||||
logger.info(count)
|
||||
|
||||
if count % 20000 == 0:
|
||||
# Subdivide insertions - slower, but needed for low memory
|
||||
# environments like production machine
|
||||
logger.info('Inserting...')
|
||||
insert_all(newobjects, delete=(not inserted_once))
|
||||
inserted_once = True
|
||||
newobjects = []
|
||||
|
||||
ca_raw = dict(zip(fields, row))
|
||||
fullname = get_normalized_full_name(ca_raw['fullname'])
|
||||
|
||||
date_str = ca_raw['cd']
|
||||
date = datetime.strptime(date_str, '%Y-%b-%d %H:%M')
|
||||
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname)
|
||||
ca = CloseApproach(
|
||||
space_object=space_object,
|
||||
date=date,
|
||||
dist_au=float(ca_raw['dist']),
|
||||
dist_min_au=float(ca_raw['dist_min']),
|
||||
v_rel=float(ca_raw['v_rel']),
|
||||
# TODO(ian): Make hmag nullable
|
||||
h_mag=float(ca_raw['h'] if ca_raw['h'] else -99),
|
||||
)
|
||||
newobjects.append(ca)
|
||||
except SpaceObject.DoesNotExist:
|
||||
logger.error('Cannot find space object %s' % fullname)
|
||||
|
||||
logger.info('Inserting final records...')
|
||||
insert_all(newobjects, delete=(not inserted_once))
|
||||
|
||||
logger.info('Done.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.info('Processing close approach data')
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
data_path = os.path.realpath(os.path.join(dir_path, 'rawdata/close_approach.json'))
|
||||
with open(data_path) as f:
|
||||
close_approach_file = json.load(f)
|
||||
process(close_approach_file["fields"],
|
||||
close_approach_file["data"])
|
||||
128
data/process_damit.py
Executable file
128
data/process_damit.py
Executable file
@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import codecs
|
||||
import csv
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import django
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import SpaceObject, ShapeModel
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def convert_shape_to_obj(inpath, outpath):
|
||||
outlines = []
|
||||
with open(inpath, 'r') as f:
|
||||
count = int(f.readline().split()[0])
|
||||
for x in range(count):
|
||||
outlines.append('v %s' % (f.readline()))
|
||||
line = f.readline()
|
||||
while line:
|
||||
outlines.append('f %s' % line)
|
||||
line = f.readline()
|
||||
|
||||
with open(outpath, 'w') as f:
|
||||
f.write(''.join(outlines))
|
||||
|
||||
def process_references(f_in):
|
||||
reader = csv.DictReader(codecs.EncodedFile(f_in, 'utf8', 'utf-8-sig'), delimiter=',')
|
||||
ret = {}
|
||||
for row in reader:
|
||||
cite = '%s. %s. %s. %s:%s' % (row['Author'], row['Year'], row['Title'], row['Publication'], row['Page'])
|
||||
ret[row['Reference ID']] = {
|
||||
'cite': cite,
|
||||
'url': row['URI'],
|
||||
}
|
||||
return ret
|
||||
|
||||
def process_shapes(f_in, refs):
|
||||
reader = csv.DictReader(f_in, delimiter=',')
|
||||
|
||||
# Map from fullname to SpaceObject
|
||||
spaceobject_lookup = {}
|
||||
|
||||
matched = 0
|
||||
count = 0
|
||||
newobjects = []
|
||||
for row in reader:
|
||||
count += 1
|
||||
|
||||
reconstructed_desig = '%s %s' % (row['asteroid number'], row['asteroid name'])
|
||||
desig_with_parens = '(%s)' % row['asteroid designation']
|
||||
fullname = reconstructed_desig if row['asteroid name'] else desig_with_parens
|
||||
|
||||
logger.info('%d: %s' % (count, fullname))
|
||||
|
||||
# Locate SpaceObject match
|
||||
space_object = spaceobject_lookup.get(fullname)
|
||||
if space_object:
|
||||
matched += 1
|
||||
else:
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname)
|
||||
matched += 1
|
||||
except SpaceObject.MultipleObjectsReturned:
|
||||
logger.error('Multiple objects returned (ambiguous query) for %s' % fullname)
|
||||
continue
|
||||
except SpaceObject.DoesNotExist:
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname__contains=fullname)
|
||||
matched += 1
|
||||
except SpaceObject.DoesNotExist:
|
||||
logger.error('Cannot find space object %s' % fullname)
|
||||
continue
|
||||
except SpaceObject.MultipleObjectsReturned:
|
||||
logger.error('Multiple objects returned (ambiguous query) for %s' % fullname)
|
||||
continue
|
||||
spaceobject_lookup[fullname] = space_object
|
||||
|
||||
# Create ShapeModel object
|
||||
ast_id = row['asteroid id']
|
||||
model_id = row['model id']
|
||||
filename = 'A%s.M%s' % (ast_id, model_id)
|
||||
convert_shape_to_obj('./rawdata/shapes/archive/%s.shape.txt' % filename,
|
||||
'./rawdata/shapes/archive/%s.obj' % filename)
|
||||
shape_path = '/data/shapefiles/damit/%s.obj' % filename
|
||||
|
||||
render_path = '/data/shapefiles/damit/%s.shape.png' % filename
|
||||
yorp = float(row['yorp']) if row['yorp'] else None
|
||||
quality = float(row['quality flag']) if row['quality flag'] else -1
|
||||
diam = float(row['equivalent diameter']) if row['equivalent diameter'] else None
|
||||
#reference = refs[row['reference id']]
|
||||
newobjects.append(ShapeModel(space_object=space_object,
|
||||
shape_path=shape_path,
|
||||
render_path=render_path,
|
||||
spin_latitude=float(row['beta']),
|
||||
spin_longitude=float(row['beta']),
|
||||
spin_angle=float(row['phi0']),
|
||||
period_hr=float(row['period']),
|
||||
jd=float(row['jd0']),
|
||||
yorp=yorp,
|
||||
equiv_diameter_km=diam,
|
||||
quality=quality,
|
||||
source='damit',
|
||||
#reference=reference,
|
||||
))
|
||||
logger.info('%d/%d objects matched' % (matched, count))
|
||||
|
||||
logger.info('Creating...')
|
||||
ShapeModel.objects.all().delete()
|
||||
ShapeModel.objects.bulk_create(newobjects)
|
||||
logger.info('Done.')
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('rawdata/shapes/damit_flush_extended.csv', 'r', encoding='utf-8-sig') as f_main, \
|
||||
open('rawdata/shapes/damit_flush_refs.csv', 'r') as f_refs:
|
||||
#refs = process_references(f_refs)
|
||||
refs = {}
|
||||
process_shapes(f_main, refs)
|
||||
93
data/process_manual_shapes.py
Executable file
93
data/process_manual_shapes.py
Executable file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import codecs
|
||||
import csv
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import django
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import SpaceObject, ShapeModel
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SHAPES = [
|
||||
{
|
||||
'name': '486958 Arrokoth (2014 MU69)',
|
||||
'shape_path': '2014_mu69.obj',
|
||||
'render_path': '2014_mu69.png',
|
||||
# https://science.sciencemag.org/content/364/6441/eaaw9771?intcmp=trendmd-sci
|
||||
'source': 'S. A. Stern et al., Science, 2019',
|
||||
},
|
||||
{
|
||||
'name': '101955 Bennu (1999 RQ36)',
|
||||
'shape_path': 'bennu.obj',
|
||||
'render_path': 'bennu.gif',
|
||||
# https://www.asteroidmission.org/updated-bennu-shape-model-3d-files/
|
||||
'source': 'NASA/Goddard/University of Arizona',
|
||||
},
|
||||
# http://observations.lam.fr/astero/
|
||||
{
|
||||
'name': '2 Pallas',
|
||||
'shape_path': 'Pallas_ADAM.obj',
|
||||
'render_path': 'pallas.png',
|
||||
# https://www.nature.com/articles/s41550-019-1007-5
|
||||
'source': 'Marsset et al., Nature Astronomy, 2020',
|
||||
},
|
||||
]
|
||||
|
||||
def process_shapes():
|
||||
# Map from fullname to SpaceObject
|
||||
spaceobject_lookup = {}
|
||||
|
||||
newobjects = []
|
||||
matched = 0
|
||||
for count, shape in enumerate(SHAPES):
|
||||
fullname = shape['name']
|
||||
|
||||
logger.info('%d: %s' % (count, fullname))
|
||||
|
||||
# Locate SpaceObject match
|
||||
space_object = spaceobject_lookup.get(fullname)
|
||||
if space_object:
|
||||
matched += 1
|
||||
else:
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname)
|
||||
matched += 1
|
||||
except SpaceObject.DoesNotExist:
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname__contains=fullname)
|
||||
matched += 1
|
||||
except SpaceObject.DoesNotExist:
|
||||
logger.error('Cannot find space object %s' % fullname)
|
||||
continue
|
||||
spaceobject_lookup[fullname] = space_object
|
||||
|
||||
# Create ShapeModel object
|
||||
shape_path = '/data/shapefiles/manual/%s' % shape['shape_path']
|
||||
render_path = '/data/shapefiles/manual/%s' % shape['render_path']
|
||||
|
||||
newobjects.append(ShapeModel(space_object=space_object,
|
||||
shape_path=shape_path,
|
||||
render_path=render_path,
|
||||
source=shape['source'],
|
||||
))
|
||||
logger.info('%d/%d objects matched' % (matched, count))
|
||||
|
||||
logger.info('Creating...')
|
||||
#ShapeModel.objects.all().delete()
|
||||
ShapeModel.objects.bulk_create(newobjects)
|
||||
logger.info('Done.')
|
||||
|
||||
if __name__ == '__main__':
|
||||
process_shapes()
|
||||
65
data/process_nhats.py
Executable file
65
data/process_nhats.py
Executable file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# TODO(ian): Process detail for each object, including orbital plot
|
||||
# TODO(ian): Orbit condition codes (occ) https://minorplanetcenter.net/iau/info/UValue.html
|
||||
|
||||
import csv
|
||||
import django
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import NhatsObject, SpaceObject
|
||||
from data.util import get_normalized_full_name
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def process(entries):
|
||||
newobjects = []
|
||||
count = 0
|
||||
for entry in entries:
|
||||
count += 1
|
||||
if count % 500 == 0:
|
||||
logger.info(count)
|
||||
|
||||
fullname = get_normalized_full_name(entry['fullname'])
|
||||
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname)
|
||||
newobj = NhatsObject(
|
||||
space_object=space_object,
|
||||
min_dv=entry['min_dv']['dv'],
|
||||
min_dv_duration=entry['min_dv']['dur'],
|
||||
min_diameter=entry['min_size'],
|
||||
max_diameter=entry['max_size'],
|
||||
num_trajectories=entry['n_via_traj'],
|
||||
)
|
||||
newobjects.append(newobj)
|
||||
except SpaceObject.DoesNotExist:
|
||||
logger.error('Cannot find space object %s' % fullname)
|
||||
|
||||
logger.info('Inserting records...')
|
||||
NhatsObject.objects.all().delete()
|
||||
NhatsObject.objects.bulk_create(newobjects, batch_size=499)
|
||||
logger.info('%d records inserted' % len(newobjects))
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.info('Processing sentry data')
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
data_path = os.path.realpath(os.path.join(dir_path, 'rawdata/nhats.json'))
|
||||
with open(data_path) as f:
|
||||
result = json.load(f)
|
||||
process(result['data'])
|
||||
127
data/process_sbdb.py
Executable file
127
data/process_sbdb.py
Executable file
@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import csv
|
||||
import gzip
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import django
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import transaction
|
||||
from django.utils.text import slugify
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings_pipeline')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import SpaceObject, OrbitClass, ObjectType
|
||||
from data.util import get_normalized_full_name, queryset_iterator
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@transaction.atomic
|
||||
def insert_all(newobjects, delete=False):
|
||||
if delete:
|
||||
logger.info('Deleting...')
|
||||
for obj in SpaceObject.objects.all().only('pk').iterator():
|
||||
obj.delete()
|
||||
logger.info('Finished deleting.')
|
||||
SpaceObject.objects.bulk_create(newobjects, batch_size=499)
|
||||
|
||||
def process(reader):
|
||||
newobjects = []
|
||||
inserted_once = False
|
||||
failures_ma = 0
|
||||
for count, row in enumerate(reader, 1):
|
||||
if count % 1000 == 0:
|
||||
logger.info(count)
|
||||
|
||||
if count % 1000 == 0:
|
||||
# Subdivide insertions - slower, but needed for low memory
|
||||
# environments like production machine
|
||||
logger.info('Inserting...')
|
||||
insert_all(newobjects, delete=(not inserted_once))
|
||||
inserted_once = True
|
||||
newobjects = []
|
||||
|
||||
if not row['ma']:
|
||||
logger.warn('Missing mean anom: Failed to parse row %d (%s): %s' % \
|
||||
(count, row.get('full_name', '?'), json.dumps(row)))
|
||||
failures_ma += 1
|
||||
continue
|
||||
fullname = get_normalized_full_name(row['full_name'])
|
||||
|
||||
try:
|
||||
orbit_class = OrbitClass.objects.get(abbrev__iexact=row['class'])
|
||||
except ObjectDoesNotExist:
|
||||
orbit_class = None
|
||||
|
||||
object_type = ObjectType.from_class(row['class'])
|
||||
if row['name'] and object_type != ObjectType.COMET:
|
||||
shortname = row['name'].strip()
|
||||
else:
|
||||
shortname = fullname
|
||||
|
||||
magnitude = float(row['H']) if row['H'] else None
|
||||
if not magnitude:
|
||||
# Comet total magnitude
|
||||
magnitude = float(row['M1']) if row['M1'] else None
|
||||
|
||||
try:
|
||||
diam = float(row['diameter'].strip())
|
||||
except:
|
||||
diam = None
|
||||
|
||||
space_object = SpaceObject(
|
||||
fullname = fullname,
|
||||
name = shortname,
|
||||
slug = slugify(fullname.replace('/',' ')),
|
||||
a = float(row['a']),
|
||||
e = float(row['e']),
|
||||
i = float(row['i']),
|
||||
om = float(row['om']),
|
||||
w = float(row['w']),
|
||||
ma = float(row['ma']),
|
||||
epoch = float(row['epoch']),
|
||||
is_nea = True if row['neo'] == 'Y' else False,
|
||||
is_pha = True if row['pha'] == 'Y' else False,
|
||||
orbit_class = orbit_class,
|
||||
object_type = object_type,
|
||||
diameter = diam,
|
||||
spec_B = row['spec_B'],
|
||||
spec_T = row['spec_T'],
|
||||
H = magnitude,
|
||||
sbdb_entry = row,
|
||||
)
|
||||
|
||||
newobjects.append(space_object)
|
||||
|
||||
logger.info('Inserting final records...')
|
||||
insert_all(newobjects, delete=(not inserted_once))
|
||||
|
||||
logger.warning('%d blank mean anomalies' % failures_ma)
|
||||
|
||||
logger.info('Done.')
|
||||
|
||||
def generate_rows(fields, data):
|
||||
for row in data:
|
||||
yield dict(zip(fields, row))
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.info('Loading sbdb data...')
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
data_path = os.path.realpath(os.path.join(dir_path, 'rawdata/sbdb.json.gz'))
|
||||
with gzip.open(data_path) as f:
|
||||
obj = json.load(f)
|
||||
logger.info('Loaded sbdb data, processing...')
|
||||
fields = obj['fields']
|
||||
data = obj['data']
|
||||
rows = generate_rows(fields, data)
|
||||
process(rows)
|
||||
75
data/process_sentry.py
Executable file
75
data/process_sentry.py
Executable file
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import csv
|
||||
import django
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
parent_dir = os.path.join(current_dir, '../')
|
||||
sys.path.insert(0, os.path.realpath(parent_dir))
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'spacedb.settings')
|
||||
django.setup()
|
||||
|
||||
from spaceobjects.models import SentryEvent, SpaceObject
|
||||
from data.util import get_normalized_full_name
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def process(events):
|
||||
newobjects = []
|
||||
count = 0
|
||||
invalid_count = 0
|
||||
for event in events:
|
||||
count += 1
|
||||
if count % 2000 == 0:
|
||||
logger.info(count)
|
||||
|
||||
fullname = get_normalized_full_name(event['fullname'])
|
||||
|
||||
date_str = event['date']
|
||||
try:
|
||||
date = datetime.strptime(date_str[:date_str.find('.')], '%Y-%m-%d')
|
||||
except:
|
||||
invalid_count += 1
|
||||
continue
|
||||
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname)
|
||||
except SpaceObject.DoesNotExist:
|
||||
try:
|
||||
space_object = SpaceObject.objects.get(fullname=fullname.replace('(', '').replace(')', ''))
|
||||
except SpaceObject.DoesNotExist:
|
||||
logger.error('Cannot find space object %s' % fullname)
|
||||
|
||||
se = SentryEvent(
|
||||
space_object=space_object,
|
||||
date=date,
|
||||
energy_mt=float(event['energy']),
|
||||
prob=float(event['ip']),
|
||||
torino_scale=float(event['ts']) if event['ts'] else -1,
|
||||
palermo_scale=float(event['ps']),
|
||||
)
|
||||
newobjects.append(se)
|
||||
|
||||
logger.warn('%d invalid dates' % invalid_count)
|
||||
logger.info('Inserting records...')
|
||||
SentryEvent.objects.all().delete()
|
||||
SentryEvent.objects.bulk_create(newobjects, batch_size=499)
|
||||
logger.info('%d records inserted' % len(newobjects))
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.info('Processing sentry data')
|
||||
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
data_path = os.path.realpath(os.path.join(dir_path, 'rawdata/sentry.json'))
|
||||
with open(data_path) as f:
|
||||
result = json.load(f)
|
||||
process(result['data'])
|
||||
9
data/run_pipeline.sh
Executable file
9
data/run_pipeline.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
./download.sh
|
||||
./process.sh
|
||||
|
||||
popd &>/dev/null
|
||||
|
||||
25
data/util.py
Normal file
25
data/util.py
Normal file
@ -0,0 +1,25 @@
|
||||
import gc
|
||||
|
||||
from spaceobjects.models import ObjectType
|
||||
|
||||
def get_normalized_full_name(raw):
|
||||
fullname = raw.strip()
|
||||
if fullname[0] == '(' and fullname[-1] == ')':
|
||||
return fullname[1:-1]
|
||||
return fullname
|
||||
|
||||
def queryset_iterator(qs, batchsize = 500, gc_collect = True):
|
||||
iterator = qs.values_list('pk', flat=True).order_by('pk').distinct().iterator()
|
||||
eof = False
|
||||
while not eof:
|
||||
primary_key_buffer = []
|
||||
try:
|
||||
while len(primary_key_buffer) < batchsize:
|
||||
primary_key_buffer.append(iterator.next())
|
||||
except StopIteration:
|
||||
eof = True
|
||||
for obj in qs.filter(pk__in=primary_key_buffer).order_by('pk').iterator():
|
||||
yield obj
|
||||
if gc_collect:
|
||||
gc.collect()
|
||||
|
||||
46
docker-compose.yml
Normal file
46
docker-compose.yml
Normal file
@ -0,0 +1,46 @@
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:10.1-alpine
|
||||
volumes:
|
||||
- /var/spacedb/postgres/data:/var/lib/postgresql/data/
|
||||
networks:
|
||||
- db_network
|
||||
|
||||
app:
|
||||
build: .
|
||||
command: gunicorn --access-logfile - --error-logfile - --capture-output --log-level info -b '0.0.0.0:8000' -w 5 spacedb.wsgi
|
||||
environment:
|
||||
- DJANGO_SETTINGS_MODULE=spacedb.settings_prod
|
||||
volumes:
|
||||
- ./static:/app/static
|
||||
- /var/spacedb/raw:/app/data/rawdata
|
||||
- /var/spacedb/manual:/app/data/manual
|
||||
ports:
|
||||
- 8000:8000
|
||||
networks:
|
||||
- nginx_network
|
||||
- db_network
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
nginx:
|
||||
image: nginx:1.13
|
||||
volumes:
|
||||
- ./config/nginx/conf.d:/etc/nginx/conf.d
|
||||
- ./static:/var/www/static
|
||||
- /var/spacedb/raw/shapes/archive:/var/www/static/data/shapefiles/damit
|
||||
- /var/spacedb/manual/shapes:/var/www/static/data/shapefiles/manual
|
||||
ports:
|
||||
- 80:80
|
||||
networks:
|
||||
- nginx_network
|
||||
depends_on:
|
||||
- app
|
||||
|
||||
networks:
|
||||
nginx_network:
|
||||
driver: bridge
|
||||
db_network:
|
||||
driver: bridge
|
||||
22
manage.py
Executable file
22
manage.py
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "spacedb.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError:
|
||||
# The above import may fail for some other reason. Ensure that the
|
||||
# issue is really that Django is missing to avoid masking other
|
||||
# exceptions on Python 2.
|
||||
try:
|
||||
import django
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
)
|
||||
raise
|
||||
execute_from_command_line(sys.argv)
|
||||
35
package.json
Normal file
35
package.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "spacedb",
|
||||
"version": "0.0.1",
|
||||
"main": "client/index.js",
|
||||
"repository": "git@github.com:judymou/spacedb.git",
|
||||
"author": "Ian and Judy",
|
||||
"license": "N/A",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"build:watch": "webpack --watch",
|
||||
"lint": "eslint ./client",
|
||||
"lint:fix": "eslint --fix ./client"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.6.3",
|
||||
"react-dom": "^16.6.3",
|
||||
"react-proptypes": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.2.2",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.2.0",
|
||||
"@babel/preset-env": "^7.2.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-loader": "^8.0.4",
|
||||
"eslint": "^5.10.0",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"react-select": "^2.1.2",
|
||||
"webpack": "^4.27.1",
|
||||
"webpack-cli": "^3.1.2"
|
||||
}
|
||||
}
|
||||
7
requirements.txt
Normal file
7
requirements.txt
Normal file
@ -0,0 +1,7 @@
|
||||
Django==1.11.29
|
||||
jsonfield==1.0.3
|
||||
gunicorn==19.9.0
|
||||
psycopg2==2.7.6.1
|
||||
PyYAML==5.4
|
||||
enum34==1.1.6
|
||||
setuptools==65.5.1
|
||||
11
scripts/bootstrap_new_instance.sh
Executable file
11
scripts/bootstrap_new_instance.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run the initial migrations, creating the database
|
||||
docker-compose run --rm app /bin/sh -c "cd /app; ./manage.py migrate"
|
||||
docker-compose run --rm app /bin/sh -c "cd /app; ./manage.py loaddata orbit_class"
|
||||
|
||||
# Run the pipeline
|
||||
docker-compose run --rm app /bin/bash -c "cd /app; ./data/run_pipeline.sh"
|
||||
|
||||
# Create an admin login
|
||||
docker-compose run --rm app /bin/sh -c "cd /app; ./manage.py createsuperuser"
|
||||
13
scripts/prod_update.sh
Executable file
13
scripts/prod_update.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
pushd $(dirname $0) &>/dev/null
|
||||
|
||||
cd ..
|
||||
git pull
|
||||
docker-compose build
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
|
||||
docker system prune -af
|
||||
|
||||
popd &>/dev/null
|
||||
4
scripts/run_migration.sh
Executable file
4
scripts/run_migration.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run new migrations
|
||||
docker-compose run --rm app /bin/sh -c "cd /app && ./manage.py migrate && ./manage.py loaddata orbit_class"
|
||||
4
scripts/run_pipeline.sh
Executable file
4
scripts/run_pipeline.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run the pipeline
|
||||
time docker-compose run --rm app /bin/bash -c "cd /app; ./data/run_pipeline.sh"
|
||||
0
spacedb/__init__.py
Normal file
0
spacedb/__init__.py
Normal file
130
spacedb/settings.py
Normal file
130
spacedb/settings.py
Normal file
@ -0,0 +1,130 @@
|
||||
"""
|
||||
Django settings for spacedb project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.11.16.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.11/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '!f-34x!n5^0az@59f=$(hjbk$-x!z8dkb&e1#h8=6w)q3j$r%*'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
'django.contrib.sitemaps',
|
||||
'spaceobjects',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'spacedb.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': ['templates/'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'spacedb.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'static/')
|
||||
]
|
||||
|
||||
# TODO(ian): Uncomment this and comment the above before running collectstatic.
|
||||
#STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
||||
126
spacedb/settings_pipeline.py
Normal file
126
spacedb/settings_pipeline.py
Normal file
@ -0,0 +1,126 @@
|
||||
"""
|
||||
Django settings for spacedb project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.11.16.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.11/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '!f-34x!n5^0az@59f=$(hjbk$-x!z8dkb&e1#h8=6w)q3j$r%*'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
'spaceobjects',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'spacedb.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': ['templates/'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'spacedb.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'static'),
|
||||
]
|
||||
130
spacedb/settings_prod.py
Normal file
130
spacedb/settings_prod.py
Normal file
@ -0,0 +1,130 @@
|
||||
"""
|
||||
Django settings for spacedb project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.11.16.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.11/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.11/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '!f-34x!n5^0az@59f=$(hjbk$-x!z8dkb&e1#h8=6w)q3j$r%*'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = ['www.spacereference.org', 'localhost']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
'django.contrib.sitemaps',
|
||||
'spaceobjects',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'spacedb.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': ['templates/'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'spacedb.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'postgres',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': '',
|
||||
'HOST': 'db',
|
||||
'PORT': '5432',
|
||||
}
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'static'),
|
||||
]
|
||||
22
spacedb/urls.py
Normal file
22
spacedb/urls.py
Normal file
@ -0,0 +1,22 @@
|
||||
"""spacedb URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/1.11/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.conf.urls import url, include
|
||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.conf.urls import url, include
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^admin/', admin.site.urls),
|
||||
url(r'', include('spaceobjects.urls')),
|
||||
]
|
||||
16
spacedb/wsgi.py
Normal file
16
spacedb/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for spacedb project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "spacedb.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
0
spaceobjects/__init__.py
Normal file
0
spaceobjects/__init__.py
Normal file
6
spaceobjects/admin.py
Normal file
6
spaceobjects/admin.py
Normal file
@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
8
spaceobjects/apps.py
Normal file
8
spaceobjects/apps.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SpaceobjectsConfig(AppConfig):
|
||||
name = 'spaceobjects'
|
||||
315
spaceobjects/description.py
Normal file
315
spaceobjects/description.py
Normal file
@ -0,0 +1,315 @@
|
||||
'''
|
||||
Helpers for building an asteroid description.
|
||||
'''
|
||||
|
||||
COMET_CLASSES = set(['COM', 'CTc', 'ETc', 'HTC', 'HYP', 'JFc', 'JFC', 'PAR'])
|
||||
|
||||
def get_diameter_comparison(roid):
|
||||
diameter = roid.get_diameter_estimate()
|
||||
if not diameter:
|
||||
return None
|
||||
|
||||
diameter_sq = diameter * diameter
|
||||
|
||||
# http://www.decisionsciencenews.com/2015/02/20/put-size-countries-perspective-comparing-us-states/
|
||||
# https://en.wikipedia.org/wiki/List_of_United_States_cities_by_area
|
||||
if diameter_sq < 0.018:
|
||||
return 'a school bus or smaller'
|
||||
if diameter_sq < 0.029:
|
||||
return 'a basketball court'
|
||||
if diameter_sq < 0.110:
|
||||
return 'a football field'
|
||||
if diameter_sq < 0.0728434:
|
||||
return 'the U.S. White House'
|
||||
if diameter_sq < 0.234718:
|
||||
return 'the U.S. Capitol building'
|
||||
if diameter_sq < 1.280:
|
||||
return 'the Golden Gate Bridge'
|
||||
if diameter_sq < 2.35932:
|
||||
return 'the U.S. Pentagon'
|
||||
if diameter_sq < 8.848:
|
||||
return 'Mount Everest'
|
||||
if diameter_sq < 21:
|
||||
return 'the island of Manhattan'
|
||||
if diameter_sq < 97:
|
||||
return 'the San Francisco Bay'
|
||||
if diameter_sq < 124:
|
||||
return 'the city of Boston'
|
||||
if diameter_sq < 214:
|
||||
return 'the city of Cleveland, Ohio'
|
||||
if diameter_sq < 239:
|
||||
return 'the city of Baltimore'
|
||||
if diameter_sq < 370:
|
||||
return 'the city of Philadelphia'
|
||||
if diameter_sq < 400:
|
||||
return 'the city of Denver'
|
||||
if diameter_sq < 953:
|
||||
return 'the city of Indianapolis'
|
||||
if diameter_sq < 999:
|
||||
return 'the city of Dallas'
|
||||
if diameter_sq < 1213:
|
||||
return 'the city of New York'
|
||||
if diameter_sq < 1302:
|
||||
return 'the city of Los Angeles'
|
||||
if diameter_sq < 1625:
|
||||
return 'the city of Houston'
|
||||
if diameter_sq < 5000:
|
||||
return 'the U.S. state of Rhode Island'
|
||||
if diameter_sq < 14000:
|
||||
return 'the U.S. state of Delaware'
|
||||
if diameter_sq < 22000:
|
||||
return 'the U.S. state of Connecticut'
|
||||
if diameter_sq < 24000:
|
||||
return 'the U.S. state of New Jersey'
|
||||
if diameter_sq < 27000:
|
||||
return 'the U.S. state of Vermont'
|
||||
if diameter_sq < 32000:
|
||||
return 'the U.S. state of Massachusetts'
|
||||
if diameter_sq < 62000:
|
||||
return 'the U.S. state of Maryland'
|
||||
if diameter_sq < 82000:
|
||||
return 'the U.S. state of West Virginia'
|
||||
if diameter_sq < 91000:
|
||||
return 'the U.S. state of South Carolina'
|
||||
if diameter_sq < 94000:
|
||||
return 'Portugal'
|
||||
if diameter_sq < 104000:
|
||||
return 'South Korea'
|
||||
if diameter_sq < 109000:
|
||||
return 'Iceland'
|
||||
if diameter_sq < 119000:
|
||||
return 'the U.S. state of Virginia'
|
||||
if diameter_sq < 125000:
|
||||
return 'the U.S. state of Pennsylvania'
|
||||
if diameter_sq < 134000:
|
||||
return 'the U.S. state of Mississippi'
|
||||
if diameter_sq < 170000:
|
||||
return 'the U.S. state of Iowa'
|
||||
if diameter_sq < 200000:
|
||||
return 'the U.S. state of South Dakota'
|
||||
if diameter_sq < 300000:
|
||||
return 'Great Britain'
|
||||
if diameter_sq < 400000:
|
||||
return 'Japan'
|
||||
if diameter_sq < 500000:
|
||||
return 'France'
|
||||
if diameter_sq < 700000:
|
||||
return 'the U.S. state of Texas'
|
||||
return 'the U.S. state of Alaska'
|
||||
|
||||
# Approximate mapping from Tholen spectral type to SMASS, from Asterank
|
||||
# https://github.com/typpo/asterank/blob/master/data/pipeline/run/10_sbdb/horizon.py
|
||||
THOLEN_MAPPINGS = {
|
||||
'M': 'M',
|
||||
'E': 'M',
|
||||
'P': 'P',
|
||||
'B': 'B',
|
||||
'C': 'C',
|
||||
'F': 'C',
|
||||
'G': 'Cgh',
|
||||
'Q': 'Q',
|
||||
'R': 'R',
|
||||
'V': 'V',
|
||||
'T': 'T',
|
||||
'D': 'D',
|
||||
'A': 'A',
|
||||
}
|
||||
|
||||
# Keys are asteroid spectra type. Values are maps from a material
|
||||
# to the percent mass of each material.
|
||||
SPECTRA_INDEX = {
|
||||
'?': {},
|
||||
'A': {},
|
||||
'B': {
|
||||
'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
'iron': 10,
|
||||
},
|
||||
'C': {# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .2,
|
||||
'iron': .166,
|
||||
'nickel': .014,
|
||||
'cobalt': .002,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'Ch': {# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .2,
|
||||
'iron': .166,
|
||||
'nickel': .014,
|
||||
'cobalt': .002,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'Cg': {# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .2,
|
||||
'iron': .166,
|
||||
'nickel': .014,
|
||||
'cobalt': .002,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'Cgh': {# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .2,
|
||||
'iron': .166,
|
||||
'nickel': .014,
|
||||
'cobalt': .002,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'C type': {# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .2,
|
||||
'iron': .166,
|
||||
'nickel': .014,
|
||||
'cobalt': .002,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'Cb': {# transition object between C and B# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .1,
|
||||
'iron': .083,
|
||||
'nickel': .007,
|
||||
'cobalt': .001,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'D': {
|
||||
'water': 0.000023,
|
||||
},
|
||||
'E': {
|
||||
|
||||
},
|
||||
'K': {# cross between S and C# from Keck report at http: //www.kiss.caltech.edu/study/asteroid/asteroid_final_report.pdf
|
||||
'water': .1,
|
||||
'iron': .083,
|
||||
'nickel': .007,
|
||||
'cobalt': .001,
|
||||
|
||||
#volatiles 'hydrogen': 0.235,
|
||||
'nitrogen': 0.001,
|
||||
'ammonia': 0.001,
|
||||
},
|
||||
'L': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
'aluminum': 7
|
||||
},
|
||||
'Ld': {# copied from S
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'M': {
|
||||
'iron': 88,
|
||||
'nickel': 10,
|
||||
'cobalt': 0.5,
|
||||
},
|
||||
'O': {
|
||||
'nickel-iron': 2.965,
|
||||
'platinum': 1.25,
|
||||
},
|
||||
'P': {# correspond to CI, CM carbonaceous chondrites
|
||||
'water': 12.5,
|
||||
},
|
||||
'R': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'S': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
#Sa, Sq, Sr, Sk, and Sl all transition objects(assume half / half)
|
||||
'Sa': {
|
||||
'magnesium silicate': 5e-31,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'Sq': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'Sr': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'Sk': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'Sl': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'S(IV)': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'Q': {
|
||||
'nickel-iron': 13.315,
|
||||
},
|
||||
'R': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
'T': {
|
||||
'iron': 6,
|
||||
},
|
||||
'U': {
|
||||
|
||||
},
|
||||
'V': {
|
||||
'magnesium silicate': 1e-30,
|
||||
'iron silicate': 0,
|
||||
},
|
||||
|
||||
#TODO use density to decide what kind of X the object is ?
|
||||
|
||||
'X' : {# TODO these vals only apply to M - type within X
|
||||
'iron': 88,
|
||||
'nickel': 10,
|
||||
'cobalt': 0.5,
|
||||
},
|
||||
'Xe': {# TODO these vals only apply to M - type within X
|
||||
'iron': 88,
|
||||
'nickel': 10,
|
||||
'cobalt': 0.5,
|
||||
},
|
||||
'Xc': {# TODO these vals only apply to M - type within X
|
||||
'iron': 88,
|
||||
'nickel': 10,
|
||||
'cobalt': 0.5,
|
||||
'platinum': 0.005,
|
||||
},
|
||||
'Xk': {# TODO these vals only apply to M - type within X
|
||||
'iron': 88,
|
||||
'nickel': 10,
|
||||
'cobalt': 0.5,
|
||||
},
|
||||
'comet': {# no estimates for now, because assumed mass, etc.would be off
|
||||
},
|
||||
}
|
||||
|
||||
def composition(roid):
|
||||
ret = []
|
||||
spec = roid.sbdb_entry.get('spec_B')
|
||||
if not spec:
|
||||
# Try to convert Tholen to SMASS spectral classification
|
||||
spec = roid.sbdb_entry.get('spec_T')
|
||||
if not spec:
|
||||
return []
|
||||
spec = THOLEN_MAPPINGS.get(spec)
|
||||
if not spec:
|
||||
return []
|
||||
return SPECTRA_INDEX.get(spec, {}).keys()
|
||||
190
spaceobjects/fixtures/orbit_class.yaml
Normal file
190
spaceobjects/fixtures/orbit_class.yaml
Normal file
@ -0,0 +1,190 @@
|
||||
# https://pdssbn.astro.umd.edu/data_other/objclass.shtml
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 1
|
||||
fields:
|
||||
abbrev: COM
|
||||
name: Unclassified Comet
|
||||
slug: unclassified-comets
|
||||
desc: Comets whose orbits do not match any defined orbit class
|
||||
orbit_sentence: whose orbit does not match any defined comet orbit class
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 2
|
||||
fields:
|
||||
abbrev: CTc
|
||||
name: Chiron-type Comet
|
||||
slug: chiron-type-comets
|
||||
desc: Chiron-type comet, as defined by Levison and Duncan (TJupiter > 3; a > aJupiter)
|
||||
orbit_sentence: whose orbit is approximately between Jupiter and Neptune
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 3
|
||||
fields:
|
||||
abbrev: ETc
|
||||
name: Encke-type Comet
|
||||
slug: encke-type-comets
|
||||
desc: Encke-type comet, as defined by Levison and Duncan (TJupiter > 3; a < aJupiter)
|
||||
orbit_sentence: whose orbit brings it closer to the sun than Jupiter
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 4
|
||||
fields:
|
||||
abbrev: HTC
|
||||
name: Halley-type Comet
|
||||
slug: halley-type-comets
|
||||
desc: Halley-type comet, classical definition (20 y < P < 200 y)
|
||||
orbit_sentence: with a medium-length orbit that is highly inclined to the ecliptic plane of the solar system
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 5
|
||||
fields:
|
||||
abbrev: HYP
|
||||
name: Hyperbolic Comet
|
||||
slug: hyperbolic-comets
|
||||
desc: Comets on hyperbolic orbits (e > 1.0)
|
||||
orbit_sentence: with a trajectory through the solar system likely originating from the Oort Cloud
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 6
|
||||
fields:
|
||||
abbrev: JFc
|
||||
name: Jupiter-family Comet
|
||||
slug: jupiter-family-comets
|
||||
desc: Jupiter-family comets, as defined by Levison and Duncan (2 < TJupiter < 3)
|
||||
orbit_sentence: whose orbit features a relatively short period, low inclination, and is controlled by Jupiter's gravitational effects
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 8
|
||||
fields:
|
||||
abbrev: PAR
|
||||
name: Parabolic Comet
|
||||
slug: parabolic-comets
|
||||
desc: Comets on parabolic orbits (e = 1.0)
|
||||
orbit_sentence: with an extremely long orbital period, likely originating from the Oort Cloud
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 9
|
||||
fields:
|
||||
abbrev: AMO
|
||||
name: Amor-class Asteroid
|
||||
slug: amor-class-asteroids
|
||||
desc: Near-Earth asteroid whose orbits are similar to that of 1221 Amor (a > 1.0 AU; 1.017 AU < q < 1.3 AU)
|
||||
orbit_sentence: whose orbit approaches the orbit of Earth but does not cross it
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 10
|
||||
fields:
|
||||
abbrev: APO
|
||||
name: Apollo-class Asteroid
|
||||
slug: apollo-class-asteroids
|
||||
desc: Near-Earth asteroids whose orbits cross the Earth's orbit similar to that of 1862 Apollo (a > 1.0 AU; q < 1.017 AU).
|
||||
orbit_sentence: whose orbit crosses the orbit of Earth
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 11
|
||||
fields:
|
||||
abbrev: AST
|
||||
name: Asteroid
|
||||
slug: asteroids
|
||||
desc: Asteroid orbit not matching any defined orbit class
|
||||
orbit_sentence: whose orbit does not match any defined asteroid orbital class
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 12
|
||||
fields:
|
||||
abbrev: ATE
|
||||
name: Aten-class Asteroid
|
||||
slug: aten-class-asteroids
|
||||
desc: Near-Earth asteroid orbits similar to that of 2062 Aten (a < 1.0 AU; Q > 0.983 AU)
|
||||
orbit_sentence: whose orbit could bring it in close proximity to Earth
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 13
|
||||
fields:
|
||||
abbrev: CEN
|
||||
name: Centaur-class Asteroid
|
||||
slug: centaur-class-asteroids
|
||||
desc: Objects with orbits between Jupiter and Neptune (5.5 AU < a < 30.1 AU)
|
||||
orbit_sentence: with an orbit between Jupiter and Neptune
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 14
|
||||
fields:
|
||||
abbrev: HYA
|
||||
name: Hyperbolic Asteroid
|
||||
slug: hyperbolic-asteroids
|
||||
desc: Asteroids on hyperbolic orbits (e > 1.0)
|
||||
orbit_sentence: with an orbit not bound to the sun
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 15
|
||||
fields:
|
||||
abbrev: IEO
|
||||
name: Interior-Earth Asteroid
|
||||
slug: interior-earth-asteroids
|
||||
desc: Asteroids with orbits contained entirely within the orbit of the Earth (Q < 0.983 AU)
|
||||
orbit_sentence: with an orbit that is entirely confined within Earth's orbit
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 16
|
||||
fields:
|
||||
abbrev: IMB
|
||||
name: Inner Main-belt Asteroid
|
||||
slug: inner-main-belt-asteroids
|
||||
desc: Asteroids with orbital elements constrained by (a < 2.0 AU; q > 1.666 AU)
|
||||
orbit_sentence: orbiting between Mars and Jupiter within the inner portion of the asteroid belt
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 17
|
||||
fields:
|
||||
abbrev: MBA
|
||||
name: Main-belt Asteroid
|
||||
slug: main-belt-asteroids
|
||||
desc: Asteroids with orbital elements constrained by (2.0 AU < a < 3.2 AU; q > 1.666 AU)
|
||||
orbit_sentence: orbiting between Mars and Jupiter in the main portion of the asteroid belt
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 18
|
||||
fields:
|
||||
abbrev: MCA
|
||||
name: Mars-crossing Asteroid
|
||||
slug: mars-crossing-asteroids
|
||||
desc: Asteroids that cross the orbit of Mars constrained by (1.3 AU < q < 1.666 AU; a < 3.2 AU)
|
||||
orbit_sentence: with an orbit that crosses the orbit of Mars
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 19
|
||||
fields:
|
||||
abbrev: OMB
|
||||
name: Outer Main-belt Asteroid
|
||||
slug: outer-main-belt-asteroids
|
||||
desc: Asteroids with orbital elements constrained by (3.2 AU < a < 4.6 AU)
|
||||
orbit_sentence: that orbits between Mars and Jupiter in the outer reaches of the main asteroid belt
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 20
|
||||
fields:
|
||||
abbrev: PAA
|
||||
name: Parabolic Asteroid
|
||||
slug: parabolic-asteroids
|
||||
desc: Asteroids on parabolic orbits (e = 1.0)
|
||||
orbit_sentence: with an unusual orbit that brings it far beyond the normal boundaries of asteroids in the solar system
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 21
|
||||
fields:
|
||||
abbrev: TJN
|
||||
name: Jupiter Trojan
|
||||
slug: jupiter-trojans
|
||||
desc: Asteroids trapped in Jupiter's L4/L5 Lagrange points (4.6 AU < a < 5.5 AU; e < 0.3)
|
||||
orbit_sentence: that shares Jupiter's orbit around the sun
|
||||
|
||||
- model: spaceobjects.OrbitClass
|
||||
pk: 22
|
||||
fields:
|
||||
abbrev: TNO
|
||||
name: Trans-Neptunian Object
|
||||
slug: trans-neptunian-objects
|
||||
desc: Objects with orbits outside Neptune (a > 30.1 AU)
|
||||
orbit_sentence: whose orbit extends beyond the orbit of Neptune
|
||||
23
spaceobjects/migrations/0001_initial.py
Normal file
23
spaceobjects/migrations/0001_initial.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-02 07:24
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SpaceObject',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=500)),
|
||||
],
|
||||
),
|
||||
]
|
||||
33
spaceobjects/migrations/0002_auto_20181208_2313.py
Normal file
33
spaceobjects/migrations/0002_auto_20181208_2313.py
Normal file
@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-08 23:13
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CloseApproach',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('dist_min', models.FloatField()),
|
||||
],
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='spaceobject',
|
||||
old_name='name',
|
||||
new_name='fullname',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='space_object',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.SpaceObject'),
|
||||
),
|
||||
]
|
||||
21
spaceobjects/migrations/0003_spaceobject_name.py
Normal file
21
spaceobjects/migrations/0003_spaceobject_name.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-08 23:34
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0002_auto_20181208_2313'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='name',
|
||||
field=models.CharField(default=1, max_length=500),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
57
spaceobjects/migrations/0004_auto_20181209_2225.py
Normal file
57
spaceobjects/migrations/0004_auto_20181209_2225.py
Normal file
@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-09 22:25
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0003_spaceobject_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='a',
|
||||
field=models.FloatField(default=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='e',
|
||||
field=models.FloatField(default=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='epoch',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='i',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='ma',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='om',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='w',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
22
spaceobjects/migrations/0005_spaceobject_sbdb_entry.py
Normal file
22
spaceobjects/migrations/0005_spaceobject_sbdb_entry.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-13 01:59
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0004_auto_20181209_2225'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='sbdb_entry',
|
||||
field=jsonfield.fields.JSONField(default={}),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
31
spaceobjects/migrations/0006_auto_20181214_2300.py
Normal file
31
spaceobjects/migrations/0006_auto_20181214_2300.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-14 23:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0005_spaceobject_sbdb_entry'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='slug',
|
||||
field=models.CharField(default='', max_length=200),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='fullname',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='name',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
]
|
||||
19
spaceobjects/migrations/0007_auto_20181216_2116.py
Normal file
19
spaceobjects/migrations/0007_auto_20181216_2116.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-16 21:16
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0006_auto_20181214_2300'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['fullname'], name='spaceobject_fullnam_51b141_idx'),
|
||||
),
|
||||
]
|
||||
39
spaceobjects/migrations/0008_auto_20181216_2135.py
Normal file
39
spaceobjects/migrations/0008_auto_20181216_2135.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-16 21:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0007_auto_20181216_2116'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='dist',
|
||||
field=models.FloatField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='h_mag',
|
||||
field=models.FloatField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='time_jd',
|
||||
field=models.FloatField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='v_rel',
|
||||
field=models.FloatField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
30
spaceobjects/migrations/0009_sentryevent.py
Normal file
30
spaceobjects/migrations/0009_sentryevent.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-17 02:52
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0008_auto_20181216_2135'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SentryEvent',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField()),
|
||||
('energy_mt', models.FloatField()),
|
||||
('dist_km', models.FloatField()),
|
||||
('dist_err', models.FloatField()),
|
||||
('palermo_scale', models.FloatField()),
|
||||
('torino_scale', models.FloatField()),
|
||||
('prob', models.FloatField()),
|
||||
('space_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.SpaceObject')),
|
||||
],
|
||||
),
|
||||
]
|
||||
26
spaceobjects/migrations/0010_auto_20181217_0556.py
Normal file
26
spaceobjects/migrations/0010_auto_20181217_0556.py
Normal file
@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-17 05:56
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0009_sentryevent'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='closeapproach',
|
||||
name='time_jd',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='closeapproach',
|
||||
name='date',
|
||||
field=models.DateField(default=datetime.datetime(2018, 12, 17, 5, 56, 9, 89760)),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
25
spaceobjects/migrations/0011_auto_20181217_0615.py
Normal file
25
spaceobjects/migrations/0011_auto_20181217_0615.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-17 06:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0010_auto_20181217_0556'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='closeapproach',
|
||||
old_name='dist',
|
||||
new_name='dist_au',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='closeapproach',
|
||||
old_name='dist_min',
|
||||
new_name='dist_min_au',
|
||||
),
|
||||
]
|
||||
27
spaceobjects/migrations/0012_nhatsobject.py
Normal file
27
spaceobjects/migrations/0012_nhatsobject.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-21 15:12
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0011_auto_20181217_0615'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NhatsObject',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('min_dv', models.FloatField()),
|
||||
('min_dv_duration', models.FloatField()),
|
||||
('min_diameter', models.FloatField()),
|
||||
('max_diameter', models.FloatField()),
|
||||
('space_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.SpaceObject')),
|
||||
],
|
||||
),
|
||||
]
|
||||
21
spaceobjects/migrations/0013_nhatsobject_num_trajectories.py
Normal file
21
spaceobjects/migrations/0013_nhatsobject_num_trajectories.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-21 15:48
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0012_nhatsobject'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='nhatsobject',
|
||||
name='num_trajectories',
|
||||
field=models.IntegerField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
19
spaceobjects/migrations/0014_auto_20181227_1730.py
Normal file
19
spaceobjects/migrations/0014_auto_20181227_1730.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-12-27 17:30
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0013_nhatsobject_num_trajectories'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['slug'], name='spaceobject_slug_f1242a_idx'),
|
||||
),
|
||||
]
|
||||
56
spaceobjects/migrations/0015_auto_20190105_0740.py
Normal file
56
spaceobjects/migrations/0015_auto_20190105_0740.py
Normal file
@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 07:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0014_auto_20181227_1730'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='H',
|
||||
field=models.FloatField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='diameter',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='neo',
|
||||
field=models.BooleanField(default=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='orbit_class',
|
||||
field=models.CharField(default='A', max_length=200),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='pha',
|
||||
field=models.BooleanField(default=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='spec_B',
|
||||
field=models.CharField(default='C', max_length=200),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='spec_T',
|
||||
field=models.CharField(default='C', max_length=200),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
23
spaceobjects/migrations/0016_auto_20190105_1716.py
Normal file
23
spaceobjects/migrations/0016_auto_20190105_1716.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 17:16
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0015_auto_20190105_0740'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='spaceobject',
|
||||
name='neo',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='spaceobject',
|
||||
name='pha',
|
||||
),
|
||||
]
|
||||
27
spaceobjects/migrations/0017_auto_20190105_1727.py
Normal file
27
spaceobjects/migrations/0017_auto_20190105_1727.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 17:27
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0016_auto_20190105_1716'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='is_neo',
|
||||
field=models.BooleanField(default=False),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='is_pha',
|
||||
field=models.BooleanField(default=False),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
26
spaceobjects/migrations/0018_orbitclass.py
Normal file
26
spaceobjects/migrations/0018_orbitclass.py
Normal file
@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 17:48
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0017_auto_20190105_1727'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OrbitClass',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('slug', models.CharField(max_length=200, unique=True)),
|
||||
('abbrev', models.CharField(max_length=10)),
|
||||
('desc', models.CharField(max_length=500)),
|
||||
('orbit_sentence', models.CharField(max_length=500)),
|
||||
],
|
||||
),
|
||||
]
|
||||
21
spaceobjects/migrations/0019_auto_20190105_1818.py
Normal file
21
spaceobjects/migrations/0019_auto_20190105_1818.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 18:18
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0018_orbitclass'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='orbit_class',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.OrbitClass'),
|
||||
),
|
||||
]
|
||||
23
spaceobjects/migrations/0020_auto_20190105_1820.py
Normal file
23
spaceobjects/migrations/0020_auto_20190105_1820.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-05 18:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0019_auto_20190105_1818'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='orbitclass',
|
||||
index=models.Index(fields=['slug'], name='spaceobject_slug_610d6e_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='orbitclass',
|
||||
index=models.Index(fields=['abbrev'], name='spaceobject_abbrev_697070_idx'),
|
||||
),
|
||||
]
|
||||
33
spaceobjects/migrations/0021_shapemodel.py
Normal file
33
spaceobjects/migrations/0021_shapemodel.py
Normal file
@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-29 03:44
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0020_auto_20190105_1820'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ShapeModel',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('shape_path', models.CharField(max_length=200)),
|
||||
('render_path', models.CharField(max_length=200)),
|
||||
('spin_latitude', models.FloatField()),
|
||||
('spin_longitude', models.FloatField()),
|
||||
('spin_angle', models.FloatField()),
|
||||
('period_hr', models.FloatField()),
|
||||
('jd', models.FloatField()),
|
||||
('yorp', models.FloatField()),
|
||||
('equiv_diameter_km', models.FloatField()),
|
||||
('quality', models.IntegerField()),
|
||||
('space_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.SpaceObject')),
|
||||
],
|
||||
),
|
||||
]
|
||||
20
spaceobjects/migrations/0022_auto_20190129_0346.py
Normal file
20
spaceobjects/migrations/0022_auto_20190129_0346.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-29 03:46
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0021_shapemodel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='yorp',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
20
spaceobjects/migrations/0023_auto_20190129_0347.py
Normal file
20
spaceobjects/migrations/0023_auto_20190129_0347.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-29 03:47
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0022_auto_20190129_0346'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='equiv_diameter_km',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
20
spaceobjects/migrations/0024_auto_20190129_0347.py
Normal file
20
spaceobjects/migrations/0024_auto_20190129_0347.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-01-29 03:47
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0023_auto_20190129_0347'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='quality',
|
||||
field=models.FloatField(),
|
||||
),
|
||||
]
|
||||
30
spaceobjects/migrations/0025_auto_20190202_0328.py
Normal file
30
spaceobjects/migrations/0025_auto_20190202_0328.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-02 03:28
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import spaceobjects.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0024_auto_20190129_0347'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='object_type',
|
||||
field=models.CharField(choices=[(spaceobjects.models.ObjectType('ASTEROID'), 'ASTEROID'), (spaceobjects.models.ObjectType('COMET'), 'COMET')], default='ASTEROID', max_length=20),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['orbit_class'], name='spaceobject_orbit_c_56d89c_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['object_type'], name='spaceobject_object__a115d6_idx'),
|
||||
),
|
||||
]
|
||||
28
spaceobjects/migrations/0026_auto_20190223_1913.py
Normal file
28
spaceobjects/migrations/0026_auto_20190223_1913.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-23 19:13
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0025_auto_20190202_0328'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='spaceobject',
|
||||
old_name='is_neo',
|
||||
new_name='is_nea',
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['is_nea'], name='spaceobject_is_nea_27a9a3_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['is_pha'], name='spaceobject_is_pha_3d9700_idx'),
|
||||
),
|
||||
]
|
||||
21
spaceobjects/migrations/0027_spaceobject_sbdb_order_id.py
Normal file
21
spaceobjects/migrations/0027_spaceobject_sbdb_order_id.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-24 19:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0026_auto_20190223_1913'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='sbdb_order_id',
|
||||
field=models.IntegerField(default=-1),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
19
spaceobjects/migrations/0028_auto_20190224_1945.py
Normal file
19
spaceobjects/migrations/0028_auto_20190224_1945.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-24 19:45
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0027_spaceobject_sbdb_order_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['sbdb_order_id'], name='spaceobject_sbdb_or_ff8d91_idx'),
|
||||
),
|
||||
]
|
||||
23
spaceobjects/migrations/0029_auto_20190224_2033.py
Normal file
23
spaceobjects/migrations/0029_auto_20190224_2033.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-24 20:33
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0028_auto_20190224_1945'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveIndex(
|
||||
model_name='spaceobject',
|
||||
name='spaceobject_sbdb_or_ff8d91_idx',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='spaceobject',
|
||||
name='sbdb_order_id',
|
||||
),
|
||||
]
|
||||
34
spaceobjects/migrations/0030_auto_20190226_0604.py
Normal file
34
spaceobjects/migrations/0030_auto_20190226_0604.py
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-02-26 06:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0029_auto_20190224_2033'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='orbitclass',
|
||||
options={'ordering': ['id']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='spaceobject',
|
||||
options={'ordering': ['id']},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='H',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='orbit_class',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='spaceobjects.OrbitClass'),
|
||||
),
|
||||
]
|
||||
43
spaceobjects/migrations/0031_auto_20190304_0448.py
Normal file
43
spaceobjects/migrations/0031_auto_20190304_0448.py
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-03-04 04:48
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0030_auto_20190226_0604'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='closeapproach',
|
||||
options={'ordering': ['id']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='nhatsobject',
|
||||
options={'ordering': ['id']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='sentryevent',
|
||||
options={'ordering': ['id']},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='closeapproach',
|
||||
index=models.Index(fields=['date'], name='spaceobject_date_e8c089_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['diameter'], name='spaceobject_diamete_a2968b_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='sentryevent',
|
||||
index=models.Index(fields=['prob'], name='spaceobject_prob_b35e86_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='nhatsobject',
|
||||
index=models.Index(fields=['min_dv'], name='spaceobject_min_dv_014adf_idx'),
|
||||
),
|
||||
]
|
||||
40
spaceobjects/migrations/0032_auto_20190516_2237.py
Normal file
40
spaceobjects/migrations/0032_auto_20190516_2237.py
Normal file
@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-05-16 22:37
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0031_auto_20190304_0448'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='jd',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='period_hr',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='spin_angle',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='spin_latitude',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='spin_longitude',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
20
spaceobjects/migrations/0033_auto_20190516_2241.py
Normal file
20
spaceobjects/migrations/0033_auto_20190516_2241.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-05-16 22:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0032_auto_20190516_2237'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='shapemodel',
|
||||
name='quality',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
21
spaceobjects/migrations/0034_shapemodel_source.py
Normal file
21
spaceobjects/migrations/0034_shapemodel_source.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-05-16 22:51
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0033_auto_20190516_2241'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='shapemodel',
|
||||
name='source',
|
||||
field=models.CharField(default='damit', max_length=512),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
19
spaceobjects/migrations/0035_auto_20190707_0613.py
Normal file
19
spaceobjects/migrations/0035_auto_20190707_0613.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-07-07 06:13
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0034_shapemodel_source'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='spaceobject',
|
||||
index=models.Index(fields=['a'], name='spaceobject_a_f9bd0b_idx'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-08-31 16:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0035_auto_20190707_0613'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spaceobject',
|
||||
name='diameter_estimate',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
20
spaceobjects/migrations/0037_auto_20190831_1918.py
Normal file
20
spaceobjects/migrations/0037_auto_20190831_1918.py
Normal file
@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2019-08-31 19:18
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0036_spaceobject_diameter_estimate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='object_type',
|
||||
field=models.CharField(choices=[(b'ASTEROID', 'ASTEROID'), (b'COMET', 'COMET')], max_length=20),
|
||||
),
|
||||
]
|
||||
25
spaceobjects/migrations/0038_auto_20200117_1722.py
Normal file
25
spaceobjects/migrations/0038_auto_20200117_1722.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.23 on 2020-01-17 17:22
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spaceobjects', '0037_auto_20190831_1918'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='spec_B',
|
||||
field=models.CharField(blank=True, max_length=200, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='spaceobject',
|
||||
name='spec_T',
|
||||
field=models.CharField(blank=True, max_length=200, null=True),
|
||||
),
|
||||
]
|
||||
0
spaceobjects/migrations/__init__.py
Normal file
0
spaceobjects/migrations/__init__.py
Normal file
494
spaceobjects/models.py
Normal file
494
spaceobjects/models.py
Normal file
@ -0,0 +1,494 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import math
|
||||
from datetime import datetime, date
|
||||
from enum import Enum
|
||||
|
||||
from django.contrib import admin
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from jsonfield import JSONField
|
||||
|
||||
from spaceobjects.description import get_diameter_comparison, composition, COMET_CLASSES
|
||||
|
||||
class ObjectType(Enum):
|
||||
ASTEROID = 'ASTEROID'
|
||||
COMET = 'COMET'
|
||||
|
||||
@classmethod
|
||||
def from_class(self, classname):
|
||||
if classname in COMET_CLASSES:
|
||||
return self.COMET
|
||||
return self.ASTEROID
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
class OrbitClass(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
slug = models.CharField(max_length=200, unique=True)
|
||||
abbrev = models.CharField(max_length=10)
|
||||
|
||||
desc = models.CharField(max_length=500)
|
||||
orbit_sentence = models.CharField(max_length=500)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('category', args=[self.slug])
|
||||
|
||||
def __str__(self):
|
||||
return self.abbrev
|
||||
|
||||
class Meta:
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['slug']),
|
||||
models.Index(fields=['abbrev']),
|
||||
]
|
||||
|
||||
class SpaceObject(models.Model):
|
||||
fullname = models.CharField(max_length=200)
|
||||
name = models.CharField(max_length=200)
|
||||
slug = models.CharField(max_length=200)
|
||||
|
||||
orbit_class = models.ForeignKey(OrbitClass, blank=True, null=True)
|
||||
object_type = models.CharField(max_length = 20,
|
||||
choices=[(tag.name, tag.value) for tag in ObjectType])
|
||||
|
||||
# Basic orbital elements
|
||||
a = models.FloatField()
|
||||
e = models.FloatField()
|
||||
i = models.FloatField()
|
||||
om = models.FloatField()
|
||||
w = models.FloatField()
|
||||
ma = models.FloatField()
|
||||
epoch = models.FloatField()
|
||||
|
||||
is_nea = models.BooleanField()
|
||||
is_pha = models.BooleanField()
|
||||
spec_B = models.CharField(max_length=200, null=True, blank=True)
|
||||
spec_T = models.CharField(max_length=200, null=True, blank=True)
|
||||
H = models.FloatField(null=True, blank=True)
|
||||
|
||||
# For now this is only SBDB diameter. See get_diameter_estimate below.
|
||||
diameter = models.FloatField(null=True, blank=True)
|
||||
|
||||
# Automatically filled via get_diameter_estimate
|
||||
diameter_estimate = models.FloatField(null=True, blank=True)
|
||||
|
||||
# sbdb blob
|
||||
sbdb_entry = JSONField()
|
||||
|
||||
def get_absolute_url(self):
|
||||
if self.object_type == ObjectType.COMET.value:
|
||||
return reverse('detail_comet', args=[self.slug])
|
||||
return reverse('detail_asteroid', args=[self.slug])
|
||||
|
||||
@cached_property
|
||||
def shorthand(self):
|
||||
if self.name.find('(') > -1:
|
||||
return self.name[self.name.find('(') + 1 : self.name.find(')')]
|
||||
return self.name
|
||||
|
||||
@cached_property
|
||||
def has_shorthand(self):
|
||||
return self.shorthand() != self.name
|
||||
|
||||
@cached_property
|
||||
def get_object_type(self):
|
||||
if self.fullname == '1 Ceres':
|
||||
return 'object'
|
||||
|
||||
if self.is_comet:
|
||||
return 'comet'
|
||||
if self.is_asteroid:
|
||||
return 'asteroid'
|
||||
|
||||
# This should never happen...
|
||||
return 'object'
|
||||
|
||||
@cached_property
|
||||
def composition(self):
|
||||
return composition(self)
|
||||
|
||||
@cached_property
|
||||
def perihelion(self):
|
||||
return self.a * (1 - self.e)
|
||||
|
||||
@cached_property
|
||||
def aphelion(self):
|
||||
return self.a * (1 + self.e)
|
||||
|
||||
@cached_property
|
||||
def moid(self):
|
||||
entry = self.sbdb_entry.get('moid')
|
||||
if not entry:
|
||||
return None
|
||||
return float(entry)
|
||||
|
||||
@cached_property
|
||||
def firstobs_date(self):
|
||||
firstobs = self.sbdb_entry.get('first_obs')
|
||||
return datetime.strptime(firstobs, '%Y-%m-%d')
|
||||
|
||||
@cached_property
|
||||
def lastobs_date(self):
|
||||
lastobs = self.sbdb_entry.get('last_obs')
|
||||
return datetime.strptime(lastobs, '%Y-%m-%d')
|
||||
|
||||
@cached_property
|
||||
def size_adjective(self):
|
||||
diameter = self.get_diameter_estimate()
|
||||
if not diameter:
|
||||
return None
|
||||
|
||||
if diameter < 0.5:
|
||||
return 'very small'
|
||||
if diameter < 1:
|
||||
return 'small'
|
||||
if diameter < 10:
|
||||
return 'mid-sized'
|
||||
if diameter < 100:
|
||||
return 'large'
|
||||
if diameter < 200:
|
||||
return 'large'
|
||||
if diameter < 300:
|
||||
return 'very large'
|
||||
if self.object_type == ObjectType.ASTEROID.value:
|
||||
return 'dwarf planet'
|
||||
return 'large'
|
||||
|
||||
@cached_property
|
||||
def avg_orbital_speed(self):
|
||||
# in km/s
|
||||
if self.period_in_days > 0:
|
||||
return (2 * math.pi * self.a * 149597870.7) / (self.period_in_days * 86400)
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def is_dwarf_planet(self):
|
||||
return self.size_adjective == 'dwarf planet'
|
||||
|
||||
@cached_property
|
||||
def is_asteroid(self):
|
||||
return self.object_type == ObjectType.ASTEROID.value
|
||||
|
||||
@cached_property
|
||||
def is_comet(self):
|
||||
return self.object_type == ObjectType.COMET.value
|
||||
|
||||
@cached_property
|
||||
def has_size_info(self):
|
||||
diam = self.sbdb_entry.get('diameter')
|
||||
return diam != '' and diam is not None
|
||||
|
||||
@cached_property
|
||||
def has_size_info_estimate(self):
|
||||
return self.get_diameter_estimate() is not None
|
||||
|
||||
@cached_property
|
||||
def get_size_rough_comparison(self):
|
||||
diameter = self.get_diameter_estimate()
|
||||
if not diameter:
|
||||
return None
|
||||
if diameter > 900:
|
||||
return 'the largest asteroid/dwarf planet'
|
||||
if diameter > 300:
|
||||
return 'one of the largest objects'
|
||||
if diameter > 1:
|
||||
return 'larger than 99% of asteroids'
|
||||
if diameter > 0.5:
|
||||
return 'larger than ~97% of asteroids but small compared to large asteroids'
|
||||
if diameter > 0.3:
|
||||
return 'larger than 90% of asteroids but tiny compared to large asteroids'
|
||||
return 'a small to average asteroid'
|
||||
|
||||
@cached_property
|
||||
def get_diameter_comparison(self):
|
||||
return get_diameter_comparison(self)
|
||||
|
||||
@cached_property
|
||||
def get_similar_orbits(self, n=3):
|
||||
a_range = [self.a - 0.01, self.a + 0.01]
|
||||
similar = SpaceObject.objects.filter(a__range=a_range).exclude(pk=self.pk)
|
||||
return similar[:n]
|
||||
|
||||
@cached_property
|
||||
def period_in_days(self):
|
||||
try:
|
||||
return float(self.sbdb_entry['per'])
|
||||
except:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def period_in_years(self):
|
||||
try:
|
||||
return float(self.sbdb_entry['per']) / 365.25
|
||||
except:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def ordered_close_approaches(self):
|
||||
return self.closeapproach_set.all().order_by('date')
|
||||
|
||||
@cached_property
|
||||
def future_close_approaches(self):
|
||||
return self.closeapproach_set.filter(date__gte=date.today()).order_by('date')
|
||||
|
||||
@cached_property
|
||||
def ordered_sentry_events(self):
|
||||
return self.sentryevent_set.all().order_by('-prob')
|
||||
|
||||
@cached_property
|
||||
def ordered_shape_models(self):
|
||||
return self.shapemodel_set.all().order_by('-quality')
|
||||
|
||||
|
||||
def get_diameter_estimate_low(self):
|
||||
return self.get_diameter_estimate(method='LOW')
|
||||
|
||||
def get_diameter_estimate_high(self):
|
||||
return self.get_diameter_estimate(method='HIGH')
|
||||
|
||||
def get_diameter_estimate(self, method='MID'):
|
||||
'''Diameter estimate in km, using either SBDB-supplied estimate
|
||||
or estimate based on magnitude/albedo'''
|
||||
diameter = self.diameter
|
||||
if diameter:
|
||||
return diameter
|
||||
|
||||
# NHATS also has a diameter estimate
|
||||
nhats_set = self.nhatsobject_set.all()
|
||||
if len(nhats_set):
|
||||
nhats = nhats_set[0]
|
||||
if method == 'MID':
|
||||
return (nhats.min_diameter + nhats.max_diameter) / 2.0 / 1000.
|
||||
elif method == 'HIGH':
|
||||
return nhats.max_diameter / 1000.
|
||||
else:
|
||||
# method == LOW
|
||||
return nhats.min_diameter / 1000.
|
||||
|
||||
try:
|
||||
if 'H' in self.sbdb_entry:
|
||||
mag = float(self.sbdb_entry['H'])
|
||||
if method == 'MID':
|
||||
albedo_default = 0.15
|
||||
elif method == 'HIGH':
|
||||
albedo_default = 0.05
|
||||
else:
|
||||
# method == LOW
|
||||
albedo_default = 0.25
|
||||
elif 'M2' in self.sbdb_entry:
|
||||
# Comet nuclear magnitude
|
||||
mag = float(self.sbdb_entry['M2'])
|
||||
# Typical albedo for a comet
|
||||
# https://en.wikipedia.org/wiki/Comet_nucleus#Albedo
|
||||
albedo_default = 0.04
|
||||
|
||||
albedo_known = self.sbdb_entry.get('albedo')
|
||||
albedo = float(albedo_known) if albedo_known else albedo_default
|
||||
|
||||
# Estimate diameter in km
|
||||
# http://www.physics.sfasu.edu/astro/asteroids/sizemagnitude.html
|
||||
return 1329 / math.sqrt(albedo) * math.pow(10, -0.2 * mag)
|
||||
except ValueError:
|
||||
pass
|
||||
except KeyError:
|
||||
pass
|
||||
except TypeError:
|
||||
pass
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def get_1wtc_pct(self):
|
||||
# Helper function used to get size ratio compared to 1 WTC in New York City.
|
||||
diam_km = self.get_diameter_estimate()
|
||||
return diam_km / 0.5413 * 100.0
|
||||
|
||||
@cached_property
|
||||
def get_everest_pct(self):
|
||||
# Helper function used to get size ratio compared to Mt Everest prominence of photo.
|
||||
# Photo shows elevation from ~16417 ft to ~29032 ft = 3.845052 km * adjustment.
|
||||
diam_km = self.get_diameter_estimate()
|
||||
return diam_km / (3.845052 * 2.25) * 100.0
|
||||
|
||||
def to_search_result(self):
|
||||
q = self.sbdb_entry.get('q', None)
|
||||
if q:
|
||||
q = float(q)
|
||||
tp = self.sbdb_entry.get('tp', None)
|
||||
if tp:
|
||||
tp = float(tp)
|
||||
n = self.sbdb_entry.get('n', None)
|
||||
if n:
|
||||
n = float(n)
|
||||
return {
|
||||
'fullname': self.fullname,
|
||||
'name': self.name,
|
||||
'slug': self.slug,
|
||||
'ephem': {
|
||||
'a': self.a,
|
||||
'e': self.e,
|
||||
'i': self.i,
|
||||
'om': self.om,
|
||||
'w': self.w,
|
||||
'ma': self.ma,
|
||||
'q': q,
|
||||
'n': n,
|
||||
'tp': tp,
|
||||
'epoch': self.epoch,
|
||||
}
|
||||
}
|
||||
|
||||
def to_orbit_obj(self):
|
||||
q = self.sbdb_entry.get('q', None)
|
||||
if q:
|
||||
q = float(q)
|
||||
tp = self.sbdb_entry.get('tp', None)
|
||||
if tp:
|
||||
tp = float(tp)
|
||||
return {
|
||||
'a': self.a,
|
||||
'e': self.e,
|
||||
'i': self.i,
|
||||
'om': self.om,
|
||||
'w': self.w,
|
||||
'ma': self.ma,
|
||||
'q': q,
|
||||
'tp': tp,
|
||||
'epoch': self.epoch,
|
||||
}
|
||||
|
||||
def save(self):
|
||||
self.diameter_estimate = self.get_diameter_estimate()
|
||||
super(SpaceObject, self).save()
|
||||
|
||||
def __str__(self):
|
||||
return self.fullname
|
||||
|
||||
class Meta:
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['fullname']),
|
||||
models.Index(fields=['slug']),
|
||||
models.Index(fields=['orbit_class']),
|
||||
models.Index(fields=['object_type']),
|
||||
models.Index(fields=['is_nea']),
|
||||
models.Index(fields=['is_pha']),
|
||||
models.Index(fields=['diameter']),
|
||||
models.Index(fields=['a']),
|
||||
]
|
||||
|
||||
class CloseApproach(models.Model):
|
||||
space_object = models.ForeignKey(SpaceObject)
|
||||
|
||||
date = models.DateField()
|
||||
v_rel = models.FloatField()
|
||||
h_mag = models.FloatField()
|
||||
|
||||
# Distances in AU
|
||||
dist_au = models.FloatField()
|
||||
dist_min_au = models.FloatField()
|
||||
|
||||
@cached_property
|
||||
def dist_km(self):
|
||||
return self.dist_au * 1.496e8
|
||||
|
||||
class Meta:
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['date']),
|
||||
]
|
||||
|
||||
class SentryEvent(models.Model):
|
||||
space_object = models.ForeignKey(SpaceObject)
|
||||
|
||||
date = models.DateField()
|
||||
energy_mt = models.FloatField()
|
||||
palermo_scale = models.FloatField()
|
||||
torino_scale = models.FloatField()
|
||||
prob = models.FloatField()
|
||||
|
||||
@cached_property
|
||||
def prob_percentage(self):
|
||||
return self.prob * 100.0
|
||||
|
||||
@cached_property
|
||||
def energy_with_units(self):
|
||||
if self.energy_mt > 1:
|
||||
return '%s megatons' % (self.energy_mt)
|
||||
return '%s kilotons' % (self.energy_mt * 1000)
|
||||
|
||||
class Meta:
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['prob']),
|
||||
]
|
||||
|
||||
class NhatsObject(models.Model):
|
||||
space_object = models.ForeignKey(SpaceObject)
|
||||
|
||||
num_trajectories = models.IntegerField()
|
||||
|
||||
min_dv = models.FloatField()
|
||||
min_dv_duration = models.FloatField()
|
||||
|
||||
# Diameter in meters
|
||||
min_diameter = models.FloatField()
|
||||
max_diameter = models.FloatField()
|
||||
|
||||
def __str__(self):
|
||||
return self.space_object.fullname
|
||||
|
||||
class Meta:
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['min_dv']),
|
||||
]
|
||||
|
||||
class ShapeModel(models.Model):
|
||||
space_object = models.ForeignKey(SpaceObject)
|
||||
|
||||
source = models.CharField(max_length=512)
|
||||
|
||||
# Path to shapefile
|
||||
shape_path = models.CharField(max_length=200)
|
||||
|
||||
# Path to image
|
||||
render_path = models.CharField(max_length=200)
|
||||
|
||||
# Ecliptic lat/lng of the spin axis direction (beta and lambda
|
||||
# respectively).
|
||||
spin_latitude = models.FloatField(null=True, blank=True)
|
||||
spin_longitude = models.FloatField(null=True, blank=True)
|
||||
# Initial rotation angle (phi)
|
||||
spin_angle = models.FloatField(null=True, blank=True)
|
||||
|
||||
# Period in hours
|
||||
period_hr = models.FloatField(null=True, blank=True)
|
||||
|
||||
# Initial julian date
|
||||
jd = models.FloatField(null=True, blank=True)
|
||||
|
||||
# Linear change in the rotation rate (dω / dt) caused by the
|
||||
# Yarkovsky-O'Keefe-Radzievskii-Paddack effect (rad / day2)
|
||||
yorp = models.FloatField(null=True, blank=True)
|
||||
|
||||
# References string
|
||||
# reference = models.CharField(max_length=1000)
|
||||
|
||||
# Equivalent diameter - diameter of sphere that has the same volume as
|
||||
# model.
|
||||
equiv_diameter_km = models.FloatField(null=True, blank=True)
|
||||
|
||||
# Quality level
|
||||
quality = models.FloatField(null=True, blank=True)
|
||||
|
||||
admin.site.register(SpaceObject)
|
||||
admin.site.register(CloseApproach)
|
||||
admin.site.register(SentryEvent)
|
||||
admin.site.register(NhatsObject)
|
||||
admin.site.register(OrbitClass)
|
||||
admin.site.register(ShapeModel)
|
||||
21
spaceobjects/sitemap.py
Normal file
21
spaceobjects/sitemap.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
|
||||
from spaceobjects.models import SpaceObject, OrbitClass
|
||||
|
||||
class SpaceObjectSitemap(Sitemap):
|
||||
protocol = 'https'
|
||||
|
||||
def items(self):
|
||||
return SpaceObject.objects.filter(is_pha=True) | SpaceObject.objects.filter(diameter__gt=100)
|
||||
|
||||
def priority(self, obj):
|
||||
if obj.is_pha:
|
||||
return 0.25
|
||||
return 0.5
|
||||
|
||||
class OrbitClassSitemap(Sitemap):
|
||||
protocol = 'https'
|
||||
priority = 0.6
|
||||
|
||||
def items(self):
|
||||
return OrbitClass.objects.all()
|
||||
143
spaceobjects/templates/spaceobjects/category.html
Normal file
143
spaceobjects/templates/spaceobjects/category.html
Normal file
@ -0,0 +1,143 @@
|
||||
{% extends 'layout.html' %}
|
||||
{% load humanize %}
|
||||
{% load static %}
|
||||
|
||||
{% block title%}{{page_name}} | Space Reference{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/lib/three.r98.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/TrackballControls.js" %}"></script>
|
||||
<script src="{% static "js/lib/spacekit.js" %}"></script>
|
||||
<script src="{% static "js/orbitDiagram.js" %}"></script>
|
||||
<script src="{% static "js/lib/d3.v3.js" %}"></script>
|
||||
<!--
|
||||
<script src="http://localhost:8001/src/lib/three.r98.min.js"></script>
|
||||
<script src="http://localhost:8001/src/lib/TrackballControls.js"></script>
|
||||
<script src="http://localhost:8001/build/spacekit.js"></script>
|
||||
-->
|
||||
<script>
|
||||
window.OBJECT_DEFINITIONS = [
|
||||
{% for object in objects %}
|
||||
{
|
||||
name: unescape("{{object.name}}"),
|
||||
slug: "{{object.slug}}",
|
||||
ephem: {
|
||||
a: {{object.a}},
|
||||
e: {{object.e}},
|
||||
i: {{object.i}},
|
||||
om: {{object.om}},
|
||||
w: {{object.w}},
|
||||
ma: {{object.ma}},
|
||||
q: {{object.sbdb_entry.q}},
|
||||
n: {{object.sbdb_entry.n}} + 0,
|
||||
tp: {{object.sbdb_entry.tp}},
|
||||
epoch: {{object.epoch}}
|
||||
}
|
||||
},
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
window.BACKGROUND_QUERY_URL = '/api/category/{{category_slug}}/orbits';
|
||||
|
||||
window.VIZ_SIMULATION_OPTS = {
|
||||
jdPerSecond: 5,
|
||||
};
|
||||
window.VIZ_OBJECT_OPTS = {
|
||||
ecliptic: {
|
||||
displayLines: false,
|
||||
},
|
||||
};
|
||||
|
||||
var diagram = new OrbitDiagram('.orbit-diagram', {
|
||||
// object's semimajor axis should be 40px
|
||||
pixels_per_au: 40 / {{objects.0.a}},
|
||||
});
|
||||
diagram.prepareRender();
|
||||
diagram.renderPlanets(true /* useSmartLabels */, {{objects.0.a}});
|
||||
{% for object in objects %}
|
||||
diagram.plotOrbit({{object.a}}, {{object.e}}, {{object.w}}, '#fff');
|
||||
{% endfor %}
|
||||
|
||||
function selectOrbit(domElement) {
|
||||
window.spaceobjects[domElement.dataset.slug].getOrbit().setHexColor(0xff0000);
|
||||
}
|
||||
function deselectOrbit(domElement) {
|
||||
window.spaceobjects[domElement.dataset.slug].getOrbit().setHexColor(0xffffff);
|
||||
}
|
||||
</script>
|
||||
<script src="{% static "js/main.js" %}"></script>
|
||||
<script>
|
||||
init3dVis();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<h1 class="mainheading">{{page_name}}</h1>
|
||||
<div class="orbit-diagram"></div>
|
||||
</div>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<div class="breadcrumbs">
|
||||
<a href="/">Space Reference</a>
|
||||
»
|
||||
{{page_name}}
|
||||
</div>
|
||||
<div class="item-container col-sm-12">
|
||||
{% if orbit_class %}
|
||||
{{orbit_class.name}}s ({{orbit_class.abbrev}}) are objects {{orbit_class.orbit_sentence}}. There are {{count|intcomma}} {{orbit_class.name|capfirst}}s in this database out of {{total_count|intcomma}} total, accounting for {{population_pct|floatformat:1}}% of objects.
|
||||
{% else %}
|
||||
There are {{count|intcomma}} {{page_name|lower}} of this type in the database out of {{total_count|intcomma}} total, accounting for {{population_pct|floatformat:1}}% of objects.
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="item-container col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h3>Search</h3>
|
||||
<div class="react-search"></div>
|
||||
</div>
|
||||
<div class="item-container__inner tile-list">
|
||||
{% for object in objects %}
|
||||
<div class="tile" data-slug="{{object.slug}}"
|
||||
onmouseover="if (typeof selectOrbit !== 'undefined') selectOrbit(this)"
|
||||
onmouseout="if (typeof deselectOrbit !== 'undefined') deselectOrbit(this)"
|
||||
onclick="window.location.href='/asteroid/{{object.slug}}'"
|
||||
>
|
||||
<div>
|
||||
<h5><a href="/asteroid/{{object.slug}}">{{object.name}}</a></h5>
|
||||
<div class="tile-content">
|
||||
<span class="label label-danger">{{object.size_adjective}}</span>
|
||||
{% if object.is_pha %}
|
||||
<span class="label label-warning">Potentially Hazardous</span>
|
||||
{% else %}
|
||||
<span class="label label-info">Not Hazardous</span>
|
||||
{% endif %}
|
||||
<br>
|
||||
<div class="tile-desc">
|
||||
{{object.shorthand}} orbits the sun every {{object.sbdb_entry.per|floatformat:0|intcomma}} days, coming as close as {{object.perihelion|floatformat:2}} AU and reaching as far as {{object.aphelion|floatformat:2}} AU from the sun.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-8">
|
||||
<div class="item-container__inner">
|
||||
<div class="vis-panel">
|
||||
<div class="vis-controls">
|
||||
<button class="vis-controls__slower">Slower</button>
|
||||
<button class="vis-controls__faster">Faster</button>
|
||||
<button class="vis-controls__set-date">Set Date</button>
|
||||
<span class="vis-status"></span>
|
||||
<span class="vis-fullscreen-shortcut"><a href="/solar-system#cat={{category_slug}}">⧉ </a></span>
|
||||
</div>
|
||||
<div id="orbit-sim" class="vis-container vis-container__category"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
504
spaceobjects/templates/spaceobjects/detail.html
Normal file
504
spaceobjects/templates/spaceobjects/detail.html
Normal file
@ -0,0 +1,504 @@
|
||||
{% extends 'layout.html' %}
|
||||
{% load humanize %}
|
||||
{% load static %}
|
||||
|
||||
{% block title%}{% if object.is_asteroid %}Asteroid {% elif object.is_comet %}Comet {% endif %}{{object.name}} | Space Reference{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static "css/lib/celestial0.6.css" %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/lib/three.r98.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/TrackballControls.js" %}"></script>
|
||||
<script src="{% static "js/lib/spacekit.js" %}"></script>
|
||||
<script src="{% static "js/orbitDiagram.js" %}"></script>
|
||||
<script src="{% static "js/sizeComparison.js" %}"></script>
|
||||
<script src="{% static "js/lib/d3.v3.js" %}"></script>
|
||||
<script src="{% static "js/lib/d3.geo.zoom.js" %}"></script>
|
||||
<script src="{% static "js/lib/d3.geo.projection.js" %}"></script>
|
||||
<script src="{% static "js/lib/celestial0.6.js" %}"></script>
|
||||
<!--
|
||||
<script src="http://localhost:8001/src/lib/three.r98.min.js"></script>
|
||||
<script src="http://localhost:8001/src/lib/TrackballControls.js"></script>
|
||||
<script src="http://localhost:8001/build/spacekit.js"></script>
|
||||
-->
|
||||
<script>
|
||||
window.OBJECT_DEFINITIONS = [{
|
||||
name: unescape("{{object.name}}"),
|
||||
slug: "{{object.slug}}",
|
||||
ephem: {
|
||||
a: {{object.a}},
|
||||
e: {{object.e}},
|
||||
i: {{object.i}},
|
||||
om: {{object.om}},
|
||||
w: {{object.w}},
|
||||
ma: {{object.ma}},
|
||||
q: {{object.sbdb_entry.q}},
|
||||
n: {{object.sbdb_entry.n}} + 0,
|
||||
tp: {{object.sbdb_entry.tp}},
|
||||
epoch: {{object.epoch}}
|
||||
}
|
||||
}];
|
||||
window.VIZ_SIMULATION_OPTS = {
|
||||
jdPerSecond: 0.1,
|
||||
startPaused: true,
|
||||
};
|
||||
window.VIZ_OBJECT_OPTS = {
|
||||
ecliptic: {
|
||||
displayLines: {{object.i}} < 20,
|
||||
},
|
||||
labelText: '{{object.name}}',
|
||||
};
|
||||
|
||||
// This is here because celestial.js doesn't play nice with other canvases on
|
||||
// the page. Don't load anything else until celestial is done loading.
|
||||
window.pageReady = false;
|
||||
</script>
|
||||
<script src="{% static "js/main.js" %}"></script>
|
||||
<script src="{% static "js/detail.js" %}"></script>
|
||||
<script>
|
||||
let onPageReadyHandlers = [];
|
||||
|
||||
onPageReadyHandlers.push(() => {
|
||||
if ({{object.a}} < 0) {
|
||||
return;
|
||||
}
|
||||
const diagram = new OrbitDiagram('.orbit-diagram', {
|
||||
// object's semimajor axis should be 40px
|
||||
pixels_per_au: 40 / {{object.a}},
|
||||
});
|
||||
diagram.prepareRender();
|
||||
diagram.renderPlanets(true /* useSmartLabels */, {{object.a}});
|
||||
diagram.plotOrbit({{object.a}}, {{object.e}}, {{object.w}}, '#fff', '{{object.shorthand}}');
|
||||
});
|
||||
|
||||
onPageReadyHandlers.push(init3dVis);
|
||||
onPageReadyHandlers.push(initReferenceTables);
|
||||
|
||||
{% if object.has_size_info_estimate %}
|
||||
(function() {
|
||||
var overlay = document.getElementById('size-comparison-overlay');
|
||||
overlay.onclick = function() {
|
||||
const sizeComparison = new SizeComparison('#size-comparison', {});
|
||||
sizeComparison.render({{object.get_diameter_estimate}});
|
||||
};
|
||||
})();
|
||||
{% endif %}
|
||||
|
||||
const t = setInterval(function() {
|
||||
if (window.pageReady) {
|
||||
onPageReadyHandlers.forEach(fn => fn());
|
||||
clearInterval(t);
|
||||
}
|
||||
}, 500);
|
||||
</script>
|
||||
{% if object.has_size_info_estimate %}
|
||||
<script async defer
|
||||
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCGGGEBu3lHIz-sfzh-OB6PUe3-6mBteQI">
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<!-- Spaceref OBJECT ID: {{object.id}} -->
|
||||
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<h1 class="mainheading">{{object.name}}</h1>
|
||||
<h2 class="subheading">
|
||||
{% if object.fullname == object.name %}
|
||||
{% if object.has_size_info_estimate %}
|
||||
{{object.size_adjective|capfirst}}
|
||||
{% endif %}
|
||||
{{object.orbit_class.name}}
|
||||
{% else %}
|
||||
{{object.fullname}}
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% if object.is_nea %}
|
||||
<span class="label label-info"><a href="/category/near-earth-asteroids">Near-Earth</a></span>
|
||||
{% endif %}
|
||||
{% if object.is_pha %}
|
||||
<span class="label label-warning"><a href="/category/potentially-hazardous-asteroids">Potentially Hazardous</a></span>
|
||||
{% endif %}
|
||||
<div class="orbit-diagram"></div>
|
||||
</div>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="/">Space Reference</a>
|
||||
»
|
||||
<a href="/category/{{object.orbit_class.slug}}">{{object.orbit_class.name}}s</a>
|
||||
»
|
||||
{{object.name}}
|
||||
</div>
|
||||
<div class="item-container col-sm-8">
|
||||
<div class="item-container__inner">
|
||||
<h3>Key Facts</h3>
|
||||
<ul class="keyfacts">
|
||||
<li>Categorized as a <a href="/category/{{object.orbit_class.slug}}">{{object.orbit_class.name}}</a></li>
|
||||
{% if object.has_size_info %}
|
||||
<li>Comparable in size to {{object.get_diameter_comparison}} ({{object.sbdb_entry.diameter | floatformat:2}} km diameter)</li>
|
||||
{% elif object.has_size_info_estimate %}
|
||||
<li>Comparable in size to {{object.get_diameter_comparison}}</li>
|
||||
{% endif %}
|
||||
{% if object.closeapproach_set.all|length %}
|
||||
{% with approach=object.closeapproach_set.all.0 %}
|
||||
<li>Will pass within {{approach.dist_km|floatformat:0|intcomma}} km of Earth in {{approach.date|date:"Y"}}</li>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% if object.is_nea %}
|
||||
<li>Classified as a Near Earth Asteroid (NEA)</li>
|
||||
{% else %}
|
||||
<li>Not a Near Earth Object</li>
|
||||
{% endif %}
|
||||
{% if object.is_pha %}
|
||||
<li>Classified as a Potentially Hazardous Asteroid (PHA)</li>
|
||||
{% else %}
|
||||
<li>Not a Potentially Hazardous Object</li>
|
||||
{% endif %}
|
||||
<li><a href="/solar-system#ob={{object.slug}}">See orbit simulation</a></li>
|
||||
</ul>
|
||||
<h3>Overview</h3>
|
||||
<p>
|
||||
{% if object.is_dwarf_planet %}
|
||||
{{object.name}} is a dwarf planet {{object.orbit_class.orbit_sentence}}.
|
||||
{% elif object.has_size_info_estimate %}
|
||||
{{object.name}} is a {{object.size_adjective}} {{object.get_object_type}} {{object.orbit_class.orbit_sentence}}.
|
||||
{% else %}
|
||||
{{object.get_object_type|capfirst}} {{object.name}} is an object {{object.orbit_class.orbit_sentence}}.
|
||||
{% endif %}
|
||||
|
||||
{% if object.is_pha and object.is_nea %}
|
||||
NASA JPL has classified {{object.shorthand}} as a "Potentially Hazardous Asteroid" due to its predicted close pass(es) with Earth.
|
||||
{% elif object.is_nea %}
|
||||
NASA JPL has classified {{object.shorthand}} as a "Near Earth Asteroid" due to its orbit's proximity to Earth, but it is not considered potentially hazardous because computer simulations have not indicated any imminent likelihood of future collision.
|
||||
{% else %}
|
||||
NASA JPL has not classified {{object.shorthand}} as potentially hazardous because its orbit does not bring it close to Earth.
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{{object.shorthand}} orbits the sun every {{object.period_in_days|floatformat:0|intcomma}} days ({{object.period_in_years|floatformat:2|intcomma}} years), coming as close as {{object.perihelion|floatformat:2}} AU and reaching as far as {{object.aphelion|floatformat:2}} AU from the sun.
|
||||
{% if object.e > .7 %}
|
||||
Its orbit is highly elliptical.
|
||||
{% endif %}
|
||||
{% if object.has_size_info %}
|
||||
{{object.shorthand}} is about {{object.sbdb_entry.diameter | floatformat:1}} kilometers in diameter, making it {{object.get_size_rough_comparison}}, comparable in size to {{object.get_diameter_comparison}}.
|
||||
{% elif object.has_size_info_estimate %}
|
||||
Based on its brightness and the way it reflects light, {{object.shorthand}} is <a href="https://cneos.jpl.nasa.gov/tools/ast_size_est.html">probably</a> between {{object.get_diameter_estimate_low | floatformat:3}} to {{object.get_diameter_estimate_high | floatformat:3}} kilometers in diameter, making it {{object.get_size_rough_comparison}}, very roughly comparable in size to {{object.get_diameter_comparison}}.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if object.sbdb_entry.rot_per %}
|
||||
<p>
|
||||
The rotation of {{object.shorthand}} has been observed. It completes a rotation on its axis every {{object.sbdb_entry.rot_per|floatformat:2}} hours.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if object.composition %}
|
||||
<p>
|
||||
{{object.shorthand}}'s spectral type {{object.sbdb_entry.spec_T}} (<a href="http://adsabs.harvard.edu/abs/1989aste.conf..298T">Tholen</a>) / {{object.sbdb_entry.spec_B}} (<a href="http://smass.mit.edu/smass.html">SMASSII</a>) indicates that it is likely to contain
|
||||
{% include 'spaceobjects/partials/composition.html' %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if object.ordered_close_approaches|length < 1 and object.ordered_sentry_events|length < 1 %}
|
||||
<h3>No Close Approaches</h3>
|
||||
{% else %}
|
||||
<h3>Close Approaches</h3>
|
||||
{% endif %}
|
||||
{% if object.moid %}
|
||||
<p>
|
||||
{{object.shorthand}}'s orbit is {{object.moid | floatformat:2}} AU from Earth's orbit at its closest point.
|
||||
{% if object.moid > 1 %}
|
||||
This means that there is an extremely wide berth between this asteroid and Earth at all times.
|
||||
{% elif object.moid > 0.5 %}
|
||||
This means that there is a very wide berth between this asteroid and Earth at all times.
|
||||
{% elif object.moid > 0.01 %}
|
||||
This means that there is a wide berth between this asteroid and Earth at all times.
|
||||
{% elif object.moid < 0.001 %}
|
||||
This means that its orbit is very close to Earth's orbit.
|
||||
{% elif object.moid < 0.0001 %}
|
||||
This means that its orbit is extremely close to Earth's orbit.
|
||||
{% else %}
|
||||
This means that its orbit is relatively close to Earth's orbit.
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.moid_jup < 0.5 %}
|
||||
<p>
|
||||
The orbit of {{object.shorthand}} brings it close to Jupiter's orbit.
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
{% if object.ordered_close_approaches|length < 1 %}
|
||||
Orbital simulations conducted by NASA JPL's CNEOS do not show any close approaches to Earth.
|
||||
{% else %}
|
||||
<p>
|
||||
{{object.shorthand}} has {{object.ordered_close_approaches|length}} close approaches predicted in the coming decades:
|
||||
</p>
|
||||
<div class="reference-table">
|
||||
<div class="reference-table-content">
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Distance from Earth (km)</th>
|
||||
<th>Velocity (km/s)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for close_approach in object.ordered_close_approaches %}
|
||||
<tr>
|
||||
<td>{{close_approach.date | date}}</td>
|
||||
<td>{{close_approach.dist_km|floatformat:0|intcomma}}</td>
|
||||
<td>{{close_approach.v_rel|floatformat:3}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if object.ordered_close_approaches|length > 10 %}
|
||||
<div class="reference-table-gradient"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if object.ordered_sentry_events %}
|
||||
<p>
|
||||
<a href="https://cneos.jpl.nasa.gov/sentry/details.html#?des={{object.sbdb_entry.pdes}}">NASA Sentry</a> has assessed impact risk for {{object.ordered_sentry_events|length}} very close approach scenarios. Here are the top scenarios ordered by probability of impact:
|
||||
<ul>
|
||||
</ul>
|
||||
<div class="reference-table">
|
||||
<div class="reference-table-content">
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Probability of Impact (%)</th>
|
||||
<th>Impact Energy (Mt)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in object.ordered_sentry_events %}
|
||||
<tr>
|
||||
<td>{{event.date|date}}</td>
|
||||
<td>{{event.prob_percentage|floatformat:5}}</td>
|
||||
<td>{{event.energy_mt}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if object.ordered_sentry_events|length > 10 %}
|
||||
<div class="reference-table-gradient"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</p>
|
||||
{% endif %}
|
||||
</p>
|
||||
<h3>Images and Observations</h3>
|
||||
<p>
|
||||
{{object.shorthand}}'s orbit is determined by observations dating back to {{object.firstobs_date | date}}. It was last officially observed on {{object.lastobs_date | date}}. The IAU Minor Planet Center records {{object.sbdb_entry.n_obs_used|intcomma}} observations used to determine its orbit.
|
||||
</p>
|
||||
{% if object.ordered_shape_models|length %}
|
||||
<p>
|
||||
Scientists have been able to determine this object's shape:
|
||||
</p>
|
||||
<p>
|
||||
<a href="/asteroid/{{object.slug}}/shape"><img loading="lazy" class="img-responsive" src="{% static object.ordered_shape_models.0.render_path %}" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<strong>View <a href="/asteroid/{{object.slug}}/shape">{{object.get_object_type}} {{object.name}} in 3D</a>.</strong>
|
||||
</p>
|
||||
{% endif %}
|
||||
<h3>Accessibility and Exploration</h3>
|
||||
{% if object.nhatsobject_set.all|length %}
|
||||
{% with nhats=object.nhatsobject_set.all.0 %}
|
||||
<p>
|
||||
{{object.shorthand}} can be reached with a journey of {{nhats.min_dv_duration|floatformat:0|intcomma}} days. This trajectory would require a <a href="https://en.wikipedia.org/wiki/Delta-v_budget">delta-v</a> of {{nhats.min_dv}} km/s. To put this into perspective, the delta-v to launch a rocket to Low-Earth Orbit is 9.7 km/s. There are {{nhats.num_trajectories|intcomma}} potential trajectories and launch windows to this {{object.get_object_type}}.
|
||||
</p>
|
||||
<p>
|
||||
See more at the <a href="https://cneos.jpl.nasa.gov/nhats/details.html#?des={{object.sbdb_entry.pdes}}">NHATS Mission Trajectories</a> table for {{object.shorthand}}.
|
||||
</p>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
This {{object.get_object_type}} is not considered a viable target for human exploration by the <a href="https://cneos.jpl.nasa.gov/nhats/">NHATS study</a>.
|
||||
{% endif %}
|
||||
{% if object.get_similar_orbits|length %}
|
||||
<h3>Similar Objects</h3>
|
||||
These objects have orbits that share similar characteristics to the orbit of {{object.shorthand}}:
|
||||
<ul>
|
||||
{% for similar in object.get_similar_orbits %}
|
||||
<li>
|
||||
<a rel="nofollow" href="/asteroid/{{similar.slug}}">{{similar.fullname}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<h3>References</h3>
|
||||
<ul>
|
||||
<li><a rel="nofollow" href="https://ssd.jpl.nasa.gov/sbdb.cgi?sstr={{object.sbdb_entry.pdes}}">JPL Small Body Database</a></li>
|
||||
<li><a rel="nofollow" href="https://ssd.jpl.nasa.gov/?mdesign_server&des={{object.sbdb_entry.pdes}}">Mission Design</a></li>
|
||||
<li><a rel="nofollow" href="https://in-the-sky.org/findercharts.php?objtxt=A{{object.sbdb_entry.pdes}}&duration=5">Sky Finder Chart</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h4>Search</h4>
|
||||
<div class="react-search"></div>
|
||||
or view a <a rel="nofollow" href="/asteroid/random">random</a> object
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h4>Orbital Elements</h4>
|
||||
<ul class="keyfacts">
|
||||
<li>Epoch: {{object.epoch}} JD</li>
|
||||
<li>Semi-major axis: {{object.a}} AU</li>
|
||||
<li>Eccentricity: {{object.e}}</li>
|
||||
<li>Inclination: {{object.i}}°</li>
|
||||
<li>Longitude of Ascending Node: {{object.om}}°</li>
|
||||
<li>Argument of Periapsis: {{object.w}}°</li>
|
||||
<li>Mean Anomaly: {{object.ma}}°</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h4>Physical Characteristics</h4>
|
||||
<ul class="keyfacts">
|
||||
{% if object.has_size_info %}
|
||||
<li>Diameter: {{object.sbdb_entry.diameter | floatformat:5}} km</li>
|
||||
{% elif object.has_size_info_estimate %}
|
||||
<li>Diameter: ~{{object.get_diameter_estimate | floatformat:3}} km</li>
|
||||
{% endif %}
|
||||
{% if object.H %}
|
||||
<li>Magnitude: {{object.H}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.albedo %}
|
||||
<li>Albedo: {{object.sbdb_entry.albedo}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.spec_T %}
|
||||
<li>Spectral type (Tholen): {{object.spec_T}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.spec_B %}
|
||||
<li>Spectral type (SMASS): {{object.spec_B}}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h4>Derived Characteristics</h4>
|
||||
<ul class="keyfacts">
|
||||
{% if object.period_in_days %}
|
||||
<li>Orbit Period: {{object.period_in_days|floatformat:0|intcomma}} days ({{object.period_in_years|floatformat:2|intcomma}} years)</li>
|
||||
{% endif %}
|
||||
{% if object.avg_orbital_speed %}
|
||||
<li>Avg. Orbit Speed: {{object.avg_orbital_speed|floatformat:2|intcomma}} km/s</li>
|
||||
{% endif %}
|
||||
{% if object.aphelion %}
|
||||
<li>Aphelion Distance: {{object.aphelion|floatformat:2}} AU</li>
|
||||
{% endif %}
|
||||
<li>Perihelion Distance: {{object.perihelion|floatformat:2}} AU</li>
|
||||
{% if object.sbdb_entry.rot_per %}
|
||||
<li>Rotation Period: {{object.sbdb_entry.rot_per|floatformat:2|intcomma}} hours</li>
|
||||
{% endif %}
|
||||
{% if object.composition %}
|
||||
<li>Approx. Composition: {% include 'spaceobjects/partials/composition.html' %}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% if object.has_size_info_estimate %}
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<h4>Map Comparison</h4>
|
||||
<div id="size-comparison">
|
||||
<div class="size-comparison-placeholder">
|
||||
<div id="size-comparison-overlay" class="size-comparison-overlay">
|
||||
Click to load map
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div id="height-comparison">
|
||||
<div>
|
||||
<img src="{% static "images/empire-state-building.svg" %}" />
|
||||
Empire State Building
|
||||
</div>
|
||||
<div>
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="50" cy="50" r="50" style="fill:#ccc" />
|
||||
<circle cx="25" cy="25" r="4" style="fill:#999" />
|
||||
<circle cx="65" cy="15" r="5" style="fill:#999" />
|
||||
<circle cx="35" cy="70" r="4" style="fill:#999" />
|
||||
<circle cx="45" cy="35" r="3" style="fill:#999" />
|
||||
<circle cx="80" cy="60" r="5" style="fill:#999" />
|
||||
</svg>
|
||||
{{object.name}}
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="item-container col-sm-12">
|
||||
<div class="item-container__inner">
|
||||
<h3>Orbit Simulation</h3>
|
||||
<div class="vis-panel">
|
||||
<div class="vis-controls">
|
||||
<button class="vis-controls__slower">Slower</button>
|
||||
<button class="vis-controls__faster">Faster</button>
|
||||
<button class="vis-controls__set-date">Set Date</button>
|
||||
<span class="vis-status"></span>
|
||||
<span class="vis-fullscreen-shortcut"><a href="/solar-system#ob={{object.slug}}">⧉ </a></span>
|
||||
</div>
|
||||
<div id="orbit-sim" class="vis-container vis-container__detail"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container col-sm-12">
|
||||
<div class="item-container__inner">
|
||||
<h3>Sky Map</h3>
|
||||
<p>
|
||||
The position of {{object.name}} is indicated by a <span style="color:rgba(255, 0, 204, 1);font-weight:bold">◯ pink circle</span>. Note that the object may not be in your current field of view. Use the controls below to adjust position, location, and time.
|
||||
</p>
|
||||
<div class="skymap-container">
|
||||
<div id="celestial-map" class="skymap-panel"></div>
|
||||
<div id="celestial-form"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if object.get_1wtc_pct > 5 and object.get_1wtc_pct <= 100.0 %}
|
||||
<div class="item-container col-sm-12">
|
||||
<div class="item-container__inner">
|
||||
<h3>Size Rendering</h3>
|
||||
<p>
|
||||
The below comparison is an artistic rendering that uses available data on the diameter of {{object.shorthand}} to create an approximate landscape rendering with New York City in the background. This approximation is built for full-resolution desktop browsers. Shape, color, and texture of asteroid are imagined.
|
||||
</p>
|
||||
<div id="artistic-comparison" class="artistic-comparison">
|
||||
<img loading="lazy" class="background" src="{% static "images/nyc-skyline.png" %}" />
|
||||
<img loading="lazy" class="object" src="{% static "images/generic-asteroid.png" %}" style="height:{{object.get_1wtc_pct}}%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% elif object.get_everest_pct > 5 and object.get_everest_pct <= 80 %}
|
||||
<div class="item-container col-sm-12">
|
||||
<div class="item-container__inner">
|
||||
<h3>Size Rendering</h3>
|
||||
<p>
|
||||
The above comparison is an artistic rendering that uses available data on the diameter of {{object.shorthand}} to create an approximate landscape rendering with Mount Everest in the background. This approximation is built for full-resolution desktop browsers. Shape, color, and texture of asteroid are imagined.
|
||||
</p>
|
||||
<div id="artistic-comparison" class="artistic-comparison">
|
||||
<img loading="lazy" class="background" src="{% static "images/everest-background3.png" %}" />
|
||||
<img loading="lazy" class="object" src="{% static "images/generic-asteroid.png" %}" style="height:{{object.get_everest_pct}}%; z-index:999; box-shadow: 0 0 110px 0 rgba(0, 0, 0, 1); border-radius: 50%; border: 1px solid #ffa5006b; box-sizing: content-box" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
199
spaceobjects/templates/spaceobjects/index.html
Normal file
199
spaceobjects/templates/spaceobjects/index.html
Normal file
@ -0,0 +1,199 @@
|
||||
{% extends 'layout.html' %}
|
||||
{% load humanize %}
|
||||
{% load static %}
|
||||
|
||||
{% block title%}Comprehensive Asteroid and Comet Database | Space Reference{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/lib/three.r98.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/TrackballControls.js" %}"></script>
|
||||
<script src="{% static "js/lib/spacekit.js" %}"></script>
|
||||
<!--
|
||||
<script src="http://localhost:8001/src/lib/three.r98.min.js"></script>
|
||||
<script src="http://localhost:8001/src/lib/TrackballControls.js"></script>
|
||||
<script src="http://localhost:8001/build/spacekit.js"></script>
|
||||
-->
|
||||
<script>
|
||||
window.OBJECT_DEFINITIONS= [
|
||||
{% for object_set in object_sets %}
|
||||
{% for object in object_set.data %}
|
||||
{
|
||||
name: unescape("{{object.name}}"),
|
||||
slug: "{{object.slug}}",
|
||||
ephem: {
|
||||
a: {{object.a}},
|
||||
e: {{object.e}},
|
||||
i: {{object.i}},
|
||||
om: {{object.om}},
|
||||
w: {{object.w}},
|
||||
ma: {{object.ma}},
|
||||
epoch: {{object.epoch}}
|
||||
}
|
||||
},
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
window.VIZ_SIMULATION_OPTS = {
|
||||
jdPerSecond: 2,
|
||||
};
|
||||
window.VIZ_OBJECT_OPTS = {
|
||||
particleSize: 10,
|
||||
};
|
||||
|
||||
function selectOrbit(domElement) {
|
||||
Object.keys(window.spaceobjects).forEach(function(key) {
|
||||
const ob = window.spaceobjects[key];
|
||||
const obOrbit = ob.getOrbit();
|
||||
if (key === domElement.dataset.slug) {
|
||||
obOrbit.setVisibility(true);
|
||||
obOrbit.setHexColor(0xff0000);
|
||||
ob.setLabelVisibility(true);
|
||||
} else {
|
||||
obOrbit.setVisibility(false);
|
||||
ob.setLabelVisibility(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
function deselectOrbit(domElement) {
|
||||
window.spaceobjects[domElement.dataset.slug].getOrbit().setHexColor(0xffffff);
|
||||
}
|
||||
</script>
|
||||
<script src="{% static "js/main.js" %}"></script>
|
||||
<script>
|
||||
init3dVis();
|
||||
Object.keys(window.spaceobjects).forEach(function(key) {
|
||||
// TODO(ian): Until there is a better way to lazily create labels and orbits,
|
||||
// we have to create them and then hide them...
|
||||
const ob = window.spaceobjects[key];
|
||||
ob.setLabelVisibility(false);
|
||||
ob.getOrbit().setVisibility(false);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<h1 class="mainheading">Space Reference</h1>
|
||||
<h4 class="subheading">Compiled data & simulations for {{object_count|intcomma}} celestial objects</h4>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="item-container col-sm-8">
|
||||
<div class="item-container__inner">
|
||||
<p>
|
||||
Welcome to SpaceReference.org. The purpose of this site is to catalog and showcase every known object in space. We've started with asteroids and comets but this <a href="https://www.github.com/judymou/spacedb">open-source</a> project is being quickly expanded.
|
||||
</p>
|
||||
<p>
|
||||
SpaceDB compiles data from the NASA/JPL Small Body Database, the IAU Minor Planet Center, and the NASA/JPL Center for Near Earth Object Studies.
|
||||
</p>
|
||||
<p>
|
||||
If you'd like to create a customized solar system model, take a look at the full-screen interactive <a href="/solar-system">solar system</a> view.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-container item-container__rightside col-sm-4">
|
||||
<div class="item-container__inner">
|
||||
<div class="react-search"></div>
|
||||
or view a <a rel="nofollow" href="/asteroid/random">random</a> object
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="item-container">
|
||||
<h2>Asteroids and Comets</h2>
|
||||
<p>
|
||||
We've organized hundreds of thousands celestial objects into these categories below for your perusal.
|
||||
</p>
|
||||
<div class="sticky vis-container vis-container__home"></div>
|
||||
<p>
|
||||
Mouseover objects in the lists below to highlight them in the orbit view. Click or tap to learn more about each object.
|
||||
</p>
|
||||
{% for object_set in object_sets %}
|
||||
<div class="vis-selector" data-showvis="{{object_set.name}}">
|
||||
<h3>{{object_set.name}}</h3>
|
||||
<p>
|
||||
{{object_set.description}} <!--<a href="/solar-system#cat={{object_set.category}}">See all</a>-->
|
||||
</p>
|
||||
<div class="carousel-flex-container">
|
||||
<div class="carousel-flex-inner">
|
||||
{% for object in object_set.data %}
|
||||
<div class="tile carousel-item" data-slug="{{object.slug}}" onmouseover="if (typeof selectOrbit !== 'undefined') selectOrbit(this)"
|
||||
onmouseout="if (typeof deselectOrbit !== 'undefined') deselectOrbit(this)">
|
||||
<a href="{{object.get_absolute_url}}">
|
||||
<div>
|
||||
<h5>{{object.name}}</h5>
|
||||
<div class="tile-content">
|
||||
<span class="label label-default">{{object.size_adjective|title}}</span>
|
||||
{% if object.is_nea %}
|
||||
<span class="label label-info">Near-Earth</span>
|
||||
{% endif %}
|
||||
{% if object.future_close_approaches|length %}
|
||||
<span class="label label-warning">Close Approach</span>
|
||||
{% endif %}
|
||||
{% if object.is_pha %}
|
||||
<span class="label label-danger">Potentially Hazardous</span>
|
||||
{% endif %}
|
||||
<br>
|
||||
<div class="tile-desc">
|
||||
{{object.shorthand}} orbits the sun every {{object.period_in_years|floatformat:2|intcomma}} years and is about {{object.get_diameter_estimate|floatformat:3}} km in diameter, comparable in size to {{object.get_diameter_comparison}}.
|
||||
{% if object.ordered_sentry_events|length and not object_set.hide_impact_probability %}
|
||||
{% with object.ordered_sentry_events.0 as event %}
|
||||
<em>It will pass near Earth with an impact probability of {{event.prob_percentage|floatformat:3}}% in {{event.date | date:"Y"}}.</em>
|
||||
{% endwith %}
|
||||
{% elif object.future_close_approaches|length %}
|
||||
{% with object.future_close_approaches.0 as event %}
|
||||
<em>It will pass by Earth on {{event.date | date}}.</em>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div> <!-- end item-container -->
|
||||
</div> <!-- end row -->
|
||||
<div class="row">
|
||||
<div class="item-container">
|
||||
<div class="item-container__inner">
|
||||
<h2>Object Classifications</h2>
|
||||
The two most noteworthy classifications for asteroids are "Near Earth Asteroid" (NEA) and "Potentially Hazardous Asteroid" (PHA). Despite the names, neither classification indicates any direct danger to Earth.
|
||||
<ul>
|
||||
<li><a href="/category/near-earth-asteroids">Near Earth Asteroids</a> - asteroids whose orbit perihelion is less than 1.3 AU</li>
|
||||
<li><a href="/category/potentially-hazardous-asteroids">Potentially Hazardous Asteroids</a> - near-Earth asteroids whose orbits passes within 0.05 AU of Earth's and whose absolute magnitude H is 22.0 or brighter</li>
|
||||
</ul>
|
||||
Learn more about various <a href="https://cneos.jpl.nasa.gov/about/neo_groups.html">NEO groups</a> here.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="item-container">
|
||||
<div class="item-container__inner">
|
||||
<h2>Categories</h2>
|
||||
<ul>
|
||||
<li><a href="/category/asteroid-shapes">Asteroids with known shapes</a> - these asteroids have been mapped by light curve inversion, radar, or flybys. Click through to see 3D models.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The categories below are orbital classifications as defined by <a href="https://pdssbn.astro.umd.edu/data_other/objclass.shtml">NASA PDS</a>:
|
||||
</p>
|
||||
<ul>
|
||||
{% for orbit_class in orbit_classes %}
|
||||
<li><a href="/category/{{orbit_class.slug}}">{{orbit_class.name}}</a> - {{orbit_class.desc}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,13 @@
|
||||
{% if object.composition|length == 1 %}
|
||||
{{object.composition.0}}.
|
||||
{% elif object.composition|length == 2 %}
|
||||
{{object.composition.0}} and {{object.composition.1}}.
|
||||
{% else %}
|
||||
{% for material in object.composition %}
|
||||
{% if forloop.last %}
|
||||
and {{material}}.
|
||||
{% else %}
|
||||
{{material}},
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
115
spaceobjects/templates/spaceobjects/shape_model.html
Normal file
115
spaceobjects/templates/spaceobjects/shape_model.html
Normal file
@ -0,0 +1,115 @@
|
||||
{% extends 'layout.html' %}
|
||||
{% load humanize %}
|
||||
{% load static %}
|
||||
|
||||
{% block title%}{{object.name}} Shape Model | Space Reference{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
window.SHAPE_PATH = "{% static shape_models.0.shape_path %}";
|
||||
</script>
|
||||
<script src="{% static "js/lib/three.r98.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/TrackballControls.js" %}"></script>
|
||||
<script src="{% static "js/lib/OBJLoader.js" %}"></script>
|
||||
<script src="{% static "js/lib/spacekit.js" %}"></script>
|
||||
<script src="{% static "js/shape.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<h1 class="mainheading">{{object.name}} Shape Model</h1>
|
||||
<h2 class="subheading">
|
||||
{% if object.fullname == object.name %}
|
||||
{{object.size_adjective|capfirst}} {{object.orbit_class.name}}
|
||||
{% else %}
|
||||
{{object.fullname}}
|
||||
{% endif %}
|
||||
{% if object.is_nea %}
|
||||
|
||||
<span class="label label-info">Near-Earth</span>
|
||||
{% endif %}
|
||||
{% if object.is_pha %}
|
||||
<span class="label label-warning">Potentially Hazardous</span>
|
||||
{% endif %}
|
||||
</h2>
|
||||
<div class="orbit-diagram"></div>
|
||||
</div>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<div class="breadcrumbs">
|
||||
<a href="/">Space Reference</a>
|
||||
»
|
||||
<a href="/category/{{object.orbit_class.slug}}">{{object.orbit_class.name}}s</a>
|
||||
»
|
||||
<a href="/asteroid/{{object.slug}}">{{object.name}}</a>
|
||||
»
|
||||
Shape Model
|
||||
</div>
|
||||
<div class="item-container col-sm-4">
|
||||
<p>
|
||||
<h3>Orbital Elements</h3>
|
||||
<ul class="keyfacts">
|
||||
<li>Epoch: {{object.epoch}} JD</li>
|
||||
<li>Semi-major axis: {{object.a}} AU</li>
|
||||
<li>Eccentricity: {{object.e}}</li>
|
||||
<li>Inclination: {{object.i}} deg</li>
|
||||
<li>Longitude of Ascending Node: {{object.om}} deg</li>
|
||||
<li>Argument of Periapsis: {{object.w}} deg</li>
|
||||
<li>Mean Anomaly: {{object.ma}} deg</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<h3>Physical Characteristics</h3>
|
||||
<ul class="keyfacts">
|
||||
{% if object.sbdb_entry.diameter %}
|
||||
<li>Diameter: {{object.sbdb_entry.diameter | floatformat:5}} km</li>
|
||||
{% elif object.get_diameter_estimate %}
|
||||
<li>Diameter: ~{{object.get_diameter_estimate | floatformat:2}} km</li>
|
||||
{% endif %}
|
||||
{% if object.H %}
|
||||
<li>Magnitude: {{object.sbdb_entry.H}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.albedo %}
|
||||
<li>Albedo: {{object.sbdb_entry.albedo}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.spec_T %}
|
||||
<li>Spectral type (Tholen): {{object.spec_T}}</li>
|
||||
{% endif %}
|
||||
{% if object.sbdb_entry.spec_B %}
|
||||
<li>Spectral type (SMASS): {{object.spec_B}}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</p>
|
||||
{% if shape_models.0.source == 'damit' %}
|
||||
<p>
|
||||
<h3>Shape Model Characteristics</h3>
|
||||
At {{shape_models.0.jd}} JD:
|
||||
<ul class="keyfacts">
|
||||
<li>Spin period in hours: {{shape_models.0.period_hr}}</li>
|
||||
<li>Spin latitude: {{shape_models.0.spin_latitude}}</li>
|
||||
<li>Spin longitude: {{shape_models.0.spin_longitude}}</li>
|
||||
<li>Spin angle: {{shape_models.0.spin_angle}}</li>
|
||||
<li>Quality level: {{shape_models.0.quality}}</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
This shape model of {{object.get_object_type}} {{object.name}} is provided by the <a href="http://astro.troja.mff.cuni.cz/projects/asteroids3D/web.php">DAMIT database</a> from The Astronomical Institute of the Charles University in Prague, Czechia.
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
This shape model of {{object.get_object_type}} {{object.name}} is sourced from {{shape_models.0.source}}.
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
The model is rotated on its Z axis for the purpose of this visualization, which may not reflect actual rotation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="item-container col-sm-8">
|
||||
<div id="shape-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
65
spaceobjects/templates/spaceobjects/solar_system.html
Normal file
65
spaceobjects/templates/spaceobjects/solar_system.html
Normal file
@ -0,0 +1,65 @@
|
||||
{% extends 'layout_fullscreen.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title%}Solar System | Space Reference{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static "css/fullscreen.css" %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/lib/three.r98.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/TrackballControls.js" %}"></script>
|
||||
<script src="{% static "js/lib/spacekit.js" %}"></script>
|
||||
<!--
|
||||
<script src="http://localhost:8001/src/lib/three.r98.min.js"></script>
|
||||
<script src="http://localhost:8001/src/lib/TrackballControls.js"></script>
|
||||
<script src="http://localhost:8001/build/spacekit.js"></script>
|
||||
-->
|
||||
<script>
|
||||
window.OBJECT_DEFINITIONS = [
|
||||
];
|
||||
window.VIZ_SIMULATION_OPTS = {
|
||||
{% verbatim %}
|
||||
particleTextureUrl: '{{assets}}/sprites/fuzzyparticle.png',
|
||||
{% endverbatim %}
|
||||
particleDefaultSize: 20,
|
||||
maxNumParticles: 1000000,
|
||||
jdPerSecond: 0.1
|
||||
};
|
||||
window.VIZ_OBJECT_OPTS = {
|
||||
particleSize: 20,
|
||||
ecliptic: {
|
||||
displayLines: true,
|
||||
},
|
||||
};
|
||||
|
||||
function selectOrbit(domElement) {
|
||||
window.spaceobjects[domElement.dataset.slug].getOrbit().setHexColor(0xff0000);
|
||||
}
|
||||
function deselectOrbit(domElement) {
|
||||
window.spaceobjects[domElement.dataset.slug].getOrbit().setHexColor(0xffffff);
|
||||
}
|
||||
</script>
|
||||
<script src="{% static "js/main.js" %}"></script>
|
||||
<script>
|
||||
init3dVis();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="add-object-panel">
|
||||
<h4>Add Objects</h4>
|
||||
<div class="react-search-and-visualize"></div>
|
||||
</div>
|
||||
<div class="vis-panel">
|
||||
<div class="vis-controls">
|
||||
<a href="/"><button>« Main Site</button></a>
|
||||
<button class="vis-controls__slower">Slower</button>
|
||||
<button class="vis-controls__faster">Faster</button>
|
||||
<button class="vis-controls__set-date">Set Date</button>
|
||||
<span class="vis-status"></span>
|
||||
</div>
|
||||
<div id="orbit-sim" class="vis-container"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user