##// END OF EJS Templates
Fix bugs and plots
jespinoza -
r6:7771bbd8f772
parent child
Show More
@@ -1,21 +1,21
1 1 # configuration
2 2
3 3 upstream djangomad {
4 4 server web:8000;
5 5 }
6 6
7 7 server {
8 listen 80;
8 listen 8080;
9 9
10 location / {
11 proxy_http_version 1.1;
12 proxy_set_header Upgrade $http_upgrade;
13 proxy_set_header Connection "upgrade";
10 location /madrigal {
11 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
12 proxy_set_header Host $host;
14 13 proxy_redirect off;
14 proxy_set_header X-Script-Name /madrigal;
15 15 proxy_pass http://djangomad;
16 16 }
17 17
18 location /static/ {
18 location /madrigal/static/ {
19 19 alias /static/;
20 20 }
21 } No newline at end of file
21 }
@@ -1,83 +1,83
1 1
2 2 from django.contrib.auth.decorators import login_required
3 3 from django.shortcuts import render
4 4 from .forms import UpdataForm, ExpForm
5 5 from django.core.files.storage import FileSystemStorage
6 6 from django.contrib import messages
7 7
8 8 import os
9 9
10 10 # madrigal imports
11 11 import madrigal.metadata
12 12 import madrigal.ui.web
13 13 import madrigal.admin
14 14
15 @login_required
15 @login_required(login_url='/madrigal/accounts/login/')
16 16 def index(request):
17 17 '''
18 18 Uploading experiments data view. Allows user to upload experiment files
19 19
20 20 '''
21 21 dbAdminObj = madrigal.admin.MadrigalDBAdmin()
22 22 madDB = madrigal.metadata.MadrigalDB()
23 23 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
24 24 siteName, siteList = madWebObj.getSiteInfo()
25 25
26 26 if request.method == 'POST':
27 27 form = UpdataForm(request.POST, request.FILES)
28 28 files = request.FILES.getlist('file')
29 29
30 30 if form.is_valid():
31 31 try:
32 32 description = form.cleaned_data['description']
33 33 instCode = int(form.cleaned_data['instruments'])
34 34 expId = form.cleaned_data['experiments']
35 35 perm = int(form.cleaned_data['type'])
36 36
37 37 #saving file
38 38 for f in files:
39 39 fs = FileSystemStorage(location='/tmp')
40 40 fs.save(f.name, f)
41 41 madExp = madrigal.metadata.MadrigalExperiment()
42 42 filepath = os.path.join('/tmp', f.name)
43 43 expTitle = madExp.getExpNameByExpId(expId)
44 44
45 45 dbAdminObj.createMadrigalExperiment(filepath,expTitle, perm, description, instCode)
46 46
47 47
48 48 madInstParams = madrigal.metadata.MadrigalInstrumentParameters()
49 49 madInstKindats = madrigal.metadata.MadrigalInstrumentKindats()
50 50
51 51 print('*** Updating local metadata ***')
52 52 dbAdminObj.__updateLocalMetadata__()
53 53 print('*** Rebuilding instParmTab.txt ***')
54 54 madInstParams.rebuildInstParmTable()
55 55 print('*** Rebuilding instKindatTab.txt ***')
56 56 madInstKindats.rebuildInstKindatTable()
57 57 messages.success(
58 58 request, 'Experimento(s) creado(s) exitosamente')
59 59 form = UpdataForm()
60 60
61 61 except Exception as e:
62 62 messages.error(
63 63 request, str(e))
64 64 else:
65 65 form = UpdataForm()
66 66
67 67 return render(request, 'updata/index.html', {
68 68 'form': form,
69 69 'site_name': siteName,
70 70 'site_list': siteList,
71 71 })
72 72
73 73
74 74 def get_experiments(request):
75 75 """get_experiments is a Ajax call that returns the experiments select html to support the
76 76 updata UI. Called when a user modifies the intruments select field.
77 77
78 78 Inputs:
79 79 request
80 80 """
81 81 form = ExpForm(request.GET)
82 82
83 83 return render(request, 'updata/experiments.html', {'form': form})
@@ -1,138 +1,138
1 1 """
2 2 Django settings for djangoMad project.
3 3
4 4 For more information on this file, see
5 5 https://docs.djangoproject.com/en/1.7/topics/settings/
6 6
7 7 For the full list of settings and their values, see
8 8 https://docs.djangoproject.com/en/1.7/ref/settings/
9 9 """
10 10
11 11 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
12 12 import os
13 13 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
14 14
15 15 # Quick-start development settings - unsuitable for production
16 16 # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
17 17
18 18 # SECURITY WARNING: keep the secret key used in production secret!
19 19 SECRET_KEY = '^c1l3d35+q28^66d2pc1qlu(k$wmw^*gg3rfitz^s)t=9eu1ui'
20 20
21 21 # SECURITY WARNING: don't run with debug turned on in production!
22 22 DEBUG = True
23 23
24 24
25 ALLOWED_HOSTS = ['localhost:8000', '127.0.0.1', 'localhost']
25 ALLOWED_HOSTS = ['localhost:8000', '127.0.0.1', 'localhost', '10.10.120.60']
26 26
27 27 ADMINS = (('Bill Rideout', 'brideout@haystack.mit.edu'),)
28 28
29 29 EMAIL_HOST = 'hyperion.haystack.mit.edu'
30 30
31 31 SEND_BROKEN_LINK_EMAILS = True
32 32
33 33 MANAGERS = (('Bill Rideout', 'brideout@haystack.mit.edu'),)
34 34
35 35
36 36 # Application definition
37 37
38 38 INSTALLED_APPS = (
39 39 'django.contrib.admin',
40 40 'django.contrib.auth',
41 41 'django.contrib.contenttypes',
42 42 'django.contrib.sessions',
43 43 'django.contrib.messages',
44 44 'django.contrib.staticfiles',
45 45 'madweb',
46 46 'django_bootstrap_calendar',
47 47 'bootstrap3',
48 48 'apps.login',
49 49 'apps.updata',
50 50 )
51 51
52 52 MIDDLEWARE = [
53 53 'django.middleware.security.SecurityMiddleware',
54 54 'django.contrib.sessions.middleware.SessionMiddleware',
55 55 'django.middleware.common.CommonMiddleware',
56 56 'django.middleware.csrf.CsrfViewMiddleware',
57 57 'django.contrib.auth.middleware.AuthenticationMiddleware',
58 58 'django.contrib.messages.middleware.MessageMiddleware',
59 59 'django.middleware.clickjacking.XFrameOptionsMiddleware',
60 60 ]
61 61
62 62 ROOT_URLCONF = 'djangoMad.urls'
63 63
64 64 WSGI_APPLICATION = 'djangoMad.wsgi.application'
65 65
66 66
67 67 TEMPLATES = [
68 68 {
69 69 'BACKEND': 'django.template.backends.django.DjangoTemplates',
70 70 'DIRS': [
71 71 os.path.join(BASE_DIR, "templates"),
72 72 ],
73 73 'APP_DIRS': True,
74 74 'OPTIONS': {
75 75 'context_processors': [
76 76 'django.contrib.auth.context_processors.auth',
77 77 'django.template.context_processors.debug',
78 78 'django.template.context_processors.i18n',
79 79 'django.template.context_processors.media',
80 80 'django.template.context_processors.static',
81 81 'django.template.context_processors.tz',
82 82 'django.contrib.messages.context_processors.messages',
83 83 'django.template.context_processors.request',
84 84 ],
85 85 },
86 86 },
87 87 ]
88 88
89 89
90 90 # Database
91 91 # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
92 92
93 93 DATABASES = {
94 94 'default': {
95 95 'ENGINE': 'django.db.backends.sqlite3',
96 96 'NAME': 'madrigal.sqlite',
97 97 }
98 98 }
99 99
100 100
101 101 # Internationalization
102 102 # https://docs.djangoproject.com/en/1.7/topics/i18n/
103 103
104 104 LANGUAGE_CODE = 'en-us'
105 105
106 106 TIME_ZONE = 'UTC'
107 107
108 108 USE_I18N = True
109 109
110 110 USE_L10N = True
111 111
112 112 USE_TZ = True
113 113
114 114
115 115 # Absolute filesystem path to the directory that will hold user-uploaded files.
116 116 # Example: "/home/media/media.lawrence.com/media/"
117 117 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
118 118
119 119 # URL that handles the media served from MEDIA_ROOT. Make sure to use a
120 120 # trailing slash.
121 121 # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
122 122 MEDIA_URL = '/media/'
123 123
124 124 # Absolute path to the directory static files should be collected to.
125 125 # Don't put anything in this directory yourself; store your static files
126 126 # in apps' "static/" subdirectories and in STATICFILES_DIRS.
127 127 # Example: "/home/media/media.lawrence.com/static/"
128 128 # STATIC_ROOT = os.path.join(BASE_DIR, 'static')
129 129
130 130 # URL prefix for static files.
131 131 # Example: "http://media.lawrence.com/static/"
132 STATIC_URL = '/static/'
132 STATIC_URL = '/madrigal/static/'
133 133
134 134 BOOTSTRAP3 = {
135 135 # Include jQuery with Bootstrap JavaScript (affects django-bootstrap3 template tags)
136 'jquery_url': '/static/jquery.min.js',
136 'jquery_url': '/madrigal/static/jquery.min.js',
137 137 'include_jquery': True,
138 138 }
@@ -1,11 +1,12
1 1 from django.conf.urls import include, url
2 2 from django.contrib import admin
3 3 import madweb.views
4 4
5 5 urlpatterns = [
6 url(r'^', include('madweb.urls')),
6 url(r'^madrigal/', include('madweb.urls')),
7 7 url(r'^$', madweb.views.index),
8 url(r'^updata/', include('apps.updata.urls', namespace="updata")),
9 url(r'^accounts/', include('apps.login.urls', namespace="login")),
10 url(r'^admin/', admin.site.urls),
8 url(r'^madrigal/updata/', include('apps.updata.urls', namespace="updata")),
9 url(r'^madrigal/accounts/', include('apps.login.urls', namespace="login")),
10 url(r'^madrigal/admin/', admin.site.urls),
11 # url(r'^madrigal/register/?$', madweb.views.view_registration, name='view_registration'),
11 12 ]
@@ -1,2208 +1,2220
1 1 """Forms for madweb application
2 2
3 3 $Id: forms.py 7288 2020-12-10 16:49:16Z brideout $
4 4 """
5 5
6 6 # standard python imports
7 7 import os.path
8 8 import datetime
9 9 import itertools
10 10
11 11 # django imports
12 12 import django.forms
13 13 import django.utils.html
14 14 import django.utils.safestring
15 15 import django.template.defaulttags
16 16
17 17 # third party imports
18 18 import numpy
19 19 import h5py
20 20
21 21 # Madrigal imports
22 22 import madrigal.metadata
23 23 import madrigal.ui.web
24 24
25 25 # temp only
26 26 import logging
27 27
28 28 @django.template.defaulttags.register.filter
29 29 def get_item(dictionary, key):
30 30 return(dictionary.get(key))
31 31
32 32 @django.template.defaulttags.register.filter
33 33 def modulo(num, val):
34 34 return(num % val == 0)
35 35
36 36 class HorizontalRadioSelect(django.forms.RadioSelect):
37 37 template_name = 'madweb/horizontal_select.html'
38 38
39 39
40 40
41 41 def getSelection(keyword, args, kwargs):
42 42 """getSelection returns '0' if keyword not a key in either args[0] or kwargs,
43 43 otherwise the value
44 44
45 45 args, kwargs - arguments as passed into SingleExpDefaultForm __init__
46 46 """
47 47 if len(args) == 0 and len(list(kwargs.keys())) == 0:
48 48 return('0') # default case when no data passed in
49 49 elif len(args) > 0:
50 50 # args[0] is data dict argument to bind data
51 51 if keyword in args[0]:
52 52 return(args[0][keyword])
53 53 else:
54 54 return('0')
55 55 elif keyword in kwargs:
56 56 return(kwargs[keyword])
57 57 elif 'data' in kwargs:
58 58 if keyword in kwargs['data']:
59 59 return(kwargs['data'][keyword])
60 60 else:
61 61 return('0')
62 62 else:
63 63 return('0')
64 64
65 65
66 66 def getIsGlobal(args, kwargs):
67 67 """getIsGlobal is a helper function returns True if 'isGlobal' not found in either args[0] or kwargs,
68 68 otherwise the bool of the value
69 69
70 70 args, kwargs - arguments as passed into SingleExpDefaultForm __init__
71 71 """
72 72 if len(args) == 0 and len(list(kwargs.keys())) == 0:
73 73 return(True) # default case when no data passed in
74 74 elif len(args) > 0:
75 75 # args[0] is data dict argument to bind data
76 76 if 'isGlobal' in args[0]:
77 77 if args[0]['isGlobal'] == '0':
78 78 return(False)
79 79 else:
80 80 return(bool(args[0]['isGlobal']))
81 81 else:
82 82 return(False)
83 83 elif 'data' in kwargs:
84 84 if 'isGlobal' in kwargs['data']:
85 85 if kwargs['data']['isGlobal'] == '0':
86 86 return(False)
87 87 else:
88 88 return(bool(kwargs['data']['isGlobal']))
89 89 else:
90 90 return(False)
91 91 elif 'isGlobal' in kwargs:
92 92 if kwargs['isGlobal'] == '0':
93 93 return(False)
94 94 else:
95 95 return(bool(kwargs['isGlobal']))
96 96 else:
97 97 return(False)
98 98
99 99
100 100 def getCategoryList(args, kwargs, madInstData, forList=False):
101 101 """getCategoryList is a helper function that returns the categories choices in
102 102 SingleExpDefaultForm.categories at runtime
103 103
104 104 Inputs:
105 105 args, kwargs - arguments as passed into SingleExpDefaultForm __init__. Used only to
106 106 determine isGlobal
107 107 madInstData - madrigal.metadata.MadrigalInstrumentData object
108 108 forList - if False (the default) category list if for single interface, If True, for List interface
109 109 """
110 110 if not forList:
111 111 local = not getIsGlobal(args, kwargs)
112 112 else:
113 113 local = False
114 114 categories = madInstData.getCategories(local)
115 115 if forList:
116 116 catList = [('0', 'All instrument categories'),]
117 117 else:
118 118 catList = [('0', 'Choose instrument type: '),]
119 119 for catID, catDesc in categories:
120 120 catList.append((str(catID), catDesc))
121 121 return(catList)
122 122
123 123
124 124
125 125 def getInstrumentList(args, kwargs, madInstData, header='Select an instrument: ', local=None, includeYears=False):
126 126 """getInstrumentList is a helper function that returns the instrument choices in
127 127 SingleExpDefaultForm.categories at runtime
128 128
129 129 Inputs:
130 130 args, kwargs - arguments as passed into SingleExpDefaultForm __init__. Used to
131 131 determine categoryId and local
132 132 madInstData - madrigal.metadata.MadrigalInstrumentData object
133 133 header - text of first item in selection
134 134 local - if None (the default), set local flag via args and kwargs. If boolean,
135 135 set local flag to arg.
136 136 includeYear - if True, include data years in description. If False (the default), do not.
137 137 """
138 138 if local is None:
139 139 local = not getIsGlobal(args, kwargs)
140 140 else:
141 141 local = bool(local)
142 142 if header == 'Select an instrument: ':
143 143 categoryId = int(getSelection('categories', args, kwargs))
144 144 else:
145 145 categoryId = 0
146 146 instruments = madInstData.getInstruments(categoryId, local)
147 147 instList = [('0', header),]
148 148 for kinst, instDesc, siteID in instruments:
149 149 if includeYears:
150 150 instYears = madInstData.getInstrumentYears(kinst)
151 151 instList.append((str(kinst), '%s [%i-%i]' % (instDesc, instYears[0], instYears[-1])))
152 152 else:
153 153 instList.append((str(kinst), instDesc))
154 154 return(instList)
155 155
156 156
157 157 def getYearList(args, kwargs, madInstData):
158 158 """getYearList is a helper function that returns the year choices in
159 159 SingleExpDefaultForm.categories at runtime
160 160
161 161 Inputs:
162 162 args, kwargs - arguments as passed into SingleExpDefaultForm __init__. Used to
163 163 determine categoryId and local and kinst
164 164 madInstData - madrigal.metadata.MadrigalInstrumentData object
165 165 """
166 166 local = not getIsGlobal(args, kwargs)
167 167 kinst = int(getSelection('instruments', args, kwargs))
168 168 years = madInstData.getInstrumentYears(kinst)
169 169 yearsList = [('0', 'Select a year: '),]
170 170 for thisYear in reversed(years):
171 171 yearsList.append((str(thisYear), str(thisYear)))
172 172 return(yearsList)
173 173
174 174
175 175 def getMonthList(args, kwargs, madWebObj):
176 176 """getMonthList is a helper function that returns the month choices in
177 177 SingleExpDefaultForm.categories at runtime. Value is (month number,
178 178 month name)
179 179
180 180 Inputs:
181 181 args, kwargs - arguments as passed into SingleExpDefaultForm __init__. Used to
182 182 determine and kinst and year
183 183 madWebObj - madrigal.ui.web.MadrigalWeb object
184 184 """
185 185 kinst = int(getSelection('instruments', args, kwargs))
186 186 year = int(getSelection('years', args, kwargs))
187 187 monthList = [('0', 'Select a month: '),]
188 188 addedMonthList = madWebObj.getMonths(kinst, year)
189 189 if len(addedMonthList) == 0:
190 190 addedMonthList = madWebObj.getMonths(kinst, year, optimize=False)
191 191 monthList += addedMonthList
192 192 return([(str(monthNumber), monthName) for monthNumber, monthName in monthList])
193 193
194 194
195 195 def getDayList():
196 196 """always returns 1 ... 31
197 197 """
198 198 dayList = [(i, str(i)) for i in range(1,32)]
199 199 return(dayList)
200 200
201 201
202 202 def getExpList(args, kwargs, madWebObj):
203 203 """getExpList is a helper function that returns the experiment choices in
204 204 SingleExpDefaultForm.categories at runtime. Value is (expId,
205 205 expDesc, expDir, pi_name, pi_email)
206 206
207 207 Inputs:
208 208 args, kwargs - arguments as passed into SingleExpDefaultForm __init__. Used to
209 209 determine and kinst, year, month, day
210 210 madWebObj - madrigal.ui.web.MadrigalWeb object
211 211 """
212 212 kinst = int(getSelection('instruments', args, kwargs))
213 213 year = int(getSelection('years', args, kwargs))
214 214 month = int(getSelection('months', args, kwargs))
215 215 day = int(getSelection('days', args, kwargs))
216 216 expList = madWebObj.getExpsOnDate(kinst, year, month, day)
217 217 if len(expList) == 0:
218 218 expList = madWebObj.getExpsOnDate(kinst, year, month, day, optimize=False)
219 219 return(expList)
220 220
221 221
222 222 def handle_registration(kwargs, user_email, expUrl, kinst, madDB):
223 223 """handle_registration causes the user to register or unregister interest in getting emails
224 224 when a particular experiment or instrument is updated
225 225
226 226 Inputs:
227 227 kwargs - dictionary as passed into form
228 228 user_email - users email address
229 229 expUrl - experiment url (part after /madtoc/)
230 230 kinst - instrument code
231 231 madDB - madrigal.metadata.MadrigalDB object
232 232 """
233 233 # first find out if this exp or inst is already registered
234 234 madUserObj = madrigal.ui.userData.MadrigalUserData(madDB)
235 235 expsRegistered = madUserObj.getRegisteredExperiments(user_email)
236 236 if expUrl in expsRegistered:
237 237 thisExpRegistered = True
238 238 else:
239 239 thisExpRegistered = False
240 240 instsRegistered = madUserObj.getRegisteredInstruments(user_email)
241 241 if kinst in instsRegistered:
242 242 thisInstRegistered = True
243 243 else:
244 244 thisInstRegistered = False
245 245
246 246 # check registration status, update if needed, and let form know how to print this
247 247 # 0 - no registration, 1 - exp registered, 2 - inst registered
248 248 if 'registerExp' in kwargs:
249 249 if not thisExpRegistered:
250 250 madUserObj.registerExperiment(user_email, expUrl)
251 251 return('1')
252 252 elif 'registerInst' in kwargs:
253 253 if not thisInstRegistered:
254 254 madUserObj.registerInstrument(user_email, kinst)
255 255 return('2')
256 256 elif 'unregisterExp' in kwargs:
257 257 if thisExpRegistered:
258 258 madUserObj.unregisterExperiment(user_email, expUrl)
259 259 return('0')
260 260 elif 'unregisterInst' in kwargs:
261 261 if thisInstRegistered:
262 262 madUserObj.unregisterInstrument(user_email, kinst)
263 263 return('0')
264 264 elif thisExpRegistered:
265 265 return('1')
266 266 elif thisInstRegistered:
267 267 return('2')
268 268 else:
269 269 return('0')
270 270
271 271
272 272 def getFormatChoices(basename, expID):
273 273 """getFormatChoices returns a list with 3 tuples, where each tuple
274 274 is 1. filename with correct extension, 2. Format
275 275
276 276 Inputs:
277 277 basename - basename of Madrigal Hdf5 file
278 278 expID - needed to determine if cached file available in near real time
279 279 """
280 280 madWebObj = madrigal.ui.web.MadrigalWeb()
281 281 formats = madWebObj.getFormatsAvailable(expID, basename)
282 282 fileName, fileExtension = os.path.splitext(basename)
283 283 retList = []
284 284 retList.append((basename, 'Hdf5')) # file is assumed to be in Hdf5 format
285 285 if 'ascii' in formats:
286 286 retList.append((fileName + '.txt', 'Space-delimited ascii'))
287 287 if 'netCDF4' in formats:
288 288 retList.append((fileName + '.nc', 'netCDF4'))
289 289 return(retList)
290 290
291 291
292 292 class RegisterForm(django.forms.Form):
293 293 """RegisterForm is the form class that supports the Register page
294 294 """
295 295 def __init__(self, *args, **kwargs):
296 296 super(RegisterForm, self).__init__(*args, **kwargs)
297 297 self.fields['user_fullname'] = django.forms.CharField(label='Full name', min_length=2, max_length=256)
298 298 self.fields['user_email'] = django.forms.EmailField(label='Email')
299 299 self.fields['user_affiliation'] = django.forms.CharField(label='Affliation (type "None" if individual)', min_length=2, max_length=256)
300 300
301 301
302 302
303 303 class SingleExpDefaultForm(django.forms.Form):
304 304 """SingleExpDefaultForm is a Form class for the default fields in the Single Experiment interface
305 305 (formally the Simple interface)
306 306 """
307 307 def __init__(self, *args, **kwargs):
308 308 super(SingleExpDefaultForm, self).__init__(*args, **kwargs)
309 309 madDB = madrigal.metadata.MadrigalDB()
310 310 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
311 311 user_email = getSelection('user_email', args, kwargs)
312 312 self.fields['isGlobal'] = django.forms.BooleanField(widget = django.forms.CheckboxInput(attrs={"onChange":'populateCat(this)'}),
313 313 required=False, label='Use all Madrigal sites: ',
314 314 initial=getIsGlobal(args, kwargs))
315 315
316 316
317 317 categoriesSelection = getSelection('categories', args, kwargs)
318 318 self.fields['categories'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateInst(this)'}),
319 319 choices=getCategoryList(args, kwargs, madInstData),
320 320 initial=categoriesSelection,
321 321 label='Instrument category:')
322 322
323 323 # the following fields may or may not be populated. All are also available as individual classes
324 324 # to allow AJAX calls to not need to create this full object
325 325
326 326 if categoriesSelection != '0':
327 327 instrumentSelection = getSelection('instruments', args, kwargs)
328 328 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateYear(this)'}),
329 329 choices=getInstrumentList(args, kwargs, madInstData),
330 330 initial=instrumentSelection,
331 331 required=False, label='Instrument:')
332 332 else:
333 333 return # no need to create any further fields
334 334
335 335 if instrumentSelection != '0':
336 336 yearSelection = getSelection('years', args, kwargs)
337 337 self.fields['years'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateMonth(this)'}),
338 338 choices=getYearList(args, kwargs, madInstData),
339 339 initial=yearSelection,
340 340 required=False, label='Year:')
341 341
342 342 else:
343 343 return # no need to create any further fields
344 344
345 345 if yearSelection != '0':
346 346 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
347 347 monthSelection = getSelection('months', args, kwargs)
348 348 self.fields['months'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateCalendar(this)'}),
349 349 choices=getMonthList(args, kwargs, madWebObj),
350 350 initial=monthSelection, label='Month:')
351 351
352 352 else:
353 353 return # no need to create any further fields
354 354
355 355
356 356 if monthSelection != '0':
357 357 daySelection = getSelection('days', args, kwargs)
358 358 # this field is only used to help display the calendar
359 359 self.fields['days'] = django.forms.ChoiceField(required=False, choices=getDayList())
360 360
361 361 else:
362 362 return # no need to create any further fields
363 363
364 364 if daySelection != '0':
365 365 expFullList = getExpList(args, kwargs, madWebObj)
366 366 expIdSelection = None
367 367 if len(expFullList) > 1:
368 368 expList = [('0', 'Select one of multiple experiments')] + [(items[0], items[1]) for items in expFullList]
369 369 expIdSelection = getSelection('experiment_list', args, kwargs)
370 370 self.fields['experiment_list'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateFile(this)'}),
371 371 choices=expList, initial=expIdSelection,
372 372 required=False, label='Select experiment:')
373 373
374 374 if expIdSelection == '0':
375 375 # no need to create any further fields
376 376 return
377 377
378 378 if expIdSelection is None:
379 379 expIdSelection = expFullList[0][0]
380 380 expDir = expFullList[0][2]
381 381 else:
382 382 expDir = None
383 383 for expId, thisExpDesc, thisExpDir in expFullList:
384 384 if int(expIdSelection) == int(expId):
385 385 expDir = thisExpDir
386 386 break
387 387
388 388 fileList = madWebObj.getFileFromExpDir(expDir, int(instrumentSelection))
389 389 fileList = [('0', 'Select file')] + fileList
390 390 fileSelection = getSelection('file_list', args, kwargs)
391 391 self.fields['file_list'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'changeFile(this)'}),
392 392 choices=fileList, initial=fileSelection,
393 393 required=False, label='Select file:')
394 394 self.fields['exp_id'] = django.forms.CharField(initial=str(expIdSelection),
395 395 widget=django.forms.HiddenInput(attrs={'value': str(expIdSelection)}),
396 396 required=False,
397 397 label=str(expIdSelection))
398 398
399 399 pi_name, pi_email, expUrl, kinst, expDesc, kinstDesc = madWebObj.getExpInfoFromExpID(int(expIdSelection))
400 400
401 401 self.fields['exp_desc'] = django.forms.CharField(initial=str(expDesc),
402 402 widget=django.forms.HiddenInput(attrs={'value': str(expDesc)}),
403 403 required=False,
404 404 label=str(expDesc))
405 405 self.fields['user_email'] = django.forms.CharField(initial=str(user_email),
406 406 widget=django.forms.HiddenInput(attrs={'value': str(user_email)}),
407 407 required=False,
408 408 label=str(user_email))
409 409 self.fields['inst_desc'] = django.forms.CharField(initial=str(kinstDesc),
410 410 widget=django.forms.HiddenInput(attrs={'value': str(kinstDesc)}),
411 411 required=False,
412 412 label=str(kinstDesc))
413 413 self.fields['pi_name'] = django.forms.CharField(initial=pi_name,
414 414 widget=django.forms.HiddenInput(attrs={'value': pi_name}),
415 415 required=False,
416 416 label=pi_name)
417 417 self.fields['pi_email'] = django.forms.CharField(initial=pi_email,
418 418 widget=django.forms.HiddenInput(attrs={'value': pi_email}),
419 419 required=False,
420 420 label=pi_email)
421 421
422 422 # handle any needed registration or unregistration
423 423 register = handle_registration(args[0], user_email, expUrl, kinst, madDB)
424 424 self.fields['register'] = django.forms.CharField(initial=register,
425 425 widget=django.forms.HiddenInput(attrs={'value': register}),
426 426 required=False,
427 427 label=register)
428 428
429 429
430 430 else:
431 431 return # no need to create any further fields
432 432
433 433 if fileSelection != '0':
434 434 self.fields['file_buttons'] = django.forms.CharField(initial='',
435 435 widget=django.forms.HiddenInput(attrs={'value': ''}),
436 436 required=False,
437 437 label='')
438 438
439 439
440 440 else:
441 441 return # no need to create any further fields
442 442
443 443
444 444
445 445
446 446
447 447
448 448
449 449
450 450
451 451 class SingleExpInstForm(django.forms.Form):
452 452 """SingleExpInstForm is a Form class for the instrument select field in the Single Experiment interface.
453 453 Use this because its faster to create than the full SingleExpDefaultForm
454 454 """
455 455 def __init__(self, *args, **kwargs):
456 456 super(SingleExpInstForm, self).__init__(*args, **kwargs)
457 457 madDB = madrigal.metadata.MadrigalDB()
458 458 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
459 459 instrumentSelection = getSelection('instruments', args, kwargs)
460 460 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateYear(this)'}),
461 461 choices=getInstrumentList(args, kwargs, madInstData),
462 462 initial=instrumentSelection,
463 463 label='Instrument:')
464 464
465 465 class SingleExpYearForm(django.forms.Form):
466 466 """SingleExpYearForm is a Form class for the year select field in the Single Experiment interface.
467 467 Use this because its faster to create than the full SingleExpDefaultForm
468 468 """
469 469 def __init__(self, *args, **kwargs):
470 470 super(SingleExpYearForm, self).__init__(*args, **kwargs)
471 471 madDB = madrigal.metadata.MadrigalDB()
472 472 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
473 473 yearSelection = getSelection('years', args, kwargs)
474 474 self.fields['years'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateMonth(this)'}),
475 475 choices=getYearList(args, kwargs, madInstData),
476 476 initial=yearSelection, label='Year:')
477 477
478 478
479 479 class SingleExpMonthForm(django.forms.Form):
480 480 """SingleExpMonthForm is a Form class for the month select field in the Single Experiment interface.
481 481 Use this because its faster to create than the full SingleExpDefaultForm
482 482 """
483 483 def __init__(self, *args, **kwargs):
484 484 super(SingleExpMonthForm, self).__init__(*args, **kwargs)
485 485 madDB = madrigal.metadata.MadrigalDB()
486 486 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
487 487 monthSelection = getSelection('months', args, kwargs)
488 488 self.fields['months'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateCalendar(this)'}),
489 489 choices=getMonthList(args, kwargs, madWebObj),
490 490 initial=monthSelection, label='Month:')
491 491
492 492
493 493 class SingleExpCalendarForm(django.forms.Form):
494 494 """SingleExpCalendarForm is a Form class for the calendar field in the Single Experiment interface.
495 495 Use this because its faster to create than the full SingleExpDefaultForm
496 496 """
497 497 def __init__(self, *args, **kwargs):
498 498 super(SingleExpCalendarForm, self).__init__(*args, **kwargs)
499 499 madDB = madrigal.metadata.MadrigalDB()
500 500 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
501 501
502 502
503 503 class SingleExpFileForm(django.forms.Form):
504 504 """SingleExpFileForm is a Form class for the file select field in the Single Experiment interface.
505 505 Use this because its faster to create than the full SingleExpDefaultForm
506 506 """
507 507 def __init__(self, *args, **kwargs):
508 508 super(SingleExpFileForm, self).__init__(*args, **kwargs)
509 509 madDB = madrigal.metadata.MadrigalDB()
510 510 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
511 511 expID = getSelection('experiment_list', args, kwargs)
512 512 try:
513 513 expID = int(expID)
514 514 except ValueError:
515 515 # convert expPath to expID
516 516 expID = madWebObj.getExpIDFromExpPath(expID, True)
517 517 user_email = getSelection('user_email', args, kwargs)
518 518 include_non_default = getSelection('includeNonDefault', args, kwargs)
519 519 if include_non_default == '0':
520 520 include_non_default = False
521 521 fileList = madWebObj.getFileFromExpID(expID, include_non_default)
522 522 fileList = [('0', 'Select file')] + fileList
523 523
524 524 fileSelection = getSelection('file_list', args, kwargs)
525 525 self.fields['file_list'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'changeFile(this)'}),
526 526 choices=fileList, initial=fileSelection,
527 527 required=False, label='Select file:')
528 528 if int(expID) != 0:
529 529 self.fields['exp_id'] = django.forms.CharField(initial=str(expID),
530 530 widget=django.forms.HiddenInput(attrs={'value': str(expID)}),
531 531 required=False,
532 532 label=str(expID))
533 533 pi_name, pi_email, expUrl, kinst, expDesc, kinstDesc = madWebObj.getExpInfoFromExpID(int(expID))
534 534
535 535 self.fields['exp_desc'] = django.forms.CharField(initial=str(expDesc),
536 536 widget=django.forms.HiddenInput(attrs={'value': str(expDesc)}),
537 537 required=False,
538 538 label=str(expDesc))
539 539 self.fields['user_email'] = django.forms.CharField(initial=str(user_email),
540 540 widget=django.forms.HiddenInput(attrs={'value': str(user_email)}),
541 541 required=False,
542 542 label=str(user_email))
543 543 self.fields['inst_desc'] = django.forms.CharField(initial=str(kinstDesc),
544 544 widget=django.forms.HiddenInput(attrs={'value': str(kinstDesc)}),
545 545 required=False,
546 546 label=str(kinstDesc))
547 547 self.fields['pi_name'] = django.forms.CharField(initial=pi_name,
548 548 widget=django.forms.HiddenInput(attrs={'value': pi_name}),
549 549 required=False,
550 550 label=pi_name)
551 551 self.fields['pi_email'] = django.forms.CharField(initial=pi_email,
552 552 widget=django.forms.HiddenInput(attrs={'value': pi_email}),
553 553 required=False,
554 554 label=pi_email)
555 555 self.fields['includeNonDefault'] = django.forms.BooleanField(widget = django.forms.CheckboxInput(attrs={"onChange":'reloadFiles(this)'}),
556 556 required=False, label='Show non-default files: ',
557 557 initial=include_non_default)
558 558 # handle any needed registration or unregistration
559 559 register = handle_registration(args[0], user_email, expUrl, kinst, madDB)
560 560 self.fields['register'] = django.forms.CharField(initial=register,
561 561 widget=django.forms.HiddenInput(attrs={'value': register}),
562 562 required=False,
563 563 label=register)
564 564
565 565 if fileSelection != '0':
566 566 self.fields['file_buttons'] = django.forms.CharField(initial='',
567 567 widget=django.forms.HiddenInput(attrs={'value': ''}),
568 568 required=False,
569 569 label='')
570 570 self.fields['basename'] = django.forms.CharField(initial=str(fileSelection),
571 571 widget=django.forms.HiddenInput(attrs={'value': str(fileSelection)}),
572 572 required=False,
573 573 label=str(fileSelection))
574 574
575 575
576 576
577 577
578 578
579 579 class SingleExpButtonsForm(django.forms.Form):
580 580 """SingleExpButtonsForm is a Form class for the file buttons field in the Single Experiment interface.
581 581 Use this because its faster to create than the full SingleExpDefaultForm
582 582 """
583 583 def __init__(self, *args, **kwargs):
584 584 super(SingleExpButtonsForm, self).__init__(*args, **kwargs)
585 585 madDB = madrigal.metadata.MadrigalDB()
586 586 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
587 587 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
588 588 expID = getSelection('experiment_list', args, kwargs)
589 589 try:
590 590 expID = int(expID)
591 591 except ValueError:
592 592 # convert expPath to expID
593 593 expID = madWebObj.getExpIDFromExpPath(expID, True)
594 594
595 595 fileSelection = getSelection('file_list', args, kwargs)
596 596
597 597 expDir = madExpObj.getExpDirByExpId(int(expID))
598 598 filesize = os.path.getsize(os.path.join(expDir, str(fileSelection)))
599 599
600 600 self.fields['file_buttons'] = django.forms.CharField(initial='',
601 601 widget=django.forms.HiddenInput(attrs={'value': ''}),
602 602 required=False,
603 603 label='')
604 604 self.fields['exp_id'] = django.forms.CharField(initial=str(expID),
605 605 widget=django.forms.HiddenInput(attrs={'value': str(expID)}),
606 606 required=False,
607 607 label=str(expID))
608 608 self.fields['basename'] = django.forms.CharField(initial=str(fileSelection),
609 609 widget=django.forms.HiddenInput(attrs={'value': str(fileSelection)}),
610 610 required=False,
611 611 label=str(fileSelection))
612 612 self.fields['filesize'] = django.forms.IntegerField(initial=filesize,
613 613 widget=django.forms.HiddenInput(attrs={'value': filesize}),
614 614 required=False,
615 615 label=str(filesize))
616 616
617 617
618 618 class SingleExpPlotsForm(django.forms.Form):
619 619 """SingleExpPlotsForm is a Form class for the file data/show plots field in the Single Experiment interface.
620 620 Use this because its faster to create than the full SingleExpDefaultForm
621 621 """
622 622 def __init__(self, *args, **kwargs):
623 623 super(SingleExpPlotsForm, self).__init__(*args, **kwargs)
624 624 madDB = madrigal.metadata.MadrigalDB()
625 625 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
626 626 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
627 627 expID = getSelection('experiment_list', args, kwargs)
628 628 try:
629 629 expID = int(expID)
630 630 except ValueError:
631 631 # convert expPath to expID
632 632 expID = madWebObj.getExpIDFromExpPath(expID, True)
633 633 plotList = madExpObj.getExpLinksByExpId(expID)
634 634 if len(plotList) == 0:
635 635 plotList = [('No plots available', '')]
636 636
637 637 self.fields['plot_list'] = django.forms.ChoiceField(widget = django.forms.Select(),
638 638 choices=plotList,
639 639 required=False)
640 640
641 641 '''get_params2 retrieves a list of 1d and 2d parameters of type 1 hdf5 files'''
642 642
643 643 def check_mnemonic(s):
644 644
645 s.replace('vipe1', 'vipe')
646 s.replace('vipe2', 'vipe')
647 s.replace('vipn1', 'vipn')
648 s.replace('vipn2', 'vipn')
649 s.replace('vi72', 'vi7')
650 s.replace('vi82', 'vi8')
651 s.replace('dvipe1', 'dvipe')
652 s.replace('dvipe2', 'dvipe')
653 s.replace('dvipn1', 'dvipn')
654 s.replace('dvipn2', 'dvipn')
655 s.replace('dvi72', 'dvi7')
656 s.replace('dvi82', 'dvi8')
645 657 return s.replace('+', '%2b')
646 658
647 659 def get_params1(args, kwargs, madExpObj, madWebObj):
648 660
649 661 expID = getSelection('experiment_list', args, kwargs)
650 662 expDir = madExpObj.getExpDirByExpId(expID)
651 663 fileList = madWebObj.getFileFromExpID(expID, False)
652 664
653 665 firsttuple = [a_tuple[0] for a_tuple in fileList]
654 666 basename = firsttuple[0]
655 667 fullFilename = os.path.join(expDir, basename)
656 668 f = h5py.File(fullFilename, "r")
657 669
658 670 data = f['Data']
659 671
660 672 choices1d = [(check_mnemonic(x[0].decode().lower()), x[1].decode()) for x in data['Array Layout']['1D Parameters']['Data Parameters']]
661 673 choices2d = [(check_mnemonic(x[0].decode().lower()), x[1].decode()) for x in data['Array Layout']['2D Parameters']['Data Parameters']]
662 674 choices = [[('0', 'Select Parameter')] + choices1d, [('0', 'Select Parameter')] + choices2d]
663 675 f.close()
664 676 return choices
665 677
666 678
667 679 '''get params2 retrieves a list of 1d parameters of type 2 of hdf5 files'''
668 680 def get_params2(args, kwargs, madExpObj, madWebObj):
669 681
670 682 expID = getSelection('experiment_list', args, kwargs)
671 683 expDir = madExpObj.getExpDirByExpId(expID)
672 684 fileList = madWebObj.getFileFromExpID(expID, False)
673 685
674 686 firsttuple = [a_tuple[0] for a_tuple in fileList]
675 687 basename = firsttuple[0]
676 688 fullFilename = os.path.join(expDir, basename)
677 689 f = h5py.File(fullFilename, "r")
678 690 parameters = [(x[0].decode().lower(), x[1].decode()) for x in f['Metadata']['Data Parameters']]
679 691 f.close()
680 692 return [('0', 'Select Parameter')] + parameters
681 693
682 694
683 695 class SingleExpPlotsSelectionForm(django.forms.Form):
684 696 """SingleExpPlotsSselectionForm is a Form class for the parameters selection for plotting in the Single Experiment interface.
685 697 Use this because its faster to create than the full SingleExpDefaultForm
686 698 """
687 699
688 700 def __init__(self, *args, **kwargs):
689 701 super(SingleExpPlotsSelectionForm, self).__init__(*args, **kwargs)
690 702 madDB = madrigal.metadata.MadrigalDB()
691 703 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
692 704 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
693 705 expID = getSelection('experiment_list', args, kwargs)
694 706 try:
695 707 expID = int(expID)
696 708 except ValueError:
697 709 # convert expPath to expID
698 710 expID = madWebObj.getExpIDFromExpPath(expID, True)
699 711 expDir = madExpObj.getExpDirByExpId(expID)
700 712 fileList = madWebObj.getFileFromExpID(expID, False)
701 713
702 714 firsttuple = [a_tuple[0] for a_tuple in fileList]
703 715 basename = firsttuple[0]
704 716 fullFilename = os.path.join(expDir, basename)
705 717 f = h5py.File(fullFilename, "r")
706 718 data = f[list(f.keys())[0]]
707 719
708 720 if 'Array Layout' in list(data.keys()):
709 721 choices = get_params1(args, kwargs, madExpObj, madWebObj)
710 722 params1d = choices[0]
711 723 params2d = choices[1]
712 724 self.fields['param_list1d'] = django.forms.ChoiceField(widget = django.forms.Select(), choices=params1d, label="1D Parameters", required=False)
713 725 self.fields['param_list2d'] = django.forms.ChoiceField(widget = django.forms.Select(), choices=params2d, label="2D Parameters", required=False)
714 726
715 727 else:
716 728 params1d = get_params2(args, kwargs, madExpObj, madWebObj)
717 729 self.fields['param_list1d'] = django.forms.ChoiceField(widget = django.forms.Select(), choices=params1d, label="1D Parameters", required=False)
718 730
719 731
720 732 class SingleExpDownloadAsIsForm(django.forms.Form):
721 733 """SingleExpDownloadAsIsForm is a Form class for the download as is field in the Single Experiment interface.
722 734 Use this because its faster to create than the full SingleExpDefaultForm
723 735 """
724 736 def __init__(self, *args, **kwargs):
725 737 super(SingleExpDownloadAsIsForm, self).__init__(*args, **kwargs)
726 738 basename = getSelection('format_select', args, kwargs)
727 739 expID = int(getSelection('expID', args, kwargs))
728 740 formatChoices = getFormatChoices(basename, expID)
729 741
730 742 self.fields['format_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(attrs={"onChange":'changeFormat(this)'}),
731 743 choices=formatChoices,
732 744 required=False)
733 745
734 746
735 747
736 748
737 749 class IsprintChoiceField(django.forms.TypedMultipleChoiceField):
738 750 """IsprintChoiceField is subclass of TypedMultipleChoiceField
739 751 """
740 752 def __init__(self, *args, **kwargs):
741 753 """__init__ allows all the arguments of TypedMultipleChoiceField, plus extra
742 754 keyword arguments:
743 755 madWebObject madrigal.ui.web.MadrigalWeb object
744 756 """
745 757 self.isDerivedDict = kwargs.pop('isDerivedDict')
746 758 self.parmDescDict = kwargs.pop('parmDescDict')
747 759 try:
748 760 self.separateProlog = kwargs.pop('separateProlog')
749 761 except:
750 762 self.separateProlog = False
751 763
752 764 kwargs['widget'] = IsprintWidget(attrs={'isDerivedDict':self.isDerivedDict,
753 765 'parmDescDict':self.parmDescDict,
754 766 'separateProlog':self.separateProlog})
755 767 super(IsprintChoiceField, self).__init__(*args, **kwargs)
756 768 self.widget.set_parm_lists(self.isDerivedDict, self.parmDescDict, self.separateProlog)
757 769
758 770
759 771
760 772
761 773 class IsprintWidget(django.forms.CheckboxSelectMultiple):
762 774 """IsprintWidget is a subclass of CheckboxSelectMultiple with additional parameters passed in
763 775 to modify rendering
764 776 """
765 777 def __init__(self, *args, **kwargs):
766 778 """__init__ allows all the arguments of CheckboxSelectMultiple, plus extra
767 779 keyword arguments:
768 780 madWebObject madrigal.ui.web.MadrigalWeb object
769 781 """
770 782 super(IsprintWidget, self).__init__(*args, **kwargs)
771 783 self.renderer = django.forms.CheckboxSelectMultiple
772 784 self.template_name = 'madweb/parameter_multiple.html'
773 785
774 786
775 787 def set_parm_lists(self, isDerivedDict, parmDescDict, separateProlog=False):
776 788 """set_parm_lists sets class variables used by the html renderer
777 789
778 790 measParmList - parms in the file
779 791 derivedParmList - parms derivable
780 792 allParmList - above lists combined
781 793 separateProlog - if true, create separate div tags so prolog parms can be hidden or not.
782 794 Default is False, in which case no div tags are used
783 795 """
784 796 self.renderer.isDerivedDict = isDerivedDict
785 797 self.renderer.parmDescDict = parmDescDict
786 798 self.renderer.iterator = itertools.count()
787 799 self.renderer.separateProlog = separateProlog
788 800
789 801
790 802
791 803
792 804 class IsprintForm(django.forms.Form):
793 805 """IsprintForm is the form for the enhanced isprint page
794 806 """
795 807 def __init__(self, *args, **kwargs):
796 808
797 809 madFileObj = getSelection('madFileObj', args, kwargs)
798 810 type = getSelection('type', args, kwargs)
799 811 formatChoices = [('ascii', 'Space-delimited ascii')]
800 812 if type == 'download':
801 813 formatChoices.insert(0, ('netCDF4', 'netCDF4'))
802 814 formatChoices.insert(0, ('Hdf5', 'Hdf5'))
803 815 separateProlog = True
804 816 else:
805 817 separateProlog = False
806 818
807 819 madDB = getSelection('madDB', args, kwargs)
808 820 madParmObj = getSelection('madParmObj', args, kwargs)
809 821 derivedParmList = getSelection('derivedParmList', args, kwargs)
810 822 allParmList = getSelection('allParmList', args, kwargs)
811 823 allParmDescList = getSelection('allParmDescList', args, kwargs)
812 824 self.parmList = list(zip(allParmList, allParmDescList))
813 825 super(IsprintForm, self).__init__(*args, **kwargs)
814 826
815 827 madCatObj = madrigal.metadata.MadrigalParmCategory(madDB)
816 828
817 829 catList = madCatObj.getCategoryList()
818 830 catDict = madParmObj.getCategoryDict(allParmList)
819 831
820 832 choices = []
821 833 isDerivedDict = {}
822 834 parmDescDict = {}
823 835 for catDesc, catID in catList:
824 836 if catID not in list(catDict.keys()):
825 837 continue
826 838 theseParms = []
827 839 for parm in catDict[catID][1]:
828 840 theseParms.append((parm, parm))
829 841 if parm in derivedParmList:
830 842 isDerivedDict[parm] = True
831 843 else:
832 844 isDerivedDict[parm] = False
833 845 parmDescDict[parm] = madParmObj.getParmDescription(parm)
834 846 choices.append((catDesc, theseParms))
835 847
836 848 choices_with_null = [('None', 'None')] + choices
837 849
838 850 earliestTime = madFileObj.getEarliestTime()
839 851 latestTime = madFileObj.getLatestTime()
840 852 earliestDT = datetime.datetime(*earliestTime)
841 853 latestDT = datetime.datetime(*latestTime)
842 854 earliestStr = earliestDT.strftime('%Y-%m-%d %H:%M:%S')
843 855 latestStr = latestDT.strftime('%Y-%m-%d %H:%M:%S')
844 856
845 857 self.fields['fullFilename'] = django.forms.CharField(required=False, widget=django.forms.HiddenInput())
846 858 self.fields['type'] = django.forms.CharField(required=False, widget=django.forms.HiddenInput())
847 859
848 860 # format fields
849 861 self.fields['formats'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(attrs={"onChange":'changeFormat(this)'}),
850 862 choices=formatChoices, initial='ascii',
851 863 required=False, label='Select output format:')
852 864
853 865 self.fields['showHeaders'] = django.forms.BooleanField(required=False, label='Show headers:',
854 866 help_text="Select this to show a header line before each record")
855 867
856 868 self.fields['missing'] = django.forms.CharField(required=False,
857 869 label='Missing value string: ',
858 870 help_text='Modify this field to display something other than NaN for missing or assumed or known bad data.')
859 871
860 872 # form fields
861 873 self.fields['parameters'] = IsprintChoiceField(choices=choices,
862 874 required=False,
863 875 initial=['YEAR', 'MIN'],
864 876 isDerivedDict=isDerivedDict,
865 877 parmDescDict=parmDescDict,
866 878 separateProlog=separateProlog,
867 879 label = "")
868 880
869 881 # time selection
870 882 self.fields['start_date'] = django.forms.DateTimeField(input_formats=['%Y-%m-%dT%H:%M:%S'],
871 883 label='Start datetime',
872 884 help_text='Modify this field to remove all records before this start time. Initial start datetime is the time of the first record.',
873 885 widget=django.forms.DateTimeInput(format='%Y-%m-%dT%H:%M:%S'),
874 886 required=False)
875 887
876 888 self.fields['end_date'] = django.forms.DateTimeField(input_formats=['%Y-%m-%dT%H:%M:%S'],
877 889 label='End datetime',
878 890 help_text='Modify this field to remove all records after this end time. Initial end datetime is the time of the last record.',
879 891 widget=django.forms.DateTimeInput(format='%Y-%m-%dT%H:%M:%S'),
880 892 required=False)
881 893
882 894 self.fields['parm_1'] = django.forms.ChoiceField(required=False,
883 895 choices=choices_with_null)
884 896 self.fields['parm_1_lower'] = django.forms.CharField(required=False, initial='')
885 897 self.fields['parm_1_upper'] = django.forms.CharField(required=False, initial='')
886 898
887 899 self.fields['parm_2'] = django.forms.ChoiceField(required=False,
888 900 choices=choices_with_null)
889 901 self.fields['parm_2_lower'] = django.forms.CharField(required=False, initial='')
890 902 self.fields['parm_2_upper'] = django.forms.CharField(required=False, initial='')
891 903
892 904 self.fields['parm_3'] = django.forms.ChoiceField(required=False,
893 905 choices=choices_with_null)
894 906 self.fields['parm_3_lower'] = django.forms.CharField(required=False, initial='')
895 907 self.fields['parm_3_upper'] = django.forms.CharField(required=False, initial='')
896 908
897 909 # add optional fields
898 910 if 'GDALT' in allParmList:
899 911 min_alt_value = getSelection('min_alt', args, kwargs)
900 912 max_alt_value = getSelection('max_alt', args, kwargs)
901 913 if min_alt_value != max_alt_value:
902 914 self.fields['min_alt'] = django.forms.CharField(required=False,
903 915 label='Min altitude:',
904 916 help_text='Modify this field to remove all data with altitudes below this level.')
905 917 self.fields['max_alt'] = django.forms.CharField(required=False,
906 918 label='Max altitude:',
907 919 help_text='Modify this field to remove all data with altitudes above this level.')
908 920
909 921 if 'AZM' in allParmList:
910 922 self.fields['min_az'] = django.forms.CharField(required=False,
911 923 label='Min azimuth:',
912 924 help_text='Modify this field to remove all azimuths (-180 to 180) below this value. You can also have two separate azimuth ranges by using the Azimuth 2 fields.')
913 925 self.fields['max_az'] = django.forms.CharField(required=False,
914 926 label='Max azimuth:',
915 927 help_text='Modify this field to remove all azimuths (-180 to 180) above this value. You can also have two separate azimuth ranges by using the Azimuth 2 fields.')
916 928 self.fields['min_az2'] = django.forms.CharField(required=False,
917 929 label='Min azimuth 2:',
918 930 help_text='Modify this field to have a second allowed azimuth range. This would set the lower limit of the second range.')
919 931 self.fields['max_az2'] = django.forms.CharField(required=False,
920 932 label='Max azimuth 2:',
921 933 help_text='Modify this field to have a second allowed azimuth range. This would set the upper limit of the second range.')
922 934
923 935 if 'ELM' in allParmList:
924 936 self.fields['min_el'] = django.forms.CharField(required=False,
925 937 label='Min elevation:',
926 938 help_text='Modify this field to remove all elevations (0 to 90) below this value. You can also have two separate elevations ranges by using the Elevations 2 fields.')
927 939 self.fields['max_el'] = django.forms.CharField(required=False,
928 940 label='Max elevation:',
929 941 help_text='Modify this field to remove all elevations (0 to 90) above this value. You can also have two separate elevations ranges by using the Elevations 2 fields.')
930 942 self.fields['min_el2'] = django.forms.CharField(required=False,
931 943 label='Min elevation 2:',
932 944 help_text='Modify this field to have a second allowed elevation range. This would set the lower limit of the second range.')
933 945 self.fields['max_el2'] = django.forms.CharField(required=False,
934 946 label='Max elevation 2:',
935 947 help_text='Modify this field to have a second allowed elevation range. This would set the upper limit of the second range.')
936 948
937 949 if 'PL' in allParmList:
938 950 min_pl_value = getSelection('min_pl', args, kwargs)
939 951 max_pl_value = getSelection('max_pl', args, kwargs)
940 952 self.fields['min_pl'] = django.forms.CharField(required=False,
941 953 label='Min pulse len (microsec): ',
942 954 help_text='Modify this field to remove all pulse lengths in microsecs below this value.')
943 955 self.fields['max_pl'] = django.forms.CharField(required=False,
944 956 label='Max pulse len (microsec): ',
945 957 help_text='Modify this field to remove all pulse lengths in microsecs above this value.')
946 958
947 959
948 960 def clean_fullFilename(self):
949 961 fullFilename = self.cleaned_data['fullFilename']
950 962 # make sure the file exists
951 963 if not os.access(fullFilename, os.R_OK):
952 964 raise django.forms.ValidationError('Invalid filename: %(value)s cannot be opened',
953 965 code='io_error',
954 966 params={'value': fullFilename})
955 967
956 968 return(fullFilename)
957 969
958 970
959 971 def clean_formats(self):
960 972 formats = self.cleaned_data['formats']
961 973 # make sure the format valid
962 974 if formats not in ('Hdf5', 'netCDF4', 'ascii'):
963 975 raise django.forms.ValidationError('Invalid format: %(value)s not legal format',
964 976 code='invalid',
965 977 params={'value': formats})
966 978
967 979 return(formats)
968 980
969 981
970 982 def clean_min_alt(self):
971 983 min_alt = self.cleaned_data['min_alt']
972 984 if len(min_alt) != 0:
973 985 try:
974 986 min_alt_value = float(min_alt)
975 987 except:
976 988 raise django.forms.ValidationError('Invalid minimum altitude: %(value)s cannot be converted to a float',
977 989 code='invalid',
978 990 params={'value': min_alt})
979 991 if min_alt_value < 0.0:
980 992 raise django.forms.ValidationError('Invalid minimum altitude: %(value)s cannot be less than 0.0 kilometers',
981 993 code='invalid',
982 994 params={'value': min_alt})
983 995 return(min_alt)
984 996
985 997 def clean_max_alt(self):
986 998 max_alt = self.cleaned_data['max_alt']
987 999 if len(max_alt) != 0:
988 1000 try:
989 1001 max_alt_value = float(max_alt)
990 1002 except:
991 1003 raise django.forms.ValidationError('Invalid maximum altitude: %(value)s cannot be converted to a float',
992 1004 code='invalid',
993 1005 params={'value': max_alt})
994 1006 if max_alt_value < 0.0:
995 1007 raise django.forms.ValidationError('Invalid maximum altitude: %(value)s cannot be less than 0.0 kilometers',
996 1008 code='invalid',
997 1009 params={'value': max_alt})
998 1010 return(max_alt)
999 1011
1000 1012
1001 1013 def clean_min_az(self):
1002 1014 min_az = self.cleaned_data['min_az']
1003 1015 if len(min_az) != 0:
1004 1016 try:
1005 1017 min_az_value = float(min_az)
1006 1018 except:
1007 1019 raise django.forms.ValidationError('Invalid minimum azimuth: %(value)s cannot be converted to a float',
1008 1020 code='invalid',
1009 1021 params={'value': min_az})
1010 1022 if min_az_value < -180.0:
1011 1023 raise django.forms.ValidationError('Invalid minimum azimuth: %(value)s cannot be less than -180 degrees',
1012 1024 code='invalid',
1013 1025 params={'value': min_az})
1014 1026 if min_az_value > 180.0:
1015 1027 raise django.forms.ValidationError('Invalid minimum azimuth: %(value)s cannot be more than 180 degrees',
1016 1028 code='invalid',
1017 1029 params={'value': min_az})
1018 1030 return(min_az)
1019 1031
1020 1032
1021 1033 def clean_max_az(self):
1022 1034 max_az = self.cleaned_data['max_az']
1023 1035 if len(max_az) != 0:
1024 1036 try:
1025 1037 max_az_value = float(max_az)
1026 1038 except:
1027 1039 raise django.forms.ValidationError('Invalid maximum azimuth: %(value)s cannot be converted to a float',
1028 1040 code='invalid',
1029 1041 params={'value': max_az})
1030 1042 if max_az_value < -180.0:
1031 1043 raise django.forms.ValidationError('Invalid maximum azimuth: %(value)s cannot be less than -180 degrees',
1032 1044 code='invalid',
1033 1045 params={'value': max_az})
1034 1046 if max_az_value > 180.0:
1035 1047 raise django.forms.ValidationError('Invalid maximum azimuth: %(value)s cannot be more than 180 degrees',
1036 1048 code='invalid',
1037 1049 params={'value': max_az})
1038 1050 return(max_az)
1039 1051
1040 1052
1041 1053 def clean_min_el(self):
1042 1054 min_el = self.cleaned_data['min_el']
1043 1055 if len(min_el) != 0:
1044 1056 try:
1045 1057 min_el_value = float(min_el)
1046 1058 except:
1047 1059 raise django.forms.ValidationError('Invalid minimum elevation: %(value)s cannot be converted to a float',
1048 1060 code='invalid',
1049 1061 params={'value': min_el})
1050 1062 if min_el_value < 0.0:
1051 1063 raise django.forms.ValidationError('Invalid minimum elevation: %(value)s cannot be less than 0 degrees',
1052 1064 code='invalid',
1053 1065 params={'value': min_el})
1054 1066 if min_el_value > 90.0:
1055 1067 raise django.forms.ValidationError('Invalid minimum elevation: %(value)s cannot be more than 90 degrees',
1056 1068 code='invalid',
1057 1069 params={'value': min_el})
1058 1070 return(min_el)
1059 1071
1060 1072
1061 1073 def clean_max_el(self):
1062 1074 max_el = self.cleaned_data['max_el']
1063 1075 if len(max_el) != 0:
1064 1076 try:
1065 1077 max_el_value = float(max_el)
1066 1078 except:
1067 1079 raise django.forms.ValidationError('Invalid maximum elevation: %(value)s cannot be converted to a float',
1068 1080 code='invalid',
1069 1081 params={'value': max_el})
1070 1082 if max_el_value < 0.0:
1071 1083 raise django.forms.ValidationError('Invalid maximum elevation: %(value)s cannot be less than 0 degrees',
1072 1084 code='invalid',
1073 1085 params={'value': max_el})
1074 1086 if max_el_value > 90.0:
1075 1087 raise django.forms.ValidationError('Invalid maximum elevation: %(value)s cannot be more than 90 degrees',
1076 1088 code='invalid',
1077 1089 params={'value': max_el})
1078 1090 return(max_el)
1079 1091
1080 1092
1081 1093 def clean_min_az2(self):
1082 1094 min_az2 = self.cleaned_data['min_az2']
1083 1095 if len(min_az2) != 0:
1084 1096 try:
1085 1097 min_az2_value = float(min_az2)
1086 1098 except:
1087 1099 raise django.forms.ValidationError('Invalid minimum azimuth 2: %(value)s cannot be converted to a float',
1088 1100 code='invalid',
1089 1101 params={'value': min_az2})
1090 1102 if min_az2_value < -180.0:
1091 1103 raise django.forms.ValidationError('Invalid minimum azimuth 2: %(value)s cannot be less than -180 degrees',
1092 1104 code='invalid',
1093 1105 params={'value': min_az2})
1094 1106 if min_az2_value > 180.0:
1095 1107 raise django.forms.ValidationError('Invalid minimum azimuth 2: %(value)s cannot be more than 180 degrees',
1096 1108 code='invalid',
1097 1109 params={'value': min_az2})
1098 1110 return(min_az2)
1099 1111
1100 1112
1101 1113 def clean_max_az2(self):
1102 1114 max_az2 = self.cleaned_data['max_az2']
1103 1115 if len(max_az2) != 0:
1104 1116 try:
1105 1117 max_az2_value = float(max_az2)
1106 1118 except:
1107 1119 raise django.forms.ValidationError('Invalid maximum azimuth 2: %(value)s cannot be converted to a float',
1108 1120 code='invalid',
1109 1121 params={'value': max_az2})
1110 1122 if max_az2_value < -180.0:
1111 1123 raise django.forms.ValidationError('Invalid maximum azimuth 2: %(value)s cannot be less than -180 degrees',
1112 1124 code='invalid',
1113 1125 params={'value': max_az2})
1114 1126 if max_az2_value > 180.0:
1115 1127 raise django.forms.ValidationError('Invalid maximum azimuth 2: %(value)s cannot be more than 180 degrees',
1116 1128 code='invalid',
1117 1129 params={'value': max_az2})
1118 1130 return(max_az2)
1119 1131
1120 1132
1121 1133 def clean_min_el2(self):
1122 1134 min_el2 = self.cleaned_data['min_el2']
1123 1135 if len(min_el2) != 0:
1124 1136 try:
1125 1137 min_el2_value = float(min_el2)
1126 1138 except:
1127 1139 raise django.forms.ValidationError('Invalid minimum elevation 2: %(value)s cannot be converted to a float',
1128 1140 code='invalid',
1129 1141 params={'value': min_el2})
1130 1142 if min_el2_value < 0.0:
1131 1143 raise django.forms.ValidationError('Invalid minimum elevation 2: %(value)s cannot be less than 0 degrees',
1132 1144 code='invalid',
1133 1145 params={'value': min_el2})
1134 1146 if min_el2_value > 90.0:
1135 1147 raise django.forms.ValidationError('Invalid minimum elevation 2: %(value)s cannot be more than 90 degrees',
1136 1148 code='invalid',
1137 1149 params={'value': min_el2})
1138 1150 return(min_el2)
1139 1151
1140 1152
1141 1153 def clean_max_el2(self):
1142 1154 max_el2 = self.cleaned_data['max_el2']
1143 1155 if len(max_el2) != 0:
1144 1156 try:
1145 1157 max_el2_value = float(max_el2)
1146 1158 except:
1147 1159 raise django.forms.ValidationError('Invalid maximum elevation 2: %(value)s cannot be converted to a float',
1148 1160 code='invalid',
1149 1161 params={'value': max_el2})
1150 1162 if max_el2_value < 0.0:
1151 1163 raise django.forms.ValidationError('Invalid maximum elevation 2: %(value)s cannot be less than 0 degrees',
1152 1164 code='invalid',
1153 1165 params={'value': max_el2})
1154 1166 if max_el2_value > 90.0:
1155 1167 raise django.forms.ValidationError('Invalid maximum elevation 2: %(value)s cannot be more than 90 degrees',
1156 1168 code='invalid',
1157 1169 params={'value': max_el2})
1158 1170 return(max_el2)
1159 1171
1160 1172
1161 1173 def clean_min_pl(self):
1162 1174 min_pl = self.cleaned_data['min_pl']
1163 1175 if len(min_pl) != 0:
1164 1176 try:
1165 1177 min_pl_value = float(min_pl)
1166 1178 except:
1167 1179 raise django.forms.ValidationError('Invalid lower limit for pulse length: %(value)s cannot be converted to a float',
1168 1180 code='invalid',
1169 1181 params={'value': min_pl})
1170 1182 return(min_pl)
1171 1183
1172 1184
1173 1185 def clean_max_pl(self):
1174 1186 max_pl = self.cleaned_data['max_pl']
1175 1187 if len(max_pl) != 0:
1176 1188 try:
1177 1189 max_pl_value = float(max_pl)
1178 1190 except:
1179 1191 raise django.forms.ValidationError('Invalid upper limit for pulse length: %(value)s cannot be converted to a float',
1180 1192 code='invalid',
1181 1193 params={'value': max_pl})
1182 1194 return(max_pl)
1183 1195
1184 1196
1185 1197 def clean_parm_1_lower(self):
1186 1198 parm_1_lower = self.cleaned_data['parm_1_lower']
1187 1199 if len(parm_1_lower) != 0:
1188 1200 try:
1189 1201 parm_1_lower_value = float(parm_1_lower)
1190 1202 except:
1191 1203 raise django.forms.ValidationError('Invalid lower limit for parm 1: %(value)s cannot be converted to a float',
1192 1204 code='invalid',
1193 1205 params={'value': parm_1_lower})
1194 1206 return(parm_1_lower)
1195 1207
1196 1208
1197 1209 def clean_parm_1_upper(self):
1198 1210 parm_1_upper = self.cleaned_data['parm_1_upper']
1199 1211 if len(parm_1_upper) != 0:
1200 1212 try:
1201 1213 parm_1_upper_value = float(parm_1_upper)
1202 1214 except:
1203 1215 raise django.forms.ValidationError('Invalid upper limit for parm 1: %(value)s cannot be converted to a float',
1204 1216 code='invalid',
1205 1217 params={'value': parm_1_upper})
1206 1218 return(parm_1_upper)
1207 1219
1208 1220
1209 1221 def clean_parm_2_lower(self):
1210 1222 parm_2_lower = self.cleaned_data['parm_2_lower']
1211 1223 if len(parm_2_lower) != 0:
1212 1224 try:
1213 1225 parm_2_lower_value = float(parm_2_lower)
1214 1226 except:
1215 1227 raise django.forms.ValidationError('Invalid lower limit for parm 2: %(value)s cannot be converted to a float',
1216 1228 code='invalid',
1217 1229 params={'value': parm_2_lower})
1218 1230 return(parm_2_lower)
1219 1231
1220 1232
1221 1233 def clean_parm_2_upper(self):
1222 1234 parm_2_upper = self.cleaned_data['parm_2_upper']
1223 1235 if len(parm_2_upper) != 0:
1224 1236 try:
1225 1237 parm_2_upper_value = float(parm_2_upper)
1226 1238 except:
1227 1239 raise django.forms.ValidationError('Invalid upper limit for parm 2: %(value)s cannot be converted to a float',
1228 1240 code='invalid',
1229 1241 params={'value': parm_2_upper})
1230 1242 return(parm_2_upper)
1231 1243
1232 1244
1233 1245 def clean_parm_3_lower(self):
1234 1246 parm_3_lower = self.cleaned_data['parm_3_lower']
1235 1247 if len(parm_3_lower) != 0:
1236 1248 try:
1237 1249 parm_3_lower_value = float(parm_3_lower)
1238 1250 except:
1239 1251 raise django.forms.ValidationError('Invalid lower limit for parm 3: %(value)s cannot be converted to a float',
1240 1252 code='invalid',
1241 1253 params={'value': parm_3_lower})
1242 1254 return(parm_3_lower)
1243 1255
1244 1256
1245 1257 def clean_parm_3_upper(self):
1246 1258 parm_3_upper = self.cleaned_data['parm_3_upper']
1247 1259 if len(parm_3_upper) != 0:
1248 1260 try:
1249 1261 parm_3_upper_value = float(parm_3_upper)
1250 1262 except:
1251 1263 raise django.forms.ValidationError('Invalid upper limit for parm 3: %(value)s cannot be converted to a float',
1252 1264 code='invalid',
1253 1265 params={'value': parm_3_upper})
1254 1266 return(parm_3_upper)
1255 1267
1256 1268
1257 1269
1258 1270
1259 1271 def clean(self):
1260 1272 """clean in the Django method to validate things in a form that require looking at multiple fields
1261 1273 """
1262 1274 # rule 1 - start_date < end_date
1263 1275 if self.cleaned_data['start_date'] > self.cleaned_data['end_date']:
1264 1276 raise django.forms.ValidationError('Error - start datetime greater than end datetime.')
1265 1277
1266 1278 # rule 2 - min_alt <= max_alt
1267 1279 try:
1268 1280 min_alt = float(self.cleaned_data['min_alt'])
1269 1281 max_alt = float(self.cleaned_data['max_alt'])
1270 1282 except:
1271 1283 min_alt = 0.0
1272 1284 max_alt = 1.0
1273 1285 if min_alt > max_alt:
1274 1286 raise django.forms.ValidationError('Error - Minimum altitude greater than maximum altitude.')
1275 1287
1276 1288 # rule 3 - min_az <= max_az
1277 1289 try:
1278 1290 min_az = float(self.cleaned_data['min_az'])
1279 1291 max_az = float(self.cleaned_data['max_az'])
1280 1292 except:
1281 1293 min_az = 0.0
1282 1294 max_az = 1.0
1283 1295 if min_az > max_az:
1284 1296 raise django.forms.ValidationError('Error - Minimum azimuth greater than maximum azimuth.')
1285 1297
1286 1298 # rule 4 - min_el <= max_el
1287 1299 try:
1288 1300 min_el = float(self.cleaned_data['min_el'])
1289 1301 max_el = float(self.cleaned_data['max_el'])
1290 1302 except:
1291 1303 min_el = 0.0
1292 1304 max_el = 1.0
1293 1305 if min_el > max_el:
1294 1306 raise django.forms.ValidationError('Error - Minimum elevation greater than maximum elevation.')
1295 1307
1296 1308 # rule 5 - min_az2 <= max_az2
1297 1309 try:
1298 1310 min_az2 = float(self.cleaned_data['min_az2'])
1299 1311 max_az2 = float(self.cleaned_data['max_az2'])
1300 1312 except:
1301 1313 min_az2 = 0.0
1302 1314 max_az2 = 1.0
1303 1315 if min_az2 > max_az2:
1304 1316 raise django.forms.ValidationError('Error - Minimum azimuth 2 greater than maximum azimuth 2.')
1305 1317
1306 1318 # rule 6 - min_el2 <= max_el2
1307 1319 try:
1308 1320 min_el2 = float(self.cleaned_data['min_el2'])
1309 1321 max_el2 = float(self.cleaned_data['max_el2'])
1310 1322 except:
1311 1323 min_el2 = 0.0
1312 1324 max_el2 = 1.0
1313 1325 if min_el2 > max_el2:
1314 1326 raise django.forms.ValidationError('Error - Minimum elevation 2 greater than maximum elevation 2.')
1315 1327
1316 1328 # rule 7 - min_pl <= max_pl
1317 1329 try:
1318 1330 min_pl = float(self.cleaned_data['min_pl'])
1319 1331 max_pl = float(self.cleaned_data['max_pl'])
1320 1332 except:
1321 1333 min_pl = 0.0
1322 1334 max_pl = 1.0
1323 1335 if min_pl > max_pl:
1324 1336 raise django.forms.ValidationError('Error - Minimum pulse length greater than maximum pulse length.')
1325 1337
1326 1338 # rule 8 - parm_1_lower <= parm_1_upper
1327 1339 try:
1328 1340 parm_1_lower = float(self.cleaned_data['parm_1_lower'])
1329 1341 parm_1_upper = float(self.cleaned_data['parm_1_upper'])
1330 1342 except:
1331 1343 parm_1_lower = 0.0
1332 1344 parm_1_upper = 1.0
1333 1345 if parm_1_lower > parm_1_upper:
1334 1346 raise django.forms.ValidationError('Error - parm 1 lower limit greater than upper limit.')
1335 1347
1336 1348 # rule 9 - parm_2_lower <= parm_2_upper
1337 1349 try:
1338 1350 parm_2_lower = float(self.cleaned_data['parm_2_lower'])
1339 1351 parm_2_upper = float(self.cleaned_data['parm_2_upper'])
1340 1352 except:
1341 1353 parm_2_lower = 0.0
1342 1354 parm_2_upper = 1.0
1343 1355 if parm_2_lower > parm_2_upper:
1344 1356 raise django.forms.ValidationError('Error - parm 2 lower limit greater than upper limit.')
1345 1357
1346 1358 # rule 10 - parm_3_lower <= parm_3_upper
1347 1359 try:
1348 1360 parm_3_lower = float(self.cleaned_data['parm_3_lower'])
1349 1361 parm_3_upper = float(self.cleaned_data['parm_3_upper'])
1350 1362 except:
1351 1363 parm_3_lower = 0.0
1352 1364 parm_3_upper = 1.0
1353 1365 if parm_3_lower > parm_3_upper:
1354 1366 raise django.forms.ValidationError('Error - parm 3 lower limit greater than upper limit.')
1355 1367
1356 1368
1357 1369 class ListExpForm(django.forms.Form):
1358 1370 """ListExpForm is a Form class for the default fields in the List Experiment interface
1359 1371 """
1360 1372 def __init__(self, *args, **kwargs):
1361 1373 super(ListExpForm, self).__init__(*args, **kwargs)
1362 1374 madDB = madrigal.metadata.MadrigalDB()
1363 1375 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1364 1376 isGlobal = True # default load
1365 1377 now = datetime.datetime.now()
1366 1378 endDateTime = datetime.datetime(now.year, 12, 31, 23, 59, 59)
1367 1379 self.fields['isGlobal'] = django.forms.BooleanField(widget = django.forms.CheckboxInput(attrs={"onChange":'changeGlobal(this.form)'}),
1368 1380 required=False, label='Use all Madrigal sites: ',
1369 1381 initial=isGlobal)
1370 1382
1371 1383
1372 1384 categoriesSelection = '0'
1373 1385 self.fields['categories'] = django.forms.MultipleChoiceField(widget=django.forms.SelectMultiple(attrs={"onChange":"updateInstruments(this.form)"}),
1374 1386 choices=getCategoryList(args, kwargs, madInstData, True),
1375 1387 initial='0',
1376 1388 label='Choose instrument category(s):')
1377 1389
1378 1390 self.fields['instruments'] = django.forms.MultipleChoiceField(widget = django.forms.SelectMultiple(),
1379 1391 choices=getInstrumentList(args, kwargs, madInstData, 'All instruments', local=False, includeYears=True),
1380 1392 initial='0', label='Choose instrument(s)')
1381 1393
1382 1394 self.fields['showDefault'] = django.forms.BooleanField(widget = django.forms.CheckboxInput(),
1383 1395 label='Show only default files: ',
1384 1396 initial=True)
1385 1397
1386 1398 # time selection
1387 1399 self.fields['start_date'] = django.forms.SplitDateTimeField(input_date_formats=['%Y-%m-%d'], input_time_formats=['%H:%M:%S'],
1388 1400 label='Start date',
1389 1401 help_text='Modify this field to select experiments after this start time.',
1390 1402 initial=datetime.datetime(1950,1,1))
1391 1403
1392 1404 self.fields['end_date'] = django.forms.SplitDateTimeField(input_date_formats=['%Y-%m-%d'], input_time_formats=['%H:%M:%S'],
1393 1405 label='End date',
1394 1406 help_text='Modify this field to select experiments before this end time.',
1395 1407 initial=endDateTime)
1396 1408
1397 1409
1398 1410
1399 1411 # attributes to support javascript
1400 1412 local_categories = madInstData.getCategories(True)
1401 1413 global_categories = madInstData.getCategories(False)
1402 1414 local_category_ids = [cat[0] for cat in local_categories]
1403 1415 self.categories = [] # each item a tuple of (category description, category id, global only js bool)
1404 1416 self.instruments = [] # each item a tiple of (instrument desc, category id, kinst, local start year, local end year, global sy, global ey)
1405 1417 for id, desc in global_categories:
1406 1418 if id in local_category_ids:
1407 1419 localBool = 'false'
1408 1420 else:
1409 1421 localBool = 'true'
1410 1422 self.categories.append((desc, id, localBool))
1411 1423 for kinst, instDesc, siteId in madInstData.getInstruments(id):
1412 1424 if siteId == madDB.getSiteID():
1413 1425 localInst = True
1414 1426 else:
1415 1427 localInst = False
1416 1428 yearList = madInstData.getInstrumentYears(kinst)
1417 1429 if localInst:
1418 1430 self.instruments.append((instDesc, id, kinst, yearList[0], yearList[-1], yearList[0], yearList[-1]))
1419 1431 else:
1420 1432 self.instruments.append((instDesc, id, kinst, 0, 0, yearList[0], yearList[-1]))
1421 1433
1422 1434
1423 1435 def clean(self):
1424 1436 """clean in the Django method to validate things in a form that require looking at multiple fields
1425 1437 """
1426 1438 # rule 1 - start_date < end_date
1427 1439 if self.cleaned_data['start_date'] > self.cleaned_data['end_date']:
1428 1440 raise django.forms.ValidationError('Error - start datetime greater than end datetime.')
1429 1441
1430 1442
1431 1443 class DownloadAsIsScriptForm(django.forms.Form):
1432 1444 """DownloadAsIsScriptForm is a Form class for the default fields in the download files as is script generator interface
1433 1445 """
1434 1446 def __init__(self, *args, **kwargs):
1435 1447 super(DownloadAsIsScriptForm, self).__init__(*args, **kwargs)
1436 1448 madDB = madrigal.metadata.MadrigalDB()
1437 1449 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1438 1450 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1439 1451 madInstKindatObj = madrigal.metadata.MadrigalInstrumentKindats(madDB)
1440 1452 now = datetime.datetime.now()
1441 1453 endDateTime = datetime.datetime(now.year, 12, 31, 23, 59, 59)
1442 1454 kwargs['isGlobal'] = '0'
1443 1455 formatChoices = (('hdf5', 'Hdf5'), ('ascii', 'Space-delimited ascii'), ('netCDF4', 'netCDF4'))
1444 1456 languageChoices = (('python', 'python'), ('Matlab', 'Matlab'), ('IDL', 'IDL'))
1445 1457
1446 1458 categoriesSelection = '0'
1447 1459 self.fields['categories'] = django.forms.ChoiceField(widget=django.forms.Select(attrs={"onChange":"updateInstruments(this.form)"}),
1448 1460 choices=getCategoryList(args, kwargs, madInstData),
1449 1461 initial='0',
1450 1462 label='Choose an instrument category if desired:')
1451 1463
1452 1464 self.fields['instruments'] = django.forms.ChoiceField(widget=django.forms.Select(attrs={"onChange":"updateKindats(this.form)"}),
1453 1465 choices=getInstrumentList(args, kwargs, madInstData, local=True, includeYears=True),
1454 1466 initial='0', label='Choose one instrument')
1455 1467
1456 1468 # time selection
1457 1469 self.fields['start_date'] = django.forms.DateField(input_formats=['%Y-%m-%d'],
1458 1470 label='Start date',
1459 1471 help_text='Modify this field to select experiments after this start time.',
1460 1472 initial=datetime.datetime(1950,1,1))
1461 1473
1462 1474
1463 1475 self.fields['end_date'] = django.forms.DateField(input_formats=['%Y-%m-%d'],
1464 1476 label='End date',
1465 1477 help_text='Modify this field to select experiments before this end time.',
1466 1478 initial=endDateTime)
1467 1479
1468 1480 self.fields['format_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(),
1469 1481 choices=formatChoices,
1470 1482 initial=formatChoices[0][0],
1471 1483 label='File format to download:')
1472 1484
1473 1485 self.fields['language_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(),
1474 1486 choices=languageChoices,
1475 1487 initial=languageChoices[0][0],
1476 1488 label='Choose scripting language:')
1477 1489
1478 1490 choices=(('0', 'Select an instrument first to see list'),)
1479 1491 if len(args) > 0:
1480 1492 if 'kindat_select' in args[0]:
1481 1493 choices = [(kindat, kindat) for kindat in args[0].getlist('kindat_select')]
1482 1494 self.fields['kindat_select'] = django.forms.MultipleChoiceField(choices=choices,
1483 1495 initial='0',
1484 1496 label='Choose one or more kinds of data:',
1485 1497 required=False)
1486 1498 self.fields['kindat_select'].widget.attrs['style']="max-width:100%;"
1487 1499
1488 1500 self.fields['expName'] = django.forms.CharField(max_length=256, required=False)
1489 1501
1490 1502 self.fields['fileDesc'] = django.forms.CharField(max_length=256, required=False)
1491 1503
1492 1504
1493 1505
1494 1506 # attributes to support javascript
1495 1507 local_categories = madInstData.getCategories(True)
1496 1508 local_category_ids = [cat[0] for cat in local_categories]
1497 1509 self.categories = [] # each item a tuple of (category description, category id, global only js bool)
1498 1510 self.instruments = [] # each item a tiple of (instrument desc, category id, kinst, local start year, local end year)
1499 1511 self.kindats = [] # each item is a tuple of (kindat, kindatDesc, kinst)
1500 1512 for id, desc in local_categories:
1501 1513 self.categories.append((desc, id))
1502 1514 for kinst, instDesc, siteId in madInstData.getInstruments(id):
1503 1515 if siteId != madDB.getSiteID():
1504 1516 continue
1505 1517 yearList = madInstData.getInstrumentYears(kinst)
1506 1518 self.instruments.append((instDesc, id, kinst, yearList[0], yearList[-1]))
1507 1519 kindatList = madInstKindatObj.getKindatListForInstruments([kinst])
1508 1520 for kindat in kindatList:
1509 1521 self.kindats.append((kindat, madKindatObj.getKindatDescription(kindat, kinst),
1510 1522 kinst))
1511 1523
1512 1524
1513 1525 def clean(self):
1514 1526 """clean is the Django method to validate things in a form that require looking at multiple fields
1515 1527 """
1516 1528 # rule 1 - start_date < end_date
1517 1529 if self.cleaned_data['start_date'] > self.cleaned_data['end_date']:
1518 1530 raise django.forms.ValidationError('Error - start datetime greater than end datetime.')
1519 1531
1520 1532
1521 1533 class DownloadAdvancedScriptForm(django.forms.Form):
1522 1534 """DownloadAdvancedScriptForm is a Form class for the default fields in the download advanced script generator interface
1523 1535 """
1524 1536 def __init__(self, *args, **kwargs):
1525 1537 super(DownloadAdvancedScriptForm, self).__init__(*args, **kwargs)
1526 1538 madDB = madrigal.metadata.MadrigalDB()
1527 1539 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1528 1540 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1529 1541 madInstKindatObj = madrigal.metadata.MadrigalInstrumentKindats(madDB)
1530 1542 now = datetime.datetime.now()
1531 1543 endDateTime = datetime.datetime(now.year, 12, 31, 23, 59, 59)
1532 1544 kwargs['isGlobal'] = '0'
1533 1545 formatChoices = (('hdf5', 'Hdf5'), ('ascii', 'Space-delimited ascii'), ('netCDF4', 'netCDF4'))
1534 1546 directoryChoices = (('Directory', 'Directory'), ('File', 'File'))
1535 1547 languageChoices = (('python', 'python'), ('Matlab', 'Matlab'), ('IDL', 'IDL'))
1536 1548
1537 1549 categoriesSelection = '0'
1538 1550 self.fields['categories'] = django.forms.ChoiceField(widget=django.forms.Select(attrs={"onChange":"updateInstruments(this.form)"}),
1539 1551 choices=getCategoryList(args, kwargs, madInstData),
1540 1552 initial='0',
1541 1553 label='Choose an instrument category if desired:')
1542 1554
1543 1555 self.fields['instruments'] = django.forms.ChoiceField(widget=django.forms.Select(attrs={"onChange":"updateParmsKindats(this.form)"}),
1544 1556 choices=getInstrumentList(args, kwargs, madInstData, local=True, includeYears=True),
1545 1557 initial='0', label='Choose one instrument')
1546 1558
1547 1559 # time selection
1548 1560 self.fields['start_date'] = django.forms.DateField(input_formats=['%Y-%m-%d'],
1549 1561 label='Start date',
1550 1562 help_text='Modify this field to select experiments after this start time.',
1551 1563 initial=datetime.datetime(1950,1,1))
1552 1564
1553 1565 self.fields['end_date'] = django.forms.DateField(input_formats=['%Y-%m-%d'],
1554 1566 label='End date',
1555 1567 help_text='Modify this field to select experiments before this end time.',
1556 1568 initial=endDateTime)
1557 1569
1558 1570 self.fields['format_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(attrs={"onChange":'changeFormat(this)'}),
1559 1571 choices=formatChoices,
1560 1572 initial=formatChoices[0][0],
1561 1573 label='File format to download:')
1562 1574
1563 1575 self.fields['directory_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(),
1564 1576 choices=directoryChoices,
1565 1577 initial=directoryChoices[0][0],
1566 1578 label='If ascii, download result to:')
1567 1579
1568 1580 self.fields['language_select'] = django.forms.ChoiceField(widget = HorizontalRadioSelect(),
1569 1581 choices=languageChoices,
1570 1582 initial=languageChoices[0][0],
1571 1583 label='Choose scripting language:')
1572 1584
1573 1585 choices=(('0', 'Select an instrument first to see list'),)
1574 1586 if len(args) > 0:
1575 1587 if 'kindat_select' in args[0]:
1576 1588 choices = [(kindat, kindat) for kindat in args[0].getlist('kindat_select')]
1577 1589 self.fields['kindat_select'] = django.forms.MultipleChoiceField(choices=choices,
1578 1590 initial='0',
1579 1591 label='Choose one or more kinds of data:',
1580 1592 required=False)
1581 1593 self.fields['kindat_select'].widget.attrs['style']="max-width:100%;"
1582 1594
1583 1595 self.fields['expName'] = django.forms.CharField(max_length=256, required=False)
1584 1596
1585 1597 self.fields['fileDesc'] = django.forms.CharField(max_length=256, required=False)
1586 1598
1587 1599 self.fields['seasonalStartDay'] = django.forms.IntegerField(min_value=1, max_value=31, initial=1)
1588 1600 self.fields['seasonalStartMonth'] = django.forms.IntegerField(min_value=1, max_value=12, initial=1)
1589 1601 self.fields['seasonalEndDay'] = django.forms.IntegerField(min_value=1, max_value=31, initial=31)
1590 1602 self.fields['seasonalEndMonth'] = django.forms.IntegerField(min_value=1, max_value=12, initial=12)
1591 1603
1592 1604
1593 1605 # attributes to support javascript
1594 1606 local_categories = madInstData.getCategories(True)
1595 1607 local_category_ids = [cat[0] for cat in local_categories]
1596 1608 self.categories = [] # each item a tuple of (category description, category id, global only js bool)
1597 1609 self.instruments = [] # each item a tiple of (instrument desc, category id, kinst, local start year, local end year)
1598 1610 self.kindats = [] # each item is a tuple of (kindat, kindatDesc, kinst)
1599 1611 for id, desc in local_categories:
1600 1612 self.categories.append((desc, id))
1601 1613 for kinst, instDesc, siteId in madInstData.getInstruments(id):
1602 1614 if siteId != madDB.getSiteID():
1603 1615 continue
1604 1616 yearList = madInstData.getInstrumentYears(kinst)
1605 1617 self.instruments.append((instDesc, id, kinst, yearList[0], yearList[-1]))
1606 1618 kindatList = madInstKindatObj.getKindatListForInstruments([kinst])
1607 1619 for kindat in kindatList:
1608 1620 self.kindats.append((kindat, madKindatObj.getKindatDescription(kindat, kinst),
1609 1621 kinst))
1610 1622
1611 1623
1612 1624 def clean(self):
1613 1625 """clean is the Django method to validate things in a form that require looking at multiple fields
1614 1626 """
1615 1627 # rule 1 - start_date < end_date
1616 1628 if self.cleaned_data['start_date'] > self.cleaned_data['end_date']:
1617 1629 raise django.forms.ValidationError('Error - start datetime greater than end datetime.')
1618 1630
1619 1631 # rule 2 - seasonal start must be before seasonal end
1620 1632 if ((self.cleaned_data['seasonalStartDay'] + 31*self.cleaned_data['seasonalStartMonth']) > \
1621 1633 (self.cleaned_data['seasonalEndDay'] + 31*self.cleaned_data['seasonalEndMonth'])):
1622 1634 raise django.forms.ValidationError('Error - seasonal start after seasonal end.')
1623 1635
1624 1636
1625 1637
1626 1638 class AdvScriptParmsForm(django.forms.Form):
1627 1639 """AdvScriptParmsForm is the form for the parameters
1628 1640 """
1629 1641 def __init__(self, *args, **kwargs):
1630 1642
1631 1643 kinst = int(getSelection('instruments', args, kwargs))
1632 1644 if kinst == 0:
1633 1645 raise ValueError('kinst should never be zero')
1634 1646 madDB = madrigal.metadata.MadrigalDB()
1635 1647 madParmObj = madrigal.data.MadrigalParameters(madDB)
1636 1648 parmList = madParmObj.getParametersForInstruments([kinst])
1637 1649 self.parmList = []
1638 1650 for parm in parmList:
1639 1651 self.parmList.append((parm, madParmObj.getSimpleParmDescription(parm)))
1640 1652
1641 1653 madCatObj = madrigal.metadata.MadrigalParmCategory(madDB)
1642 1654
1643 1655 catList = madCatObj.getCategoryList()
1644 1656 catDict = madParmObj.getCategoryDict(parmList)
1645 1657
1646 1658 choices = []
1647 1659 isDerivedDict = {}
1648 1660 parmDescDict = {}
1649 1661 for catDesc, catID in catList:
1650 1662 if catID not in list(catDict.keys()):
1651 1663 continue
1652 1664 theseParms = []
1653 1665 for parm in catDict[catID][1]:
1654 1666 theseParms.append((parm, parm))
1655 1667 isDerivedDict[parm] = False
1656 1668 parmDescDict[parm] = madParmObj.getParmDescription(parm)
1657 1669 choices.append((catDesc, theseParms))
1658 1670
1659 1671 super(AdvScriptParmsForm, self).__init__(*args, **kwargs)
1660 1672
1661 1673 self.fields['parameters'] = IsprintChoiceField(choices=choices,
1662 1674 initial=['YEAR', 'MIN'],
1663 1675 required=False,
1664 1676 isDerivedDict=isDerivedDict,
1665 1677 parmDescDict=parmDescDict,
1666 1678 separateProlog=False,
1667 1679 label = "")
1668 1680
1669 1681
1670 1682 class AdvScriptParmsFiltersForm(django.forms.Form):
1671 1683 """AdvScriptParmsFiltersForm is the form for the parameter filters in the scrip generator
1672 1684 """
1673 1685 def __init__(self, *args, **kwargs):
1674 1686
1675 1687 kinst = int(getSelection('instruments', args, kwargs))
1676 1688 if kinst == 0:
1677 1689 raise ValueError('kinst should never be zero')
1678 1690 madDB = madrigal.metadata.MadrigalDB()
1679 1691 madParmObj = madrigal.data.MadrigalParameters(madDB)
1680 1692 parmList = madParmObj.getParametersForInstruments([kinst])
1681 1693 self.parmList = []
1682 1694 for parm in parmList:
1683 1695 self.parmList.append((parm, madParmObj.getSimpleParmDescription(parm)))
1684 1696
1685 1697 super(AdvScriptParmsFiltersForm, self).__init__(*args, **kwargs)
1686 1698
1687 1699 choices = [(parm, parm) for parm in parmList]
1688 1700 choices_with_null = [('None', 'None')] + choices
1689 1701
1690 1702 self.fields['parm_1'] = django.forms.ChoiceField(required=False,
1691 1703 choices=choices_with_null)
1692 1704 self.fields['parm_1_lower'] = django.forms.CharField(required=False, initial='')
1693 1705 self.fields['parm_1_upper'] = django.forms.CharField(required=False, initial='')
1694 1706
1695 1707 self.fields['parm_2'] = django.forms.ChoiceField(required=False,
1696 1708 choices=choices_with_null)
1697 1709 self.fields['parm_2_lower'] = django.forms.CharField(required=False, initial='')
1698 1710 self.fields['parm_2_upper'] = django.forms.CharField(required=False, initial='')
1699 1711
1700 1712 self.fields['parm_3'] = django.forms.ChoiceField(required=False,
1701 1713 choices=choices_with_null)
1702 1714 self.fields['parm_3_lower'] = django.forms.CharField(required=False, initial='')
1703 1715 self.fields['parm_3_upper'] = django.forms.CharField(required=False, initial='')
1704 1716
1705 1717
1706 1718
1707 1719 class MadCalculatorForm(django.forms.Form):
1708 1720 """MadCalculatorForm is the form for the madCalculator page
1709 1721 """
1710 1722 def __init__(self, *args, **kwargs):
1711 1723 """
1712 1724 """
1713 1725 madDB = madrigal.metadata.MadrigalDB()
1714 1726 madParmObj = madrigal.data.MadrigalParameters(madDB)
1715 1727 super(MadCalculatorForm, self).__init__(*args, **kwargs)
1716 1728 fullDerivedParmList = madrigal.derivation.getDerivableParms(['gdalt', 'gdlat', 'glon'])
1717 1729
1718 1730 # removed unwanted time and prolog parameters
1719 1731 rejectedCats = ('Time Related Parameter', 'Prolog Parameters', 'Radar Instrument Operation Parameter',
1720 1732 'Madrigal Hdf5 Prolog Parameters')
1721 1733 # define time parameters that do make sense to calculate
1722 1734 neededTimeParms = ('APLT', 'CONJ_SUNRISE_H', 'CONJ_SUNSET_H',
1723 1735 'SUNRISE_H', 'SUNSET_H', 'MLT')
1724 1736
1725 1737 # skip parms related to inst location
1726 1738 instLocationParms = ('AZM','ELM','GALTR','GDLONR','GDLATR','RANGE', 'ASPECT',
1727 1739 'GDALT', 'GDLAT', 'GLON', 'CXR', 'CYR', 'CZR')
1728 1740
1729 1741 madCatObj = madrigal.metadata.MadrigalParmCategory(madDB)
1730 1742
1731 1743 catList = madCatObj.getCategoryList()
1732 1744 catDict = madParmObj.getCategoryDict(fullDerivedParmList)
1733 1745 choices = []
1734 1746 isDerivedDict = {}
1735 1747 self.parmDescDict = {}
1736 1748 for catDesc, catID in catList:
1737 1749 if catDesc in rejectedCats[1:]:
1738 1750 continue
1739 1751 if catID not in list(catDict.keys()):
1740 1752 continue
1741 1753 theseParms = []
1742 1754 for parm in catDict[catID][1]:
1743 1755 if parm in instLocationParms:
1744 1756 continue
1745 1757 if catDesc in rejectedCats and parm not in neededTimeParms:
1746 1758 continue
1747 1759 if not parm in fullDerivedParmList:
1748 1760 continue
1749 1761 theseParms.append((parm, parm))
1750 1762 isDerivedDict[parm] = True
1751 1763 self.parmDescDict[parm] = madParmObj.getParmDescription(parm)
1752 1764 choices.append((catDesc, theseParms))
1753 1765
1754 1766
1755 1767
1756 1768 # form fields
1757 1769 self.fields['min_latitude'] = django.forms.FloatField(initial=-90.0, min_value=-90.0,
1758 1770 max_value=90.0)
1759 1771 self.fields['max_latitude'] = django.forms.FloatField(initial=90.0, min_value=-90.0,
1760 1772 max_value=90.0)
1761 1773 self.fields['delta_latitude'] = django.forms.FloatField(initial=45, min_value=1.0E-6)
1762 1774
1763 1775 self.fields['min_longitude'] = django.forms.FloatField(initial=-180.0, min_value=-180.0,
1764 1776 max_value=180.0)
1765 1777 self.fields['max_longitude'] = django.forms.FloatField(initial=180.0, min_value=-180.0,
1766 1778 max_value=180.0)
1767 1779 self.fields['delta_longitude'] = django.forms.FloatField(initial=90, min_value=1.0E-6)
1768 1780
1769 1781 self.fields['min_altitude'] = django.forms.FloatField(initial=0.0, min_value=0.0)
1770 1782 self.fields['max_altitude'] = django.forms.FloatField(initial=600.0, min_value=0.0)
1771 1783 self.fields['delta_altitude'] = django.forms.FloatField(initial=200, min_value=1.0E-6)
1772 1784
1773 1785 # time selection
1774 1786 now = datetime.datetime.utcnow()
1775 1787 self.fields['datetime'] = django.forms.SplitDateTimeField(input_date_formats=['%Y-%m-%d'], input_time_formats=['%H:%M:%S'],
1776 1788 label='Select UT datetime',
1777 1789 help_text='Select the UT time at which to run this calcuation',
1778 1790 initial=datetime.datetime(now.year,1,1))
1779 1791
1780 1792 self.fields['parameters'] = IsprintChoiceField(choices=choices,
1781 1793 required=False,
1782 1794 isDerivedDict=isDerivedDict,
1783 1795 parmDescDict=self.parmDescDict,
1784 1796 separateProlog=False,
1785 1797 label = "")
1786 1798
1787 1799
1788 1800 def clean(self):
1789 1801 """clean is the Django method to validate things in a form that require looking at multiple fields
1790 1802 """
1791 1803 max_len = 1.0E5
1792 1804 try:
1793 1805 a1 = numpy.arange(self.cleaned_data['min_latitude'], self.cleaned_data['max_latitude'], self.cleaned_data['delta_latitude'])
1794 1806 if len(a1) > max_len:
1795 1807 raise django.forms.ValidationError('Too many latitudes: %i.' % (len(a1)))
1796 1808 except ZeroDivisionError:
1797 1809 raise django.forms.ValidationError('Infinite latitudes')
1798 1810
1799 1811 try:
1800 1812 a2 = numpy.arange(self.cleaned_data['min_longitude'], self.cleaned_data['max_longitude'], self.cleaned_data['delta_longitude'])
1801 1813 if len(a1) > max_len:
1802 1814 raise django.forms.ValidationError('Too many longitudes: %i.' % (len(a1)))
1803 1815 except ZeroDivisionError:
1804 1816 raise django.forms.ValidationError('Infinite longitudes')
1805 1817
1806 1818 try:
1807 1819 a3 = numpy.arange(self.cleaned_data['min_altitude'], self.cleaned_data['max_altitude'], self.cleaned_data['delta_altitude'])
1808 1820 if len(a1) > max_len:
1809 1821 raise django.forms.ValidationError('Too many altitudes: %i.' % (len(a1)))
1810 1822 except ZeroDivisionError:
1811 1823 raise django.forms.ValidationError('Infinite altitudes')
1812 1824
1813 1825 total = len(a1) * len(a2) * len(a3)
1814 1826 if total > max_len:
1815 1827 raise django.forms.ValidationError('Too many calculations: %i' % (total))
1816 1828
1817 1829
1818 1830
1819 1831 class GetMetadataForm(django.forms.Form):
1820 1832 """GetMetadataForm is the form for the getMetadata page
1821 1833 """
1822 1834 def __init__(self, *args, **kwargs):
1823 1835 """
1824 1836 """
1825 1837 super(GetMetadataForm, self).__init__(*args, **kwargs)
1826 1838
1827 1839 fileTypeChoices = (("0", "Experiment Table"),
1828 1840 ("1", "File Table"),
1829 1841 ("3", "Instrument Table"),
1830 1842 ("4", "Parameter Table"),
1831 1843 ("5", "Site Table"),
1832 1844 ("6", "Type Table"),
1833 1845 ("7", "Instrument Kindat Table"),
1834 1846 ("8", "Instrument Parameter Table"),
1835 1847 ("9", "Madrigal categories table"),
1836 1848 ("10", "Instrument categories table"),)
1837 1849
1838 1850 self.fields['fileType'] = django.forms.ChoiceField(widget = django.forms.RadioSelect,
1839 1851 choices=fileTypeChoices,
1840 1852 initial="0",
1841 1853 label="Choose the metadata file type to download")
1842 1854
1843 1855
1844 1856 class LookerSelectForm(django.forms.Form):
1845 1857 """LookerSelectForm is the form for the looker_form page
1846 1858 """
1847 1859 def __init__(self, *args, **kwargs):
1848 1860 """
1849 1861 """
1850 1862 super(LookerSelectForm, self).__init__(*args, **kwargs)
1851 1863
1852 1864 lookerOptionChoices = (("1", "Geodetic latitude, longitude and altitude of the points"),
1853 1865 ("2", "Apex latitude, longitude and altitude of the points"),
1854 1866 ("3", "Geodetic latitude, longitude and altitude of the points"),
1855 1867 ("4", "Azimuth, elevation and range of the points from a specified instrument (output includes aspect angle)"),
1856 1868 ("5", "Azimuth, elevation, range from specified instrument"),
1857 1869 ("6", "Geodetic latitude, longitude, altitude of a point on the field line"),
1858 1870 ("7", "Apex latitude, longitude of the field line"),
1859 1871 ("8", "Geodetic latitude, longitude and altitude of the points"))
1860 1872
1861 1873 self.fields['looker_options'] = django.forms.ChoiceField(widget = django.forms.RadioSelect,
1862 1874 choices=lookerOptionChoices,
1863 1875 initial="1")
1864 1876
1865 1877
1866 1878 class LookerGeodeticRadar(django.forms.Form):
1867 1879 """LookerGeodeticRadar is the form for the geodetic to radar page
1868 1880 """
1869 1881 def __init__(self, *args, **kwargs):
1870 1882 """
1871 1883 """
1872 1884 super(LookerGeodeticRadar, self).__init__(*args, **kwargs)
1873 1885 madDB = madrigal.metadata.MadrigalDB()
1874 1886 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1875 1887 dict1 = {'isGlobal': True, 'categories': "0"}
1876 1888
1877 1889 self.fields['looker_options'] = django.forms.CharField(initial="1",
1878 1890 widget=django.forms.HiddenInput(attrs={'value': "1"}))
1879 1891
1880 1892 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
1881 1893 choices=getInstrumentList([], dict1, madInstData, 'Set location manually', local=False),
1882 1894 required=False, label='Instrument: ')
1883 1895
1884 1896 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
1885 1897 widget=django.forms.TextInput(attrs={'size':5}))
1886 1898 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
1887 1899 widget=django.forms.TextInput(attrs={'size':5}))
1888 1900 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
1889 1901 widget=django.forms.TextInput(attrs={'size':5}))
1890 1902 self.fields['start_lat'] = django.forms.FloatField(initial=30.0, min_value=-90.0, max_value=90.0,
1891 1903 widget=django.forms.TextInput(attrs={'size':5}))
1892 1904 self.fields['stop_lat'] = django.forms.FloatField(initial=50.0, min_value=-90.0, max_value=90.0,
1893 1905 widget=django.forms.TextInput(attrs={'size':5}))
1894 1906 self.fields['step_lat'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1895 1907 widget=django.forms.TextInput(attrs={'size':5}))
1896 1908 self.fields['start_lon'] = django.forms.FloatField(initial=-100.0, min_value=-180.0, max_value=180.0,
1897 1909 widget=django.forms.TextInput(attrs={'size':5}))
1898 1910 self.fields['stop_lon'] = django.forms.FloatField(initial=-80.0, min_value=-180.0, max_value=180.0,
1899 1911 widget=django.forms.TextInput(attrs={'size':5}))
1900 1912 self.fields['step_lon'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1901 1913 widget=django.forms.TextInput(attrs={'size':5}))
1902 1914 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
1903 1915 widget=django.forms.TextInput(attrs={'size':5}))
1904 1916 self.fields['stop_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1905 1917 widget=django.forms.TextInput(attrs={'size':5}))
1906 1918 self.fields['step_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1907 1919 widget=django.forms.TextInput(attrs={'size':5}))
1908 1920
1909 1921
1910 1922 class LookerGeomagRadar(django.forms.Form):
1911 1923 """LookerGeomagRadar is the form for the geomagnetic to radar page
1912 1924 """
1913 1925 def __init__(self, *args, **kwargs):
1914 1926 """
1915 1927 """
1916 1928 super(LookerGeomagRadar, self).__init__(*args, **kwargs)
1917 1929 madDB = madrigal.metadata.MadrigalDB()
1918 1930 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1919 1931 dict1 = {'isGlobal': True, 'categories': "0"}
1920 1932
1921 1933 self.fields['looker_options'] = django.forms.CharField(initial="2",
1922 1934 widget=django.forms.HiddenInput(attrs={'value': "2"}))
1923 1935
1924 1936 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
1925 1937 choices=getInstrumentList([], dict1, madInstData, 'Set location manually', local=False),
1926 1938 required=False, label='Instrument: ')
1927 1939
1928 1940 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
1929 1941 widget=django.forms.TextInput(attrs={'size':5}))
1930 1942 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
1931 1943 widget=django.forms.TextInput(attrs={'size':5}))
1932 1944 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
1933 1945 widget=django.forms.TextInput(attrs={'size':5}))
1934 1946 self.fields['start_lat'] = django.forms.FloatField(initial=30.0, min_value=-90.0, max_value=90.0,
1935 1947 widget=django.forms.TextInput(attrs={'size':5}))
1936 1948 self.fields['stop_lat'] = django.forms.FloatField(initial=50.0, min_value=-90.0, max_value=90.0,
1937 1949 widget=django.forms.TextInput(attrs={'size':5}))
1938 1950 self.fields['step_lat'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1939 1951 widget=django.forms.TextInput(attrs={'size':5}))
1940 1952 self.fields['start_lon'] = django.forms.FloatField(initial=-100.0, min_value=-180.0, max_value=180.0,
1941 1953 widget=django.forms.TextInput(attrs={'size':5}))
1942 1954 self.fields['stop_lon'] = django.forms.FloatField(initial=-80.0, min_value=-180.0, max_value=180.0,
1943 1955 widget=django.forms.TextInput(attrs={'size':5}))
1944 1956 self.fields['step_lon'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1945 1957 widget=django.forms.TextInput(attrs={'size':5}))
1946 1958 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
1947 1959 widget=django.forms.TextInput(attrs={'size':5}))
1948 1960 self.fields['stop_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1949 1961 widget=django.forms.TextInput(attrs={'size':5}))
1950 1962 self.fields['step_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1951 1963 widget=django.forms.TextInput(attrs={'size':5}))
1952 1964 now = datetime.datetime.utcnow()
1953 1965 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
1954 1966 widget=django.forms.TextInput(attrs={'size':5}))
1955 1967
1956 1968 class LookerGeomagFromGeodetic(django.forms.Form):
1957 1969 """LookerGeomagFromGeodetic is the form for the geomagnetic from geodetic page
1958 1970 """
1959 1971 def __init__(self, *args, **kwargs):
1960 1972 """
1961 1973 """
1962 1974 super(LookerGeomagFromGeodetic, self).__init__(*args, **kwargs)
1963 1975
1964 1976 self.fields['looker_options'] = django.forms.CharField(initial="3",
1965 1977 widget=django.forms.HiddenInput(attrs={'value': "3"}))
1966 1978
1967 1979 self.fields['start_lat'] = django.forms.FloatField(initial=30.0, min_value=-90.0, max_value=90.0,
1968 1980 widget=django.forms.TextInput(attrs={'size':5}))
1969 1981 self.fields['stop_lat'] = django.forms.FloatField(initial=50.0, min_value=-90.0, max_value=90.0,
1970 1982 widget=django.forms.TextInput(attrs={'size':5}))
1971 1983 self.fields['step_lat'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1972 1984 widget=django.forms.TextInput(attrs={'size':5}))
1973 1985 self.fields['start_lon'] = django.forms.FloatField(initial=-100.0, min_value=-180.0, max_value=180.0,
1974 1986 widget=django.forms.TextInput(attrs={'size':5}))
1975 1987 self.fields['stop_lon'] = django.forms.FloatField(initial=-80.0, min_value=-180.0, max_value=180.0,
1976 1988 widget=django.forms.TextInput(attrs={'size':5}))
1977 1989 self.fields['step_lon'] = django.forms.FloatField(initial=10.0, min_value=0.0,
1978 1990 widget=django.forms.TextInput(attrs={'size':5}))
1979 1991 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
1980 1992 widget=django.forms.TextInput(attrs={'size':5}))
1981 1993 self.fields['stop_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1982 1994 widget=django.forms.TextInput(attrs={'size':5}))
1983 1995 self.fields['step_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
1984 1996 widget=django.forms.TextInput(attrs={'size':5}))
1985 1997 now = datetime.datetime.utcnow()
1986 1998 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
1987 1999 widget=django.forms.TextInput(attrs={'size':5}))
1988 2000
1989 2001 class LookerGeomagFromRadar(django.forms.Form):
1990 2002 """LookerGeomagFromRadar is the form for the geomagnetic from radar page
1991 2003 """
1992 2004 def __init__(self, *args, **kwargs):
1993 2005 """
1994 2006 """
1995 2007 super(LookerGeomagFromRadar, self).__init__(*args, **kwargs)
1996 2008 madDB = madrigal.metadata.MadrigalDB()
1997 2009 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
1998 2010 dict1 = {'isGlobal': True, 'categories': "0"}
1999 2011
2000 2012 self.fields['looker_options'] = django.forms.CharField(initial="4",
2001 2013 widget=django.forms.HiddenInput(attrs={'value': "4"}))
2002 2014
2003 2015 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
2004 2016 choices=getInstrumentList([], dict1, madInstData, local=False)[1:],
2005 2017 required=False, label='Instrument: ')
2006 2018
2007 2019 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
2008 2020 widget=django.forms.TextInput(attrs={'size':5}))
2009 2021 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
2010 2022 widget=django.forms.TextInput(attrs={'size':5}))
2011 2023 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2012 2024 widget=django.forms.TextInput(attrs={'size':5}))
2013 2025 self.fields['start_az'] = django.forms.FloatField(initial=-180.0, min_value=-180.0, max_value=180.0,
2014 2026 widget=django.forms.TextInput(attrs={'size':5}))
2015 2027 self.fields['stop_az'] = django.forms.FloatField(initial=180.0, min_value=-180.0, max_value=180.0,
2016 2028 widget=django.forms.TextInput(attrs={'size':5}))
2017 2029 self.fields['step_az'] = django.forms.FloatField(initial=45.0, min_value=0.0,
2018 2030 widget=django.forms.TextInput(attrs={'size':5}))
2019 2031 self.fields['start_el'] = django.forms.FloatField(initial=0.0, min_value=0.0, max_value=90.0,
2020 2032 widget=django.forms.TextInput(attrs={'size':5}))
2021 2033 self.fields['stop_el'] = django.forms.FloatField(initial=90.0, min_value=0.0, max_value=90.0,
2022 2034 widget=django.forms.TextInput(attrs={'size':5}))
2023 2035 self.fields['step_el'] = django.forms.FloatField(initial=30.0, min_value=0.0,
2024 2036 widget=django.forms.TextInput(attrs={'size':5}))
2025 2037 self.fields['start_range'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2026 2038 widget=django.forms.TextInput(attrs={'size':5}))
2027 2039 self.fields['stop_range'] = django.forms.FloatField(initial=600.0, min_value=0.0,
2028 2040 widget=django.forms.TextInput(attrs={'size':5}))
2029 2041 self.fields['step_range'] = django.forms.FloatField(initial=200.0, min_value=0.0,
2030 2042 widget=django.forms.TextInput(attrs={'size':5}))
2031 2043 now = datetime.datetime.utcnow()
2032 2044 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
2033 2045 widget=django.forms.TextInput(attrs={'size':5}))
2034 2046
2035 2047
2036 2048 class LookerFieldLineFromRadar(django.forms.Form):
2037 2049 """LookerFieldLineFromRadar is the form for the field line from radar page
2038 2050 """
2039 2051 def __init__(self, *args, **kwargs):
2040 2052 """
2041 2053 """
2042 2054 super(LookerFieldLineFromRadar, self).__init__(*args, **kwargs)
2043 2055 madDB = madrigal.metadata.MadrigalDB()
2044 2056 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
2045 2057 dict1 = {'isGlobal': True, 'categories': "0"}
2046 2058
2047 2059 self.fields['looker_options'] = django.forms.CharField(initial="5",
2048 2060 widget=django.forms.HiddenInput(attrs={'value': "5"}))
2049 2061
2050 2062 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
2051 2063 choices=getInstrumentList([], dict1, madInstData, 'Set location manually', local=False),
2052 2064 required=False, label='Instrument: ')
2053 2065
2054 2066 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
2055 2067 widget=django.forms.TextInput(attrs={'size':5}))
2056 2068 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
2057 2069 widget=django.forms.TextInput(attrs={'size':5}))
2058 2070 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2059 2071 widget=django.forms.TextInput(attrs={'size':5}))
2060 2072 self.fields['fl_az'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
2061 2073 widget=django.forms.TextInput(attrs={'size':5}))
2062 2074 self.fields['fl_el'] = django.forms.FloatField(initial=45.0, min_value=0.0, max_value=90.0,
2063 2075 widget=django.forms.TextInput(attrs={'size':5}))
2064 2076 self.fields['fl_range'] = django.forms.FloatField(initial=1000.0, min_value=0.0,
2065 2077 widget=django.forms.TextInput(attrs={'size':5}))
2066 2078
2067 2079 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2068 2080 widget=django.forms.TextInput(attrs={'size':5}))
2069 2081 self.fields['stop_alt'] = django.forms.FloatField(initial=1000.0, min_value=0.0,
2070 2082 widget=django.forms.TextInput(attrs={'size':5}))
2071 2083 self.fields['step_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2072 2084 widget=django.forms.TextInput(attrs={'size':5}))
2073 2085 now = datetime.datetime.utcnow()
2074 2086 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
2075 2087 widget=django.forms.TextInput(attrs={'size':5}))
2076 2088
2077 2089
2078 2090
2079 2091 class LookerFieldLineFromGeodetic(django.forms.Form):
2080 2092 """LookerFieldLineFromGeodetic is the form for the field line from geodetic page
2081 2093 """
2082 2094 def __init__(self, *args, **kwargs):
2083 2095 """
2084 2096 """
2085 2097 super(LookerFieldLineFromGeodetic, self).__init__(*args, **kwargs)
2086 2098 madDB = madrigal.metadata.MadrigalDB()
2087 2099 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
2088 2100 dict1 = {'isGlobal': True, 'categories': "0"}
2089 2101
2090 2102 self.fields['looker_options'] = django.forms.CharField(initial="6",
2091 2103 widget=django.forms.HiddenInput(attrs={'value': "6"}))
2092 2104
2093 2105 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
2094 2106 choices=getInstrumentList([], dict1, madInstData, 'Set location manually', local=False),
2095 2107 required=False, label='Instrument: ')
2096 2108
2097 2109 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
2098 2110 widget=django.forms.TextInput(attrs={'size':5}))
2099 2111 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
2100 2112 widget=django.forms.TextInput(attrs={'size':5}))
2101 2113 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2102 2114 widget=django.forms.TextInput(attrs={'size':5}))
2103 2115 self.fields['fl_lat'] = django.forms.FloatField(initial=45.0, min_value=-90.0, max_value=90.0,
2104 2116 widget=django.forms.TextInput(attrs={'size':5}))
2105 2117 self.fields['fl_lon'] = django.forms.FloatField(initial=-90.0, min_value=-180.0, max_value=180.0,
2106 2118 widget=django.forms.TextInput(attrs={'size':5}))
2107 2119 self.fields['fl_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2108 2120 widget=django.forms.TextInput(attrs={'size':5}))
2109 2121
2110 2122 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2111 2123 widget=django.forms.TextInput(attrs={'size':5}))
2112 2124 self.fields['stop_alt'] = django.forms.FloatField(initial=1000.0, min_value=0.0,
2113 2125 widget=django.forms.TextInput(attrs={'size':5}))
2114 2126 self.fields['step_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2115 2127 widget=django.forms.TextInput(attrs={'size':5}))
2116 2128 now = datetime.datetime.utcnow()
2117 2129 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
2118 2130 widget=django.forms.TextInput(attrs={'size':5}))
2119 2131
2120 2132
2121 2133 class LookerFieldLineFromApex(django.forms.Form):
2122 2134 """LookerFieldLineFromApex is the form for the field line from apex coordinates page
2123 2135 """
2124 2136 def __init__(self, *args, **kwargs):
2125 2137 """
2126 2138 """
2127 2139 super(LookerFieldLineFromApex, self).__init__(*args, **kwargs)
2128 2140 madDB = madrigal.metadata.MadrigalDB()
2129 2141 madInstData = madrigal.metadata.MadrigalInstrumentData(madDB)
2130 2142 dict1 = {'isGlobal': True, 'categories': "0"}
2131 2143
2132 2144 self.fields['looker_options'] = django.forms.CharField(initial="7",
2133 2145 widget=django.forms.HiddenInput(attrs={'value': "7"}))
2134 2146
2135 2147 self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={'size':'3'}),
2136 2148 choices=getInstrumentList([], dict1, madInstData, 'Set location manually', local=False),
2137 2149 required=False, label='Instrument: ')
2138 2150
2139 2151 self.fields['inst_lat'] = django.forms.FloatField(initial=0.0, min_value=-90.0, max_value=90.0,
2140 2152 widget=django.forms.TextInput(attrs={'size':5}))
2141 2153 self.fields['inst_lon'] = django.forms.FloatField(initial=0.0, min_value=-180.0, max_value=180.0,
2142 2154 widget=django.forms.TextInput(attrs={'size':5}))
2143 2155 self.fields['inst_alt'] = django.forms.FloatField(initial=0.0, min_value=0.0,
2144 2156 widget=django.forms.TextInput(attrs={'size':5}))
2145 2157 self.fields['fl_apex_lat'] = django.forms.FloatField(initial=65.0, min_value=-00.0, max_value=90.0,
2146 2158 widget=django.forms.TextInput(attrs={'size':5}))
2147 2159 self.fields['fl_apex_lon'] = django.forms.FloatField(initial=-90.0, min_value=-180.0, max_value=180.0,
2148 2160 widget=django.forms.TextInput(attrs={'size':5}))
2149 2161
2150 2162 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2151 2163 widget=django.forms.TextInput(attrs={'size':5}))
2152 2164 self.fields['stop_alt'] = django.forms.FloatField(initial=1000.0, min_value=0.0,
2153 2165 widget=django.forms.TextInput(attrs={'size':5}))
2154 2166 self.fields['step_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2155 2167 widget=django.forms.TextInput(attrs={'size':5}))
2156 2168 now = datetime.datetime.utcnow()
2157 2169 self.fields['year'] = django.forms.FloatField(initial=float(now.year), min_value=1950.0,
2158 2170 widget=django.forms.TextInput(attrs={'size':5}))
2159 2171
2160 2172
2161 2173 class LookerConjugateFromGeodetic(django.forms.Form):
2162 2174 """LookerConjugateFromGeodetic is the form for the geomagnetic/conjugate from geodetic page
2163 2175 """
2164 2176 def __init__(self, *args, **kwargs):
2165 2177 """
2166 2178 """
2167 2179 super(LookerConjugateFromGeodetic, self).__init__(*args, **kwargs)
2168 2180
2169 2181 parmChoices = [("MAGCONJLAT", 'Magnetic conjugate latitude'),
2170 2182 ("MAGCONJLON", 'Magnetic conjugate longitude'),
2171 2183 ("SZEN", 'Solar zenith angle'),
2172 2184 ("SZENC", 'Magnetic conjugate solar zenith angle'),
2173 2185 ("SDWHT", 'Shadow height (km)'),
2174 2186 ("MAGCONJSDWHT", 'Magnetic conjugate shadow height (km)')]
2175 2187 parmInitial = [key for key, value in parmChoices]
2176 2188
2177 2189 self.fields['looker_options'] = django.forms.CharField(initial="8",
2178 2190 widget=django.forms.HiddenInput(attrs={'value': "8"}))
2179 2191
2180 2192 self.fields['start_lat'] = django.forms.FloatField(initial=30.0, min_value=-90.0, max_value=90.0,
2181 2193 widget=django.forms.TextInput(attrs={'size':5}))
2182 2194 self.fields['stop_lat'] = django.forms.FloatField(initial=50.0, min_value=-90.0, max_value=90.0,
2183 2195 widget=django.forms.TextInput(attrs={'size':5}))
2184 2196 self.fields['step_lat'] = django.forms.FloatField(initial=10.0, min_value=0.0,
2185 2197 widget=django.forms.TextInput(attrs={'size':5}))
2186 2198 self.fields['start_lon'] = django.forms.FloatField(initial=-100.0, min_value=-180.0, max_value=180.0,
2187 2199 widget=django.forms.TextInput(attrs={'size':5}))
2188 2200 self.fields['stop_lon'] = django.forms.FloatField(initial=-80.0, min_value=-180.0, max_value=180.0,
2189 2201 widget=django.forms.TextInput(attrs={'size':5}))
2190 2202 self.fields['step_lon'] = django.forms.FloatField(initial=10.0, min_value=0.0,
2191 2203 widget=django.forms.TextInput(attrs={'size':5}))
2192 2204 self.fields['start_alt'] = django.forms.FloatField(initial=100.0, min_value=0.0,
2193 2205 widget=django.forms.TextInput(attrs={'size':5}))
2194 2206 self.fields['stop_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
2195 2207 widget=django.forms.TextInput(attrs={'size':5}))
2196 2208 self.fields['step_alt'] = django.forms.FloatField(initial=500.0, min_value=0.0,
2197 2209 widget=django.forms.TextInput(attrs={'size':5}))
2198 2210
2199 2211 # time selection
2200 2212 now = datetime.datetime.utcnow()
2201 2213 self.fields['datetime'] = django.forms.SplitDateTimeField(input_date_formats=['%Y-%m-%d'], input_time_formats=['%H:%M:%S'],
2202 2214 label='Select UT datetime',
2203 2215 help_text='Select the UT time at which to run this calcuation',
2204 2216 initial=datetime.datetime(now.year,1,1))
2205 2217
2206 2218 self.fields['pList'] = django.forms.MultipleChoiceField(widget=django.forms.CheckboxSelectMultiple(),
2207 2219 choices=parmChoices, initial=parmInitial)
2208 2220
1 NO CONTENT: modified file, binary diff hidden
@@ -1,75 +1,75
1 1 {% load static %}
2 2
3 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 4 <html xmlns="http://www.w3.org/1999/xhtml"><!-- InstanceBegin template="/Templates/doc_template.dwt" codeOutsideHTMLIsLocked="false" -->
5 5 <head>
6 6 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
7 7 <!-- InstanceBeginEditable name="doctitle" -->
8 8 <title>Madrigal administrator's guide</title>
9 9 <!-- InstanceEndEditable --><!-- InstanceBeginEditable name="head" --><!-- InstanceEndEditable -->
10 <link href="/static/madrigal.css" rel="stylesheet" type="text/css" />
10 <link href="/madrigal/static/madrigal.css" rel="stylesheet" type="text/css" />
11 11 <style type="text/css">
12 12 html body {
13 13 background-color: {{bg_color}};
14 14 }
15 15 </style>
16 16 <!-- InstanceParam name="href_up_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_top" type="text" value="ad_appropriate.html" --><!-- InstanceParam name="href_back_top" type="text" value="rr_fortran95.html" --><!-- InstanceParam name="href_back_bottom" type="text" value="rr_fortran95.html" --><!-- InstanceParam name="href_up_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_bottom" type="text" value="ad_appropriate.html" --><!-- InstanceParam name="href_prev_top" type="text" value="rr_fortran95.html" --><!-- InstanceParam name="href_uptitle_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_top" type="text" value="ad_appropriate.html" --><!-- InstanceParam name="href_prevtitle_bottom" type="text" value="rr_fortran95.html" --><!-- InstanceParam name="href_uptitle_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_bottom" type="text" value="ad_appropriate.html" -->
17 17 </head>
18 18
19 19 <body>
20 20 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
21 21 <tr>
22 <td width="5%"><a href="{% url 'docs' 'rr_fortran95.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'ad_appropriate.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
22 <td width="5%"><a href="{% url 'docs' 'rr_fortran95.html' %}"><img src="{% static 'previous.png' %}" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="{% static 'up.png' %}" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'ad_appropriate.html' %}"><img src="{% static 'next.png' %}" alt="next" width="32" height="32" /></a></td>
25 25 <td width="54%"><!-- InstanceBeginEditable name="EditTitleTop" -->Madrigal administrator's guide<!-- InstanceEndEditable --></td>
26 26 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
27 27 <td width="18%"><a href="/">Madrigal home</a></td>
28 28 </tr>
29 29 </table>
30 30 <div class='online-navigation'>
31 31 <b class="navlabel">Previous:</b>
32 32 <a class="sectref" href="{% url 'docs' 'rr_fortran95.html' %}"><!-- InstanceBeginEditable name="PreviousTitle" -->Fortran95 remote API reference <!-- InstanceEndEditable --></A>
33 33 <b class="navlabel">&nbsp;&nbsp;Up:</b>
34 34 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle" -->Doc home <!-- InstanceEndEditable --></A>
35 35 <b class="navlabel">&nbsp;&nbsp;Next:</b>
36 36 <a class="sectref" href="{% url 'docs' 'ad_appropriate.html' %}"><!-- InstanceBeginEditable name="NextTitle" -->Is Madrigal appropriate?<!-- InstanceEndEditable --></A></div>
37 37 <hr/>
38 38 <!-- InstanceBeginEditable name="EditDoc" -->
39 39 <h1 align="center">Madrigal administrator's guide</h1>
40 40 <p>This section of the Madrigal documentation is meant for people considering installing Madrigal to hold data from their instruments, or those who have already installed Madrigal and are responsible for administering or updating it. This guide describes how to determine whether Madrigal is right for your data, and how to install it if it is. It also discusses how to create Madrigal data files, and how to add them to Madrigal. </p>
41 41 <ul>
42 42 <li><a href="{% url 'docs' 'ad_appropriate.html' %}">Is Madrigal appropriate for my instrument(s)?</a></li>
43 43 <li><a href="{% url 'docs' 'ad_install.html' %}">Installing Madrigal for the first time </a></li>
44 44 <li><a href="{% url 'docs' 'ad_upgrade.html' %}">Upgrading Madrigal to the latest release</a></li>
45 45 <li><a href="{% url 'docs' 'ad_metadata.html' %}">The Madrigal data model and metadata files</a></li>
46 46 <li><a href="{% url 'docs' 'ad_experiments.html' %}">How Madrigal data is organized</a></li>
47 47 <li><a href="{% url 'docs' 'ad_createFiles.html' %}">Creating Madrigal data files</a></li>
48 48 <li><a href="{% url 'docs' 'ad_createExp.html' %}">Creating and updating Madrigal experiments</a></li>
49 49 <li><a href="{% url 'docs' 'ad_other.html' %}">Other administrative tasks</a></li>
50 50 <li><a href="{% url 'docs' 'ad_logging.html' %}">User access logging</a></li>
51 51 <li><a href="{% url 'docs' 'ad_links.html' %}">Creating direct links to experiments/files</a></li>
52 52 <li><a href="{% url 'docs' 'ad_isprint.html' %}">Using isprint for file quick looks</a></li>
53 53 </ul>
54 54 <!-- InstanceEndEditable -->
55 55 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
56 56 <tr>
57 <td width="5%"><a href="{% url 'docs' 'rr_fortran95.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
58 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
59 <td width="5%"><a href="{% url 'docs' 'ad_appropriate.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
57 <td width="5%"><a href="{% url 'docs' 'rr_fortran95.html' %}"><img src="{% static 'previous.png' %}" alt="previous" width="32" height="32" /></a></td>
58 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="{% static 'up.png' %}" alt="up" width="32" height="32" /></a></td>
59 <td width="5%"><a href="{% url 'docs' 'ad_appropriate.html' %}"><img src="{% static 'next.png' %}" alt="next" width="32" height="32" /></a></td>
60 60 <td width="54%"><!-- InstanceBeginEditable name="EditTitleBottom" -->Madrigal administrator's guide<!-- InstanceEndEditable --></td>
61 61 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
62 62 <td width="18%"><a href="/">Madrigal home</a></td>
63 63 </tr>
64 64 </table>
65 65 <div class='online-navigation'>
66 66 <b class="navlabel">Previous:</b>
67 67 <a class="sectref" href="{% url 'docs' 'rr_fortran95.html' %}"><!-- InstanceBeginEditable name="PreviousTitle2" -->Fortran95 remote API reference <!-- InstanceEndEditable --></A>
68 68 <b class="navlabel">&nbsp;&nbsp;Up:</b>
69 69 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle2" -->Doc home <!-- InstanceEndEditable --></A>
70 70 <b class="navlabel">&nbsp;&nbsp;Next:</b>
71 71 <a class="sectref" href="{% url 'docs' 'ad_appropriate.html' %}"><!-- InstanceBeginEditable name="NextTitle2" -->Is Madrigal appropriate? <!-- InstanceEndEditable --></A></div>
72 72 <hr/>
73 73 <p>&nbsp;</p>
74 74 </body>
75 75 <!-- InstanceEnd --></html>
@@ -1,87 +1,87
1 1 {% load static %}
2 2
3 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 4 <html xmlns="http://www.w3.org/1999/xhtml"><!-- InstanceBegin template="/Templates/doc_template.dwt" codeOutsideHTMLIsLocked="false" -->
5 5 <head>
6 6 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
7 7 <!-- InstanceBeginEditable name="doctitle" -->
8 8 <title>Madrigal developer's guide</title>
9 9 <!-- InstanceEndEditable --><!-- InstanceBeginEditable name="head" --><!-- InstanceEndEditable -->
10 <link href="/static/madrigal.css" rel="stylesheet" type="text/css" />
10 <link href="{% static 'madrigal.css' %}" rel="stylesheet" type="text/css" />
11 11 <style type="text/css">
12 12 html body {
13 13 background-color: {{bg_color}};
14 14 }
15 15 </style>
16 16 <!-- InstanceParam name="href_up_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_top" type="text" value="madrigal/index.html" --><!-- InstanceParam name="href_back_top" type="text" value="ad_isprint.html" --><!-- InstanceParam name="href_back_bottom" type="text" value="ad_isprint.html" --><!-- InstanceParam name="href_up_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_bottom" type="text" value="madrigal/index.html" --><!-- InstanceParam name="href_prev_top" type="text" value="ad_isprint.html" --><!-- InstanceParam name="href_uptitle_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_top" type="text" value="madrigal/index.html" --><!-- InstanceParam name="href_prevtitle_bottom" type="text" value="ad_isprint.html" --><!-- InstanceParam name="href_uptitle_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_bottom" type="text" value="madrigal/index.html" -->
17 17 </head>
18 18
19 19 <body>
20 20 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
21 21 <tr>
22 <td width="5%"><a href="{% url 'docs' 'ad_isprint.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'madrigal/index.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
22 <td width="5%"><a href="{% url 'docs' 'ad_isprint.html' %}"><img src="{% static 'previous.png' %}" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="{% static 'up.png' %}" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'madrigal/index.html' %}"><img src="{% static 'next.png' %}" alt="next" width="32" height="32" /></a></td>
25 25 <td width="54%"><!-- InstanceBeginEditable name="EditTitleTop" -->Madrigal developer's guide <!-- InstanceEndEditable --></td>
26 26 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
27 27 <td width="18%"><a href="/">Madrigal home</a></td>
28 28 </tr>
29 29 </table>
30 30 <div class='online-navigation'>
31 31 <b class="navlabel">Previous:</b>
32 32 <a class="sectref" href="{% url 'docs' 'ad_isprint.html' %}"><!-- InstanceBeginEditable name="PreviousTitle" -->Using isprint<!-- InstanceEndEditable --></A>
33 33 <b class="navlabel">&nbsp;&nbsp;Up:</b>
34 34 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle" -->Doc home <!-- InstanceEndEditable --></A>
35 35 <b class="navlabel">&nbsp;&nbsp;Next:</b>
36 36 <a class="sectref" href="{% url 'docs' 'madrigal/index.html' %}"><!-- InstanceBeginEditable name="NextTitle" -->Internal python API<!-- InstanceEndEditable --></A></div>
37 37 <hr/>
38 38 <!-- InstanceBeginEditable name="EditDoc" -->
39 39 <h1 align="center">Madrigal developer's guide</h1>
40 40 <p>This section of the Madrigal documentation is meant for developers working to extend or modify Madrigal. It is not meant for users of Madrigal or Madrigal administrators. </p>
41 41 <p>With the release of Madrigal 3.0, Madrigal has only a single python API. The C and Fortran code installed in Madrigal is purely scientific code used in the derivation engine, and is exposed only as a python extension, madrigal._derive.</p>
42 42 <p>The web interface is now a Django web application, and no direct cgi scripts remain. The django application is contained in MADROOT/source/madpy/djangoMad.</p>
43 43 <ul>
44 44 <li><a href="madrigal/index.html">Internal Madrigal Python API</a>
45 45 <ul>
46 46 <li><a href="{% url 'docs' 'madrigal/admin.m.html' %}">madrigal.admin</a></li>
47 47 <li><a href="{% url 'docs' 'madrigal/cedar.m.html' %}">madrigal.cedar</a></li>
48 48 <li><a href="{% url 'docs' 'madrigal/data.m.html' %}">madrigal.data</a></li>
49 49 <li><a href="{% url 'docs' 'madrigal/derivation.m.html' %}">madrigal.derivation</a></li>
50 50 <li><a href="{% url 'docs' 'madrigal/isprint.m.html' %}">madrigal.isprint</a></li>
51 51 <li><a href="{% url 'docs' 'madrigal/metadata.m.html' %}">madrigal.metadata</a></li>
52 52 <li><a href="{% url 'docs' 'madrigal/openmadrigal.m.html' %}">madrigal.openmadrigal</a></li>
53 53 <li><a href="{% url 'docs' 'madrigal/ui/index.html' %}">madrigal.ui</a>
54 54 <ul>
55 55 <li><a href="{% url 'docs' 'madrigal/ui/madrigalPlot.m.html' %}">madrigal.ui.madrigalPlot</a></li>
56 56 <li><a href="{% url 'docs' 'madrigal/ui/userData.m.html' %}">madrigal.ui.userData</a></li>
57 57 <li><a href="{% url 'docs' 'madrigal/ui/web.m.html' %}">madrigal.ui.web</a></li>
58 58 </ul>
59 59 </li>
60 60 </ul>
61 61 </li>
62 62 <li><a href="{% url 'docs' 'dev_derivation.html' %}">Madrigal derivation engine</a></li>
63 63 <li><a href="/static/CEDARMadrigalHdf5Format.pdf">CEDAR Madrigal Hdf5 file format</a></li>
64 64 <li><a href="/static/cedarFormat.pdf">Deprecated Cedar file format</a></li>
65 65 </ul>
66 66 <!-- InstanceEndEditable -->
67 67 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
68 68 <tr>
69 <td width="5%"><a href="{% url 'docs' 'ad_isprint.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
70 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
71 <td width="5%"><a href="{% url 'docs' 'madrigal/index.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
69 <td width="5%"><a href="{% url 'docs' 'ad_isprint.html' %}"><img src="{% static 'previous.png' %}" alt="previous" width="32" height="32" /></a></td>
70 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="{% static 'up.png' %}" alt="up" width="32" height="32" /></a></td>
71 <td width="5%"><a href="{% url 'docs' 'madrigal/index.html' %}"><img src="{% static 'next.png' %}" alt="next" width="32" height="32" /></a></td>
72 72 <td width="54%"><!-- InstanceBeginEditable name="EditTitleBottom" -->Madrigal developer's guide<!-- InstanceEndEditable --></td>
73 73 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
74 74 <td width="18%"><a href="/">Madrigal home</a></td>
75 75 </tr>
76 76 </table>
77 77 <div class='online-navigation'>
78 78 <b class="navlabel">Previous:</b>
79 79 <a class="sectref" href="{% url 'docs' 'ad_isprint.html' %}"><!-- InstanceBeginEditable name="PreviousTitle2" -->Using isprint <!-- InstanceEndEditable --></A>
80 80 <b class="navlabel">&nbsp;&nbsp;Up:</b>
81 81 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle2" -->Doc home <!-- InstanceEndEditable --></A>
82 82 <b class="navlabel">&nbsp;&nbsp;Next:</b>
83 83 <a class="sectref" href="{% url 'docs' 'madrigal/index.html' %}"><!-- InstanceBeginEditable name="NextTitle2" -->Internal python API <!-- InstanceEndEditable --></A></div>
84 84 <hr/>
85 85 <p>&nbsp;</p>
86 86 </body>
87 87 <!-- InstanceEnd --></html>
@@ -1,50 +1,50
1 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 2 <html xmlns="http://www.w3.org/1999/xhtml">
3 3 <head>
4 4 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5 5 <title>Madrigal documentation - v3.0</title>
6 <link href="/static/madrigal.css" rel="stylesheet" type="text/css" />
6 <link href="/madrigal/static/madrigal.css" rel="stylesheet" type="text/css" />
7 7 <style type="text/css">
8 8 html body {
9 9 background-color: {{bg_color}};
10 10 }
11 11 </style>
12 12 </head>
13 13
14 14 <body>
15 15 <center>
16 16 <h1>Madrigal Database v3.2.1 Documentation - Contents</h1>
17 17 <table width="100%" border="1">
18 18 <tr>
19 19 <td class="navigation"><a href="/">Home</a></td>
20 20 </tr>
21 21 </table>
22 22 </center>
23 23 <hr size="4" />
24 24 <ul>
25 25 <li><a href="{% url 'docs' 'madIntroduction.html' %}">1. Brief history of Madrigal</a></li>
26 26 </ul>
27 27 <ul>
28 28 <li><a href="{% url 'docs' 'whatsNew.html' %}">2. What's new in Madrigal 3.2.1</a></li>
29 29 </ul>
30 30 <ul>
31 31 <li><a href="{% url 'docs' 'wt_usersGuide.html' %}">3. Madrigal user's guide (How do I access Madrigal data?) </a>
32 32 <ul>
33 33 <li><a href="{% url 'docs' 'wt_contents.html' %}">2.1 Web interface tutorial </a></li>
34 34 <li><a href="{% url 'docs' 'rt_contents.html' %}">2.2 Remote data access programming tutorial</a></li>
35 35 <li><a href="{% url 'docs' 'rr_contents.html' %}">2.3 Remote data access programming reference guide</a></li>
36 36 </ul>
37 37 </li>
38 38 </ul>
39 39 <ul>
40 40 <li><a href="{% url 'docs' 'admin.html' %}">4. Madrigal Administrator's Guide</a></li>
41 41 </ul>
42 42 <ul>
43 43 <li><a href="{% url 'docs' 'dev_contents.html' %}">5. Madrigal Developer's Guide</a></li>
44 44 </ul>
45 45 <ul>
46 46 <li><a href="{{ siteSpecific }}">6. Site specific documentation</a></li>
47 47 </ul>
48 48 <p>&nbsp;</p>
49 49 </body>
50 50 </html>
@@ -1,71 +1,71
1 1 {% load static %}
2 2
3 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 4 <html xmlns="http://www.w3.org/1999/xhtml"><!-- InstanceBegin template="/Templates/doc_template.dwt" codeOutsideHTMLIsLocked="false" -->
5 5 <head>
6 6 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
7 7 <!-- InstanceBeginEditable name="doctitle" -->
8 8 <title>Madrigal history</title>
9 9 <!-- InstanceEndEditable --><!-- InstanceBeginEditable name="head" -->
10 10 <!-- InstanceEndEditable -->
11 <link href="/static/madrigal.css" rel="stylesheet" type="text/css" />
11 <link href="/madrigal/static/madrigal.css" rel="stylesheet" type="text/css" />
12 12 <style type="text/css">
13 13 html body {
14 14 background-color: {{bg_color}};
15 15 }
16 16 </style>
17 17 <!-- InstanceParam name="href_up_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_top" type="text" value="whatsNew.html" --><!-- InstanceParam name="href_back_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_back_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_up_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_bottom" type="text" value="whatsNew.html" --><!-- InstanceParam name="href_prev_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_uptitle_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_top" type="text" value="whatsNew.html" --><!-- InstanceParam name="href_prevtitle_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_uptitle_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_bottom" type="text" value="whatsNew.html" -->
18 18 </head>
19 19
20 20 <body>
21 21 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
22 22 <tr>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
25 <td width="5%"><a href="{% url 'docs' 'whatsNew.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/previous.png" alt="previous" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/up.png" alt="up" width="32" height="32" /></a></td>
25 <td width="5%"><a href="{% url 'docs' 'whatsNew.html' %}"><img src="/madrigal/static/next.png" alt="next" width="32" height="32" /></a></td>
26 26 <td width="54%"><!-- InstanceBeginEditable name="EditTitleTop" -->Brief history of Madrigal <!-- InstanceEndEditable --></td>
27 27 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
28 28 <td width="18%"><a href="/">Madrigal home</a></td>
29 29 </tr>
30 30 </table>
31 31 <div class='online-navigation'>
32 32 <b class="navlabel">Previous:</b>
33 33 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="PreviousTitle" -->Doc home <!-- InstanceEndEditable --></A>
34 34 <b class="navlabel">&nbsp;&nbsp;Up:</b>
35 35 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle" -->Doc home <!-- InstanceEndEditable --></A>
36 36 <b class="navlabel">&nbsp;&nbsp;Next:</b>
37 37 <a class="sectref" href="{% url 'docs' 'whatsNew.html' %}"><!-- InstanceBeginEditable name="NextTitle" -->What's new in Madrigal 3.0? <!-- InstanceEndEditable --></A></div>
38 38 <hr/>
39 39 <!-- InstanceBeginEditable name="EditDoc" -->
40 40 <center>
41 41 <h1>Brief history of Madrigal </h1>
42 42 </center>
43 43 <p>Madrigal is a database of ground-based measurements and models of the Earth's upper atmosphere and ionosphere. It is the community database of the Coupling, Energetics and Dynamics of Atmospheric Regions (<a href="http://cedarweb.vsp.ucar.edu/wiki/index.php/Main_Page">CEDAR</a>) program, which is devoted to the characterization and understanding of the atmosphere above about 60 km, with emphasis on the various processes that determine the basic structure and composition of the atmosphere, and on the mechanisms that couple different atmospheric regions. Instruments developed or upgraded under CEDAR include interferometers, spectrometers, imagers, lidars and medium, high-frequency and incoherent scatter radars. The success of CEDAR has been due, in large measure, to its ability to encourage collaborative efforts coalescing observations, theory and modeling. The CEDAR community includes about 800 scientists and students from around the world.</p>
44 44 <p>From the inception of the CEDAR program in 1988, there has been a great concern among the members of the CEDAR community to make the data collected by the CEDAR instruments easily accessible for joint studies. Consequently, a high priority was placed on establishing a repository for CEDAR data and model results. An incoherent scatter radar database had been established at the National Center for Atmospheric Research (NCAR) in 1985, and this evolved into the CEDAR Database in 1989. By the end of 1997, it had grown to include data from 44 instruments and 16 models. Over 200 users have requested information from the Database. In 2012, the Madrigal database and the CEDAR database were combined into a single database system, the Madrigal CEDAR database, based at MIT Haystack Observatory.</p>
45 <p>A central element of the CEDAR Database is a standard data format. With Madrigal 3.0 the file format is now Hdf5, with a well-defined layout and parameters. This new CEDAR Hdf5 format is described <a href="/static/CEDARMadrigalHdf5Format.pdf" target="_blank">here</a>. This format replaced the old <a href="/static/cedarFormat.pdf">16 bit integer based format</a> that evolved from the format used by the earlier incoherent scatter database, which in turn evolved from an earlier version of Madrigal developed at the MIT Haystack Observatory in 1980. </p>
45 <p>A central element of the CEDAR Database is a standard data format. With Madrigal 3.0 the file format is now Hdf5, with a well-defined layout and parameters. This new CEDAR Hdf5 format is described <a href="/madrigal/static/CEDARMadrigalHdf5Format.pdf" target="_blank">here</a>. This format replaced the old <a href="/madrigal/static/cedarFormat.pdf">16 bit integer based format</a> that evolved from the format used by the earlier incoherent scatter database, which in turn evolved from an earlier version of Madrigal developed at the MIT Haystack Observatory in 1980. </p>
46 46 <p>Haystack maintains and develops the Madrigal CEDAR database as an open-source project with community contributions. With the Madrigal CEDAR database, the site owner stores only their own data, which they can add to or update at any time. However, because the Madrigal database shares its metadata with all other Madrigal sites, users browsing any Madrigal site can search for data at any other Madrigal site. In addition, a central archival Madrigal site (<a href="http://cedar.openmadrigal.org" target="_self">cedar.openmadrigal.org</a>) archives all Madrigal sites and stores data not stored at other Madrigal sites.</p>
47 47 <p>Madrigal data are arranged into &quot;experiments&quot;, which may contain data files, images, documentation, links, etc. A key feature of Madrigal is its seamless integration of archival and real-time data. A realtime file on Madrigal is accessed in exactly the same way as any archival file.</p>
48 48 <p>Madrigal has been installed at numerous locations in addition to Millstone Hill, including EISCAT, SRI International, and Jicamarca. The inventories of experiments available at each installation are available to the other installations through shared metadata. New Madrigal sites can be automatically added at any time.</p>
49 49 <p>Madrigal is an open source project with a central <a href="http://cedar.openmadrigal.org/openmadrigal">developer's web site</a> and a <a href="http://atlas.haystack.mit.edu/cgi-bin/millstone_viewvc.cgi/openmadrigal/" target="_self">central repository</a>. A complete Subversion archive of all Madrigal software, including software which is not included with the standard distribution, is available at the developer's web site. There is also an Open Madrigal mailing list and developer's forum. Any group wishing to install Madrigal to distribute their instrument's data is welcome to - see the http://cedar.openmadrigal.org/openmadrigal web site for details. The <a href="http://atlas.haystack.mit.edu/cgi-bin/millstone_viewvc.cgi/openmadrigal/" target="_self">central repository</a> link is a place where all data from all Madrigal sites is archived. It can also be used to access data, although accessing the local sites is preferred.</p>
50 50 <!-- InstanceEndEditable -->
51 51 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
52 52 <tr>
53 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
54 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
55 <td width="5%"><a href="{% url 'docs' 'whatsNew.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
53 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/previous.png" alt="previous" width="32" height="32" /></a></td>
54 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/up.png" alt="up" width="32" height="32" /></a></td>
55 <td width="5%"><a href="{% url 'docs' 'whatsNew.html' %}"><img src="/madrigal/static/next.png" alt="next" width="32" height="32" /></a></td>
56 56 <td width="54%"><!-- InstanceBeginEditable name="EditTitleBottom" -->Brief overview of Madrigal <!-- InstanceEndEditable --></td>
57 57 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
58 58 <td width="18%"><a href="/">Madrigal home</a></td>
59 59 </tr>
60 60 </table>
61 61 <div class='online-navigation'>
62 62 <b class="navlabel">Previous:</b>
63 63 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="PreviousTitle2" -->Doc Home <!-- InstanceEndEditable --></A>
64 64 <b class="navlabel">&nbsp;&nbsp;Up:</b>
65 65 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle2" -->Doc home <!-- InstanceEndEditable --></A>
66 66 <b class="navlabel">&nbsp;&nbsp;Next:</b>
67 67 <a class="sectref" href="{% url 'docs' 'whatsNew.html' %}"><!-- InstanceBeginEditable name="NextTitle2" -->What's new in Madrigal 3.0? <!-- InstanceEndEditable --></A></div>
68 68 <hr/>
69 69 <p>&nbsp;</p>
70 70 </body>
71 71 <!-- InstanceEnd --></html>
@@ -1,50 +1,50
1 1 <div class="row" style="margin-bottom: 20px">
2 2 Select parameter: <br>
3 3 {{ form.param_list1d.label }}
4 4 {{ form.param_list1d }}
5 5 {% if form.param_list2d %}
6 6 {{ form.param_list2d.label }}
7 7 {{ form.param_list2d }}
8 8 {% endif %}
9 9
10 10 </div>
11 11
12 12 <script>
13 13 $('#id_param_list2d').bind('change', function (e) {
14 14 var expID = '{{ expID }}';
15 15 var param = $(this).val();
16 var url = '{% url 'plot' %}' + '?expID=' + expID + '&param2d=' + param;
16 var url = '{% url 'plot' %}' + '?expID=' + expID + '&param2d=' + param + '&filename=' + $('#id_file_list').val();
17 17 console.log(url)
18 18 // first delete all forms that are now out of date
19 19 divIndex = $(".single_form").index($( "#file_plot" ))
20 20 $(".single_form").slice(divIndex).empty()
21 21 // second populate the file_plot html if '0' not selected
22 22 if (param != '0') {
23 23 $(".single_form").slice(divIndex,divIndex+1).html("<img src=\"static/loader.gif\" class=\"load_center\"/>").load(url);
24 24 }
25 25 })
26 26 $('#id_param_list1d').bind('change', function (e) {
27 27 var expID = '{{ expID }}';
28 28 var param = $(this).val();
29 var url = '{% url 'plot' %}' + '?expID=' + expID + '&param1d=' + param;
29 var url = '{% url 'plot' %}' + '?expID=' + expID + '&param1d=' + param + '&filename=' + $('#id_file_list').val();
30 30 console.log(url)
31 31 // first delete all forms that are now out of date
32 32 divIndex = $(".single_form").index($( "#file_plot" ))
33 33 $(".single_form").slice(divIndex).empty()
34 34 // second populate the file_plot html if '0' not selected
35 35 if (param != '0') {
36 36 $(".single_form").slice(divIndex,divIndex+1).html("<img src=\"static/loader.gif\" class =\"load_center\"/>").load(url);
37 37 }
38 38 })
39 39 </script>
40 40 <style>
41 41 .load_center {
42 42 display: block;
43 43 margin-left: auto;
44 44 margin-right: auto;
45 45 margin-top: 100px;
46 46 margin-bottom: 100px;
47 47 width: 4%;
48 48 align-items: center;
49 49 }
50 </style> No newline at end of file
50 </style>
@@ -1,363 +1,363
1 1 {% load static %}
2 2
3 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 4 <html xmlns="http://www.w3.org/1999/xhtml"><!-- InstanceBegin template="/Templates/doc_template.dwt" codeOutsideHTMLIsLocked="false" -->
5 5 <head>
6 6 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
7 7 <!-- InstanceBeginEditable name="doctitle" -->
8 8 <title>What's new in Madrigal 3.2?</title>
9 9 <!-- InstanceEndEditable --><!-- InstanceBeginEditable name="head" --><!-- InstanceEndEditable -->
10 <link href="/static/madrigal.css" rel="stylesheet" type="text/css" />
10 <link href="/madrigal/static/madrigal.css" rel="stylesheet" type="text/css" />
11 11 <style type="text/css">
12 12 html body {
13 13 background-color: {{bg_color}};
14 14 }
15 15 </style>
16 16 <!-- InstanceParam name="href_up_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_top" type="text" value="wt_usersGuide.html" --><!-- InstanceParam name="href_back_top" type="text" value="madIntroduction.html" --><!-- InstanceParam name="href_back_bottom" type="text" value="madIntroduction.html" --><!-- InstanceParam name="href_up_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_next_bottom" type="text" value="wt_usersGuide.html" --><!-- InstanceParam name="href_prev_top" type="text" value="madIntroduction.html" --><!-- InstanceParam name="href_uptitle_top" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_top" type="text" value="wt_usersGuide.html" --><!-- InstanceParam name="href_prevtitle_bottom" type="text" value="madIntroduction.html" --><!-- InstanceParam name="href_uptitle_bottom" type="text" value="madContents.html" --><!-- InstanceParam name="href_nexttitle_bottom" type="text" value="wt_usersGuide.html" -->
17 17 </head>
18 18
19 19 <body>
20 20 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
21 21 <tr>
22 <td width="5%"><a href="{% url 'docs' 'madIntroduction.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'wt_usersGuide.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
22 <td width="5%"><a href="{% url 'docs' 'madIntroduction.html' %}"><img src="/madrigal/static/previous.png" alt="previous" width="32" height="32" /></a></td>
23 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/up.png" alt="up" width="32" height="32" /></a></td>
24 <td width="5%"><a href="{% url 'docs' 'wt_usersGuide.html' %}"><img src="/madrigal/static/next.png" alt="next" width="32" height="32" /></a></td>
25 25 <td width="54%"><!-- InstanceBeginEditable name="EditTitleTop" -->What's new in Madrigal 3.0? <!-- InstanceEndEditable --></td>
26 26 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
27 27 <td width="18%"><a href="/">Madrigal home</a></td>
28 28 </tr>
29 29 </table>
30 30 <div class='online-navigation'>
31 31 <b class="navlabel">Previous:</b>
32 32 <a class="sectref" href="{% url 'docs' 'madIntroduction.html' %}"><!-- InstanceBeginEditable name="PreviousTitle" -->Brief History <!-- InstanceEndEditable --></A>
33 33 <b class="navlabel">&nbsp;&nbsp;Up:</b>
34 34 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle" -->Doc home <!-- InstanceEndEditable --></A>
35 35 <b class="navlabel">&nbsp;&nbsp;Next:</b>
36 36 <a class="sectref" href="{% url 'docs' 'wt_usersGuide.html' %}"><!-- InstanceBeginEditable name="NextTitle" -->Madrigal user's guide <!-- InstanceEndEditable --></A></div>
37 37 <hr/>
38 38 <!-- InstanceBeginEditable name="EditDoc" -->
39 39
40 40 <h1 align="center">What's new in Madrigal 3.2.2?</h1>
41 41 <h1 align="center" style="text-align: left">Madrigal 3.2.2 Release - Jan 2021</h1>
42 42 <p align="center" style="text-align: left">Fixed bug in linking to external data using the Select Single Experiment user interface. </p>
43 43
44 44
45 45 <h1 align="center">What's new in Madrigal 3.2.1?</h1>
46 46 <h1 align="center" style="text-align: left">Madrigal 3.2.1 Release - Nov 2020</h1>
47 47 <h2 align="center" style="text-align: left">Allows Madrigal to create citations to groups of files</h2>
48 48 <p align="center" style="text-align: left">With Madrigal 3.2.1, users can use the API to create citations to groups of files, and can display those groups with that citation. </p>
49 49
50 50
51 51 <h1 align="center">What's new in Madrigal 3.1.1?</h1>
52 52 <h1 align="center" style="text-align: left">Madrigal 3.1.1 Release - Nov 2019</h1>
53 53 <h2 align="center" style="text-align: left">Allows Madrigal to run using https</h2>
54 54 <p align="center" style="text-align: left">With Madrigal 3.1.1, the code is compatable with https. Instructions are given to install or convert Madrigal to https. </p>
55 55
56 56 <h1 align="center">What's new in Madrigal 3.1?</h1>
57 57 <h1 align="center" style="text-align: left">Madrigal 3.1 Release - Oct 2019</h1>
58 58 <h2 align="center" style="text-align: left">Conversion to Python 3</h2>
59 59 <p align="center" style="text-align: left">With Madrigal 3.1, all python code has been updated to use python 3 instead of python 2. The functionality is unchanged from Madrigal 3.0.</p>
60 60
61 61 <h1 align="center" style="text-align: left">Madrigal 3.0 Release - Sept 2017</h1>
62 62 <blockquote>
63 63 <h2 align="center" style="text-align: left">Migration to Hdf5 file format</h2>
64 64 <p align="center" style="text-align: left">With Madrigal 3.0, the old 16 bit integer based file format has been replaced with Hdf5. However, all the data model and well-defined parameters have been retained. The CEDAR Hdf5 format is designed to be completely self-contained. That is, any user with an Hdf5 reader can fully understand all data in the file without any reference to documentation. A full description of the format can be found <a href="/static/CEDARMadrigalHdf5Format.pdf">here</a>.</p>
65 65 <h2 align="center" style="text-align: left">Web interface generates scripts to download any amount of data</h2>
66 66 <p align="center" style="text-align: left">With Madrigal 3, you can generate a script command to download a whole series of files with a few click. You can also create a script that will filter those same files and allow you to choose the parameters you want, again with just a few clicks. These scripts can be run with python, Matlab, or IDL.</p>
67 67 <h2 align="center" style="text-align: left">Download files in a new format</h2>
68 68 <p align="center" style="text-align: left">Prior to Madrigal 3, files could be downloaded only as ascii or Hdf5 (or the difficult to understand CEDAR format). Now they can be downloaded as ascii, Hdf5, or netCDF4.</p>
69 69 <h2 align="center" style="text-align: left">Get data with selected/derived parameters and filters in new formats</h2>
70 70 <p align="center" style="text-align: left">Prior to Madrigal 3, data with selected/derived parameters and filters was available
71 71 only as ascii. Now it can be downloaded as ascii, Hdf5, or netCDF4.</p>
72 72 <h2 align="center" style="text-align: left">Independent spatial parameters now built in to data model</h2>
73 73 <p align="center" style="text-align: left">Prior to Madrigal 3.0, there was no way to automatically tell what the independent spatial parameters were in vector data. With Madrigal 3.0, any data with vector data must define its independent spatial parameters, which can be found in the Hdf5 Metadata group. This allows Madrigal to automatically add array layouts of the data, making for easier plotting.</p>
74 74 <h2 align="center" style="text-align: left">All new web interface</h2>
75 75 <p align="center" style="text-align: left">A much simplified web interface based on Django and bootstrap. Developed with much assistance from Jicamarca Observatory and Jose Antonio Sal y Rosas Celi.</p>
76 76 <h2 align="center" style="text-align: left">Simple FTP-like web interface added</h2>
77 77 <p align="center" style="text-align: left">Designed for non-native English speakers. The url follows a very simple pattern that can be easily parsed if the user in unable to understand the Madrigal API's and automatically generated scripts.</p>
78 78 <h2 align="center" style="text-align: left">Create CEDAR Hdf5 files with either Matlab or python</h2>
79 79 <p align="center" style="text-align: left">Prior to Madrigal 3, there was only a python API to easily create Madrigal files. Now both Matlab and python can be used to create CEDAR Hdf5 files.</p>
80 80 <h2 align="center" style="text-align: left">All metadata easily accessible</h2>
81 81 <p align="center" style="text-align: left">The <em>Access metadata</em> menu item on the main navigation menu allows easy access to all Madrigal CEDAR metadata, including Madrigal sites, instruments, parameter definitions, and kind of data codes.</p>
82 82 </blockquote>
83 83 <h1>Madrigal 2.6.3.2 Release - March 22, 2012</h1>
84 84 <p>Added support to file download cgi scripts to allow logging of remote API requests to download files.</p>
85 85 <h1>Madrigal 2.6.3.1 Release - March 13, 2012</h1>
86 86 <p>Added popup javascript window to warn users not to click &quot;Download File&quot; button multiple times.</p>
87 87 <h1>Madrigal 2.6.3 Release - Febuary 27, 2012</h1>
88 88 <p>Small bug fixes in 3 cgi scripts affecting plots: madExperiment.cgi, madDataDisplay, getMadplot.py</p>
89 89 <h1>Madrigal 2.6.2 Release - Febuary 8, 2012</h1>
90 90 <p>Small bug fix involving creating Hdf5 export files in data.py.</p>
91 91 <h1>Madrigal 2.6.1 Release - January 20, 2012</h1>
92 92 <p>Small bug fix involving a memory leak in _Madrec.c and a rare problem creating Hdf5 export files in data.py. </p>
93 93 <h1>Madrigal 2.6 Release - November 2011 </h1>
94 94 <blockquote>
95 95 <h2>New simple local web user interface </h2>
96 96 <p>A new easy to use interface to access local Madrigal data was developed by Jicamarca with support from Millstone Hill staff. This interface in now very robust and has been tested with data from all Madrigal sites.</p>
97 97 <h2>HDF5 file download availablity</h2>
98 98 <p>Users can now download data files as HDF5, in addition to simple column delimited ascii and the more complex <a href="/static/cedarFormat.pdf" target="_self">CEDAR formats</a>. This is also the result of a Jicamarca/Millstone Hill collaborations.</p>
99 99 <h2>Users can register interest in experiments or instruments</h2>
100 100 <p>Users can now register interest in experiments or instruments, and get emails whenever that Madrigal experiment or instrument is updated.</p>
101 101 <h2>Administrative improvements - can now add external disks to experiments</h2>
102 102 <p>It is now easy to expand the Madrigal database by <a href="ad_other.html#experiments" target="_self">mounting additional hard disks</a> to make more room for data.</p>
103 103 <h2>New metadata - experiment PI's and analyst</h2>
104 104 <p>Experiments now have direct email links to the experiment PI. These PI's can be updated on an experiment or intrument basis.</p>
105 105 <h2>Global seach now more robust</h2>
106 106 <p>The global search UI now generates scripts so you can run the global search right from your computer using either the <a href="rt_python.html" target="_self">python remote API</a>, the <a href="rt_matlab.html" target="_self">Matlab remote API</a>, or the<a href="rt_idl.html" target="_self"> IDL remote API</a>.</p>
107 107 <p>&nbsp;</p>
108 108 </blockquote>
109 109 <hr />
110 110 <p>&nbsp;</p>
111 111 <h1>Madrigal 2.5.2 Release - May 2009</h1>
112 112 <blockquote>
113 113 <p>A bug fix release - no new features. </p>
114 114 </blockquote>
115 115 <h1>Madrigal 2.5.1 Release - March 2009</h1>
116 116 <blockquote>
117 117 <p>This minor revision to Madrigal 2.5 was needed to support using Madrigal as an archiving database. The experiment metadata was expanded to allow archived experiments. Archived experiments are not shared between Madrigal sites, but are visible as local experiments. </p>
118 118 </blockquote>
119 119 <h1>Madrigal 2.5 Release - February 2009 </h1>
120 120 <blockquote>
121 121 <h2>Simplification of Web User Interface </h2>
122 122 <p>Both the Browse for Individual Madrigal Experiments and the Global Madrigal Database Report web interface have been simplified. Searching for instruments under Browse for Individual Madrigal Experiments is now easier through the use of an instrument category selector.</p>
123 123 <h2>One step file printing available</h2>
124 124 <p>Under Browse for Individual Madrigal Experiments, users can now choose to print an ascii version of any Madrigal file with one click. With this option they can not include any derived parameters or data filters.</p>
125 125 <h2>Installation simplified </h2>
126 126 <p>Autotools is now used to compile all code, significantly reducing the number of parameters in the madrigal.cfg configuration file.</p>
127 127 <h2>64-bit tested </h2>
128 128 <p>Madrigal has now been fully tested as a 64-bit application. It is important that all Madrigal installations switch to 64-bit machines by the year 2037, because 32-bit unix cannot handle dates beyond then.</p>
129 129 <h2>International Reference Ionosphere (IRI) derived parameters now available</h2>
130 130 <p>All parameters calculated by the International Reference Ionosphere (IRI) model can now be selected as derived parameters.</p>
131 131 <h2>Additional automatic sharing of metadata added</h2>
132 132 <p>For administrators: Now when new sites or instruments are added to Madrigal, these metadata files are automatically added to your site. </p>
133 133 <h2>Experiment level security</h2>
134 134 <p>Previously, individual Madrigal files could be made public or private. Now entire experiments can be made public, private, or hidden altogether. See the script <a href="ad_createExp.html#changeExpStatus">changeExpStatus.py</a> for details. </p>
135 135 <h2>Experiment directory naming convention modified </h2>
136 136 <p>Previous to Madrigal 2.5, all Madrigal experiments had to be stored in directory paths in the form:</p>
137 137 <pre>$MADROOT/experiments/YYYY/&lt;3 letter inst mnemonic&gt;/ddMMMyy[letter],
138 138 Example: /opt/madrigal/experiments/1998/mlh/20jan98b.</pre>
139 139 <p>Under this convention, the date of the directory name represented the start date of the experiment, with one letter optionally added. This meant there was a limited number of experiments that could be created for a particular day for a particular experiment. This part of the directory naming convention has been dropped, and now the convention is:</p>
140 140 <pre>$MADROOT/experiments/YYYY/&lt;3 letter inst mnemonic&gt;/*,
141 141 Example: /opt/madrigal/experiments/1998/mlh/mlh_exp_234.
142 142 </pre>
143 143 </blockquote>
144 144
145 145 <hr />
146 146 <h1>Madrigal 2.4 Release - February 2006 </h1>
147 147 <blockquote>
148 148 <h2>Simple web UI added</h2>
149 149 <p>A new web user-interface has been added that allows easy printing and plotting of basic Madrigal data. To make it easy to use, advanced Madrigal features such as derived parameters and filtering of data have been removed.</p>
150 150 <h2>On-demand plot creation</h2>
151 151 <p>Madrigal now allows users to create basic scatter plots and pcolor plots versus range or altitude of any measured or derived parameter in a data set.</p>
152 152 <h2>Logging of user data access</h2>
153 153 <p>Madrigal now <a href="ad_logging.html">logs user's names, emails, and affiliations</a> whenever data files are directly accessed in a file administrators can access. </p>
154 154 <h2>Automatic updating of all geophysical data</h2>
155 155 <p>Madrigal now automatically updates all its internal geophysical files (e.g., Kp, Fof2, Dst, Imf, etc) every time updateMaster is run. </p>
156 156 <h2>Simple-to-use python module to create and edit Madrigal files</h2>
157 157 <p>There is now a <a href="ad_createFiles.html#python">simple-to-use python module</a> to create and edit Madrigal files. </p>
158 158 <h2>New administrative scripts to manage Madrigal experiments</h2>
159 159 <p>Administrators can now add or modify all Madrigal experiments using <a href="ad_createExp.html">simple administrative scripts</a>, instead of trying to edit Madrigal metadata files themselves or use the complex genExp script. </p>
160 160 <h2>Complete documentation rewrite</h2>
161 161 <p>Madrigal documentation has now been completely rewritten and reorganized into three manuals: one for <a href="wt_usersGuide.html">users</a>, one for <a href="admin.html">administrators</a>, and one for <a href="dev_contents.html">developers</a>. </p>
162 162 <h2>Automatic graphics conversion</h2>
163 163 <p>Madrigal will now allow users to select any graphics format they prefer for <a href="ad_createExp.html#auxillary">graphics administrators place in experiments</a>. This feature was contributed by Eiscat. </p>
164 164 <h2>Update of IGRF/MSIS</h2>
165 165 <p>The Madrigal derivation engine is now using the <a href="http://www.ngdc.noaa.gov/IAGA/vmod/igrf.html">IGRF 2010 coefficients</a>, and the <a href="https://omniweb.gsfc.nasa.gov/vitmo/msis_vitmo.html">MSIS 2000 model</a>. </p>
166 166 <h2>Limiting of disk space used for global search files</h2>
167 167 <p>Administrators can now limit the maximum amount of disk space used to store temporary global search files. See the section on editing the madrigal.cfg file in the installation guide. </p>
168 168 </blockquote>
169 169 <p>&nbsp;</p>
170 170 <hr />
171 171 <p>&nbsp;</p>
172 172 <h1>Madrigal 2.3 Release - March 2004</h1>
173 173
174 174 <blockquote>
175 175 <h2>Remote programming access to Madrigal via web services using any platform</h2>
176 176 <p>Madrigal now exposes all the information and capabilities it has as web services, which allows
177 177 easy access to Madrigal from any computer on the internet using any platform (Unix, Windows, Mac, etc).
178 178 Madrigal's web services are basically cgi scripts with simple output that allows easy parsing of the
179 179 information. Any language that supports the HTTP standard can then access any Madrigal site. We have
180 180 written remote API's using python and Matlab, but almost any language could be used. See the section
181 181 on <a href="{% url 'docs' 'rt_contents.html' %}">remote programming access</a> for details of these APIs and the underlying web services.</p>
182 182 <p>Note that this approach of remotely accessing Madrigal data has been always possible before by parsing the
183 183 html output meant to be displayed in a web browser (this general programming method is referred to as "screen
184 184 scraping"). However, not only is this parsing difficult; but the code often breaks when the user interface
185 185 is modified in any way. With web services the returned cgi scripts are designed to be both simple to parse
186 186 and stable.</p>
187 187 <p>The web services are not implemented according to the SOAP or XMLRPC standard since not all scripting
188 188 languages have support for these standards (or for XML parsing). Instead they use the simple approach
189 189 of returning data requested via a query as a delimited text file. These web services are fully
190 190 documented <a href="{% url 'docs' 'rt_webServices.html' %}">here.</a></p>
191 191 <p>Users who want only to write programs to remotely access Madrigal, and not to install a Madrigal server
192 192 themselves, are now able to <a href="http://www.haystack.mit.edu/madrigal/madDownload.html"> download </a>
193 193 the remote python and Matlab API's from the
194 194 <a href="http://www.openmadrigal.org">OpenMadrigal</a> site.</p>
195 195 <h2> Command-line global search</h2>
196 196 <p>As an example of remote programming access to Madrigal via web services, an application
197 197 <a href="rt_python.html#globalIsprint">globalIsprint</a> was written
198 198 using the python remote API that does a global search of data on any Madrigal site that has installed Madrigal version
199 199 2.3. This application is installed as part of Madrigal, and also when the standalone remote python
200 200 API is installed. It has all the filtering ability of the web-based global search.</p>
201 201 <h2>Calculate any derivable Madrigal parameter for any time and point(s) in space</h2>
202 202 <p>By clicking on "Run Models", users can calculate any derived Madrigal parameter (such as magnetic fields,
203 203 or geophysical parameters) for arbitrary times and ranges of position. Note that this capability is also
204 204 available as a web service, and through the remote python and Matlab API's.</p>
205 205 <h2>New derived parameters</h2>
206 206 <ul>
207 207 <li>
208 208 CGM_LAT: <b>Corrected geomagnetic latitude</b> (deg) <br>
209 209 This parameter gives the location of a point in Corrected geomagnetic latitude.
210 210 This method uses code developed by Vladimir Papitashvili. For more information on CGM coordinates
211 211 and this code, click <a href="https://omniweb.gsfc.nasa.gov/vitmo/cgmm_des.html"> here.</a></li>
212 212 <li>
213 213 CGM_LONG: <b>Corrected geomagnetic longitude</b> (deg) <br>
214 214 This parameter gives the location of a point in Corrected geomagnetic longitude.
215 215 This method uses code developed by Vladimir Papitashvili. For more information on CGM coordinates
216 216 and this code, click <a href="https://omniweb.gsfc.nasa.gov/vitmo/cgmm_des.html"> here.</a></li>
217 217 <li>
218 218 TSYG_EQ_XGSM: <b>Tsyganenko field GSM XY plane X point</b> (earth radii) <br>
219 219 This parameter gives the X value in GSM coordinates of where the field line associated
220 220 with a given input point in space and time crosses the GSM XY plane (the magnetic equatorial plane). GSM stands for
221 221 Geocentric Solar Magnetospheric System, and its XY plane is the equatorial plane of
222 222 the earth's magnetic dipole field. The field lines are traced using the
223 223 Tsyganenko
224 224 Magnetospheric model, so external effects on the earth's magnetic field such the solar wind are
225 225 taken into account. This code uses the 2001 Tsyganenko model, which averages solar wind values
226 226 over the past hour, instead of simply using present values.</li>
227 227 <li> TSYG_EQ_YGSM: <b>Tsyganenko field GSM XY plane Y point</b> (earth radii) <br>
228 228 This parameter gives the Y value in GSM coordinates of where the field line associated
229 229 with a given input point in space and time crosses the GSM XY plane (the magnetic equatorial plane). GSM stands for
230 230 Geocentric Solar Magnetospheric System, and its XY plane is the equatorial plane of
231 231 the earth's magnetic dipole field. The field lines are traced using the Tsyganenko
232 232 Magnetospheric model, so external effects on the earth's magnetic field such the solar wind are
233 233 taken into account. This code uses the 2001 Tsyganenko model, which averages solar wind values
234 234 over the past hour, instead of simply using present values.</li>
235 235 <li> TSYG_EQ_XGSM: <b>Tsyganenko field GSE XY plane X point</b> (earth radii) <br>
236 236 This parameter gives the X value in GSE coordinates of where the field line associated
237 237 with a given input point in space and time crosses the GSE XY plane (the equatorial plane). GSE stands for
238 238 Geocentric Solar Ecliptic System, and its XY plane is the equatorial plane of
239 239 the earth's rotation. The field lines are traced using the Tsyganenko
240 240 Magnetospheric model, so external effects on the earth's magnetic field such the solar wind are
241 241 taken into account. This code uses the 2001 Tsyganenko model, which averages solar wind values
242 242 over the past hour, instead of simply using present values.</li>
243 243 <li> TSYG_EQ_YGSM: <b>Tsyganenko field GSE XY plane Y point</b> (earth radii) <br>
244 244 This parameter gives the Y value in GSE coordinates of where the field line associated
245 245 with a given input point in space and time crosses the GSE XY plane (the equatorial plane). GSE stands for
246 246 Geocentric Solar Ecliptic System, and its XY plane is the equatorial plane of
247 247 the earth's rotation. The field lines are traced using the Tsyganenko
248 248 Magnetospheric model, so external effects on the earth's magnetic field such the solar wind are
249 249 taken into account. This code uses the 2001 Tsyganenko model, which averages solar wind values
250 250 over the past hour, instead of simply using present values.</li>
251 251 <li> BHHMMSS and EHHMMSS: <b>Start and end time in HHMMSS</b> (suggested by Mary McCready at SRI)</li>
252 252 </ul>
253 253 <h2>Bug fixes</h2>
254 254 <p>The Madrigal C API now no longer aborts when a Cedar file contains cycle marks (Cedar
255 255 parameter 95) that are not in order. (Reported by Angela Li, SRI)</p>
256 256 <p>A problem launching the global search with the python module os.spawnlp was fixed.
257 257 (Reported by Angela Li, SRI)</p>
258 258 </blockquote>
259 259 <p>&nbsp;</p>
260 260 <hr></hr>
261 261 <h1>
262 262 Madrigal 2.2 Release - Feb 2003</h1>
263 263
264 264
265 265 <blockquote>
266 266 <h2>New derived parameters</h2>
267 267 <ul>
268 268 <li>
269 269 SUNRISE_HOUR - <b>Ionospheric sunrise</b> (hour)<br>
270 270 This parameter gives the hour UT that sunrise occurs at that particular
271 271 point in space that particular day. If that point in space is either in sunlight or in shadow
272 272 the entire UT day, sunrise_hour will be missing. To find out which, display the
273 273 Shadow height (SDWHT) parameter. If shadow height is less that the altitude of the
274 274 point, its in sunlight; if shadow height is greater than the altitude, its in the earth's shadow.</li>
275 275 <li>SUNSET_HOUR - <b>Ionospheric sunset</b> (hour)<br>
276 276 This parameter gives the hour UT that sunset occurs at that particular
277 277 point in space that particular day. If that point in space is either in sunlight or in shadow
278 278 the entire UT day, sunset_hour will be missing. To find out which, display the
279 279 Shadow height (SDWHT) parameter. If shadow height is less that the altitude of the
280 280 point, its in sunlight; if shadow height is greater than the altitude, its in the earth's shadow.</li>
281 281 <li>CONJ_SUNRISE_H - <b>Magnetic conjugate point sunrise</b> (hour)<br>
282 282 This parameter gives the hour UT that sunrise occurs at the magnetic conjugate point of the particular
283 283 point in space that particular day.</li>
284 284 <li>CONJ_SUNSET_H - <b>Magnetic conjugate point sunset</b> (hour)<br>
285 285 This parameter gives the hour UT that sunset occurs at the magnetic conjugate point of the particular
286 286 point in space that particular day.</li>
287 287 <li>SZEN - <b>Solar zenith angle in measurement vol</b> (deg) <br>
288 288 This parameter gives the solar zenith angle in degrees. If 0 degrees, the sun is directly
289 289 overhead. A solar zenith angle of between 90 and 180 degrees does not mean the sun is not
290 290 visible, due to the finite solid angle of the sun and the altitude the point may be above the
291 291 earth's surface.</li>
292 292 <li>SZENC - <b>Conjugate solar zenith angle</b> (deg) <br>
293 293 This parameter gives the solar zenith angle at the magnetic conjugate point in degrees.</li>
294 294 <li>SDWHT - <b>Shadow height</b> (km) <br>
295 295 This parameter gives the height above the earth's surface at which any part of the sun can be seen. It depends only
296 296 on the time, and on the geodetic latitude and longitude. During the day shadow height will be zero. Since the sun is
297 297 larger than the earth, the shadow height is always finite. If shadow height is less that the altitude of a given
298 298 point in space, its in sunlight; if shadow height is greater than the altitude, its in the earth's shadow.</li>
299 299 <li>MAGCONJSDWHT - <b>Magnetic conjugate shadow height</b> (km) <br>
300 300 This parameter gives the height above the earth's surface at the magnetic conjugate point's latitude and longitude at
301 301 which any part of the sun can be seen. </li>
302 302 <li><b>10 Interplanetary Magnetic Field parameters</b><br>
303 303 Includes field strength in GSM or GSE coordinates, solar wind plasma density, speed, and measuring satellite id.
304 304 Click on any parameter to see the definition of the two coordinate systems.</li>
305 305 </ul>
306 306 <h2>Filtering using any parameter</h2>
307 307 <ul>
308 308 <li>There are now also free-form filters at the end
309 309 of the filter section, which allow you to set up filters based on any
310 310 single parameter or on two parameters either added,
311 311 subtracted, multiplied, or divided together. For example, you can now filter on
312 312 Ti, the ratio Ti/dTi, or gdalt-sdwht (which is positive if the point is in sunlight).
313 313 See the tutorial for more details.</li>
314 314 </ul>
315 315 <h2>Better help understanding what each parameter means</h2>
316 316 <ul>
317 317 <li>Complex parameters now have full html descriptions accessible from the isprint page.
318 318 Just click on the parameter name and you'll see the short description. For more complex
319 319 parameters you'll also see a link to a more detailed explanation.</li>
320 320 </ul>
321 321 <h2>Improved data output</h2>
322 322 <ul>
323 323 <li>If you select only 1D parameters, or derived parameters that depend only on other 1D parameters,
324 324 isprint will only print a single line per record, making it easier to read.</li>
325 325 <li>All filters used are printed at the beginning of the report. Trivial filters that don't exclude
326 326 data (such as elevation from 0 to 90 degrees) are ignored.</li>
327 327 </ul>
328 328 <h2>Better consistency with Cedar standard</h2>
329 329 <ul>
330 330 <li>All units are now consistent with the Cedar standard (when displaying Cedar parameters).</li>
331 331 <li>The special Cedar values "missing", "assumed", and "known bad" are differentiated in isprint output,
332 332 and not all lumped together as "missing" as before.</li>
333 333 <li>Unknown parameter codes displayed with a scale factor of 1.0.</li>
334 334 </ul>
335 335 <h2>New derived parameters are simple to add</h2>
336 336 <ul>
337 337 <li>The isprint web page is now based on the madc library, and has been designed to
338 338 make it extremely simple to add new derived parameters. See the
339 339 madc API documentation for details.</li>
340 340 </ul>
341 341 </blockquote>
342 342 <!-- InstanceEndEditable -->
343 343 <table width="100%" border="1" cellpadding="0" cellspacing="2" class="navigation">
344 344 <tr>
345 <td width="5%"><a href="{% url 'docs' 'madIntroduction.html' %}"><img src="/static/previous.png" alt="previous" width="32" height="32" /></a></td>
346 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/static/up.png" alt="up" width="32" height="32" /></a></td>
347 <td width="5%"><a href="{% url 'docs' 'wt_usersGuide.html' %}"><img src="/static/next.png" alt="next" width="32" height="32" /></a></td>
345 <td width="5%"><a href="{% url 'docs' 'madIntroduction.html' %}"><img src="/madrigal/static/previous.png" alt="previous" width="32" height="32" /></a></td>
346 <td width="5%"><a href="{% url 'docs' 'madContents.html' %}"><img src="/madrigal/static/up.png" alt="up" width="32" height="32" /></a></td>
347 <td width="5%"><a href="{% url 'docs' 'wt_usersGuide.html' %}"><img src="/madrigal/static/next.png" alt="next" width="32" height="32" /></a></td>
348 348 <td width="54%"><!-- InstanceBeginEditable name="EditTitleBottom" -->What's new in Madrigal 3.0?<!-- InstanceEndEditable --></td>
349 349 <td width="13%"><a href="{% url 'docs' 'madContents.html' %}">Doc home </a></td>
350 350 <td width="18%"><a href="/">Madrigal home</a></td>
351 351 </tr>
352 352 </table>
353 353 <div class='online-navigation'>
354 354 <b class="navlabel">Previous:</b>
355 355 <a class="sectref" href="{% url 'docs' 'madIntroduction.html' %}"><!-- InstanceBeginEditable name="PreviousTitle2" -->Brief History <!-- InstanceEndEditable --></A>
356 356 <b class="navlabel">&nbsp;&nbsp;Up:</b>
357 357 <a class="sectref" href="{% url 'docs' 'madContents.html' %}"><!-- InstanceBeginEditable name="UpTitle2" -->Doc home <!-- InstanceEndEditable --></A>
358 358 <b class="navlabel">&nbsp;&nbsp;Next:</b>
359 359 <a class="sectref" href="{% url 'docs' 'wt_usersGuide.html' %}"><!-- InstanceBeginEditable name="NextTitle2" -->Madrigal user's guide <!-- InstanceEndEditable --></A></div>
360 360 <hr/>
361 361 <p>&nbsp;</p>
362 362 </body>
363 363 <!-- InstanceEnd --></html>
@@ -1,242 +1,241
1 1 '''
2 2 Created on Jul 16, 2013
3 3
4 4 @author: Jose Antonio Sal y Rosas Celi
5 5 @contact: arturo.jasyrc@gmail.com
6 6
7 7 As imported and slightly modified by Bill Rideout Jan 20, 2015
8 8
9 9 $Id: urls.py 7246 2020-10-12 14:54:26Z brideout $
10 10 '''
11 11
12 12 from django.conf.urls import url
13 13 from . import views
14 14
15 15 urlpatterns = [ url(r'^$',
16 16 views.index,
17 17 name='index'),
18 18 url(r'^index.html/?$',
19 19 views.index,
20 20 name='index'),
21 21 url(r'^single/?$',
22 22 views.check_registration(views.view_single),
23 23 name='view_single'),
24 24 url(r'^register/?$',
25 25 views.view_registration,
26 26 name='view_registration'),
27 27 url(r'^getCategories/?$',
28 28 views.get_categories,
29 29 name='get_categories'),
30 30 url(r'^getInstruments/?$',
31 31 views.get_instruments,
32 32 name='get_instruments'),
33 33 url(r'^getYears/?$',
34 34 views.get_years,
35 35 name='get_years'),
36 36 url(r'^getMonths/?$',
37 37 views.get_months,
38 38 name='get_months'),
39 39 url(r'^getCalendar/?$',
40 40 views.get_calendar,
41 41 name='get_calendar'),
42 42 url(r'^populateCalendarExperiment/?$',
43 43 views.populate_calendar_experiment,
44 44 name='populate_calendar_experiment'),
45 45 url(r'^getFiles/?$',
46 46 views.get_files,
47 47 name='get_files'),
48 48 url(r'^changeFiles/?$',
49 49 views.change_files,
50 50 name='change_files'),
51 51 url(r'^showPlots/?$',
52 52 views.show_plots,
53 53 name='show_plots'),
54 54 url(r'^view_plot/?$',
55 55 views.view_plot,
56 56 name='plot'),
57 57 url(r'^downloadAsIs/?$',
58 58 views.download_as_is,
59 59 name='download_as_is'),
60 60 url(r'^downloadFileAsIs/?$',
61 61 views.download_file_as_is,
62 62 name='download_file_as_is'),
63 63 url(r'^printAsIs/?$',
64 64 views.print_as_is,
65 65 name='print_as_is'),
66 66 url(r'^listRecords/?$',
67 67 views.list_records,
68 68 name='list_records'),
69 69 url(r'^showInfo/?$',
70 70 views.show_info,
71 71 name='show_info'),
72 72 url(r'^showDoi/?$',
73 73 views.show_doi,
74 74 name='show_doi'),
75 75 url(r'^getAdvanced/?$',
76 76 views.get_advanced,
77 77 name='get_advanced'),
78 78 url(r'^advancedDownload/?$',
79 79 views.advanced_download,
80 80 name='advanced_download'),
81 81 url(r'^advancedPrint/?$',
82 82 views.advanced_print,
83 83 name='advanced_print'),
84 84 url(r'^list/?$',
85 85 views.check_registration(views.view_list),
86 86 name='view_list'),
87 87 url(r'^downloadAsIsScript/?$',
88 88 views.download_as_is_script,
89 89 name='download_as_is_script'),
90 90 url(r'^generateDownloadFilesScript/?$',
91 91 views.generate_download_files_script,
92 92 name='generate_download_files_script'),
93 93 url(r'^downloadAdvancedScript/?$',
94 94 views.download_advanced_script,
95 95 name='download_advanced_script'),
96 96 url(r'^generateDownloadAdvancedScript/?$',
97 97 views.generate_download_advanced_script,
98 98 name='generate_download_advanced_script'),
99 99 url(r'^generateParmsScript/?$',
100 100 views.generate_parms_script,
101 101 name='generate_parms_script'),
102 102 url(r'^generateParmsFiltersScript/?$',
103 103 views.generate_parms_filters_script,
104 104 name='generate_parms_filters_script'),
105 105 url(r'^listExperiments/?$',
106 106 views.list_experiments,
107 107 name='list_experiments'),
108 108 url(r'^viewRecordPlot/?$',
109 109 views.view_record_plot,
110 110 name='view_record_plot'),
111 111 url(r'^viewRecordImage/?$',
112 112 views.view_record_image,
113 113 name='view_record_image'),
114 114 url(r'^showExperiment/?$',
115 115 views.check_registration(views.show_experiment),
116 116 name='show_experiment'),
117 117 url(r'^madExperiment.cgi/*$',
118 118 views.check_registration(views.show_experiment_v2),
119 119 name='show_experiment_v2'),
120 120 url(r'^chooseScript/?$',
121 121 views.check_registration(views.choose_script),
122 122 name='choose_script'),
123 123 url(r'^ftp/$',
124 124 views.check_registration(views.ftp),
125 125 name='ftp'),
126 126 url(r'^ftp/fullname/([^/]+)/email/([^/]+)/affiliation/([^/]+)/kinst/(\d+)/$',
127 127 views.ftp_instrument,
128 128 name='ftp_instrument'),
129 129 url(r'^ftp/fullname/([^/]+)/email/([^/]+)/affiliation/([^/]+)/kinst/(\d+)/year/(\d+)/$',
130 130 views.ftp_year,
131 131 name='ftp_year'),
132 132 url(r'^ftp/fullname/([^/]+)/email/([^/]+)/affiliation/([^/]+)/kinst/(\d+)/year/(\d+)/kindat/(\d+)/$',
133 133 views.ftp_kindat,
134 134 name='ftp_kindat'),
135 135 url(r'^ftp/fullname/([^/]+)/email/([^/]+)/affiliation/([^/]+)/kinst/(\d+)/year/(\d+)/kindat/(\d+)/format/([^/]+)/$',
136 136 views.ftp_files,
137 137 name='ftp_files'),
138 138 url(r'^ftp/fullname/([^/]+)/email/([^/]+)/affiliation/([^/]+)/kinst/(\d+)/year/(\d+)/kindat/(\d+)/format/([^/]+)/fullFilename/([^/]+)/$',
139 139 views.ftp_download,
140 140 name='ftp_download'),
141 141 url(r'ftpMultipleDownload/$',
142 142 views.ftp_multiple_download,
143 143 name='ftp_multiple_download'),
144 144 url(r'^instMetadata/?$',
145 145 views.instrument_metadata,
146 146 name='instrument_metadata'),
147 147 url(r'^siteMetadata/?$',
148 148 views.site_metadata,
149 149 name='site_metadata'),
150 150 url(r'^parameterMetadata/?$',
151 151 views.parameter_metadata,
152 152 name='parameter_metadata'),
153 153 url(r'^kindatMetadata/?$',
154 154 views.kindat_metadata,
155 155 name='kindat_metadata'),
156 156 url(r'^madCalculator/?$',
157 157 views.madrigal_calculator,
158 158 name='madrigal_calculator'),
159 159 url(r'^madCalculatorOutput/?$',
160 160 views.madrigal_calculator_output,
161 161 name='madrigal_calculator_output'),
162 162 url(r'^getMetadata/*$',
163 163 views.get_metadata,
164 164 name='get_metadata'),
165 165 url(r'^looker/?$',
166 166 views.looker_main,
167 167 name='looker_main'),
168 168 url(r'^lookerForm/?$',
169 169 views.looker_form,
170 170 name='looker_form'),
171 171 url(r'^lookerOutput/?$',
172 172 views.looker_output,
173 173 name='looker_output'),
174 174 url(r'^getVersionService.py/*$',
175 175 views.get_version_service,
176 176 name='get_version_service'),
177 177 url(r'^getInstrumentsService.py/*$',
178 178 views.get_instruments_service,
179 179 name='get_instruments_service'),
180 180 url(r'^getExperimentsService.py/*$',
181 181 views.get_experiments_service,
182 182 name='get_experiments_service'),
183 183 url(r'^getExperimentFilesService.py/*$',
184 184 views.get_experiment_files_service,
185 185 name='get_experiment_files_service'),
186 186 url(r'^getParametersService.py/*$',
187 187 views.get_parameters_service,
188 188 name='get_parameters_service'),
189 189 url(r'^isprintService.py/*$',
190 190 views.isprint_service,
191 191 name='isprint_service'),
192 192 url(r'^getMadfile.cgi/*$',
193 193 views.get_madfile_service,
194 194 name='get_madfile_service'),
195 195 url(r'^madCalculatorService.py/*$',
196 196 views.mad_calculator_service,
197 197 name='mad_calculator_service'),
198 198 url(r'^madTimeCalculatorService.py/*$',
199 199 views.mad_time_calculator_service,
200 200 name='mad_time_calculator_service'),
201 201 url(r'^madCalculator2Service.py/*$',
202 202 views.mad_calculator2_service,
203 203 name='mad_calculator2_service'),
204 204 url(r'^madCalculator2Service.py',
205 205 views.mad_calculator2_service,
206 206 name='mad_calculator2_service'),
207 207 url(r'^madCalculator3Service.py/*$',
208 208 views.mad_calculator3_service,
209 209 name='mad_calculator3_service'),
210 210 url(r'^madCalculator3Service.py',
211 211 views.mad_calculator3_service,
212 212 name='mad_calculator3_service'),
213 213 url(r'^geodeticToRadarService.py',
214 214 views.geodetic_to_radar_service,
215 215 name='geodetic_to_radar_service'),
216 216 url(r'^radarToGeodeticService.py',
217 217 views.radar_to_geodetic_service,
218 218 name='radar_to_geodetic_service'),
219 219 url(r'^listFileTimesService.py',
220 220 views.list_file_times_service,
221 221 name='list_file_times_service'),
222 222 url(r'^downloadWebFileService.py',
223 223 views.download_web_file_service,
224 224 name='download_web_file_service'),
225 225 url(r'^traceMagneticFieldService.py',
226 226 views.trace_magnetic_field_service,
227 227 name='trace_magnetic_field_service'),
228 228 url(r'^globalFileSearchService.py',
229 229 views.global_file_search_service,
230 230 name='global_file_search_service'),
231 231 url(r'^getUrlListFromGroupIdService.py',
232 232 views.get_url_list_from_group_id_service,
233 233 name='get_url_list_from_group_id_service'),
234 234 url(r'^setGroupIdFromUrlListService.py',
235 235 views.set_group_id_from_url_list_service,
236 236 name='set_group_id_from_url_list_service'),
237 237 url(r'docs/name/(.+)$',
238 238 views.docs,
239 239 name='docs'),
240 240
241 241 ]
242
@@ -1,3518 +1,3530
1 1 '''
2 2
3 3 @author: Bill Rideout
4 4 @contact: brideout@haystack.mit.edu
5 5
6 6 $Id: views.py 7345 2021-03-30 18:30:32Z brideout $
7 7 '''
8 8 # standard python imports
9 9 import os.path
10 10 import urllib
11 11 import os, sys
12 12 import json
13 13 import datetime, time
14 14 import glob
15 15 import re
16 16 import subprocess
17 17 import io
18 18 import collections
19 19 import shutil
20 20 import mimetypes
21 21 import tempfile
22 22 import random
23 23
24 24 # django imports
25 25 from django.shortcuts import render, redirect
26 26 from django.views.decorators.csrf import csrf_exempt
27 27 from django.template.context import RequestContext
28 28 #from django.conf import settings
29 29 try:
30 30 from django.urls import reverse
31 31 except ImportError:
32 32 from django.core.urlresolvers import reverse
33 33 from django.http import HttpResponse, HttpResponseRedirect, StreamingHttpResponse
34 34 import django.utils.http
35 35 import django.core.files
36 36 import django.utils.safestring
37 37 from wsgiref.util import FileWrapper
38 38
39 39 # third party imports
40 40 import numpy
41 41 import plotly.offline as py
42 42 import plotly.graph_objs as go
43 43 import h5py
44 44
45 45
46 46 # madrigal imports
47 47 import madrigal._derive
48 48 import madrigal.metadata
49 49 import madrigal.ui.web
50 50 import madrigal.cedar
51 51 import madrigal.isprint
52 52 import madweb.forms
53 53
54 54
55 55 # temp only
56 56 import logging
57 57
58 58
59 59 # constants
60 60 formatDict = collections.OrderedDict()
61 61 formatDict['hdf5'] = 'Hdf5'
62 62 formatDict['netCDF4'] = 'netCDF4'
63 63 formatDict['ascii'] = 'Column-delimited ascii'
64 64 maxSize = 50000000 # 50 MB cutoff
65 65
66 66
67 67
68 68
69 69 def index(request):
70 70 """index is the home page view
71 71 """
72 72 madDB = madrigal.metadata.MadrigalDB()
73 73 bg_color = madDB.getBackgroundColor()
74 74 welcome = madDB.getIndexHead()
75 75 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
76 76 siteName, siteList = madWebObj.getSiteInfo()
77 77 rulesRoadHtml = madDB.getLocalRulesOfRoad()
78 78 template_dict = {'home_active': 'class="active"', 'site_name': siteName, 'site_list': siteList,
79 79 'rulesOfRoad':django.utils.safestring.mark_safe(rulesRoadHtml),
80 80 'bg_color': bg_color, 'welcome': welcome}
81 81 return render(request, 'madweb/index.html', template_dict)
82 82
83 83 @csrf_exempt
84 84 def check_registration(view):
85 85 def check_cookies(request, *args, **kwargs):
86 86 # this view checks if all the needed cookies are set
87 87 cookieDict = request.COOKIES
88 88 try:
89 89 cookieDict['user_fullname']
90 90 cookieDict['user_email']
91 91 cookieDict['user_affiliation']
92 92 # no need to register
93 93 return(view(request, *args, **kwargs))
94 94 except KeyError:
95 95 return(HttpResponseRedirect(reverse('view_registration') + '?redirect=%s' % (request.get_full_path())))
96 96
97 97 return(check_cookies)
98 98
99 99
100 100 def view_registration(request):
101 101 madDB = madrigal.metadata.MadrigalDB()
102 102 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
103 103 siteName, siteList = madWeb.getSiteInfo()
104 104 redirect = 'index' # default is to redirect to home page
105 105 if request.method == 'GET':
106 106 if 'redirect' in request.GET:
107 107 redirect = request.GET['redirect']
108 108 for key in request.GET:
109 109 if key not in ('redirect', 'user_fullname', 'user_email', 'user_affiliation'):
110 110 redirect += '&%s=%s' % (key, request.GET[key])
111 111 if len(list(request.GET.keys())) > 0 and 'user_fullname' in request.GET:
112 112 form = madweb.forms.RegisterForm(request.GET)
113 113 if form.is_valid():
114 114 # write cookies and continue to main page
115 115 max_age = 3600*24*365 # one year
116 116 if redirect == 'index':
117 117 response = HttpResponseRedirect(reverse('index'))
118 118 else:
119 119 response = HttpResponseRedirect(redirect)
120 120 response.set_cookie('user_fullname', form.cleaned_data['user_fullname'], max_age=max_age, samesite='Strict')
121 121 response.set_cookie('user_email', form.cleaned_data['user_email'], max_age=max_age, samesite='Strict')
122 122 response.set_cookie('user_affiliation', form.cleaned_data['user_affiliation'], max_age=max_age, samesite='Strict')
123 123 return(response)
124 124 else:
125 125 form = madweb.forms.RegisterForm()
126 126
127 127 else:
128 128 form = madweb.forms.RegisterForm()
129 129 return render(request, 'madweb/register.html', {'form': form, 'home_active': 'class="active"',
130 130 'site_name': siteName, 'site_list': siteList,
131 131 'redirect': redirect})
132 132
133 133
134 134
135 135
136 136
137 137
138 138 def view_single(request):
139 139 """view_single is the single experiment view. It is supplemented by ajax views to speed performamnce,
140 140 but this view can also create the entire page given a complete query string
141 141 """
142 142 responseDict = {'single_active': 'class="active"'}
143 143 cookieDict = request.COOKIES
144 144 user_email = cookieDict['user_email']
145 145 queryDict = request.GET.copy()
146 146 queryDict['user_email'] = user_email
147 147 madDB = madrigal.metadata.MadrigalDB()
148 148 bg_color = madDB.getBackgroundColor()
149 149 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
150 150 siteName, siteList = madWeb.getSiteInfo()
151 151 form = madweb.forms.SingleExpDefaultForm(queryDict)
152 152 if not form.is_valid():
153 153 # new page
154 154 form = madweb.forms.SingleExpDefaultForm()
155 155 responseDict['form'] = form
156 156 responseDict['site_name'] = siteName
157 157 responseDict['site_list'] = siteList
158 158 responseDict['redirect_list'] = madWeb.getSingleRedirectList()
159 159 if 'instruments' in request.GET:
160 160 responseDict['instruments'] = request.GET['instruments']
161 161 if 'years' in request.GET:
162 162 responseDict['years'] = request.GET['years']
163 163 if 'months' in request.GET:
164 164 responseDict['months'] = request.GET['months']
165 165 try:
166 166 # add extra keys if choosing a file
167 167 form.fields['file_list']
168 168 responseDict['loader'] = 'loadSingleForm'
169 169 responseDict['redirect'] = reverse('get_files')
170 170 # handle the case with no files
171 171 if len(form.fields['file_list'].choices) < 2:
172 172 form2 = madweb.forms.SingleExpPlotsForm({'experiment_list':form['exp_id'].initial})
173 173 form.fields['plot_list'] = form2.fields['plot_list']
174 174 except:
175 175 pass
176 176 responseDict['bg_color'] = bg_color
177 177 return render(request, 'madweb/single.html', responseDict)
178 178
179 179
180 180 def get_categories(request):
181 181 """get_categories is a Ajax call that returns the categories select html to support the
182 182 single experiment UI. Called when a user modifies the isGlobal checkbox.
183 183
184 184 Inputs:
185 185 request
186 186 """
187 187 form = madweb.forms.SingleExpDefaultForm(request.GET)
188 188
189 189 return render(request, 'madweb/categories.html', {'form': form})
190 190
191 191
192 192 def get_instruments(request):
193 193 """get_instruments is a Ajax call that returns the instruments select html to support the
194 194 single experiment UI. Called when a user modifies the categories select field.
195 195
196 196 Inputs:
197 197 request
198 198 """
199 199 form = madweb.forms.SingleExpInstForm(request.GET)
200 200
201 201 return render(request, 'madweb/instruments.html', {'form': form})
202 202
203 203
204 204 def get_years(request):
205 205 """get_years is a Ajax call that returns the years select html to support the
206 206 single experiment UI. Called when a user modifies the instruments select field.
207 207
208 208 Inputs:
209 209 request
210 210 """
211 211 form = madweb.forms.SingleExpYearForm(request.GET)
212 212
213 213 is_global = madweb.forms.getIsGlobal([], request.GET)
214 214
215 215 return render(request, 'madweb/years.html', {'isGlobal': is_global,
216 216 'form': form})
217 217
218 218
219 219 def get_months(request):
220 220 """get_months is a Ajax call that returns the months select html to support the
221 221 single experiment UI. Called when a user modifies the years select field.
222 222
223 223 Inputs:
224 224 request
225 225 """
226 226 form = madweb.forms.SingleExpMonthForm(request.GET)
227 227
228 228 is_global = madweb.forms.getIsGlobal([], request.GET)
229 229 year = int(request.GET['years'])
230 230 kinst =int(request.GET['instruments'])
231 231
232 232 return render(request, 'madweb/months.html', {'isGlobal': is_global,
233 233 'years': year,
234 234 'form': form})
235 235
236 236
237 237 def get_calendar(request):
238 238 """get_calendar is a Ajax call that returns the calendar html to support the
239 239 single experiment UI. Called when a user selects month field.
240 240
241 241 Inputs:
242 242 request
243 243 """
244 244 is_global = madweb.forms.getIsGlobal([], request.GET)
245 245 year = int(request.GET['years'])
246 246 month = int(request.GET['months'])
247 247 kinst =int(request.GET['instruments'])
248 248
249 249 form = madweb.forms.SingleExpCalendarForm({'years': year,
250 250 'months': month,
251 251 'instruments': kinst})
252 252
253 253 return render(request, 'madweb/calendar.html', {'isGlobal': is_global,
254 254 'years': year,
255 255 'months': month,
256 256 'instruments': kinst,
257 257 'form': form})
258 258
259 259
260 260 def populate_calendar_experiment(request):
261 261 """populate_calendar_experiment is a ajax view that returns a json object used by the
262 262 calender widget to populate itself.
263 263
264 264 Inputs:
265 265 request
266 266 """
267 267 is_global = madweb.forms.getIsGlobal([], request.GET)
268 268 year = int(request.GET['years'])
269 269 month = int(request.GET['months'])
270 270 kinst =int(request.GET['instruments'])
271 271 madDB = madrigal.metadata.MadrigalDB()
272 272 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
273 273 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
274 274 catId = madInstObj.getCategoryId(kinst)
275 275
276 276 expDays = madWebObj.getDays(kinst, year, month)
277 277
278 278 if len(expDays) == 0:
279 279 expDays = madWebObj.getDays(kinst, year, month, optimize=False)
280 280
281 281 color = "#999"
282 282 jsonListFinal = []
283 283 for expDay in expDays:
284 284 newdate = '%i/%i/%i' % (expDay.day, expDay.month, expDay.year)
285 285 urlperDate = reverse('view_single')
286 286 query_str = '?'
287 287 if is_global:
288 288 query_str += 'isGlobal=on&'
289 289 query_str += 'categories=%i&instruments=%i&years=%i&months=%i&days=%i' % (catId, kinst, year,
290 290 expDay.month, expDay.day)
291 291 urlperDate += query_str
292 292 dayList = [newdate, "", urlperDate, color]
293 293 jsonListFinal.append(dayList)
294 294
295 295 return HttpResponse(json.dumps(jsonListFinal), content_type='application/json')
296 296
297 297
298 298 def get_files(request):
299 299 """get_files is a Ajax call that returns the files select html to support the
300 300 single experiment UI. Called when a user modifies the calendar or experiments fields.
301 301
302 302 Inputs:
303 303 request
304 304 """
305 305 cookieDict = request.COOKIES
306 306 user_email = cookieDict['user_email']
307 307 queryDict = request.GET.copy()
308 308 queryDict['user_email'] = user_email
309 309 form = madweb.forms.SingleExpFileForm(queryDict)
310 310
311 311 is_global = madweb.forms.getIsGlobal([], request.GET)
312 312
313 313 return render(request, 'madweb/file_list.html', {'isGlobal': is_global,
314 314 'form': form,
315 315 'loader': 'loadSingleForm',
316 316 'redirect': reverse('get_files')})
317 317
318 318
319 319 def change_files(request):
320 320 """change_files is a Ajax call that returns the files options html to support the
321 321 single experiment UI. Called when a user modifies the files select field.
322 322
323 323 Inputs:
324 324 request
325 325 """
326 326 expID =int(request.GET['experiment_list'])
327 327 basename = request.GET['file_list']
328 328 madDB = madrigal.metadata.MadrigalDB()
329 329 form = madweb.forms.SingleExpButtonsForm(request.GET)
330 330
331 331 return render(request, 'madweb/file_buttons.html', {'form': form,
332 332 'plot_label': madDB.getPlotButtonLabel()})
333 333
334 334
335 335 def show_plots(request):
336 336 """show_plots is a Ajax call that returns the files data html with plots to support the
337 337 single experiment UI. Called when a user modifies the files select field.
338 338
339 339 Inputs:
340 340 request
341 341 """
342 342 madDB = madrigal.metadata.MadrigalDB()
343 343 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
344 344 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
345 345
346 346 try:
347 347 expID = int(request.GET['experiment_list'])
348 348 except ValueError:
349 349 # convert expPath to expID
350 350 expID = madWebObj.getExpIDFromExpPath(request.GET['experiment_list'], True)
351 351 plotList = madExpObj.getExpLinksByExpId(expID)
352 352 if len(plotList) != 0:
353 353 form = madweb.forms.SingleExpPlotsForm(request.GET)
354 354 template = 'madweb/show_plots.html'
355 355 context = {'form': form}
356 356 else:
357 357 template = 'madweb/parameter_selection.html'
358 358 form = madweb.forms.SingleExpPlotsSelectionForm(request.GET)
359 359 context = {'form': form, 'expID': expID}
360 360
361 361 return render(request, template, context)
362 362
363 363
364 364 def view_plot(request):
365 365
366 366 param1d = request.GET.get('param1d', 0)
367 367 param2d = request.GET.get('param2d', 0)
368 368
369 369 madDB = madrigal.metadata.MadrigalDB()
370 370 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
371 371 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
372 372
373 373 expID =int(request.GET['expID'])
374 374 expDir = madExpObj.getExpDirByExpId(expID)
375 375 if expDir is None:
376 376 raise ValueError('No expDir found for exp_id %i' % (int(expID)))
377 377
378 fileList = madWebObj.getFileFromExpID(expID, False)
379 firsttuple = [a_tuple[0] for a_tuple in fileList]
380 basename = firsttuple[0]
378 # fileList = madWebObj.getFileFromExpID(expID, False)
379 # firsttuple = [a_tuple[0] for a_tuple in fileList]
380 basename = request.GET['filename']#firsttuple[0]
381 381 fullFilename = os.path.join(expDir, basename)
382 382
383 383 with h5py.File(fullFilename, "r") as f:
384 384
385 385 # Get the data
386 386
387 387 data = f['Data']
388 388
389 389 if 'Array Layout' in data:
390 390 array = data['Array Layout']
391 datatime = [datetime.datetime.fromtimestamp(t) for t in array['timestamps']]
392 yrange = array['gdalt']
391 datatime = [datetime.datetime.utcfromtimestamp(t-5*60*60) for t in array['timestamps']]
392 if 'gdalt' in array:
393 yrange = array['gdalt']
394 elif 'range' in array:
395 yrange = array['range']
396 else:
397 return HttpResponse("There is no valid data for this plot: gdalt and/or range missing")
393 398
394 399 if param1d==0:
395 plot = plot_heatmap(datatime, yrange, array['2D Parameters'][param2d], param2d)
400 kindat = data['Table Layout']['kindat'][0]
401 if kindat in (1950, 1911, 1913):
402 plot = plot_scatter(datatime, array['2D Parameters'][param2d][0], param2d, array['2D Parameters']['d'+param2d][0])
403 else:
404 plot = plot_heatmap(datatime, yrange, array['2D Parameters'][param2d], param2d)
396 405 else:
397 406 plot = plot_scatter(datatime, array['1D Parameters'][param1d], param1d)
398 407
399 408 else:
400 409 table = data['Table Layout']
401 410 datatime = [datetime.datetime.fromtimestamp(t) for t in table['ut2_unix']]
402 411 plot = plot_scatter(datatime,table[param1d],param1d)
403 412
404 413 return HttpResponse(plot)
405 414
406 def plot_scatter(datatime,dataparam,paramname):
415 def plot_scatter(datatime,dataparam,paramname, error=[]):
407 416 if (numpy.isnan(dataparam).all()):
408 plot = "There is no valid data available for this plot"
417 plot = "There is no valid data available for this plot: Empty array"
409 418
410 419 else:
420 mode = 'markers' if len(error)>0 else 'lines'
411 421 fig = go.Figure()
412 fig.add_trace(go.Scatter(x=datatime, y=dataparam))
422 fig.add_trace(go.Scatter(x=datatime, y=dataparam, mode=mode, error_y={'type':'data', 'array':error, 'visible':True, 'color':'rgba(255, 144, 14, 0.7)'}))
413 423 fig.update_yaxes(title_text=paramname)
424 fig.update_xaxes(title_text='Time [LT]')
414 425
415 426 delta = datatime[-1] - datatime[1]
416 427
417 428 if (delta>datetime.timedelta(days=30)):
418 429 # Add range slider
419 430 fig.update_layout(
420 431 xaxis=dict(
421 432 rangeselector=dict(
422 433 buttons=list([
423 434 dict(count=1,
424 435 label="1m",
425 436 step="month",
426 437 stepmode="backward"),
427 438 dict(count=6,
428 439 label="6m",
429 440 step="month",
430 441 stepmode="backward"),
431 442 dict(count=1,
432 443 label="1y",
433 444 step="year",
434 445 stepmode="backward"),
435 446 dict(step="all")
436 447 ])
437 448 ),
438 449 rangeslider=dict(
439 450 visible=True
440 451 ),
441 452 type="date"
442 453 )
443 454 )
444 455
445 456
446 457 plot = py.plot(fig, include_plotlyjs=False, output_type='div')
447 458
448 459
449 460 return plot
450 461
451 462
452 463 def plot_heatmap(datatime,datarange,dataparam,paramname):
453 464 if (numpy.all(numpy.isnan(dataparam))):
454 plot = "There is no valid data available for this plot"
465 plot = "There is no valid data available for this plot: Empty array"
455 466 else:
456 467 fig = go.Figure()
457 468 fig.add_trace(go.Heatmap(x=datatime,y=datarange,z= dataparam,colorscale='Jet',colorbar={"title":paramname}))
458 469 fig.update_yaxes(title_text="range")
470 fig.update_xaxes(title_text="Time [LT]")
459 471 fig.update_layout(
460 472 updatemenus=[
461 473 dict(
462 474 buttons=list([
463 475 dict(
464 476 args=["colorscale", "Jet"],
465 477 label="Jet",
466 478 method="restyle"
467 479 ),
468 480 dict(
469 481 args=["colorscale", "RdBu"],
470 482 label="Red-Blue",
471 483 method="restyle"
472 484 ),
473 485 dict(
474 486 args=["colorscale", "Viridis"],
475 487 label="Viridis",
476 488 method="restyle"
477 489 ),
478 490 dict(
479 491 args=["colorscale", "Cividis"],
480 492 label="Cividis",
481 493 method="restyle"
482 494 ),
483 495 dict(
484 496 args=["colorscale", "Greens"],
485 497 label="Greens",
486 498 method="restyle"
487 499 ),
488 500 ]),
489 501 type = "dropdown",
490 502 direction="down",
491 503 pad={"r": 10, "t": -10},
492 504 showactive=True,
493 505 x=0.1,
494 506 xanchor="left",
495 507 y=1.05,
496 508 yanchor="top"
497 509 ),
498 510 dict(
499 511 buttons=list([
500 512 dict(
501 513 args=[{"contours.showlines": False, "type": "contour"}],
502 514 label="Hide lines",
503 515 method="restyle"
504 516 ),
505 517 dict(
506 518 args=[{"contours.showlines": True, "type": "contour"}],
507 519 label="Show lines",
508 520 method="restyle"
509 521 ),
510 522 ]),
511 523 direction="down",
512 524 pad={"r": 10, "t": -10},
513 525 showactive=True,
514 526 x=0.32,
515 527 xanchor="left",
516 528 y=1.05,
517 529 yanchor="top"
518 530 ),
519 531
520 532 ]
521 533 )
522 534
523 535 fig.update_layout(
524 536 annotations=[
525 537 dict(text="Colorscale", showarrow=False,
526 538 x=0, xref="paper", y=1.05, yref="paper", align="left"),
527 539 dict(text="Lines", x=0.25, xref="paper", y=1.05, yref="paper",
528 540 showarrow=False)
529 541 ]
530 542 )
531 543
532 544
533 545 plot = py.plot(fig, include_plotlyjs=False, output_type='div')
534 546
535 547 return plot
536 548
537 549
538 550 def download_as_is(request):
539 551 """download_as_is is a Ajax call that returns the download as is html to support the
540 552 single experiment UI. Called when a user selects download/as is link.
541 553
542 554 Inputs:
543 555 request
544 556 """
545 557 cookieDict = request.COOKIES
546 558 if not 'user_fullname' in cookieDict:
547 559 return(HttpResponse('<p>Cookie with user_fullname required for downloadAsIs</p>'))
548 560 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
549 561 user_email = cookieDict['user_email']
550 562 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
551 563 expID =int(request.GET['experiment_list'])
552 564 file_list = request.GET['file_list']
553 565 form = madweb.forms.SingleExpDownloadAsIsForm({'format_select':file_list,
554 566 'expID': expID})
555 567
556 568 return render(request, 'madweb/download_as_is.html', {'form': form, 'exp_id':expID,
557 569 'user_fullname':user_fullname,
558 570 'user_email':user_email,
559 571 'user_affiliation': user_affiliation})
560 572
561 573
562 574 def download_file_as_is(request):
563 575 """download_file_as_is is a Ajax call that actually downloads a madrigal file.
564 576
565 577 Inputs:
566 578 request
567 579 """
568 580 madDB = madrigal.metadata.MadrigalDB()
569 581 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
570 582 user_fullname = urllib.parse.unquote_plus(request.GET['user_fullname'])
571 583 user_email = request.GET['user_email']
572 584 user_affiliation = urllib.parse.unquote_plus(request.GET['user_affiliation'])
573 585 exp_id = request.GET['exp_id']
574 586 basename = request.GET['basename']
575 587 downloadFile = madWebObj.downloadFileAsIs(exp_id, basename, user_fullname, user_email, user_affiliation)
576 588 f = open(downloadFile, 'rb')
577 589 filename = os.path.basename(downloadFile)
578 590 chunk_size = 8192
579 591 file_type = mimetypes.guess_type(downloadFile)[0]
580 592 if file_type is None:
581 593 file_type = 'application/octet-stream'
582 594 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
583 595 content_type=file_type)
584 596 response['Content-Length'] = os.path.getsize(downloadFile)
585 597 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
586 598 response.set_cookie('fileDownload', 'true', path='/', samesite='Strict')
587 599 return(response)
588 600
589 601
590 602 def print_as_is(request):
591 603 """print_as_is is a Ajax call that returns the text of the ascii file to support the
592 604 single experiment UI if request.GET has key "text", or the length of the file to be
593 605 downloaded if not. Called when a user selects print/as is link.
594 606
595 607 Inputs:
596 608 request
597 609 """
598 610 madDB = madrigal.metadata.MadrigalDB()
599 611 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
600 612 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
601 613 madParmObj = madrigal.data.MadrigalParameters(madDB)
602 614
603 615 cookieDict = request.COOKIES
604 616 if not 'user_fullname' in cookieDict:
605 617 return(HttpResponse('<p>Cookie with user_fullname required for printAsIs</p>'))
606 618 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
607 619 user_email = cookieDict['user_email']
608 620 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
609 621 expID =int(request.GET['experiment_list'])
610 622 basename = request.GET['file_list']
611 623 expDir = madExpObj.getExpDirByExpId(int(expID))
612 624 if expDir is None:
613 625 raise ValueError('No expDir found for exp_id %i' % (int(expID)))
614 626 fullFilename = os.path.join(expDir, basename)
615 627
616 628 # determine if we need to return the full file text, or just the size and name
617 629 if 'text' in request.GET:
618 630 madFileObj = madrigal.data.MadrigalFile(fullFilename, madDB)
619 631 measParms = madFileObj.getMeasuredParmList()
620 632 measParmMnemList = madParmObj.getParmMnemonicList(measParms) + madFileObj.getStandardParms(upper=True)
621 633 measParmDescList = madParmObj.getParmDescriptionList(measParmMnemList)
622 634 parmList = list(zip(measParmMnemList, measParmDescList))
623 635 f = open(request.GET['text'])
624 636 text = f.read()
625 637 f.close()
626 638
627 639 return render(request, 'madweb/print_as_is.html', {'text': text, 'parmList': parmList})
628 640
629 641 else:
630 642 tmpFilename = madWebObj.printFileAsIs(fullFilename, user_fullname, user_email, user_affiliation)
631 643 filesize = os.path.getsize(tmpFilename)
632 644 return(HttpResponse('%s:%s' % (filesize, tmpFilename)))
633 645
634 646
635 647 def list_records(request):
636 648 """list_records is a Ajax call that returns the list records text.
637 649
638 650 Inputs:
639 651 request
640 652 """
641 653 madDB = madrigal.metadata.MadrigalDB()
642 654 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
643 655 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
644 656
645 657 expID =int(request.GET['experiment_list'])
646 658 basename = request.GET['file_list']
647 659 expDir = madExpObj.getExpDirByExpId(int(expID))
648 660 if expDir is None:
649 661 raise ValueError('No expDir found for exp_id %i' % (int(expID)))
650 662 fullFilename = os.path.join(expDir, basename)
651 663
652 664 text = madWebObj.listRecords(fullFilename)
653 665
654 666 return render(request, 'madweb/list_records.html', {'expDir': expDir,
655 667 'basename': basename,
656 668 'text': text})
657 669
658 670
659 671 def view_record_plot(request):
660 672 """view_record_plot returns the view individual record page.
661 673
662 674 Inputs:
663 675 request
664 676 """
665 677 expDir = request.GET['expDir']
666 678 basename = request.GET['basename']
667 679 recno = int(request.GET['recno'])
668 680
669 681 return render(request, 'madweb/view_record_plot.html', {'expDir': expDir,
670 682 'basename': basename,
671 683 'recno': recno})
672 684
673 685
674 686 def view_record_image(request):
675 687 """view_record_plot is a Ajax call that returns the record plot.
676 688
677 689 Inputs:
678 690 request
679 691 """
680 692 expDir = request.GET['expDir']
681 693 basename = request.GET['basename']
682 694 recno = int(request.GET['recno'])
683 695 pngFiles = glob.glob(os.path.join(expDir, 'plots', basename, 'records/*%05i*.png' % (recno)))
684 696
685 697 image_data = open(pngFiles[0], "rb").read()
686 698 return HttpResponse(image_data, content_type="image/png")
687 699
688 700
689 701
690 702
691 703 def show_info(request):
692 704 """show_info is a Ajax call that returns the text of the catalog/header text to support the
693 705 single experiment UI. Called when a user selects show info link.
694 706
695 707 Inputs:
696 708 request
697 709 """
698 710 madDB = madrigal.metadata.MadrigalDB()
699 711 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
700 712
701 713 expID =int(request.GET['experiment_list'])
702 714 basename = request.GET['file_list']
703 715 expDir = madExpObj.getExpDirByExpId(int(expID))
704 716 if expDir is None:
705 717 raise ValueError('No expDir found for exp_id %i' % (int(expID)))
706 718 fullFilename = os.path.join(expDir, basename)
707 719
708 720 madFileObj = madrigal.data.MadrigalFile(fullFilename, madDB)
709 721 text = madFileObj.getCatalogHeaderStr()
710 722
711 723 return render(request, 'madweb/show_info.html', {'text':text})
712 724
713 725
714 726 def show_doi(request):
715 727 """show_doi is a Ajax call that returns the permanent url for references to support the
716 728 single experiment UI. Called when a user selects show doi link.
717 729
718 730 Inputs:
719 731 request
720 732 """
721 733 madDB = madrigal.metadata.MadrigalDB()
722 734 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
723 735 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
724 736
725 737 expID =request.GET['experiment_list']
726 738 basename = request.GET['file_list']
727 739 expDir = madExpObj.getExpDirByExpId(int(expID))
728 740 # get experiment PI and institution
729 741 PI = madExpObj.getPIByExpId(int(expID))
730 742 kinst = madExpObj.getKinstByExpId(int(expID))
731 743 startDTList = madExpObj.getExpStartDateTimeByExpId(int(expID))
732 744 yearStr = str(startDTList[0])
733 745 if PI is None:
734 746 PI = madInstObj.getContactName(kinst)
735 747 institution = madInstObj.getContactAddress1(kinst)
736 748
737 749 try:
738 750 madFileObj = madrigal.metadata.MadrigalMetaFile(madDB, os.path.join(expDir, 'fileTab.txt'))
739 751 url = madFileObj.getFileDOIUrlByFilename(basename)
740 752 except:
741 753 url = 'Unknown - please contact madrigal@haystack.mit.edu'
742 754
743 755 return render(request, 'madweb/show_doi.html', {'url':url, 'PI': PI, 'year': yearStr,
744 756 'institution': institution})
745 757
746 758
747 759 def get_advanced(request):
748 760 """get_advanced is a view that allows user to download/print files with selected parms
749 761 and filters.
750 762
751 763 Inputs:
752 764 request
753 765 """
754 766 madDB = madrigal.metadata.MadrigalDB()
755 767 bg_color = madDB.getBackgroundColor()
756 768 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
757 769 siteName, siteList = madWeb.getSiteInfo()
758 770 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
759 771 webFormatObj = madrigal.ui.web.MadrigalWebFormat()
760 772 madParmObj = madrigal.data.MadrigalParameters(madDB)
761 773 parmList = webFormatObj.getFormat('Comprehensive')
762 774 measParmList = []
763 775 derivedParmList = []
764 776 allParmList = []
765 777 sureParmList = []
766 778
767 779 if 'experiment_list' in request.GET:
768 780 expID = int(request.GET['experiment_list'])
769 781 else:
770 782 return(HttpResponse('<p>experiment_list required for getAdvanced</p>'))
771 783 basename = request.GET['file_list']
772 784 type = request.GET['type']
773 785 expDir = madExpObj.getExpDirByExpId(int(expID))
774 786 if expDir is None:
775 787 raise ValueError('No expDir found for exp_id %i' % (int(expID)))
776 788 fullFilename = os.path.join(expDir, basename)
777 789 expName, kindatDesc = madWeb.getInfoFromFile(fullFilename)
778 790 madFileObj = madrigal.data.MadrigalFile(fullFilename, madDB)
779 791 earliestTime = madFileObj.getEarliestTime()
780 792 latestTime = madFileObj.getLatestTime()
781 793 earliestDT = datetime.datetime(*earliestTime)
782 794 latestDT = datetime.datetime(*latestTime)
783 795 madFileObj.getMeasDervBothParmLists(parmList, measParmList, derivedParmList, allParmList, sureParmList)
784 796 allParmDescList = madParmObj.getParmDescriptionList(allParmList)
785 797
786 798 dataDict = {'type': type,
787 799 'fullFilename': fullFilename,
788 800 'madFileObj': madFileObj, 'parameters': [],
789 801 'measParmList': measParmList, 'derivedParmList': derivedParmList,
790 802 'allParmList': allParmList, 'allParmDescList': allParmDescList,
791 803 'madDB': madDB, 'madParmObj': madParmObj}
792 804
793 805 min_alt = madFileObj.getMinValidAltitude()
794 806 max_alt = madFileObj.getMaxValidAltitude()
795 807 try:
796 808 float(min_alt)
797 809 float(max_alt)
798 810 dataDict['min_alt'] = '%9.2f' % (min_alt)
799 811 dataDict['max_alt'] = '%9.2f' % (max_alt)
800 812 except:
801 813 pass
802 814
803 815 if 'AZM' in allParmList:
804 816 dataDict['min_az'] = '-180.0'
805 817 dataDict['max_az'] = '180.0'
806 818 dataDict['min_az2'] = '0.0'
807 819 dataDict['max_az2'] = '0.0'
808 820
809 821 if 'ELM' in allParmList:
810 822 dataDict['min_el'] = '0.0'
811 823 dataDict['max_el'] = '90.0'
812 824 dataDict['min_el2'] = '0.0'
813 825 dataDict['max_el2'] = '0.0'
814 826
815 827 if 'PL' in allParmList:
816 828 min_pl = madFileObj.getMinPulseLength()
817 829 max_pl = madFileObj.getMaxPulseLength()
818 830 try:
819 831 float(min_pl)
820 832 float(max_pl)
821 833 dataDict['min_pl'] = '%9.2f' % (min_pl)
822 834 dataDict['max_pl'] = '%9.2f' % (max_pl)
823 835 except:
824 836 pass
825 837
826 838 if type == 'download':
827 839 defaultFormat = 'Hdf5'
828 840 else:
829 841 defaultFormat = 'ascii'
830 842 dataDict['formats'] = defaultFormat
831 843 dataDict['missing'] = 'NaN'
832 844 dataDict['start_date'] = earliestDT
833 845 dataDict['end_date'] = latestDT
834 846
835 847
836 848 isprintForm = madweb.forms.IsprintForm(dataDict)
837 849
838 850 return render(request, 'madweb/get_advanced.html', {'form': isprintForm,
839 851 'parmList': isprintForm.parmList,
840 852 'measParmList': measParmList,
841 853 'site_name': siteName, 'site_list': siteList,
842 854 'expName': expName, 'kindatDesc': kindatDesc,
843 855 'basename': os.path.basename(fullFilename),
844 856 'type': type, 'bg_color': bg_color,
845 857 'datetime': True})
846 858
847 859 def advanced_download(request):
848 860 """advanced_download is a view that downloads a file with selected parms
849 861 and filters.
850 862
851 863 Inputs:
852 864 request
853 865 """
854 866 madDB = madrigal.metadata.MadrigalDB()
855 867 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
856 868 webFormatObj = madrigal.ui.web.MadrigalWebFormat()
857 869 madParmObj = madrigal.data.MadrigalParameters(madDB)
858 870
859 871 cookieDict = request.COOKIES
860 872 if not 'user_fullname' in cookieDict:
861 873 return(HttpResponse('<p>Cookie with user_fullname required for advancedDownload</p>'))
862 874 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
863 875 user_email = cookieDict['user_email']
864 876 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
865 877
866 878 parmList = webFormatObj.getFormat('Comprehensive')
867 879 measParmList = []
868 880 derivedParmList = []
869 881 allParmList = []
870 882 sureParmList = []
871 883 madFileObj = madrigal.data.MadrigalFile(request.GET['fullFilename'], madDB)
872 884 madFileObj.getMeasDervBothParmLists(parmList, measParmList, derivedParmList, allParmList, sureParmList)
873 885 allParmDescList = madParmObj.getParmDescriptionList(allParmList)
874 886
875 887 request.GET._mutable = True
876 888 request.GET['madFileObj']=madFileObj
877 889 request.GET['measParmList']=measParmList
878 890 request.GET['derivedParmList']=derivedParmList
879 891 request.GET['allParmList']=allParmList
880 892 request.GET['allParmDescList']=allParmDescList
881 893 request.GET['start_date'] = request.GET['start_date'].strip()
882 894 request.GET['end_date'] = request.GET['end_date'].strip()
883 895 # convert dates to datetime
884 896 request.GET['start_date'] = datetime.datetime.strptime(request.GET['start_date'], '%Y-%m-%dT%H:%M:%S')
885 897 request.GET['end_date'] = datetime.datetime.strptime(request.GET['end_date'], '%Y-%m-%dT%H:%M:%S')
886 898 request.GET['madDB'] = madDB
887 899 request.GET['madParmObj'] = madParmObj
888 900
889 901
890 902 isprintForm = madweb.forms.IsprintForm(request.GET)
891 903
892 904
893 905 if not isprintForm.is_valid():
894 906 raise ValueError(str(isprintForm.errors))
895 907
896 908 downloadFile = madWeb.downloadIsprintFileFromIsprintForm(isprintForm.cleaned_data, user_fullname, user_email, user_affiliation)
897 909
898 910
899 911 f = open(downloadFile, 'rb')
900 912 filename = os.path.basename(downloadFile)
901 913 chunk_size = 8192
902 914 file_type = mimetypes.guess_type(downloadFile)[0]
903 915 if file_type is None:
904 916 file_type = 'application/octet-stream'
905 917 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
906 918 content_type=file_type)
907 919 response['Content-Length'] = os.path.getsize(downloadFile)
908 920 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
909 921 return(response)
910 922
911 923
912 924 def advanced_print(request):
913 925 """advanced_download is a view that print a file with selected parms
914 926 and filters.
915 927
916 928 Inputs:
917 929 request
918 930 """
919 931 madDB = madrigal.metadata.MadrigalDB()
920 932 bg_color = madDB.getBackgroundColor()
921 933 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
922 934 webFormatObj = madrigal.ui.web.MadrigalWebFormat()
923 935 madParmObj = madrigal.data.MadrigalParameters(madDB)
924 936
925 937 cookieDict = request.COOKIES
926 938 if not 'user_fullname' in cookieDict:
927 939 return(HttpResponse('<p>Cookie with user_fullname required for advancedPrint</p>'))
928 940 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
929 941 user_email = cookieDict['user_email']
930 942 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
931 943
932 944 parmList = webFormatObj.getFormat('Comprehensive')
933 945 measParmList = []
934 946 derivedParmList = []
935 947 allParmList = []
936 948 sureParmList = []
937 949 madFileObj = madrigal.data.MadrigalFile(request.GET['fullFilename'], madDB)
938 950 madFileObj.getMeasDervBothParmLists(parmList, measParmList, derivedParmList, allParmList, sureParmList)
939 951 allParmDescList = madParmObj.getParmDescriptionList(allParmList)
940 952 fullFilename = request.GET['fullFilename']
941 953 expName, kindatDesc = madWeb.getInfoFromFile(fullFilename)
942 954
943 955 request.GET._mutable = True
944 956 request.GET['madFileObj']=madFileObj
945 957 request.GET['measParmList']=measParmList
946 958 request.GET['derivedParmList']=derivedParmList
947 959 request.GET['allParmList']=allParmList
948 960 request.GET['allParmDescList']=allParmDescList
949 961 request.GET['start_date'] = request.GET['start_date'].strip()
950 962 request.GET['end_date'] = request.GET['end_date'].strip()
951 963 # convert dates to datetime
952 964 request.GET['start_date'] = datetime.datetime.strptime(request.GET['start_date'], '%Y-%m-%dT%H:%M:%S')
953 965 request.GET['end_date'] = datetime.datetime.strptime(request.GET['end_date'], '%Y-%m-%dT%H:%M:%S')
954 966 request.GET['madDB'] = madDB
955 967 request.GET['madParmObj'] = madParmObj
956 968
957 969 isprintForm = madweb.forms.IsprintForm(request.GET)
958 970
959 971
960 972 if not isprintForm.is_valid():
961 973 raise ValueError(str(isprintForm.errors))
962 974
963 975 downloadFile = madWeb.downloadIsprintFileFromIsprintForm(isprintForm.cleaned_data, user_fullname, user_email, user_affiliation)
964 976
965 977 f = open(downloadFile, 'r')
966 978 file_text = f.read()
967 979 f.close()
968 980 os.remove(downloadFile)
969 981 return render(request, 'madweb/advanced_print.html', {'expName': expName, 'kindatDesc': kindatDesc,
970 982 'basename': os.path.basename(fullFilename),
971 983 'file_text': file_text, 'bg_color': bg_color})
972 984
973 985
974 986 def view_list(request):
975 987 """view_list is the list experiment view.
976 988 """
977 989 madDB = madrigal.metadata.MadrigalDB()
978 990 bg_color = madDB.getBackgroundColor()
979 991 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
980 992 siteName, siteList = madWebObj.getSiteInfo()
981 993 responseDict = {'list_active': 'class="active"'}
982 994 form = madweb.forms.ListExpForm()
983 995 responseDict['form'] = form
984 996 responseDict['categoryList'] = form.categories
985 997 responseDict['instrumentList'] = form.instruments
986 998 responseDict['site_name'] = siteName
987 999 responseDict['site_list'] = siteList
988 1000 responseDict['datetime'] = True
989 1001 responseDict['bg_color'] = bg_color
990 1002
991 1003 return render(request, 'madweb/list.html', responseDict)
992 1004
993 1005
994 1006 def list_experiments(request):
995 1007 """list_experiments is a view that lists all selected experiments.
996 1008
997 1009 Inputs:
998 1010 request
999 1011 """
1000 1012 madDB = madrigal.metadata.MadrigalDB()
1001 1013 bg_color = madDB.getBackgroundColor()
1002 1014 madWeb = madrigal.ui.web.MadrigalWeb(madDB)
1003 1015 siteName, siteList = madWeb.getSiteInfo()
1004 1016
1005 1017 listForm = madweb.forms.ListExpForm(request.GET)
1006 1018 try:
1007 1019 if not listForm.is_valid():
1008 1020 return(HttpResponse(str(listForm.errors)))
1009 1021 except KeyError:
1010 1022 return(HttpResponse('<p>Missing arguments in list_experiments</p>'))
1011 1023
1012 1024 kinstList = [int(kinst) for kinst in listForm.cleaned_data['instruments']]
1013 1025 startDate = listForm.cleaned_data['start_date']
1014 1026 startDT = datetime.datetime(startDate.year, startDate.month, startDate.day, 0, 0, 0)
1015 1027 endDate = listForm.cleaned_data['end_date']
1016 1028 endDT = datetime.datetime(endDate.year, endDate.month, endDate.day, 23, 59, 59)
1017 1029 localOnly = not listForm.cleaned_data['isGlobal']
1018 1030 expList = madWeb.getExperimentList(kinstList, startDT, endDT, localOnly)
1019 1031
1020 1032 return render(request, 'madweb/list_experiments.html', {'expList':expList, 'localOnly':localOnly,
1021 1033 'list_active': 'class="active"', 'site_name': siteName,
1022 1034 'site_list': siteList, 'bg_color': bg_color})
1023 1035
1024 1036
1025 1037 def show_experiment(request):
1026 1038 """show_experiment call that returns the experiment page to support the list experiments UI.
1027 1039
1028 1040 Inputs:
1029 1041 request
1030 1042 """
1031 1043 madDB = madrigal.metadata.MadrigalDB()
1032 1044 bg_color = madDB.getBackgroundColor()
1033 1045 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1034 1046 siteName, siteList = madWebObj.getSiteInfo()
1035 1047 cookieDict = request.COOKIES
1036 1048 user_email = cookieDict['user_email']
1037 1049 queryDict = request.GET.copy()
1038 1050 queryDict['user_email'] = user_email
1039 1051 if 'show_plots' in queryDict:
1040 1052 plotsForm = madweb.forms.SingleExpPlotsForm(queryDict)
1041 1053 form = madweb.forms.SingleExpFileForm(queryDict)
1042 1054 if 'show_plots' in queryDict:
1043 1055 form.fields['plot_list'] = plotsForm.fields['plot_list']
1044 1056 if len(form.fields['file_list'].choices) > 1:
1045 1057 # this experiment has data files
1046 1058 return render(request, 'madweb/show_experiment.html', {'list_active': 'class="active"',
1047 1059 'form': form, 'site_name': siteName,
1048 1060 'site_list': siteList,
1049 1061 'loader': 'loadPage',
1050 1062 'bg_color': bg_color,
1051 1063 'redirect': reverse('show_experiment')})
1052 1064
1053 1065 else:
1054 1066 # this experiment has no data files
1055 1067 form2 = madweb.forms.SingleExpPlotsForm(request.GET)
1056 1068 exp_desc = form.fields['exp_desc'].label
1057 1069 return render(request, 'madweb/show_exp_no_files.html', {'list_active': 'class="active"',
1058 1070 'form': form2, 'exp_desc': exp_desc,
1059 1071 'site_name': siteName,
1060 1072 'site_list': siteList,
1061 1073 'loader': 'loadPage',
1062 1074 'bg_color': bg_color,
1063 1075 'redirect': reverse('show_experiment')})
1064 1076
1065 1077
1066 1078 def show_experiment_v2(request):
1067 1079 """show_experiment_v2 is a slight variant of show_experiment to accept old form
1068 1080 calls from Madrigal2 sites.
1069 1081
1070 1082 Inputs:
1071 1083 request
1072 1084 """
1073 1085 madDB = madrigal.metadata.MadrigalDB()
1074 1086 bg_color = madDB.getBackgroundColor()
1075 1087 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1076 1088 siteName, siteList = madWebObj.getSiteInfo()
1077 1089 cookieDict = request.COOKIES
1078 1090 user_email = cookieDict['user_email']
1079 1091 queryDict = request.GET.copy()
1080 1092 queryDict['user_email'] = user_email
1081 1093 queryDict['experiment_list'] = queryDict['exp']
1082 1094 form = madweb.forms.SingleExpFileForm(queryDict)
1083 1095
1084 1096 return render(request, 'madweb/show_experiment.html', {'list_active': 'class="active"',
1085 1097 'form': form, 'site_name': siteName,
1086 1098 'site_list': siteList,
1087 1099 'loader': 'loadPage',
1088 1100 'bg_color': bg_color,
1089 1101 'redirect': reverse('show_experiment')})
1090 1102
1091 1103
1092 1104 def choose_script(request):
1093 1105 """choose_script that returns the choose script page.
1094 1106
1095 1107 Inputs:
1096 1108 request
1097 1109 """
1098 1110 madDB = madrigal.metadata.MadrigalDB()
1099 1111 bg_color = madDB.getBackgroundColor()
1100 1112 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1101 1113 siteName, siteList = madWebObj.getSiteInfo()
1102 1114 return render(request, 'madweb/choose_script.html', {'script_active': 'class="active"', 'site_name': siteName,
1103 1115 'site_list': siteList, 'bg_color': bg_color})
1104 1116
1105 1117
1106 1118 def download_as_is_script(request):
1107 1119 """download_as_is_script that returns the download_as_is_script script page.
1108 1120
1109 1121 Inputs:
1110 1122 request
1111 1123 """
1112 1124 madDB = madrigal.metadata.MadrigalDB()
1113 1125 bg_color = madDB.getBackgroundColor()
1114 1126 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1115 1127 siteName, siteList = madWebObj.getSiteInfo()
1116 1128 responseDict = {'script_active': 'class="active"'}
1117 1129 form = madweb.forms.DownloadAsIsScriptForm()
1118 1130 responseDict['form'] = form
1119 1131 responseDict['categoryList'] = form.categories
1120 1132 responseDict['instrumentList'] = form.instruments
1121 1133 responseDict['kindatList'] = form.kindats
1122 1134 responseDict['site_name'] = siteName
1123 1135 responseDict['site_list'] = siteList
1124 1136 responseDict['datetime'] = True
1125 1137 responseDict['bg_color'] = bg_color
1126 1138
1127 1139 return render(request, 'madweb/download_as_is_script.html', responseDict)
1128 1140
1129 1141
1130 1142 def generate_download_files_script(request):
1131 1143 """generate_download_files_script is a Ajax call that returns the generated file download script.
1132 1144
1133 1145 Inputs:
1134 1146 request
1135 1147 """
1136 1148 form = madweb.forms.DownloadAsIsScriptForm(request.GET)
1137 1149 if not form.is_valid():
1138 1150 raise ValueError('Form error: %s' % (form.errors))
1139 1151 cookieDict = request.COOKIES
1140 1152 if not 'user_fullname' in cookieDict:
1141 1153 return(HttpResponse('<p>Cookie with user_fullname required for generateDownloadFilesScript</p>'))
1142 1154 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
1143 1155 user_email = cookieDict['user_email']
1144 1156 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
1145 1157 madWebObj = madrigal.ui.web.MadrigalWeb()
1146 1158 script_text = madWebObj.generateDownloadFileScriptFromForm(form.cleaned_data, user_fullname,
1147 1159 user_email, user_affiliation)
1148 1160 return render(request, 'madweb/download_files_script.html', {'script_text': script_text})
1149 1161
1150 1162
1151 1163 def download_advanced_script(request):
1152 1164 """download_advanced_script that returns the download_advanced_script script page.
1153 1165
1154 1166 Inputs:
1155 1167 request
1156 1168 """
1157 1169 madDB = madrigal.metadata.MadrigalDB()
1158 1170 bg_color = madDB.getBackgroundColor()
1159 1171 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1160 1172 siteName, siteList = madWebObj.getSiteInfo()
1161 1173 responseDict = {'script_active': 'class="active"'}
1162 1174 form = madweb.forms.DownloadAdvancedScriptForm()
1163 1175 responseDict['form'] = form
1164 1176 responseDict['categoryList'] = form.categories
1165 1177 responseDict['instrumentList'] = form.instruments
1166 1178 responseDict['kindatList'] = form.kindats
1167 1179 responseDict['site_name'] = siteName
1168 1180 responseDict['site_list'] = siteList
1169 1181 responseDict['datetime'] = True
1170 1182 responseDict['bg_color'] = bg_color
1171 1183
1172 1184 return render(request, 'madweb/download_advanced_script.html', responseDict)
1173 1185
1174 1186
1175 1187 def generate_download_advanced_script(request):
1176 1188 """generate_download_advanced_script is a Ajax call that returns the generated advanced download script.
1177 1189
1178 1190 Inputs:
1179 1191 request
1180 1192 """
1181 1193 form1 = madweb.forms.DownloadAdvancedScriptForm(request.GET)
1182 1194 if not form1.is_valid():
1183 1195 raise ValueError('Form error: %s' % (form1.errors))
1184 1196 form2 = madweb.forms.AdvScriptParmsForm(request.GET)
1185 1197 if not form2.is_valid():
1186 1198 raise ValueError('Form error: %s' % (form2.errors))
1187 1199 form3 = madweb.forms.AdvScriptParmsFiltersForm(request.GET)
1188 1200 if not form3.is_valid():
1189 1201 raise ValueError('Form error: %s' % (form3.errors))
1190 1202 cookieDict = request.COOKIES
1191 1203 if not 'user_fullname' in cookieDict:
1192 1204 return(HttpResponse('<p>Cookie with user_fullname required for generateAdvancedDownloadScript</p>'))
1193 1205 user_fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
1194 1206 user_email = cookieDict['user_email']
1195 1207 user_affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
1196 1208 madWebObj = madrigal.ui.web.MadrigalWeb()
1197 1209 script_text = madWebObj.generateGlobalIsprintScriptFromForm(form1.cleaned_data, form2.cleaned_data,
1198 1210 form3.cleaned_data, user_fullname,
1199 1211 user_email, user_affiliation)
1200 1212 return render(request, 'madweb/download_files_script.html', {'script_text': script_text})
1201 1213
1202 1214
1203 1215 def generate_parms_script(request):
1204 1216 """generate_parms_script is a Ajax call that returns the generated parameter script.
1205 1217
1206 1218 Inputs:
1207 1219 request
1208 1220 """
1209 1221 form = madweb.forms.AdvScriptParmsForm(request.GET)
1210 1222 return render(request, 'madweb/download_adv_parms_script.html', {'form': form,
1211 1223 'parmList': form.parmList})
1212 1224
1213 1225
1214 1226 def generate_parms_filters_script(request):
1215 1227 """generate_parms_filters_script is a Ajax call that returns the generated parameter filters script.
1216 1228
1217 1229 Inputs:
1218 1230 request
1219 1231 """
1220 1232 form = madweb.forms.AdvScriptParmsFiltersForm(request.GET)
1221 1233 return render(request, 'madweb/download_adv_parms_filters_script.html', {'form': form})
1222 1234
1223 1235
1224 1236 def ftp(request):
1225 1237 """ftp creates the first ftp page listing instruments
1226 1238 """
1227 1239 madDB = madrigal.metadata.MadrigalDB()
1228 1240 bg_color = madDB.getBackgroundColor()
1229 1241 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1230 1242 siteName, siteList = madWebObj.getSiteInfo()
1231 1243 cookieDict = request.COOKIES
1232 1244 if not 'user_fullname' in cookieDict:
1233 1245 return(HttpResponse('<p>Cookie with user_fullname required for ftp</p>'))
1234 1246 fullname = django.utils.http.urlquote_plus(cookieDict['user_fullname'])
1235 1247 email = cookieDict['user_email']
1236 1248 affiliation = django.utils.http.urlquote_plus(cookieDict['user_affiliation'])
1237 1249 # create instrument with data list with tuple (instrument_name, kinst)
1238 1250 madInstDataObj = madrigal.metadata.MadrigalInstrumentData(madDB)
1239 1251 madInstList = [(instrument_name, kinst) for kinst, instrument_name, site_id in madInstDataObj.getInstruments(local=True)]
1240 1252 return render(request, 'madweb/ftp_instruments.html', {'madInstList': madInstList, 'fullname': fullname,
1241 1253 'email': email, 'affiliation':affiliation, 'site_name': siteName,
1242 1254 'site_list': siteList, 'bg_color': bg_color})
1243 1255
1244 1256
1245 1257 def ftp_instrument(request, fullname, email, affiliation, kinst):
1246 1258 """ftp_instrument creates the first ftp instrument page listing years
1247 1259 Inputs: kinst selected
1248 1260 """
1249 1261 kinst = int(kinst)
1250 1262 madDB = madrigal.metadata.MadrigalDB()
1251 1263 bg_color = madDB.getBackgroundColor()
1252 1264 madInstDataObj = madrigal.metadata.MadrigalInstrumentData(madDB)
1253 1265 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1254 1266 inst_name = madInstObj.getInstrumentName(kinst)
1255 1267 yearList = madInstDataObj.getInstrumentYears(kinst)
1256 1268 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1257 1269 siteName, siteList = madWebObj.getSiteInfo()
1258 1270 return render(request, 'madweb/ftp_years.html',{'yearList':yearList, 'kinst':kinst,
1259 1271 'inst_name':inst_name, 'fullname': fullname,
1260 1272 'email': email, 'affiliation':affiliation,
1261 1273 'site_name': siteName, 'site_list': siteList,
1262 1274 'bg_color': bg_color })
1263 1275
1264 1276
1265 1277 def ftp_year(request, fullname, email, affiliation, kinst, year):
1266 1278 """ftp_year creates the first ftp year page listing kindats
1267 1279 Inputs: kinst selected, year selected
1268 1280 """
1269 1281 kinst = int(kinst)
1270 1282 year = int(year)
1271 1283 madDB = madrigal.metadata.MadrigalDB()
1272 1284 bg_color = madDB.getBackgroundColor()
1273 1285 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1274 1286 inst_name = madInstObj.getInstrumentName(kinst)
1275 1287 madInstKindatObj = madrigal.metadata.MadrigalInstrumentKindats(madDB)
1276 1288 kindatList = madInstKindatObj.getKindatListForInstrumentYear(kinst, year)
1277 1289 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1278 1290 # create kindatDescList, a list of tuples of (kindat_desc, kindat) for that kinst, year
1279 1291 kindatDescList = []
1280 1292 for kindat in kindatList:
1281 1293 kindatDescList.append((madKindatObj.getKindatDescription(kindat, kinst), kindat))
1282 1294 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1283 1295 siteName, siteList = madWebObj.getSiteInfo()
1284 1296 return render(request, 'madweb/ftp_kindats.html', {'kindatDescList': kindatDescList, 'year': year,
1285 1297 'kinst': kinst, 'inst_name':inst_name, 'fullname': fullname,
1286 1298 'email': email, 'affiliation':affiliation,
1287 1299 'site_name': siteName, 'site_list': siteList,
1288 1300 'bg_color': bg_color })
1289 1301
1290 1302
1291 1303 def ftp_kindat(request, fullname, email, affiliation, kinst, year, kindat):
1292 1304 """ftp_kindat creates the first ftp format page listing formats to choose from
1293 1305 Inputs: kinst selected, year selected, kindat selected
1294 1306 """
1295 1307 kinst = int(kinst)
1296 1308 kindat = int(kindat)
1297 1309 madDB = madrigal.metadata.MadrigalDB()
1298 1310 bg_color = madDB.getBackgroundColor()
1299 1311 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1300 1312 kindat_desc = madKindatObj.getKindatDescription(kindat, kinst)
1301 1313 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1302 1314 inst_name = madInstObj.getInstrumentName(kinst)
1303 1315 formatDescList = [(formatDict[key], key) for key in list(formatDict.keys())]
1304 1316 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1305 1317 siteName, siteList = madWebObj.getSiteInfo()
1306 1318 return render(request, 'madweb/ftp_formats.html', {'formatDescList': formatDescList, 'year': year,
1307 1319 'kinst': kinst, 'inst_name': inst_name, 'kindat': kindat,
1308 1320 'kindat_desc': kindat_desc, 'fullname': fullname,
1309 1321 'email': email, 'affiliation': affiliation,
1310 1322 'site_name': siteName, 'site_list': siteList,
1311 1323 'bg_color': bg_color } )
1312 1324
1313 1325
1314 1326 def ftp_files(request, fullname, email, affiliation, kinst, year, kindat, format):
1315 1327 """ftp_files creates the ftp files page listing individual files
1316 1328 Inputs: kinst selected, year selected, kindat selected
1317 1329 """
1318 1330 kinst = int(kinst)
1319 1331 year = int(year)
1320 1332 dt = datetime.datetime(year,1,1) # speed up search
1321 1333 kindat = int(kindat)
1322 1334 if format not in ('hdf5', 'netCDF4', 'ascii'):
1323 1335 raise ValueError('Unknown format %s' % (format))
1324 1336 if format == 'netCDF4':
1325 1337 thisExt = '.nc'
1326 1338 elif format == 'ascii':
1327 1339 thisExt = '.txt'
1328 1340 format_desc = formatDict[format]
1329 1341 # create a list of full names, where each item is a tuple of
1330 1342 # (fullFilename in Madrigal, output basename with correct extension, date string)
1331 1343 fileList = []
1332 1344 madDB = madrigal.metadata.MadrigalDB()
1333 1345 bg_color = madDB.getBackgroundColor()
1334 1346 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1335 1347 kindat_desc = madKindatObj.getKindatDescription(kindat, kinst)
1336 1348 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1337 1349 inst_name = madInstObj.getInstrumentName(kinst)
1338 1350 pi = madInstObj.getContactName(kinst)
1339 1351 pi_email = madInstObj.getContactEmail(kinst)
1340 1352 madExpObj = madrigal.metadata.MadrigalExperiment(madDB)
1341 1353 startIndex = madExpObj.getStartPosition(dt) + 1
1342 1354 for loop in (0,1):
1343 1355 # we normally only loop once, but sometimes multi-year experiments require a slow full search
1344 1356 if loop == 0:
1345 1357 thisStartIndex = startIndex
1346 1358 else:
1347 1359 thisStartIndex = 0 # should only get to this case for rare multi-year experiments
1348 1360 for i in range(thisStartIndex, madExpObj.getExpCount()):
1349 1361 if kinst != madExpObj.getKinstByPosition(i):
1350 1362 continue
1351 1363 stTuple = madExpObj.getExpStartDateTimeByPosition(i)[0:6]
1352 1364 etTuple = madExpObj.getExpEndDateTimeByPosition(i)[0:6]
1353 1365 expTitle = madExpObj.getExpNameByPosition(i)
1354 1366 sDT = datetime.datetime(*stTuple)
1355 1367 eDT = datetime.datetime(*etTuple)
1356 1368 if sDT.year > year:
1357 1369 break
1358 1370 if eDT.year < year:
1359 1371 continue
1360 1372 dateStr = ' From %s to %s: %s' % (sDT.strftime('%Y-%m-%d %H:%M:%S'), eDT.strftime('%Y-%m-%d %H:%M:%S'), str(expTitle))
1361 1373 expDir = madExpObj.getExpDirByPosition(i)
1362 1374 # look at this exp for the right kindat
1363 1375 try:
1364 1376 madFileObj = madrigal.metadata.MadrigalMetaFile(madDB, os.path.join(expDir, 'fileTab.txt'))
1365 1377 except:
1366 1378 pass
1367 1379 for j in range(madFileObj.getFileCount()):
1368 1380 if madFileObj.getCategoryByPosition(j) not in (0,1):
1369 1381 # skip history and alternate files
1370 1382 continue
1371 1383 if madFileObj.getKindatByPosition(j) != kindat:
1372 1384 continue
1373 1385 statusStr = ' : %s' % (str(madFileObj.getStatusByPosition(j)))
1374 1386 fullFilename = os.path.join(expDir, madFileObj.getFilenameByPosition(j))
1375 1387 fullBasename = os.path.basename(fullFilename)
1376 1388 if format != 'hdf5':
1377 1389 base, file_extension = os.path.splitext(fullFilename)
1378 1390 basename = os.path.basename(base + thisExt)
1379 1391 else:
1380 1392 basename = os.path.basename(fullFilename)
1381 1393 # make sure this file isn't too big to create a cache
1382 1394 file_size = os.path.getsize(fullFilename)
1383 1395 if file_size > maxSize and format != 'hdf5':
1384 1396 # make sure cached file exists before adding
1385 1397 if format == 'netCDF4':
1386 1398 cachedFile = os.path.join(expDir, 'overview', fullBasename + thisExt)
1387 1399 else:
1388 1400 cachedFile = os.path.join(expDir, 'overview', fullBasename + thisExt + '.gz')
1389 1401 if not os.path.exists(cachedFile):
1390 1402 continue
1391 1403 fileList.append((urllib.parse.quote_plus(fullFilename), basename, dateStr + statusStr))
1392 1404
1393 1405 if len(fileList) > 0:
1394 1406 break # usually we avoid the slow full loop
1395 1407
1396 1408
1397 1409 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1398 1410 siteName, siteList = madWebObj.getSiteInfo()
1399 1411
1400 1412 return render(request, 'madweb/ftp_files.html', {'fullFilenames': fileList, 'year': year, 'kindat_desc': kindat_desc,
1401 1413 'kinst': kinst, 'inst_name':inst_name, 'fullname': fullname,
1402 1414 'kindat': kindat, 'format': format, 'format_desc': format_desc,
1403 1415 'email': email, 'affiliation':affiliation,
1404 1416 'site_name': siteName, 'site_list': siteList,
1405 1417 'pi_email': pi_email, 'pi_name': pi,
1406 1418 'bg_color': bg_color})
1407 1419
1408 1420
1409 1421 def ftp_download(request, user_fullname, user_email, user_affiliation, kinst, year, kindat, format, fullHdf5Filename):
1410 1422 """ftp_download creates the first ftp kindat page listing individual files
1411 1423 Inputs: kinst selected, year selected, kindat selected
1412 1424 """
1413 1425 madDB = madrigal.metadata.MadrigalDB()
1414 1426 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1415 1427 user_fullname = urllib.parse.unquote_plus(user_fullname)
1416 1428 user_affiliation = urllib.parse.unquote_plus(user_affiliation)
1417 1429 fullHdf5Filename = urllib.parse.unquote_plus(fullHdf5Filename)
1418 1430 fullFilename = madWebObj.downloadFullFileAsIs(fullHdf5Filename, format, user_fullname, user_email, user_affiliation)
1419 1431
1420 1432 f = open(fullFilename, 'rb')
1421 1433 filename = os.path.basename(fullFilename)
1422 1434 chunk_size = 8192
1423 1435 file_type = mimetypes.guess_type(fullFilename)[0]
1424 1436 if file_type is None:
1425 1437 file_type = 'application/octet-stream'
1426 1438 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
1427 1439 content_type=file_type)
1428 1440 response['Content-Length'] = os.path.getsize(fullFilename)
1429 1441 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
1430 1442 return(response)
1431 1443
1432 1444
1433 1445 @csrf_exempt
1434 1446 def ftp_multiple_download(request):
1435 1447 """ftp_download creates the first ftp kindat page listing individual files
1436 1448 Inputs: kinst selected, year selected, kindat selected
1437 1449 """
1438 1450 if request.method == 'POST':
1439 1451 reqDict = request.POST
1440 1452 else:
1441 1453 reqDict = request.GET
1442 1454 madDB = madrigal.metadata.MadrigalDB()
1443 1455 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1444 1456 user_fullname = urllib.parse.unquote_plus(reqDict.get('user_fullname'))
1445 1457 user_email = reqDict.get('user_email')
1446 1458 user_affiliation = urllib.parse.unquote_plus(reqDict.get('user_affiliation'))
1447 1459 format = reqDict.get('format')
1448 1460 fileList = reqDict.getlist('fullFilename')
1449 1461 fileList = [urllib.parse.unquote_plus(filename) for filename in fileList]
1450 1462 if len(fileList) > 10:
1451 1463 # send user an email with warning
1452 1464 tmpDir = os.path.join(madDB.getMadroot(), 'experiments/stage')
1453 1465 fullFilename = os.path.join(tmpDir, 'result_error_%06i.txt' % (random.randint(0,999999)))
1454 1466 f = open(fullFilename, 'w')
1455 1467 f.write('Error - you requested %i files, maximum is 10\n' % (len(fileList)))
1456 1468 f.close()
1457 1469 else:
1458 1470 fullFilename = madWebObj.downloadMultipleFiles(fileList, format, user_fullname, user_email, user_affiliation)
1459 1471
1460 1472 f = open(fullFilename, 'rb')
1461 1473 filename = os.path.basename(fullFilename)
1462 1474 chunk_size = 8192
1463 1475 file_type = mimetypes.guess_type(fullFilename)[0]
1464 1476 if file_type is None:
1465 1477 file_type = 'application/octet-stream'
1466 1478 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
1467 1479 content_type=file_type)
1468 1480 response['Content-Length'] = os.path.getsize(fullFilename)
1469 1481 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
1470 1482 return(response)
1471 1483
1472 1484
1473 1485 def instrument_metadata(request):
1474 1486 """instrument_metadata returns the instrument_metadata page.
1475 1487
1476 1488 Inputs:
1477 1489 request
1478 1490 """
1479 1491 # create a list of tuples of (kinst, name, category, latitude, longitude, altitude, pi, pi_email, mnemonic)
1480 1492 madDB = madrigal.metadata.MadrigalDB()
1481 1493 bg_color = madDB.getBackgroundColor()
1482 1494 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1483 1495 siteName, siteList = madWebObj.getSiteInfo()
1484 1496 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1485 1497 instList = []
1486 1498 for name, mnemonic, kinst, category, catID in madInstObj.getOrderedInstrumentList():
1487 1499 latitude = madInstObj.getLatitude(kinst)
1488 1500 longitude = madInstObj.getLongitude(kinst)
1489 1501 altitude = madInstObj.getAltitude(kinst)
1490 1502 pi = madInstObj.getContactName(kinst)
1491 1503 pi_email = madInstObj.getContactEmail(kinst)
1492 1504 instList.append((kinst, name, category, latitude, longitude, altitude, pi, pi_email, mnemonic))
1493 1505
1494 1506 responseDict = {'inst_active': 'class="active"', 'instList': instList,
1495 1507 'site_name': siteName, 'site_list': siteList, 'bg_color': bg_color}
1496 1508 return render(request, 'madweb/instrument_metadata.html', responseDict)
1497 1509
1498 1510
1499 1511 def site_metadata(request):
1500 1512 """site_metadata returns the site_metadata page.
1501 1513
1502 1514 Inputs:
1503 1515 request
1504 1516 """
1505 1517 # create a list of tuples of (siteId, name, url, contact, contact email, version)
1506 1518 madDB = madrigal.metadata.MadrigalDB()
1507 1519 bg_color = madDB.getBackgroundColor()
1508 1520 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1509 1521 siteName, otherSiteList = madWebObj.getSiteInfo()
1510 1522 madSiteObj = madrigal.metadata.MadrigalSite(madDB)
1511 1523 siteList = []
1512 1524 for siteId, siteName in madSiteObj.getSiteList():
1513 1525 if madSiteObj.getSiteServer(siteId).find('http') == -1:
1514 1526 url = 'http://' + os.path.join(madSiteObj.getSiteServer(siteId),
1515 1527 madSiteObj.getSiteDocRoot(siteId))
1516 1528 else:
1517 1529 url = os.path.join(madSiteObj.getSiteServer(siteId),
1518 1530 madSiteObj.getSiteDocRoot(siteId))
1519 1531 contact = madSiteObj.getSiteContactName(siteId)
1520 1532 contact_email = madSiteObj.getSiteEmail(siteId)
1521 1533 version = madSiteObj.getSiteVersion(siteId)
1522 1534 siteList.append((siteId, siteName, url, contact, contact_email, version))
1523 1535
1524 1536 responseDict = {'site_active': 'class="active"', 'siteList': siteList,
1525 1537 'site_name': siteName, 'site_list': otherSiteList, 'bg_color': bg_color}
1526 1538 return render(request, 'madweb/site_metadata.html', responseDict)
1527 1539
1528 1540
1529 1541 def parameter_metadata(request):
1530 1542 """parameter_metadata returns the site_metadata page.
1531 1543
1532 1544 Inputs:
1533 1545 request
1534 1546 """
1535 1547 madDB = madrigal.metadata.MadrigalDB()
1536 1548 bg_color = madDB.getBackgroundColor()
1537 1549 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1538 1550 siteName, siteList = madWebObj.getSiteInfo()
1539 1551 madParmObj = madrigal.data.MadrigalParameters(madDB)
1540 1552 madParmCatObj = madrigal.metadata.MadrigalParmCategory(madDB)
1541 1553 parmDict = {} # key is category string, value is list of category tuples (mnemonic, description, units, code)
1542 1554 parmList = [] # list of tuples, each tuple either a single category, or (mnemonic, description, units, code)
1543 1555 categoryList = []
1544 1556 categoryUrlList = []
1545 1557 for mnemonic in madParmObj.getSortedMnemonicList():
1546 1558 description = madParmObj.getSimpleParmDescription(mnemonic)
1547 1559 units = madParmObj.getParmUnits(mnemonic)
1548 1560 code = madParmObj.getParmCodeFromMnemonic(mnemonic)
1549 1561 category = madParmObj.getParmCategory(mnemonic)
1550 1562 if category is None:
1551 1563 # deprecated prolog parm
1552 1564 continue
1553 1565 if category in list(parmDict.keys()):
1554 1566 parmDict[category].append((mnemonic, description, units, code))
1555 1567 else:
1556 1568 parmDict[category] = [(mnemonic, description, units, code)]
1557 1569
1558 1570 # now loop through all categories
1559 1571 for thisCategory, catId in madParmCatObj.getCategoryList():
1560 1572 parmList.append((thisCategory,))
1561 1573 categoryList.append(thisCategory)
1562 1574 categoryAnchor = thisCategory.replace(' ','_')
1563 1575 categoryUrlList.append('<a href="#%s">%s</a>' % (categoryAnchor, thisCategory))
1564 1576 for values in parmDict[thisCategory]:
1565 1577 parmList.append(values)
1566 1578
1567 1579 responseDict = {'parm_active': 'class="active"', 'parmList': parmList,
1568 1580 'categoryUrlList':categoryUrlList,
1569 1581 'site_name': siteName, 'site_list': siteList, 'bg_color': bg_color}
1570 1582 return render(request, 'madweb/parameter_metadata.html', responseDict)
1571 1583
1572 1584
1573 1585 def kindat_metadata(request):
1574 1586 """kindat_metadata returns the kindat_metadata page.
1575 1587
1576 1588 Inputs:
1577 1589 request
1578 1590 """
1579 1591 # create a list of tuples of (kindat, description, kinst, instrument_name)
1580 1592 madDB = madrigal.metadata.MadrigalDB()
1581 1593 bg_color = madDB.getBackgroundColor()
1582 1594 madKindatObj = madrigal.metadata.MadrigalKindat(madDB)
1583 1595 madInstObj = madrigal.metadata.MadrigalInstrument(madDB)
1584 1596 madInstKindatObj = madrigal.metadata.MadrigalInstrumentKindats(madDB)
1585 1597 # create a dict of key = kindat code, value list of associated instruments
1586 1598 kindatDict = {}
1587 1599 for name, mnem, kinst in madInstObj.getInstrumentList():
1588 1600 thisKindatList = madInstKindatObj.getKindatListForInstruments(kinst)
1589 1601 for kindat in thisKindatList:
1590 1602 if kindat not in kindatDict:
1591 1603 kindatDict[kindat] = [kinst]
1592 1604 else:
1593 1605 kindatDict[kindat].append(kinst)
1594 1606
1595 1607 kindatList = []
1596 1608 for description, code_str in madKindatObj.getKindatList():
1597 1609 try:
1598 1610 kinst, kindat = code_str.split('_')
1599 1611 instName = madInstObj.getInstrumentName(int(kinst))
1600 1612 except:
1601 1613 kindat = code_str
1602 1614 try:
1603 1615 kinst = str(kindatDict[int(kindat)][0])
1604 1616 instName = madInstObj.getInstrumentName(int(kinst))
1605 1617 except KeyError:
1606 1618 kinst = '-'
1607 1619 instName = 'Unspecified'
1608 1620 kindatList.append((kindat, description, kinst, instName))
1609 1621 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1610 1622 siteName, siteList = madWebObj.getSiteInfo()
1611 1623
1612 1624 responseDict = {'kindat_active': 'class="active"', 'kindatList': kindatList,
1613 1625 'site_name': siteName, 'site_list': siteList, 'bg_color': bg_color}
1614 1626 return render(request, 'madweb/kindat_metadata.html', responseDict)
1615 1627
1616 1628
1617 1629 def madrigal_calculator(request):
1618 1630 """madrigal_calculator returns the Madrigal Calculator page.
1619 1631
1620 1632 Inputs:
1621 1633 request
1622 1634 """
1623 1635 madDB = madrigal.metadata.MadrigalDB()
1624 1636 bg_color = madDB.getBackgroundColor()
1625 1637 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1626 1638 siteName, siteList = madWebObj.getSiteInfo()
1627 1639 # original blank form
1628 1640 madCalculatorForm = madweb.forms.MadCalculatorForm()
1629 1641 parmList = [(parm, madCalculatorForm.parmDescDict[parm]) for parm in list(madCalculatorForm.parmDescDict.keys())]
1630 1642 return render(request, 'madweb/madrigal_calculator.html', {'madCalculator_active': 'class="active"',
1631 1643 'form': madCalculatorForm,
1632 1644 'parmList': parmList,
1633 1645 'site_name': siteName, 'site_list': siteList,
1634 1646 'bg_color': bg_color, 'datetime': True})
1635 1647
1636 1648 def madrigal_calculator_output(request):
1637 1649 """madrigal_calculator returns the output from the Madrigal Calculator page.
1638 1650
1639 1651 Inputs:
1640 1652 request
1641 1653 """
1642 1654 madDB = madrigal.metadata.MadrigalDB()
1643 1655 bg_color = madDB.getBackgroundColor()
1644 1656 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1645 1657 siteName, siteList = madWebObj.getSiteInfo()
1646 1658
1647 1659 madCalculatorForm = madweb.forms.MadCalculatorForm(request.GET)
1648 1660
1649 1661 try:
1650 1662 if not madCalculatorForm.is_valid():
1651 1663 return(HttpResponse(str(madCalculatorForm.errors)))
1652 1664 except KeyError:
1653 1665 return(HttpResponse('<p>Missing arguments in madCalculatorOutput</p>'))
1654 1666
1655 1667 text = madWebObj.runMadrigalCalculatorFromForm(madCalculatorForm.cleaned_data)
1656 1668
1657 1669 return render(request, 'madweb/madrigal_calculator_output.html', {'madCalculator_active': 'class="active"',
1658 1670 'text': text,
1659 1671 'site_name': siteName, 'site_list': siteList,
1660 1672 'bg_color': bg_color})
1661 1673
1662 1674
1663 1675 def get_metadata(request):
1664 1676 """get_metadata allows local metadata files to be downloaded.
1665 1677
1666 1678 Inputs:
1667 1679 request
1668 1680 """
1669 1681 fileDict = {'0':'expTab.txt',
1670 1682 '1': 'fileTab.txt',
1671 1683 '3': 'instTab.txt',
1672 1684 '4': 'parmCodes.txt',
1673 1685 '5': 'siteTab.txt',
1674 1686 '6': 'typeTab.txt',
1675 1687 '7': 'instKindatTab.txt',
1676 1688 '8': 'instParmTab.txt',
1677 1689 '9': 'madCatTab.txt',
1678 1690 '10': 'instType.txt'}
1679 1691 form = madweb.forms.GetMetadataForm(request.GET)
1680 1692 if form.is_valid():
1681 1693 madDB = madrigal.metadata.MadrigalDB()
1682 1694 downloadFile = os.path.join(madDB.getMetadataDir(),
1683 1695 fileDict[form.cleaned_data['fileType']])
1684 1696
1685 1697
1686 1698 f = open(downloadFile, 'rb')
1687 1699 filename = os.path.basename(downloadFile)
1688 1700 chunk_size = 8192
1689 1701 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
1690 1702 content_type=mimetypes.guess_type(downloadFile)[0])
1691 1703 response['Content-Length'] = os.path.getsize(downloadFile)
1692 1704 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
1693 1705 return(response)
1694 1706
1695 1707 else:
1696 1708 madDB = madrigal.metadata.MadrigalDB()
1697 1709 bg_color = madDB.getBackgroundColor()
1698 1710 form = madweb.forms.GetMetadataForm()
1699 1711 return render(request, 'madweb/get_metadata.html', {'form': form, 'bg_color': bg_color})
1700 1712
1701 1713
1702 1714 def looker_main(request):
1703 1715 """looker_main loads the main looker selection form.
1704 1716
1705 1717 Inputs:
1706 1718 request
1707 1719 """
1708 1720 madDB = madrigal.metadata.MadrigalDB()
1709 1721 bg_color = madDB.getBackgroundColor()
1710 1722 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1711 1723 siteName, siteList = madWebObj.getSiteInfo()
1712 1724 lookerSelectForm = madweb.forms.LookerSelectForm()
1713 1725 return render(request, 'madweb/looker_main.html', {'looker_active': 'class="active"',
1714 1726 'form': lookerSelectForm,
1715 1727 'site_name': siteName, 'site_list': siteList,
1716 1728 'bg_color': bg_color})
1717 1729
1718 1730
1719 1731 def looker_form(request):
1720 1732 """looker_form loads the appropriate looker form.
1721 1733
1722 1734 Inputs:
1723 1735 request
1724 1736 """
1725 1737 madDB = madrigal.metadata.MadrigalDB()
1726 1738 bg_color = madDB.getBackgroundColor()
1727 1739 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1728 1740 siteName, siteList = madWebObj.getSiteInfo()
1729 1741 if not 'looker_options' in request.GET:
1730 1742 return(HttpResponse('<p>looker form requires looker_options</p>'))
1731 1743 form = madweb.forms.LookerSelectForm(request.GET)
1732 1744 if form.is_valid():
1733 1745 option = form.cleaned_data['looker_options']
1734 1746 if option == '1':
1735 1747 form = madweb.forms.LookerGeodeticRadar()
1736 1748 return render(request, 'madweb/looker_geodetic_to_radar.html', {'looker_active': 'class="active"',
1737 1749 'form': form,
1738 1750 'site_name': siteName, 'site_list': siteList,
1739 1751 'bg_color': bg_color})
1740 1752 elif option == '2':
1741 1753 form = madweb.forms.LookerGeomagRadar()
1742 1754 return render(request, 'madweb/looker_geomagnetic_to_radar.html', {'looker_active': 'class="active"',
1743 1755 'form': form,
1744 1756 'site_name': siteName, 'site_list': siteList,
1745 1757 'bg_color': bg_color})
1746 1758 elif option == '3':
1747 1759 form = madweb.forms.LookerGeomagFromGeodetic()
1748 1760 return render(request, 'madweb/looker_geomagnetic_from_geodetic.html', {'looker_active': 'class="active"',
1749 1761 'form': form,
1750 1762 'site_name': siteName, 'site_list': siteList,
1751 1763 'bg_color': bg_color})
1752 1764 elif option == '4':
1753 1765 form = madweb.forms.LookerGeomagFromRadar()
1754 1766 return render(request, 'madweb/looker_geomagnetic_from_radar.html', {'looker_active': 'class="active"',
1755 1767 'form': form,
1756 1768 'site_name': siteName, 'site_list': siteList,
1757 1769 'bg_color': bg_color})
1758 1770 elif option == '5':
1759 1771 form = madweb.forms.LookerFieldLineFromRadar()
1760 1772 return render(request, 'madweb/looker_field_line_from_radar.html', {'looker_active': 'class="active"',
1761 1773 'form': form,
1762 1774 'site_name': siteName, 'site_list': siteList,
1763 1775 'bg_color': bg_color})
1764 1776 elif option == '6':
1765 1777 form = madweb.forms.LookerFieldLineFromGeodetic()
1766 1778 return render(request, 'madweb/looker_field_line_from_geodetic.html', {'looker_active': 'class="active"',
1767 1779 'form': form,
1768 1780 'site_name': siteName, 'site_list': siteList,
1769 1781 'bg_color': bg_color})
1770 1782 elif option == '7':
1771 1783 form = madweb.forms.LookerFieldLineFromApex()
1772 1784 return render(request, 'madweb/looker_field_line_from_apex.html', {'looker_active': 'class="active"',
1773 1785 'form': form,
1774 1786 'site_name': siteName, 'site_list': siteList,
1775 1787 'bg_color': bg_color})
1776 1788 elif option == '8':
1777 1789 form = madweb.forms.LookerConjugateFromGeodetic()
1778 1790 return render(request, 'madweb/looker_conjugate_from_geodetic.html', {'looker_active': 'class="active"',
1779 1791 'form': form,
1780 1792 'site_name': siteName, 'site_list': siteList,
1781 1793 'bg_color': bg_color,
1782 1794 'datetime': True})
1783 1795 else:
1784 1796 raise ValueError(str(form.errors))
1785 1797
1786 1798
1787 1799 def looker_output(request):
1788 1800 """looker_output loads the appropriate looker output.
1789 1801
1790 1802 Inputs:
1791 1803 request
1792 1804 """
1793 1805 madDB = madrigal.metadata.MadrigalDB()
1794 1806 bg_color = madDB.getBackgroundColor()
1795 1807 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
1796 1808 siteName, siteList = madWebObj.getSiteInfo()
1797 1809
1798 1810 if not 'looker_options' in request.GET:
1799 1811 return(HttpResponse('<p>looker missing arguments</p>'))
1800 1812
1801 1813 if request.GET['looker_options'] == "1":
1802 1814 form = madweb.forms.LookerGeodeticRadar(request.GET)
1803 1815 if form.is_valid():
1804 1816 text = madWebObj.runLookerFromForm(form.cleaned_data)
1805 1817 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1806 1818 'type': 'Az, El, Range to Geodetic points',
1807 1819 'text': text,
1808 1820 'site_name': siteName, 'site_list': siteList,
1809 1821 'bg_color': bg_color})
1810 1822 else:
1811 1823 raise ValueError(str(form.errors))
1812 1824 elif request.GET['looker_options'] == "2":
1813 1825 form = madweb.forms.LookerGeomagRadar(request.GET)
1814 1826 if form.is_valid():
1815 1827 text = madWebObj.runLookerFromForm(form.cleaned_data)
1816 1828 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1817 1829 'type': 'Az, El, Range to Geomagnetic (apex) points',
1818 1830 'text': text,
1819 1831 'site_name': siteName, 'site_list': siteList,
1820 1832 'bg_color': bg_color})
1821 1833 else:
1822 1834 raise ValueError(str(form.errors))
1823 1835 elif request.GET['looker_options'] == "3":
1824 1836 form = madweb.forms.LookerGeomagFromGeodetic(request.GET)
1825 1837 if form.is_valid():
1826 1838 text = madWebObj.runLookerFromForm(form.cleaned_data)
1827 1839 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1828 1840 'type': 'Apex Geomagnetic coordinates from Geodetic grid',
1829 1841 'text': text,
1830 1842 'site_name': siteName, 'site_list': siteList,
1831 1843 'bg_color': bg_color})
1832 1844 else:
1833 1845 raise ValueError(str(form.errors))
1834 1846 elif request.GET['looker_options'] == "4":
1835 1847 form = madweb.forms.LookerGeomagFromRadar(request.GET)
1836 1848 if form.is_valid():
1837 1849 text = madWebObj.runLookerFromForm(form.cleaned_data)
1838 1850 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1839 1851 'type': 'Apex Geomagnetic and geodetic coordinates and aspect angle from a grid of azimuth, elevation, and range',
1840 1852 'text': text,
1841 1853 'site_name': siteName, 'site_list': siteList,
1842 1854 'bg_color': bg_color})
1843 1855 else:
1844 1856 raise ValueError(str(form.errors))
1845 1857 elif request.GET['looker_options'] == "5":
1846 1858 form = madweb.forms.LookerFieldLineFromRadar(request.GET)
1847 1859 if form.is_valid():
1848 1860 text = madWebObj.runLookerFromForm(form.cleaned_data)
1849 1861 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1850 1862 'type': 'Field line coordinates for a field line set by radar parameters',
1851 1863 'text': text,
1852 1864 'site_name': siteName, 'site_list': siteList,
1853 1865 'bg_color': bg_color})
1854 1866 else:
1855 1867 raise ValueError(str(form.errors))
1856 1868 elif request.GET['looker_options'] == "6":
1857 1869 form = madweb.forms.LookerFieldLineFromGeodetic(request.GET)
1858 1870 if form.is_valid():
1859 1871 text = madWebObj.runLookerFromForm(form.cleaned_data)
1860 1872 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1861 1873 'type': 'Field line coordinates and radar look parameters for given field line',
1862 1874 'text': text,
1863 1875 'site_name': siteName, 'site_list': siteList,
1864 1876 'bg_color': bg_color})
1865 1877 else:
1866 1878 raise ValueError(str(form.errors))
1867 1879 elif request.GET['looker_options'] == "7":
1868 1880 form = madweb.forms.LookerFieldLineFromApex(request.GET)
1869 1881 if form.is_valid():
1870 1882 text = madWebObj.runLookerFromForm(form.cleaned_data)
1871 1883 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1872 1884 'type': 'Field line coordinates and radar look parameters for given field line',
1873 1885 'text': text,
1874 1886 'site_name': siteName, 'site_list': siteList,
1875 1887 'bg_color': bg_color})
1876 1888 else:
1877 1889 raise ValueError(str(form.errors))
1878 1890 elif request.GET['looker_options'] == "8":
1879 1891 form = madweb.forms.LookerConjugateFromGeodetic(request.GET)
1880 1892 if form.is_valid():
1881 1893 text = madWebObj.runLookerFromForm(form.cleaned_data)
1882 1894 return render(request, 'madweb/looker_output.html', {'looker_active': 'class="active"',
1883 1895 'type': 'Point/Magnetic Conjugate Point vs Latitude, Longitude, Altitude',
1884 1896 'datetime': form.cleaned_data['datetime'],
1885 1897 'text': text,
1886 1898 'site_name': siteName, 'site_list': siteList,
1887 1899 'bg_color': bg_color})
1888 1900 else:
1889 1901 raise ValueError(str(form.errors))
1890 1902
1891 1903 else:
1892 1904 raise ValueError('Unknown looker_option <%s>' % (str(request.GET['looker_options'])))
1893 1905
1894 1906
1895 1907
1896 1908 def get_version_service(request):
1897 1909 """get_version_service runs the getVersionService.py service.
1898 1910
1899 1911 Inputs:
1900 1912 request (ignored)
1901 1913
1902 1914 Returns a single line of text, with the version in the form <major_version_int>.<minor_version_int>[.<sub_version_int>]
1903 1915 """
1904 1916 madDB = madrigal.metadata.MadrigalDB()
1905 1917 siteID = madDB.getSiteID()
1906 1918 madSiteObj = madrigal.metadata.MadrigalSite(madDB)
1907 1919 return(HttpResponse(madSiteObj.getSiteVersion(siteID)))
1908 1920
1909 1921
1910 1922
1911 1923 def get_instruments_service(request):
1912 1924 """get_instruments_service runs the getInstrumentsService.py service.
1913 1925
1914 1926 Inputs:
1915 1927 request (ignored)
1916 1928
1917 1929 Returns comma-delimited data, one line for each experiment, with the following fields:
1918 1930
1919 1931 1. instrument.name Example: 'Millstone Hill Incoherent Scatter Radar'
1920 1932
1921 1933 2. instrument.code Example: 30
1922 1934
1923 1935 3. instrument.mnemonic (3 char string) Example: 'mlh'
1924 1936
1925 1937 4. instrument.latitude Example: 45.0
1926 1938
1927 1939 5. instrument.longitude Example: 110.0
1928 1940
1929 1941 6. instrument.altitude Example: 0.015 (km)
1930 1942
1931 1943 7. instrument.category Example: 'Incoherent Scatter Radars'
1932 1944
1933 1945 8. contact name
1934 1946
1935 1947 9. contact email
1936 1948 """
1937 1949 # create MadrigalDB obj
1938 1950 madDBObj = madrigal.metadata.MadrigalDB()
1939 1951
1940 1952 # create MadrigalInstument object
1941 1953 madInst = madrigal.metadata.MadrigalInstrument(madDBObj)
1942 1954
1943 1955 # get instrument list
1944 1956 instList = madInst.getInstrumentList()
1945 1957
1946 1958 # loop through each instrument
1947 1959 instStr = ''
1948 1960 for inst in instList:
1949 1961 name = inst[0]
1950 1962 code = inst[2]
1951 1963 mnemonic = inst[1]
1952 1964 latitude = madInst.getLatitude(code)
1953 1965 if latitude == None:
1954 1966 latitude = 0.0
1955 1967 longitude = madInst.getLongitude(code)
1956 1968 if longitude == None:
1957 1969 longitude = 0.0
1958 1970 altitude = madInst.getAltitude(code)
1959 1971 if altitude == None:
1960 1972 altitude = 0.0
1961 1973 category = madInst.getCategory(code)
1962 1974 if category == None:
1963 1975 category = ''
1964 1976 # print data
1965 1977 contactName = madInst.getContactName(code)
1966 1978 contactEmail = madInst.getContactEmail(code)
1967 1979 instStr += '%s,%i,%s,%f,%f,%f,%s,%s,%s\n' % (name,
1968 1980 code,
1969 1981 mnemonic,
1970 1982 latitude,
1971 1983 longitude,
1972 1984 altitude,
1973 1985 category,
1974 1986 str(contactName),
1975 1987 str(contactEmail))
1976 1988
1977 1989 return render(request, 'madweb/service.html', {'text': instStr})
1978 1990
1979 1991
1980 1992 def get_experiments_service(request):
1981 1993 """get_experiments_service runs the getExperimentsService.py service.
1982 1994
1983 1995 Inputs:
1984 1996 request/url - contains arguments:
1985 1997
1986 1998 code - one or more kindat values
1987 1999
1988 2000 startyear, startmonth, startday, starthour, startmin, startsec
1989 2001
1990 2002 endyear, endmonth, endday, endhour, endmin, endsec
1991 2003
1992 2004 local (defaults to True)
1993 2005
1994 2006 Returns comma-delimited data, one line for each experiment, with the following fields:
1995 2007
1996 2008 1. experiment.id (int) Example: 10000111
1997 2009
1998 2010 2. experiment.url (string) Example: 'http://www.haystack.mit.edu/cgi-bin/madtoc/1997/mlh/03dec97'
1999 2011
2000 2012 3. experiment.name (string) Example: 'Wide Latitude Substorm Study'
2001 2013
2002 2014 4. experiment.siteid (int) Example: 1
2003 2015
2004 2016 5. experiment.sitename (string) Example: 'Millstone Hill Observatory'
2005 2017
2006 2018 6. experiment.instcode (int) Code of instrument. Example: 30
2007 2019
2008 2020 7. experiment.instname (string) Instrument name. Example: 'Millstone Hill Incoherent Scatter Radar'
2009 2021
2010 2022 8. experiment.start year (int) year of experiment start
2011 2023
2012 2024 9. experiment.start month (int) month of experiment start
2013 2025
2014 2026 10. experiment.start day (int) day of experiment start
2015 2027
2016 2028 11. experiment.start hour (int) hour of experiment start
2017 2029
2018 2030 12. experiment.start minute (int) min of experiment start
2019 2031
2020 2032 13. experiment.start second (int) sec of experiment start
2021 2033
2022 2034 14. experiment.end year (int) year of experiment end
2023 2035
2024 2036 15. experiment.end month (int) month of experiment end
2025 2037
2026 2038 16. experiment.end day (int) day of experiment end
2027 2039
2028 2040 17. experiment.end hour (int) hour of experiment end
2029 2041
2030 2042 18. experiment.end minute (int) min of experiment end
2031 2043
2032 2044 19. experiment.end second (int) sec of experiment end
2033 2045
2034 2046 20. experiment.isLocal (int) 1 if local, 0 if not
2035 2047
2036 2048 21.experiment.PI (string) Experiment PI name Example: 'Phil Erickson'
2037 2049
2038 2050 22. experiment.PIEmail (string) Experiment PI email Example: 'perickson@haystack.mit.edu'
2039 2051
2040 2052 23. utc timestamp of last update to experiment
2041 2053
2042 2054 24. security value
2043 2055
2044 2056 """
2045 2057 codeList = request.GET.getlist('code')
2046 2058 codeList = [int(code) for code in codeList]
2047 2059 startyear = int(request.GET['startyear'])
2048 2060 startmonth = int(request.GET['startmonth'])
2049 2061 startday = int(request.GET['startday'])
2050 2062 starthour = int(request.GET['starthour'])
2051 2063 startmin = int(request.GET['startmin'])
2052 2064 startsec = int(request.GET['startsec'])
2053 2065 endyear = int(request.GET['endyear'])
2054 2066 endmonth = int(request.GET['endmonth'])
2055 2067 endday = int(request.GET['endday'])
2056 2068 endhour = int(request.GET['endhour'])
2057 2069 endmin = int(request.GET['endmin'])
2058 2070 endsec = int(request.GET['endsec'])
2059 2071 try:
2060 2072 local = int(request.GET['local'])
2061 2073 except:
2062 2074 local = 1
2063 2075
2064 2076
2065 2077 # if startsec or endsec in (60, 61), handle correctly
2066 2078 if startsec in (60, 61):
2067 2079 tmpTime = datetime.datetime(startyear,
2068 2080 startmonth,
2069 2081 startday,
2070 2082 starthour,
2071 2083 startmin,
2072 2084 59)
2073 2085 tmpTime += datetime.timedelta(0, startsec - 59)
2074 2086 startyear = tmpTime.year
2075 2087 startmonth = tmpTime.month
2076 2088 startday = tmpTime.day
2077 2089 starthour = tmpTime.hour
2078 2090 startmin = tmpTime.minute
2079 2091 startsec = tmpTime.second
2080 2092
2081 2093 if endsec in (60, 61):
2082 2094 tmpTime = datetime.datetime(endyear,
2083 2095 endmonth,
2084 2096 endday,
2085 2097 endhour,
2086 2098 endmin,
2087 2099 59)
2088 2100 tmpTime += datetime.timedelta(0, endsec - 59)
2089 2101 endyear = tmpTime.year
2090 2102 endmonth = tmpTime.month
2091 2103 endday = tmpTime.day
2092 2104 endhour = tmpTime.hour
2093 2105 endmin = tmpTime.minute
2094 2106 endsec = tmpTime.second
2095 2107
2096 2108 # if codeList is empty or contains 0, change it to only contain 0
2097 2109 if len(codeList) == 0 or 0 in codeList:
2098 2110 codeList = [0]
2099 2111
2100 2112 retStr = ''
2101 2113
2102 2114 # create MadrigalDB obj
2103 2115 madDBObj = madrigal.metadata.MadrigalDB()
2104 2116
2105 2117 # get the local site id
2106 2118 localSiteId = madDBObj.getSiteID()
2107 2119
2108 2120 # create MadrigalInstrument obj to convert kinst to instrument names
2109 2121 madInstObj = madrigal.metadata.MadrigalInstrument(madDBObj)
2110 2122
2111 2123 # create MadrigalSite obj to convert site id to site name
2112 2124 madSiteObj = madrigal.metadata.MadrigalSite(madDBObj)
2113 2125
2114 2126 madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
2115 2127 trusted = madWebObj.isTrusted()
2116 2128
2117 2129 # create starttime for filter, if possible
2118 2130 if startyear != None:
2119 2131 startTimeFilter = datetime.datetime(startyear,
2120 2132 startmonth,
2121 2133 startday,
2122 2134 starthour,
2123 2135 startmin,
2124 2136 startsec)
2125 2137 else:
2126 2138 startTimeFilter = None
2127 2139
2128 2140 # create endtime for filter, if possible
2129 2141 if endyear != None:
2130 2142 endTimeFilter = datetime.datetime(endyear,
2131 2143 endmonth,
2132 2144 endday,
2133 2145 endhour,
2134 2146 endmin,
2135 2147 endsec)
2136 2148 else:
2137 2149 endTimeFilter = None
2138 2150
2139 2151 # create MadrigalExperiments for local or all files
2140 2152 if local == 1:
2141 2153 madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)
2142 2154 else:
2143 2155 # use file expTabAll.txt to get all experiments
2144 2156 filename = madDBObj.getMadroot()
2145 2157 if filename[-1] != '/':
2146 2158 filename += '/'
2147 2159 filename += 'metadata/expTabAll.txt'
2148 2160 madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj, filename)
2149 2161
2150 2162 madExpObj.sortByDateSite()
2151 2163
2152 2164
2153 2165 # loop through the data
2154 2166 if not startTimeFilter is None:
2155 2167 position = madExpObj.getStartPosition(startTimeFilter)
2156 2168 else:
2157 2169 position = 0
2158 2170 while(True):
2159 2171 thisId = madExpObj.getExpIdByPosition(position)
2160 2172 # check for end
2161 2173 if thisId == None:
2162 2174 break
2163 2175 thisUrl = madExpObj.getExpUrlByPosition(position)
2164 2176 thisName = madExpObj.getExpNameByPosition(position)
2165 2177 thisSiteId = madExpObj.getExpSiteIdByPosition(position)
2166 2178 thisSiteName = madSiteObj.getSiteName(thisSiteId)
2167 2179 thisInstCode = madExpObj.getKinstByPosition(position)
2168 2180 thisInstName =madInstObj.getInstrumentName(thisInstCode)
2169 2181 thisStart = madExpObj.getExpStartDateTimeByPosition(position)
2170 2182 thisEnd = madExpObj.getExpEndDateTimeByPosition(position)
2171 2183 thisSecurity = madExpObj.getSecurityByPosition(position)
2172 2184 if thisSiteId == localSiteId:
2173 2185 thisLocal = 1
2174 2186 else:
2175 2187 thisLocal = 0
2176 2188 thisPI = madExpObj.getPIByPosition(position)
2177 2189 if thisPI in (None, ''):
2178 2190 thisPI = madInstObj.getContactName(thisInstCode)
2179 2191 thisPIEmail = madExpObj.getPIEmailByPosition(position)
2180 2192 if thisPIEmail in (None, ''):
2181 2193 thisPIEmail = madInstObj.getContactEmail(thisInstCode)
2182 2194 expDir = madExpObj.getExpDirByPosition(position)
2183 2195
2184 2196 position += 1
2185 2197
2186 2198 # some experiments set the end of the day to 24:00:00 - not
2187 2199 # technically correct - reset to 23:59:59
2188 2200
2189 2201 if (thisStart[3] == 24 and thisStart[4] == 0 and thisStart[5] == 0):
2190 2202 thisStart[3] = 23
2191 2203 thisStart[4] = 59
2192 2204 thisStart[5] = 59
2193 2205
2194 2206 if (thisEnd[3] == 24 and thisEnd[4] == 0 and thisEnd[5] == 0):
2195 2207 thisEnd[3] = 23
2196 2208 thisEnd[4] = 59
2197 2209 thisEnd[5] = 59
2198 2210
2199 2211 # apply filters
2200 2212
2201 2213 # first apply instrument code filter
2202 2214 if codeList[0] != 0:
2203 2215 if thisInstCode not in codeList:
2204 2216 continue
2205 2217
2206 2218 # apply starttime and endtime filters
2207 2219 thisStartTime = datetime.datetime(thisStart[0],
2208 2220 thisStart[1],
2209 2221 thisStart[2],
2210 2222 thisStart[3],
2211 2223 thisStart[4],
2212 2224 thisStart[5])
2213 2225
2214 2226 thisEndTime = datetime.datetime(thisEnd[0],
2215 2227 thisEnd[1],
2216 2228 thisEnd[2],
2217 2229 thisEnd[3],
2218 2230 thisEnd[4],
2219 2231 thisEnd[5])
2220 2232
2221 2233 if startTimeFilter != None:
2222 2234 if thisEndTime < startTimeFilter:
2223 2235 continue
2224 2236
2225 2237 if endTimeFilter != None:
2226 2238 if thisStartTime > endTimeFilter:
2227 2239 continue
2228 2240
2229 2241 # apply local filer
2230 2242 if local == 1 and thisLocal == 0:
2231 2243 continue
2232 2244
2233 2245 # apply security filter
2234 2246 if trusted == 0 and thisSecurity not in (0,2):
2235 2247 continue
2236 2248
2237 2249 # create exp timestamp
2238 2250 if local == 1:
2239 2251 thisUTTimestamp = int(os.stat(expDir).st_mtime + time.timezone)
2240 2252 else:
2241 2253 thisUTTimestamp = 0
2242 2254
2243 2255 # add this experiment
2244 2256 retStr += '%i,%s,%s,%i,%s,%i,%s,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%s,%s,%i,%i\n' % \
2245 2257 (thisId,
2246 2258 thisUrl,
2247 2259 thisName,
2248 2260 thisSiteId,
2249 2261 thisSiteName,
2250 2262 thisInstCode,
2251 2263 thisInstName,
2252 2264 thisStart[0],
2253 2265 thisStart[1],
2254 2266 thisStart[2],
2255 2267 thisStart[3],
2256 2268 thisStart[4],
2257 2269 thisStart[5],
2258 2270 thisEnd[0],
2259 2271 thisEnd[1],
2260 2272 thisEnd[2],
2261 2273 thisEnd[3],
2262 2274 thisEnd[4],
2263 2275 thisEnd[5],
2264 2276 thisLocal,
2265 2277 str(thisPI),
2266 2278 str(thisPIEmail),
2267 2279 thisUTTimestamp,
2268 2280 thisSecurity)
2269 2281
2270 2282 return render(request, 'madweb/service.html', {'text': retStr})
2271 2283
2272 2284
2273 2285 def get_experiment_files_service(request):
2274 2286 """get_experiment_files_service runs the getExperimentFilesService.py service.
2275 2287
2276 2288 Inputs:
2277 2289 request/url - contains arguments:
2278 2290
2279 2291 id - local experiment id
2280 2292
2281 2293 Returns comma-delimited data, one line for each experiment file, with the following fields:
2282 2294
2283 2295 1. file.name (string) Example '/opt/mdarigal/blah/mlh980120g.001'
2284 2296
2285 2297 2. file.kindat (int) Kindat code. Example: 3001
2286 2298
2287 2299 3. file.kindat desc (string) Kindat description: Example 'Basic Derived Parameters'
2288 2300
2289 2301 4. file.category (int) (1=default, 2=variant, 3=history, 4=real-time)
2290 2302
2291 2303 5. file.status (string)('preliminary', 'final', or any other description)
2292 2304
2293 2305 6. file.permission (int) 0 for public, 1 for private. For now will not return private files.
2294 2306
2295 2307 7. file DOI (string) - citable url to file
2296 2308
2297 2309 Returns empty string if experiment id not found. Skips files that are not Hdf5
2298 2310 """
2299 2311 id = int(request.GET['id'])
2300 2312
2301 2313 # create MadrigalDB obj
2302 2314 madDBObj = madrigal.metadata.MadrigalDB()
2303 2315
2304 2316 # create MadrigalExperiments object to get full file name
2305 2317 madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)
2306 2318
2307 2319 # create Madrigal Kindat to get Kindat descriptions
2308 2320 madKindatObj = madrigal.metadata.MadrigalKindat(madDBObj)
2309 2321
2310 2322 madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
2311 2323 trusted = madWebObj.isTrusted()
2312 2324
2313 2325
2314 2326 retStr = ''
2315 2327 thisUrl = madExpObj.getExpUrlByExpId(id)
2316 2328 if thisUrl is None:
2317 2329 raise IOError('No such id: %i' % (id))
2318 2330 expPath = madExpObj.getExpDirByExpId(id)
2319 2331 kinst = madExpObj.getKinstByExpId(id)
2320 2332 if os.access(os.path.join(expPath, 'fileTab.txt'), os.R_OK):
2321 2333 madFileObj = madrigal.metadata.MadrigalMetaFile(madDBObj, os.path.join(expPath, 'fileTab.txt'))
2322 2334 for i in range(madFileObj.getFileCount()):
2323 2335 basename = madFileObj.getFilenameByPosition(i)
2324 2336 name = os.path.join(expPath, basename)
2325 2337 base_filename, file_extension = os.path.splitext(name)
2326 2338 if file_extension not in ('.hdf5', '.hdf', '.h5'):
2327 2339 continue
2328 2340 kindat = madFileObj.getKindatByPosition(i)
2329 2341 kindatdesc = madKindatObj.getKindatDescription(kindat, kinst)
2330 2342 category = madFileObj.getCategoryByPosition(i)
2331 2343 status = madFileObj.getStatusByPosition(i)
2332 2344 permission = madFileObj.getAccessByPosition(i)
2333 2345 doi = madFileObj.getFileDOIUrlByPosition(i)
2334 2346
2335 2347 # skip private files if not trusted
2336 2348 if trusted == 0 and int(permission) != 0:
2337 2349 continue
2338 2350
2339 2351 retStr += '%s,%i,%s,%i,%s,%i,%s\n' % \
2340 2352 (name,
2341 2353 kindat,
2342 2354 kindatdesc,
2343 2355 category,
2344 2356 status,
2345 2357 permission,
2346 2358 doi)
2347 2359
2348 2360
2349 2361
2350 2362 return render(request, 'madweb/service.html', {'text': django.utils.safestring.mark_safe(retStr)})
2351 2363
2352 2364
2353 2365 def get_parameters_service(request):
2354 2366 """get_parameters_service runs the getParametersService.py service.
2355 2367
2356 2368 Inputs:
2357 2369 request/url - contains arguments:
2358 2370
2359 2371 filename=<full path to data file>
2360 2372
2361 2373 Returns backslash-delimited data, one for each parameter either measured or derivable, with the following fields:
2362 2374
2363 2375 1. parameter.mnemonic (string) Example 'dti'
2364 2376
2365 2377 2. parameter.description (string) Example:
2366 2378 "F10.7 Multiday average observed (Ott)"
2367 2379
2368 2380 3. parameter.isError (int) 1 if error parameter, 0 if not
2369 2381
2370 2382 4. parameter.units (string) Example "W/m2/Hz"
2371 2383
2372 2384 5. parameter.isMeasured (int) 1 if measured, 0 if derivable
2373 2385
2374 2386 6. parameter.category (string) Example: "Time Related Parameter"
2375 2387
2376 2388 7. parameter.isSure (int) - 1 if parameter can be found for every record, 0 if can only be found for some.
2377 2389 Not relevant to Madrigal 3, where always 1
2378 2390
2379 2391 8. parameter.isAddIncrement - 1 if additional increment, 0 if normal (Added in Madrigal 2.5)
2380 2392 Not relevant to Madrigal 3, where always -1
2381 2393 """
2382 2394 filename = request.GET['filename']
2383 2395
2384 2396 # create MadrigalDB obj
2385 2397 madDBObj = madrigal.metadata.MadrigalDB()
2386 2398
2387 2399 # create Madrigal File object
2388 2400 madFileObj = madrigal.data.MadrigalFile(filename, madDBObj)
2389 2401
2390 2402 # create Madrigal Parameter object
2391 2403 madParmObj = madrigal.data.MadrigalParameters(madDBObj)
2392 2404
2393 2405 # create Madrigal web object
2394 2406 madWebObj = madrigal.ui.web.MadrigalWebFormat()
2395 2407
2396 2408
2397 2409 # create lists of parameters
2398 2410 measParmList = []
2399 2411 derivedParmList = []
2400 2412 allParmList = []
2401 2413 sureParmList = []
2402 2414
2403 2415 # use the comprehensive list of parameters to check if derivable
2404 2416 parmList = madWebObj.getFormat('Comprehensive')
2405 2417
2406 2418 # populate lists
2407 2419 madFileObj.getMeasDervBothParmLists(parmList,
2408 2420 measParmList,
2409 2421 derivedParmList,
2410 2422 allParmList,
2411 2423 sureParmList)
2412 2424
2413 2425 retStr = ''
2414 2426
2415 2427 # loop through allParmList and output results
2416 2428 for parm in allParmList:
2417 2429 description = madParmObj.getSimpleParmDescription(parm)
2418 2430 isNorm = madParmObj.getParmType(parm)
2419 2431 if isNorm == 1:
2420 2432 isError = 0
2421 2433 else:
2422 2434 isError = 1
2423 2435 units = madParmObj.getParmUnits(parm)
2424 2436 if parm in measParmList:
2425 2437 isMeasured = 1
2426 2438 else:
2427 2439 isMeasured = 0
2428 2440 if parm in sureParmList:
2429 2441 isSure = 1
2430 2442 else:
2431 2443 isSure = 0
2432 2444 category = madParmObj.getParmCategory(parm)
2433 2445 try:
2434 2446 if madParmObj.isAddIncrement(parm):
2435 2447 isAddIncrement = 1
2436 2448 else:
2437 2449 isAddIncrement = 0
2438 2450 except:
2439 2451 isAddIncrement = -1
2440 2452 # print out this parm
2441 2453 retStr += '%s\\%s\\%i\\%s\\%i\\%s\\%i\\%i\n' % (parm,
2442 2454 description,
2443 2455 isError,
2444 2456 units,
2445 2457 isMeasured,
2446 2458 category,
2447 2459 isSure,
2448 2460 isAddIncrement)
2449 2461
2450 2462 return render(request, 'madweb/service.html', {'text': retStr})
2451 2463
2452 2464
2453 2465
2454 2466 def isprint_service(request):
2455 2467 """isprint_service runs the isprintService.py service.
2456 2468
2457 2469 Inputs:
2458 2470 request/url - contains arguments:
2459 2471
2460 2472 'file': The full path to the file to be analyzed by isprint. If over 50 MB, returns error message.
2461 2473
2462 2474 'parms': Multiple requested parameters, space (+) separated.
2463 2475
2464 2476 'filters': Multiple of filters desired, as in isprint command
2465 2477
2466 2478 'user_fullname' user name
2467 2479
2468 2480 'user_email' user email
2469 2481
2470 2482 'user_affiliation' user affiliation
2471 2483
2472 2484 'output' - option argument specifying output file basename. Will be Hdf5 format if extension in
2473 2485 ('hdf5', 'h5', 'hdf'). Will be netCDF4 is extension is '.nc'. Otherwise ascii. If not
2474 2486 given, output is ascii.
2475 2487
2476 2488 'header': t for headers, f for no header. Defaults to no header. Ignored if not ascii output
2477 2489
2478 2490 Returns data as either column delimited ascii, Hdf5, or netCDF4.
2479 2491 """
2480 2492 madDB = madrigal.metadata.MadrigalDB()
2481 2493 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
2482 2494
2483 2495 # get required arguments
2484 2496 thisFile = request.GET['file']
2485 2497 parms = request.GET.getlist('parms')
2486 2498 filters = request.GET.getlist('filters')
2487 2499 user_fullname = request.GET['user_fullname']
2488 2500 user_email = request.GET['user_email']
2489 2501 user_affiliation = request.GET['user_affiliation']
2490 2502
2491 2503 # get optional arguments
2492 2504 try:
2493 2505 output = os.path.basename(request.GET['output'])
2494 2506 filename, file_extension = os.path.splitext(output)
2495 2507 if file_extension in ('.hdf5', '.h5', '.hdf'):
2496 2508 format = 'Hdf5'
2497 2509 elif file_extension in ('.nc',):
2498 2510 format = 'netCDF4'
2499 2511 else:
2500 2512 format = 'ascii'
2501 2513 except:
2502 2514 format = 'ascii'
2503 2515 output = None
2504 2516
2505 2517 # verify thisFile exists, not too big
2506 2518 errorMessage = None
2507 2519 if not os.access(thisFile, os.R_OK):
2508 2520 errorMessage = 'File %s not found' % (thisFile)
2509 2521 elif os.path.getsize(thisFile) > 200.0E6:
2510 2522 errorMessage = 'File %s greater than 200 MB in size - running dynamic file creation not possible. Please use -- download as is -- instead.' % (thisFile)
2511 2523 if not errorMessage is None:
2512 2524 return render(request, 'madweb/service.html', {'text': errorMessage})
2513 2525
2514 2526 if not output is None:
2515 2527 # we need to write to a download file
2516 2528 downloadFile = os.path.join(tempfile.gettempdir(), output)
2517 2529 if os.access(downloadFile, os.R_OK):
2518 2530 try:
2519 2531 os.remove(downloadFile)
2520 2532 except:
2521 2533 pass
2522 2534 try:
2523 2535 header = request.GET['header']
2524 2536 if header not in ('t', 'f'):
2525 2537 raise ValueError('Unknown header value <%s>' % (header))
2526 2538 except:
2527 2539 header = 'f'
2528 2540
2529 2541 # log data access
2530 2542 madWebObj.logDataAccess(thisFile, user_fullname, user_email, user_affiliation)
2531 2543
2532 2544 # run isprint command
2533 2545 cmd = '%s/bin/isprint file=%s ' % (madDB.getMadroot(), thisFile)
2534 2546 if not output is None:
2535 2547 cmd += 'output=%s ' % (downloadFile)
2536 2548 delimiter = ' '
2537 2549 cmd += delimiter.join(parms) + ' '
2538 2550 filterStr = delimiter.join(filters)
2539 2551 cmd += filterStr + ' '
2540 2552 if format == 'ascii':
2541 2553 cmd += 'summary=f '
2542 2554 cmd += 'header=%s ' % (header)
2543 2555
2544 2556 if output is None:
2545 2557 # text response
2546 2558 #result = subprocess.check_output(cmd.split())
2547 2559 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
2548 2560 result,errtext = p.communicate()
2549 2561 if p.returncode != 0:
2550 2562 result = errtext
2551 2563 if type(result) in (bytes, numpy.bytes_):
2552 2564 result = result.decode('utf-8')
2553 2565 if header == 'f':
2554 2566 index = result.find('\n')
2555 2567 result = result[index+1:]
2556 2568 return render(request, 'madweb/service.html', {'text': result})
2557 2569 else:
2558 2570 # file download response
2559 2571 #subprocess.check_call(cmd.split())
2560 2572 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
2561 2573 result,errtext = p.communicate()
2562 2574 if p.returncode != 0:
2563 2575 # write the error to result file
2564 2576 f = open(downloadFile, 'w')
2565 2577 if type(errtext) in (bytes, numpy.bytes_):
2566 2578 errtext = errtext.decode('utf-8')
2567 2579 f.write(errtext)
2568 2580 f.close()
2569 2581
2570 2582 f = open(downloadFile, 'rb')
2571 2583 filename = os.path.basename(downloadFile)
2572 2584 chunk_size = 8192
2573 2585 file_type = mimetypes.guess_type(downloadFile)[0]
2574 2586 if file_type is None:
2575 2587 file_type = 'application/octet-stream'
2576 2588 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
2577 2589 content_type=file_type)
2578 2590 response['Content-Length'] = os.path.getsize(downloadFile)
2579 2591 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
2580 2592 os.remove(downloadFile)
2581 2593 return(response)
2582 2594
2583 2595
2584 2596 def get_madfile_service(request):
2585 2597 """get_madfile_service runs the getMadfile.cgi service.
2586 2598
2587 2599 Inputs:
2588 2600 request/url - contains arguments:
2589 2601
2590 2602 'fileName': The full path to the file to be downloaded as.
2591 2603
2592 2604 'fileType': -1 for ascii, -2 for Hdf5, -3 for netCDF4. No other values supported
2593 2605
2594 2606 'user_fullname' user name
2595 2607
2596 2608 'user_email' user email
2597 2609
2598 2610 'user_affiliation' user affiliation
2599 2611
2600 2612 Returns file as either column delimited ascii, Hdf5, or netCDF4.
2601 2613 """
2602 2614 madDB = madrigal.metadata.MadrigalDB()
2603 2615 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
2604 2616
2605 2617 # get required arguments
2606 2618 fileName = request.GET['fileName']
2607 2619 fileType = int(request.GET['fileType'])
2608 2620 user_fullname = request.GET['user_fullname']
2609 2621 user_email = request.GET['user_email']
2610 2622 user_affiliation = request.GET['user_affiliation']
2611 2623
2612 2624 if fileType not in (-1, -2, -3):
2613 2625 return(HttpResponse('<p>fileType %i not allowed: -1 for ascii, -2 for Hdf5, -3 for netCDF4</p>' % (fileType)))
2614 2626
2615 2627 # log data access
2616 2628 madWebObj.logDataAccess(fileName, user_fullname, user_email, user_affiliation)
2617 2629
2618 2630 if fileType in (-1, -3):
2619 2631 # may need to create temp file
2620 2632 filepath, file_extension = os.path.splitext(fileName)
2621 2633 basename = os.path.basename(filepath)
2622 2634 dirname = os.path.dirname(fileName)
2623 2635 if fileType == -1:
2624 2636 cachedTxtFile = os.path.join(dirname, 'overview', os.path.basename(fileName) + '.txt.gz')
2625 2637 tmpFile = os.path.join(tempfile.gettempdir(), basename + '.txt.gz')
2626 2638 if os.access(cachedTxtFile, os.R_OK):
2627 2639 shutil.copy(cachedTxtFile, tmpFile)
2628 2640 else:
2629 2641 tmpFile = os.path.join(tempfile.gettempdir(), basename + '.txt')
2630 2642 madrigal.cedar.convertToText(fileName, tmpFile)
2631 2643 else:
2632 2644 cachedNCFile = os.path.join(dirname, 'overview', os.path.basename(fileName) + '.nc')
2633 2645 tmpFile = os.path.join(tempfile.gettempdir(), basename + '.nc')
2634 2646 if os.access(cachedNCFile, os.R_OK):
2635 2647 shutil.copy(cachedNCFile, tmpFile)
2636 2648 else:
2637 2649 try:
2638 2650 madrigal.cedar.convertToNetCDF4(fileName, tmpFile)
2639 2651 except IOError:
2640 2652 cedarObj = madrigal.cedar.MadrigalCedarFile(fileName)
2641 2653 cedarObj.write('netCDF4', tmpFile)
2642 2654
2643 2655 else:
2644 2656 tmpFile = fileName
2645 2657
2646 2658 f = open(tmpFile, 'rb')
2647 2659 filename = os.path.basename(tmpFile)
2648 2660 chunk_size = 8192
2649 2661 file_type = mimetypes.guess_type(tmpFile)[0]
2650 2662 if file_type is None:
2651 2663 file_type = 'application/octet-stream'
2652 2664 response = StreamingHttpResponse(FileWrapper(f, chunk_size),
2653 2665 content_type=file_type)
2654 2666 response['Content-Length'] = os.path.getsize(tmpFile)
2655 2667 response['Content-Disposition'] = "attachment; filename=%s" % (filename)
2656 2668 if fileType in (-1, -3):
2657 2669 os.remove(tmpFile)
2658 2670 return(response)
2659 2671
2660 2672
2661 2673 def mad_calculator_service(request):
2662 2674 """mad_calculator_service runs the madCalculator service.
2663 2675
2664 2676 Inputs:
2665 2677 request/url - contains arguments:
2666 2678
2667 2679 year, month, day, hour, min, sec
2668 2680
2669 2681 startLat - Starting geodetic latitude, -90 to 90 (float)
2670 2682
2671 2683 endLat - Ending geodetic latitude, -90 to 90 (float)
2672 2684
2673 2685 stepLat - Latitude step (0.1 to 90) (float)
2674 2686
2675 2687 startLong - Starting geodetic longitude, -180 to 180 (float)
2676 2688
2677 2689 endLong - Ending geodetic longitude, -180 to 180 (float)
2678 2690
2679 2691 stepLong - Longitude step (0.1 to 180) (float)
2680 2692
2681 2693 startAlt - Starting geodetic altitude, >= 0 (float)
2682 2694
2683 2695 endAlt - Ending geodetic altitude, > 0 (float)
2684 2696
2685 2697 stepAlt - Altitude step (>= 0.1) (float)
2686 2698
2687 2699 parms - comma delimited string of Madrigal parameters desired
2688 2700
2689 2701 oneD - zero or more mnemonics,float values to set input 1D values
2690 2702
2691 2703 Returns comma-delimited data, one line for each combination of lat, long, and alt,
2692 2704 with the following fields:
2693 2705
2694 2706 1. latitude
2695 2707
2696 2708 2. longitude
2697 2709
2698 2710 3. altitude
2699 2711
2700 2712 4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
2701 2713 """
2702 2714 year = int(request.GET['year'])
2703 2715 month = int(request.GET['month'])
2704 2716 day = int(request.GET['day'])
2705 2717 hour = int(request.GET['hour'])
2706 2718 minute = int(request.GET['min'])
2707 2719 second = int(request.GET['sec'])
2708 2720 try:
2709 2721 dt = datetime.datetime(year, month, day, hour, minute, second)
2710 2722 except:
2711 2723 return(HttpResponse('Illegal time: year %i, month %i, day %i, hour %i, minute %i, second %i' % (year, month, day, hour, minute, second)))
2712 2724
2713 2725 startLat = float(request.GET['startLat'])
2714 2726 endLat = float(request.GET['endLat'])
2715 2727 if startLat == endLat:
2716 2728 endLat += 0.001
2717 2729 elif startLat > endLat:
2718 2730 return(HttpResponse('startLat %s cannot be greater than endLat %s' % (str(startLat), str(endLat))))
2719 2731 stepLat = float(request.GET['stepLat'])
2720 2732 if stepLat < 0.0:
2721 2733 return(HttpResponse('stepLat %s cannot be less than zero' % (str(stepLat))))
2722 2734 elif stepLat == 0.0:
2723 2735 stepLat = 0.001
2724 2736 latList = list(numpy.arange(startLat, endLat, stepLat))
2725 2737
2726 2738 startLong = float(request.GET['startLong'])
2727 2739 endLong = float(request.GET['endLong'])
2728 2740 if startLong == endLong:
2729 2741 endLong += 0.001
2730 2742 elif startLong > endLong:
2731 2743 return(HttpResponse('startLong %s cannot be greater than endLong %s' % (str(startLong), str(endLong))))
2732 2744 stepLong = float(request.GET['stepLong'])
2733 2745 if stepLong < 0.0:
2734 2746 return(HttpResponse('stepLong %s cannot be less than zero' % (str(stepLong))))
2735 2747 elif stepLong == 0.0:
2736 2748 stepLong = 0.001
2737 2749 lonList = list(numpy.arange(startLong, endLong, stepLong))
2738 2750
2739 2751 startAlt = float(request.GET['startAlt'])
2740 2752 endAlt = float(request.GET['endAlt'])
2741 2753 if startAlt == endAlt:
2742 2754 endAlt += 0.001
2743 2755 elif startAlt > endAlt:
2744 2756 return(HttpResponse('startAlt %s cannot be greater than endAlt %s' % (str(startAlt), str(endAlt))))
2745 2757 stepAlt = float(request.GET['stepAlt'])
2746 2758 if stepAlt < 0.0:
2747 2759 return(HttpResponse('stepAlt %s cannot be less than zero' % (str(stepAlt))))
2748 2760 elif stepAlt == 0.0:
2749 2761 stepAlt = 0.01
2750 2762 altList = list(numpy.arange(startAlt, endAlt, stepAlt))
2751 2763
2752 2764 # limit total calculations to 1E5
2753 2765 total = len(latList) * len(lonList) * len(altList)
2754 2766 if total > 1.0E5:
2755 2767 return(HttpResponse('Too many points for madCalculatorService: %i' % (total)))
2756 2768
2757 2769 parms = request.GET['parms']
2758 2770 desiredParmList = [item.strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
2759 2771
2760 2772 oneDList = request.GET.getlist('oneD')
2761 2773 oneDParmDict = {}
2762 2774 for oneDStr in oneDList:
2763 2775 mnem, strValue = oneDStr.split(',')
2764 2776 oneDParmDict[mnem] = [float(strValue)]
2765 2777
2766 2778 # capture stdout
2767 2779 old_stdout = sys.stdout
2768 2780 sys.stdout = mystdout = io.StringIO()
2769 2781 madrigal.isprint.MadCalculatorGrid(None, desiredParmList, [dt], latList, lonList, altList,
2770 2782 oneDParmDict, summary=None)
2771 2783 text = mystdout.getvalue()
2772 2784 sys.stdout = old_stdout
2773 2785
2774 2786 return render(request, 'madweb/service.html', {'text': text})
2775 2787
2776 2788
2777 2789 def mad_time_calculator_service(request):
2778 2790 """mad_time_calculator_service runs the madTimeCalculator service. Input parameters must not be location dependent
2779 2791
2780 2792 Inputs:
2781 2793 request/url - contains arguments:
2782 2794
2783 2795 1. startyear - int
2784 2796
2785 2797 2. startmonth - int
2786 2798
2787 2799 3. startday - int
2788 2800
2789 2801 4. starthour - int
2790 2802
2791 2803 5. startmin - int
2792 2804
2793 2805 6. startsec - int
2794 2806
2795 2807 7. endyear - int
2796 2808
2797 2809 8. endmonth - int
2798 2810
2799 2811 9. endday - int
2800 2812
2801 2813 10. endhour - int
2802 2814
2803 2815 11. endmin - int
2804 2816
2805 2817 12. endsec - int
2806 2818
2807 2819 13. stephours - float - number of hours per time step
2808 2820
2809 2821 14. parms - comma delimited string of Madrigal parameters desired (must not depend on location)
2810 2822
2811 2823 Returns comma-delimited data, one line for each year, month, day, hour, minute, and second,
2812 2824 with the following fields:
2813 2825
2814 2826 1-6: year, month, day, hour, minute, and second
2815 2827
2816 2828 2. requested parm fields
2817 2829 """
2818 2830 startyear = int(request.GET['startyear'])
2819 2831 startmonth = int(request.GET['startmonth'])
2820 2832 startday = int(request.GET['startday'])
2821 2833 starthour = int(request.GET['starthour'])
2822 2834 startminute = int(request.GET['startmin'])
2823 2835 startsecond = int(request.GET['startsec'])
2824 2836 endyear = int(request.GET['endyear'])
2825 2837 endmonth = int(request.GET['endmonth'])
2826 2838 endday = int(request.GET['endday'])
2827 2839 endhour = int(request.GET['endhour'])
2828 2840 endminute = int(request.GET['endmin'])
2829 2841 endsecond = int(request.GET['endsec'])
2830 2842 dt1 = datetime.datetime(startyear, startmonth, startday, starthour, startminute, startsecond)
2831 2843 dt2 = datetime.datetime(endyear, endmonth, endday, endhour, endminute, endsecond)
2832 2844 if dt1 > dt2:
2833 2845 return(HttpResponse('End Datetime %s cannot be before start datetime %s' % (str(dt2), str(dt1))))
2834 2846
2835 2847 stephours = float(request.GET['stephours'])
2836 2848 if stephours <= 0.0:
2837 2849 return(HttpResponse('stephours cannot be non-positive: %f' % (stephours)))
2838 2850
2839 2851 dtList = []
2840 2852 while dt1 <= dt2:
2841 2853 dtList.append(dt1)
2842 2854 dt1 += datetime.timedelta(hours=stephours)
2843 2855
2844 2856 parms = request.GET['parms']
2845 2857 desiredParmList = [item.strip() for item in ['year','month','day','hour','min','sec'] + parms.split(',')]
2846 2858
2847 2859 # no spatial data
2848 2860 latList = lonList = altList = []
2849 2861 # capture stdout
2850 2862 old_stdout = sys.stdout
2851 2863 sys.stdout = mystdout = io.StringIO()
2852 2864 madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, latList, lonList, altList,
2853 2865 summary=None)
2854 2866 text = mystdout.getvalue()
2855 2867 sys.stdout = old_stdout
2856 2868
2857 2869 return render(request, 'madweb/service.html', {'text': text})
2858 2870
2859 2871
2860 2872
2861 2873 @csrf_exempt
2862 2874 def mad_calculator2_service(request):
2863 2875 """mad_calculator2_service runs the madCalculator2 service.
2864 2876
2865 2877 Differs from madCalulator in that positions are a list rather than a grid.
2866 2878
2867 2879 Inputs:
2868 2880 request/url - contains arguments:
2869 2881
2870 2882 year, month, day, hour, min, sec
2871 2883
2872 2884 lats - comma separated list of latitudes to analyze
2873 2885
2874 2886 longs - comma separated list of longitudes to analyze. Len must == len(lats)
2875 2887
2876 2888 alts - comma separated list of altitudes to analyze. Len must == len(lats)
2877 2889
2878 2890 parms - comma delimited string of Madrigal parameters desired
2879 2891
2880 2892 oneD - zero or more mnemonics,float values to set input 1D values
2881 2893 Example: &oneD=kinst,31.0&oneD=elm,45.0
2882 2894
2883 2895 twoD - zero or more mnemonics,comma-separate float list of len(lats) to set input 2D values
2884 2896 Example: twoD=te,1000,1100,1200 twoD=ti,1000,1000,1000
2885 2897 where there are 3 lats
2886 2898
2887 2899 Returns comma-delimited data, one line for each lat value,
2888 2900 with the following fields:
2889 2901
2890 2902 1. latitude
2891 2903
2892 2904 2. longitude
2893 2905
2894 2906 3. altitude
2895 2907
2896 2908 4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
2897 2909 """
2898 2910 if request.method == 'POST':
2899 2911 reqDict = request.POST
2900 2912 else:
2901 2913 reqDict = request.GET
2902 2914 try:
2903 2915 year = int(reqDict.get('year'))
2904 2916 except TypeError:
2905 2917 return(HttpResponse('<p>madCalculator2Service requires year</p>'))
2906 2918 month = int(reqDict['month'])
2907 2919 day = int(reqDict['day'])
2908 2920 hour = int(reqDict['hour'])
2909 2921 minute = int(reqDict['min'])
2910 2922 second = int(reqDict['sec'])
2911 2923 dt = datetime.datetime(year, month, day, hour, minute, second)
2912 2924
2913 2925 latsStr = reqDict['lats']
2914 2926 lats = [float(item) for item in latsStr.split(',')]
2915 2927 longsStr = reqDict['longs']
2916 2928 longs = [float(item) for item in longsStr.split(',')]
2917 2929 altsStr = reqDict['alts']
2918 2930 alts = [float(item) for item in altsStr.split(',')]
2919 2931
2920 2932 parms = reqDict['parms']
2921 2933 desiredParmList = [item.strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
2922 2934
2923 2935 oneDList = reqDict.getlist('oneD')
2924 2936 oneDParmDict = {}
2925 2937 for oneDStr in oneDList:
2926 2938 mnem, strValue = oneDStr.split(',')
2927 2939 oneDParmDict[mnem] = [float(strValue)]
2928 2940
2929 2941 twoDList = reqDict.getlist('twoD')
2930 2942
2931 2943 twoDParmDict = {}
2932 2944 for twoDStr in twoDList:
2933 2945 items = twoDStr.split(',')
2934 2946 if len(items) != 1 + len(lats):
2935 2947 raise ValueError('twoDstr %s not correct number of points' % (str(twoDStr)))
2936 2948 mnem = items[0]
2937 2949 floatValues = [float(item) for item in items[1:]]
2938 2950 # now we need to expand these values to be two dimensional 1 x len(lats)
2939 2951 values = numpy.zeros((1,len(lats)), dtype=numpy.float)
2940 2952 values[0][:] = floatValues
2941 2953 twoDParmDict[mnem] = values
2942 2954
2943 2955 # capture stdout
2944 2956 old_stdout = sys.stdout
2945 2957 sys.stdout = mystdout = io.StringIO()
2946 2958 madrigal.isprint.MadCalculatorList(None, desiredParmList, [dt], lats, longs, alts,
2947 2959 oneDParmDict, twoDParmDict, summary=None)
2948 2960 text = mystdout.getvalue()
2949 2961 sys.stdout = old_stdout
2950 2962
2951 2963 return render(request, 'madweb/service.html', {'text': text})
2952 2964
2953 2965
2954 2966
2955 2967
2956 2968 @csrf_exempt
2957 2969 def mad_calculator3_service(request):
2958 2970 """mad_calculator3_service runs the madCalculator3 service.
2959 2971
2960 2972 Differs from madCalulator in that multiple times, each with a unique list of positions, can be passed in.
2961 2973
2962 2974 Inputs:
2963 2975 request/url - contains arguments:
2964 2976
2965 2977 year - a comma-separated list of years - (required)
2966 2978
2967 2979 month - a comma-separated list of months - (required)
2968 2980
2969 2981 day - a comma-separated list of days - (required)
2970 2982
2971 2983 hour - a comma-separated list of hours - (required)
2972 2984
2973 2985 min - a comma-separated list of minutes - (required)
2974 2986
2975 2987 sec - a comma-separated list of seconds - (required)
2976 2988
2977 2989 numPos - a comma-sepatated list of the number of positions for each time - (required)
2978 2990
2979 2991 lats - a comma-separated list of geodetic latitudes, -90 to 90 (required). Listed
2980 2992 for first time, then second, etc. Total must be equal to the sum
2981 2993 of numPos.
2982 2994
2983 2995 longs - a comma-separated list of longitudes (required) Listed
2984 2996 for first time, then second, etc. Total must be equal to the sum
2985 2997 of numPos.
2986 2998
2987 2999 alts - a comma-separated list of geodetic altitudes in km (required) Listed
2988 3000 for first time, then second, etc. Total must be equal to the sum
2989 3001 of numPos.
2990 3002
2991 3003 parms - comma delimited string of Madrigal parameters desired (required)
2992 3004
2993 3005 oneD - string in form <parm>,<comma-separated values> This argument allows the user to
2994 3006 set any number of one-D parameters to be used in the calculation.
2995 3007 Value must be parameter name, comma, list of values as double,
2996 3008 where length of list is equal to number of times.
2997 3009 Example: &oneD=kinst,31.0,31.0&oneD=elm,45.0,50
2998 3010 (optional - 0 or more allowed)
2999 3011
3000 3012 twoD=<parm>,<values> (optional - 0 or more allowed) This argument allows the user to
3001 3013 set any number of two-D parameters to be used in the calculation.
3002 3014 Value must be parameter name, comma, comma-separated values.
3003 3015 Number of values must equal the sum of numPos. Order is
3004 3016 first time values first, then second time values, etc
3005 3017 Example: twoD=te,1000,1100,1200,1000,1100,1200 &twoD=ti,1000,1000,1000,1000,1000,1000
3006 3018 where numPos=3,3
3007 3019
3008 3020 Returns comma-delimited data, one line for each location. Separate times are delimited by line
3009 3021
3010 3022 TIME MM/DD/YYYY HH:MM:SS
3011 3023
3012 3024 Data lines have the following fields:
3013 3025
3014 3026 1. latitude
3015 3027
3016 3028 2. longitude
3017 3029
3018 3030 3. altitude
3019 3031
3020 3032 4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
3021 3033 """
3022 3034 if request.method == 'POST':
3023 3035 reqDict = request.POST
3024 3036 else:
3025 3037 reqDict = request.GET
3026 3038 try:
3027 3039 yearList = [int(item) for item in reqDict.get('year').split(',')]
3028 3040 except AttributeError:
3029 3041 return(HttpResponse('<p>madCalculator3Service requires year</p>'))
3030 3042 monthList = [int(item) for item in reqDict.get('month').split(',')]
3031 3043 dayList = [int(item) for item in reqDict.get('day').split(',')]
3032 3044 hourList = [int(item) for item in reqDict.get('hour').split(',')]
3033 3045 minList = [int(item) for item in reqDict.get('min').split(',')]
3034 3046 secList = [int(item) for item in reqDict.get('sec').split(',')]
3035 3047 dtList = [datetime.datetime(yearList[i], monthList[i], dayList[i],
3036 3048 hourList[i], minList[i], secList[i]) for i in range(len(yearList))]
3037 3049 numPosStr = reqDict['numPos']
3038 3050 numPosList = [int(item) for item in numPosStr.split(',')]
3039 3051 totalPos = 0
3040 3052 for numPos in numPosList:
3041 3053 totalPos += numPos
3042 3054 latsStr = reqDict['lats']
3043 3055 lats = [float(item) for item in latsStr.split(',')]
3044 3056 if len(lats) != totalPos:
3045 3057 return(HttpResponse('wrong number of lats, expected %i' % (totalPos)))
3046 3058 longsStr = reqDict['longs']
3047 3059 longs = [float(item) for item in longsStr.split(',')]
3048 3060 if len(longs) != totalPos:
3049 3061 return(HttpResponse('wrong number of longs, expected %i' % (totalPos)))
3050 3062 altsStr = reqDict['alts']
3051 3063 alts = [float(item) for item in altsStr.split(',')]
3052 3064 if len(alts) != totalPos:
3053 3065 return(HttpResponse('wrong number of alts, expected %i' % (totalPos)))
3054 3066
3055 3067 parms = reqDict['parms']
3056 3068 desiredParmList = [item.strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
3057 3069
3058 3070 oneDList = reqDict.getlist('oneD')
3059 3071 twoDList = reqDict.getlist('twoD')
3060 3072
3061 3073 # since the positions can change with each call, we need to call madrigal.isprint.MadCalculatorGrid once for each time
3062 3074 startIndex = 0
3063 3075 endIndex = 0
3064 3076 fullText = ''
3065 3077 for timeIndex, numPos in enumerate(numPosList):
3066 3078 startIndex = endIndex
3067 3079 endIndex += numPos
3068 3080 thisLats = lats[startIndex:endIndex]
3069 3081 thisLongs = longs[startIndex:endIndex]
3070 3082 thisAlts = alts[startIndex:endIndex]
3071 3083
3072 3084 oneDParmDict = {}
3073 3085 for oneDStr in oneDList:
3074 3086 values = oneDStr.split(',')
3075 3087 if len(values) != 1+len(dtList):
3076 3088 return(HttpResponse('wrong number of values given for 1D parm %s' % (values[0])))
3077 3089 oneDParmDict[values[0]] = [float(values[timeIndex+1])]
3078 3090
3079 3091 twoDParmDict = {}
3080 3092
3081 3093 for twoDStr in twoDList:
3082 3094 values = twoDStr.split(',')
3083 3095 if len(values) != 1 + totalPos:
3084 3096 return(HttpResponse('twoDstr %s not correct number of points' % (str(twoDStr))))
3085 3097 mnem = values[0]
3086 3098 floatValues = [float(item) for item in values[1+startIndex:1+endIndex]]
3087 3099 # now we need to expand these values to be two dimensional - 1,len(thisLats)
3088 3100 values2D = numpy.zeros((1,len(thisLats)), dtype=numpy.float)
3089 3101 values2D[0][:] = floatValues
3090 3102 twoDParmDict[mnem] = values2D
3091 3103
3092 3104
3093 3105
3094 3106 # capture stdout
3095 3107 old_stdout = sys.stdout
3096 3108 sys.stdout = mystdout = io.StringIO()
3097 3109 madrigal.isprint.MadCalculatorList(None, desiredParmList, [dtList[timeIndex]], thisLats,
3098 3110 thisLongs, thisAlts,
3099 3111 oneDParmDict, twoDParmDict, summary=None)
3100 3112 text = mystdout.getvalue()
3101 3113 sys.stdout = old_stdout
3102 3114
3103 3115 fullText += 'TIME %s\n' % (dtList[timeIndex].strftime('%m/%d/%Y %H:%M:%S'))
3104 3116 fullText += text
3105 3117
3106 3118 return render(request, 'madweb/service.html', {'text': fullText})
3107 3119
3108 3120
3109 3121
3110 3122 def geodetic_to_radar_service(request):
3111 3123 """geodetic_to_radar_service runs the geodeticToRadar service.
3112 3124
3113 3125 Inputs:
3114 3126 request/url - contains arguments:
3115 3127
3116 3128 slatgd - radar geodetic latitude
3117 3129
3118 3130 slon - radar longitude
3119 3131
3120 3132 saltgd - radar geodetic altitude
3121 3133
3122 3134 gdlat - a comma-separated list of geodetic latitude of point
3123 3135
3124 3136 glon - a comma-separated list of longitude of point. Len must be same as gdlat
3125 3137
3126 3138 gdalt - a comma-separated list of geodetic altitude of point. Len must be same as gdlat
3127 3139
3128 3140
3129 3141 Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):
3130 3142
3131 3143 1. radar azimuth in degrees (0 = north)
3132 3144
3133 3145 2. radar elevation in degrees
3134 3146
3135 3147 3. radar range in km
3136 3148 """
3137 3149 slatgd = float(request.GET['slatgd'])
3138 3150 slon = float(request.GET['slon'])
3139 3151 saltgd = float(request.GET['saltgd'])
3140 3152 oneDParmDict = {'GDLATR': [slatgd],
3141 3153 'GDLONR': [slon],
3142 3154 'GALTR': [saltgd]}
3143 3155 gdlatStr = request.GET['gdlat']
3144 3156 gdlatList = [float(item) for item in gdlatStr.split(',')]
3145 3157 glonStr = request.GET['glon']
3146 3158 glonList = [float(item) for item in glonStr.split(',')]
3147 3159 gdaltStr = request.GET['gdalt']
3148 3160 gdaltList = [float(item) for item in gdaltStr.split(',')]
3149 3161 desiredParmList = ['azm', 'elm', 'range']
3150 3162 dtList = [datetime.datetime(2001,1,1)] # not relevant
3151 3163 if len(gdlatList) != len(glonList) or len(gdlatList) != len(gdaltList):
3152 3164 return(HttpResponse('all point list lengths must be equal'))
3153 3165
3154 3166 fullText = ''
3155 3167
3156 3168 delimiter = ','
3157 3169 for i in range(len(gdlatList)):
3158 3170 # capture stdout
3159 3171 old_stdout = sys.stdout
3160 3172 sys.stdout = mystdout = io.StringIO()
3161 3173 madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, [gdlatList[i]],
3162 3174 [glonList[i]], [gdaltList[i]], summary=None,
3163 3175 oneDParmDict=oneDParmDict)
3164 3176 text = mystdout.getvalue()
3165 3177 sys.stdout = old_stdout
3166 3178 for line in text.split('\n'):
3167 3179 items = line.split()
3168 3180 fullText += delimiter.join(items) + '\n'
3169 3181
3170 3182 return render(request, 'madweb/service.html', {'text': fullText})
3171 3183
3172 3184
3173 3185 def radar_to_geodetic_service(request):
3174 3186 """radar_to_geodetic_service runs the radarToGeodetic service.
3175 3187
3176 3188 Inputs:
3177 3189 request/url - contains arguments:
3178 3190
3179 3191 slatgd - radar geodetic latitude
3180 3192
3181 3193 slon - radar longitude
3182 3194
3183 3195 saltgd - radar geodetic altitude
3184 3196
3185 3197 azs - a comma-separated list of azimuths of point
3186 3198
3187 3199 els - a comma-separated list of elevations of point. Len must be same as azs
3188 3200
3189 3201 ranges - a comma-separated list of ranges to point. Len must be same as azs
3190 3202
3191 3203
3192 3204 Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):
3193 3205
3194 3206 1. geodetic latitude
3195 3207
3196 3208 2. longitude (-180 to 180)
3197 3209
3198 3210 3. geodetic altitude in km
3199 3211 """
3200 3212 slatgd = float(request.GET['slatgd'])
3201 3213 slon = float(request.GET['slon'])
3202 3214 saltgd = float(request.GET['saltgd'])
3203 3215 azStr = request.GET['az']
3204 3216 azList = [float(item) for item in azStr.split(',')]
3205 3217 elStr = request.GET['el']
3206 3218 elList = [float(item) for item in elStr.split(',')]
3207 3219 rangeStr = request.GET['range']
3208 3220 rangeList = [float(item) for item in rangeStr.split(',')]
3209 3221 if len(azList) != len(elList) or len(azList) != len(rangeList):
3210 3222 return(HttpResponse('all point list lengths must be equal'))
3211 3223
3212 3224 fullText = ''
3213 3225
3214 3226 for i in range(len(azList)):
3215 3227 gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slatgd, slon, saltgd,
3216 3228 azList[i], elList[i], rangeList[i])
3217 3229 fullText += '%f,%f,%f\n' % (gdlat,glon,gdalt)
3218 3230
3219 3231 return render(request, 'madweb/service.html', {'text': fullText})
3220 3232
3221 3233
3222 3234
3223 3235 def list_file_times_service(request):
3224 3236 """list_file_times_service runs the listFileTimes service.
3225 3237
3226 3238 Inputs:
3227 3239 request/url - contains arguments:
3228 3240
3229 3241 Optional: expDir - experiment directory to list. Can be absolute or relative to
3230 3242 experiments[0-9]*. Default is all files in $MADROOT/experiments*
3231 3243
3232 3244 Returns comma-delimited data, one for each file:
3233 3245
3234 3246 1. Full path of file
3235 3247
3236 3248 2. File modification time in form YYYY-MM-DD HH:MM:SS (UT time)
3237 3249 """
3238 3250 expDir = None
3239 3251 try:
3240 3252 expDir = request.GET['expDir']
3241 3253 except:
3242 3254 pass
3243 3255 madDB = madrigal.metadata.MadrigalDB()
3244 3256 fileList = madDB.listFileTimes(expDir)
3245 3257 fullText = '\n\n'
3246 3258 for filename, filetime in fileList:
3247 3259 fullText += "\'%s\', %s\n" % (filename, filetime.strftime('%Y-%m-%d %H:%M:%S'))
3248 3260
3249 3261 return render(request, 'madweb/service.html', {'text': django.utils.safestring.mark_safe(fullText)})
3250 3262
3251 3263
3252 3264 def download_web_file_service(request):
3253 3265 """download_web_file_service runs the downloadWebFile service.
3254 3266
3255 3267 Inputs:
3256 3268 request/url - contains arguments:
3257 3269
3258 3270 expPath - path to file starting at experiments*
3259 3271
3260 3272 Returns comma-delimited data, one for each file:
3261 3273
3262 3274 1. Full path of file
3263 3275
3264 3276 2. File modification time in form YYYY-MM-DD HH:MM:SS (UT time)
3265 3277 """
3266 3278 expPath = request.GET['expPath']
3267 3279 madDB = madrigal.metadata.MadrigalDB()
3268 3280 downloadFile = os.path.join(madDB.getMadroot(), expPath)
3269 3281 f = open(downloadFile, 'rb')
3270 3282 thisFile = django.core.files.File(f)
3271 3283 response = HttpResponse(thisFile, content_type='application/x-octet-stream')
3272 3284 response['Content-Disposition'] = 'attachment; filename="' + os.path.basename(downloadFile) + '"'
3273 3285 response['Content-Length'] = os.path.getsize(downloadFile)
3274 3286 return(response)
3275 3287
3276 3288
3277 3289 def trace_magnetic_field_service(request):
3278 3290 """trace_magnetic_field_service runs the traceMagneticField service.
3279 3291
3280 3292 Inputs:
3281 3293 request/url - contains arguments:
3282 3294
3283 3295 year, month, day, hour, min, sec
3284 3296
3285 3297 inputType (0 for geodetic, 1 for GSM)
3286 3298
3287 3299 outputType (0 for geodetic, 1 for GSM)
3288 3300
3289 3301 The following parameter depend on inputType:
3290 3302
3291 3303 in1 - a comma-separated list of geodetic altitudes or ZGSMs of starting point
3292 3304
3293 3305 in2 - a comma-separated list of geodetic latitudes or XGSMs of starting point
3294 3306
3295 3307 in3 - a comma-separated list of longitude or YGSM of starting point
3296 3308
3297 3309 Length of all three lists must be the same
3298 3310
3299 3311 model - 0 for Tsyganenko, 1 for IGRF
3300 3312
3301 3313 qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane
3302 3314
3303 3315 stopAlt - altitude in km to stop trace at, if qualifier is north_alt or south_alt.
3304 3316
3305 3317 If other qualifier, this parameter is not required.
3306 3318
3307 3319 Returns comma-delimited data, one line for point in in lists:
3308 3320
3309 3321 1. geodetic altitude or ZGSM of ending point
3310 3322
3311 3323 2. geodetic latitude or XGSM of ending point
3312 3324
3313 3325 3. longitude or YGSM of ending point
3314 3326 """
3315 3327 year = int(request.GET['year'])
3316 3328 month = int(request.GET['month'])
3317 3329 day = int(request.GET['day'])
3318 3330 hour = int(request.GET['hour'])
3319 3331 minute = int(request.GET['min'])
3320 3332 second = int(request.GET['sec'])
3321 3333 dt = datetime.datetime(year, month, day, hour, minute, second)
3322 3334 inputType = int(request.GET['inputType'])
3323 3335 if inputType not in (0,1):
3324 3336 return(HttpResponse('inputType must be 0 or 1, not %i' % (inputType)))
3325 3337 outputType = int(request.GET['outputType'])
3326 3338 if outputType not in (0,1):
3327 3339 return(HttpResponse('outputType must be 0 or 1, not %i' % (outputType)))
3328 3340 in1Str = request.GET['in1']
3329 3341 in1List = [float(item) for item in in1Str.split(',')]
3330 3342 in2Str = request.GET['in2']
3331 3343 in2List = [float(item) for item in in2Str.split(',')]
3332 3344 in3Str = request.GET['in3']
3333 3345 in3List = [float(item) for item in in3Str.split(',')]
3334 3346 if len(in1List) != len(in2List) or len(in1List) != len(in3List):
3335 3347 return(HttpResponse('All three in* lists must have same length'))
3336 3348 model = int(request.GET['model'])
3337 3349 if model not in (0,1):
3338 3350 return(HttpResponse('model must be 0 or 1, not %i' % (model)))
3339 3351 qualifier = int(request.GET['qualifier'])
3340 3352 if qualifier not in (0,1,2,3,4):
3341 3353 return(HttpResponse('model must be in 0,1,2,3,4 not %i' % (model)))
3342 3354 try:
3343 3355 stopAlt = float(request.GET['stopAlt'])
3344 3356 except:
3345 3357 stopAlt = 0.0
3346 3358
3347 3359 fullText = ''
3348 3360 resultArr = numpy.zeros((3,), dtype='f8')
3349 3361 madDB = madrigal.metadata.MadrigalDB()
3350 3362 madDeriveObj = madrigal.derivation.MadrigalDerivationMethods(madDB.getMadroot())
3351 3363 for i in range(len(in1List)):
3352 3364 madDeriveObj.traceMagneticField(year, month, day, hour, minute, second,
3353 3365 inputType, outputType, in1List[i], in2List[i], in3List[i],
3354 3366 model, qualifier, stopAlt, resultArr)
3355 3367 fullText += '%f,%f,%f\n' % (resultArr[0], resultArr[1], resultArr[2])
3356 3368
3357 3369 return render(request, 'madweb/service.html', {'text': fullText})
3358 3370
3359 3371
3360 3372 def global_file_search_service(request):
3361 3373 """global_file_search_service returns a list of full paths to files or citable urls based on search arguments
3362 3374
3363 3375 Inputs:
3364 3376 request/url - contains arguments:
3365 3377
3366 3378 startDate: start date in form YYYY-MM-DD to filter experiments before
3367 3379 endDate: end date in form YYYY-MM-DD to filter experiments after
3368 3380 inst: (optional, multiple allowed) an instrument code or name. For names,
3369 3381 fnmatch will be used. If not set, all instruments used.
3370 3382 kindat: (optional, multiple allowed) a kind of data codes or name. For names,
3371 3383 fnmatch will be used. If not set, all kinds of data used.
3372 3384 seasonalStartDate: (optional) in form MM/DD, rejects all days earlier in year. If not set
3373 3385 implies 01/01
3374 3386 seasonalEndDate: (optional) in form MM/DD, rejects all days later in year. If not set
3375 3387 implies 12/31
3376 3388 includeNonDefault: (optional) if "True", include realtime files when there are no default.
3377 3389 If not set, only default files.
3378 3390 expName: (optional) - filter experiments by the experiment name. fnmatch rules
3379 3391 If not set, no filtering by experiment name.
3380 3392 excludeExpName: (optional) - exclude experiments by the experiment name. fnmatch rules
3381 3393 If not set, no excluding experiments by experiment name.
3382 3394 fileDesc: (optional) filter files using input file Description string via fnmatch.
3383 3395 If not set, in no filtering by file name
3384 3396 returnCitation: (optional) if True, return a list of file citations. If not set, return
3385 3397 a list of full paths to the files selected
3386 3398
3387 3399 """
3388 3400 madDB = madrigal.metadata.MadrigalDB()
3389 3401 madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
3390 3402
3391 3403 # get required arguments
3392 3404 startDate = request.GET['startDate']
3393 3405 endDate = request.GET['endDate']
3394 3406 startDate = datetime.datetime.strptime(startDate, '%Y-%m-%d')
3395 3407 endDate = datetime.datetime.strptime(endDate, '%Y-%m-%d')
3396 3408
3397 3409 # get optional arguments
3398 3410 inst = request.GET.getlist('inst')
3399 3411 if inst == []:
3400 3412 inst = None
3401 3413 kindat = request.GET.getlist('kindat')
3402 3414 if kindat == []:
3403 3415 kindat = None
3404 3416 seasonalStartDate = request.GET.get('seasonalStartDate', default = None)
3405 3417 seasonalEndDate = request.GET.get('seasonalEndDate', default = None)
3406 3418 includeNonDefault = bool(request.GET.get('includeNonDefault', default = False))
3407 3419 expName = request.GET.get('expName', default = None)
3408 3420 excludeExpName = request.GET.get('excludeExpName', default = None)
3409 3421 fileDesc = request.GET.get('fileDesc', default = None)
3410 3422 returnCitation = bool(request.GET.get('returnCitation', default = False))
3411 3423
3412 3424 result = madWebObj.global_file_search(startDate, endDate, inst, kindat,
3413 3425 seasonalStartDate, seasonalEndDate,
3414 3426 includeNonDefault, expName, excludeExpName,
3415 3427 fileDesc, returnCitation)
3416 3428
3417 3429 fullText = ''
3418 3430 for item in result:
3419 3431 fullText += '%s\n' % (item)
3420 3432
3421 3433 return render(request, 'madweb/service.html', {'text': django.utils.safestring.mark_safe(fullText)})
3422 3434
3423 3435
3424 3436
3425 3437
3426 3438 def get_url_list_from_group_id_service(request):
3427 3439 """get_url_list_from_group_id_service returns a list of citable urls associated with group id.
3428 3440
3429 3441 Inputs:
3430 3442 request/url - contains arguments:
3431 3443
3432 3444 id - group id
3433 3445
3434 3446 Returns one line for each citable url
3435 3447
3436 3448 Returns empty string if experiment id not found. Skips files that are not Hdf5
3437 3449 """
3438 3450 id = int(request.GET['id'])
3439 3451
3440 3452 # create MadrigalDB obj
3441 3453 madDBObj = madrigal.metadata.MadrigalDB()
3442 3454
3443 3455 urlList = madDBObj.getListFromGroupId(id)
3444 3456
3445 3457 retStr = ''
3446 3458 for url in urlList:
3447 3459 retStr += '%s\n' % (url)
3448 3460
3449 3461 return render(request, 'madweb/service.html', {'text': django.utils.safestring.mark_safe(retStr)})
3450 3462
3451 3463
3452 3464 def set_group_id_from_url_list_service(request):
3453 3465 """set_group_id_from_url_list sets a list of citable urls to a group id .
3454 3466
3455 3467 Inputs:
3456 3468 request/url - contains arguments:
3457 3469
3458 3470 'user_fullname' user name
3459 3471
3460 3472 'user_email' user email
3461 3473
3462 3474 'user_affiliation' user affiliation
3463 3475
3464 3476 'url' - citable url. Multiple arguments allowed
3465 3477
3466 3478 Returns group id (integer) set
3467 3479 """
3468 3480 madDB = madrigal.metadata.MadrigalDB()
3469 3481
3470 3482 print(request.GET)
3471 3483
3472 3484 # get required arguments
3473 3485 urls = request.GET.getlist('url')
3474 3486 user_fullname = request.GET['user_fullname']
3475 3487 user_email = request.GET['user_email']
3476 3488 user_affiliation = request.GET['user_affiliation']
3477 3489
3478 3490 id = madDB.createGroupIdWithList(user_fullname, user_email, user_affiliation, urls)
3479 3491
3480 3492 return render(request, 'madweb/service.html', {'text': str(id)})
3481 3493
3482 3494
3483 3495 ### doc pages ###
3484 3496
3485 3497 def docs(request, name):
3486 3498 madDB = madrigal.metadata.MadrigalDB()
3487 3499 openMadObj = madrigal.openmadrigal.OpenMadrigal(madDB)
3488 3500 bg_color = madDB.getBackgroundColor()
3489 3501 if name.find('..') != -1:
3490 3502 # no trying to look elsewhere
3491 3503 return(HttpResponse('Illegal name passed to docs: <%s>' % (name)))
3492 3504 # check if siteSpecitic.html
3493 3505 siteSpecificPath = os.path.join(madDB.getMadroot(), 'source/madpy/djangoMad/madweb/templates/madweb/siteSpecific.html')
3494 3506 if os.access(siteSpecificPath, os.R_OK):
3495 3507 siteSpecific = reverse('docs', args=['siteSpecific.html'])
3496 3508 else:
3497 3509 siteSpecific = '#'
3498 3510 openmadrigal = openMadObj.getOpenMadrigalUrl()
3499 3511 # since google insists filenames are case insensitive, convert to right name if there is no direct match if possible
3500 3512 this_file = os.path.join(madDB.getMadroot(), 'source/madpy/djangoMad/madweb/templates/madweb', name)
3501 3513 if not os.access(this_file, os.R_OK):
3502 3514 found = False
3503 3515 existing_files = glob.glob(os.path.join(madDB.getMadroot(), 'source/madpy/djangoMad/madweb/templates/madweb/*.html'))
3504 3516 for existing_file in existing_files:
3505 3517 if name.lower() == os.path.basename(existing_file).lower():
3506 3518 name = os.path.basename(existing_file)
3507 3519 found = True
3508 3520 break # correct name found and name modified
3509 3521 if not found:
3510 3522 return(HttpResponse('<p>Cannot find %s</p>' % (str(name))))
3511 3523
3512 3524 if os.path.isdir(this_file):
3513 3525 return(HttpResponse('<p>%s is a directory</p>' % (str(name))))
3514 3526
3515 3527 return render(request, 'madweb/%s' % (name), {'bg_color': bg_color, 'siteSpecific': siteSpecific,
3516 3528 'openmadrigal': openmadrigal})
3517 3529
3518 No newline at end of file
3530
General Comments 0
You need to be logged in to leave comments. Login now