Previous: Remote access - introduction   Up: Remote access programming tutorial toc   Next: Matlab remote access

Madrigal web services tutorial

Top

services module

def get_version_service(request):
    """get_version_service runs the getVersionService.py service.  
    
    Inputs:
        request (ignored)
        
        Returns a single line of text, with the version in the form <major_version_int>.<minor_version_int>[.<sub_version_int>]
    """
    rePattern = r'\[[0-9\.]*\]'
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create cmd
    f = open(os.path.join(madDBObj.getMadroot(), 'source/configure.ac'))
    lines = f.readlines()
    f.close()
    for line in lines:
        if line.find('AC_INIT') == -1:
            continue
        if line.find('Madrigal') == -1:
            continue
        result = re.findall(rePattern, line)
        if len(result) != 1:
            raise IOError, 'problem parsing MADROOT/source/configure.ac'
        version = result[0][1:-1]
        return render_to_response('madweb/service.html', {'text': version})
        
    
    # should not get here
    raise IOError, 'problem parsing MADROOT/source/configure.ac'
    
    
    
def get_instruments_service(request):
    """get_instruments_service runs the getInstrumentsService.py service.  
    
    Inputs:
        request (ignored)
        
        Returns comma-delimited data, one line for each experiment, with the following fields:

        1. instrument.name  Example: 'Millstone Hill Incoherent Scatter Radar'

        2. instrument.code Example: 30

        3. instrument.mnemonic (3 char string) Example: 'mlh'

        4. instrument.latitude  Example: 45.0

        5. instrument.longitude  Example: 110.0

        6. instrument.altitude   Example: 0.015 (km) 
        
        7. instrument.category  Example: 'Incoherent Scatter Radars'
        
        8. contact name
        
        9. contact email
    """
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create MadrigalInstument object
    madInst = madrigal.metadata.MadrigalInstrument(madDBObj)

    # get instrument list
    instList = madInst.getInstrumentList()

    # loop through each instrument
    instStr = ''
    for inst in instList:
        name = inst[0]
        code = inst[2]
        mnemonic = inst[1]
        latitude = madInst.getLatitude(code)
        if latitude == None:
            latitude = 0.0
        longitude = madInst.getLongitude(code)
        if longitude == None:
            longitude = 0.0
        altitude = madInst.getAltitude(code)
        if altitude == None:
            altitude = 0.0
        category = madInst.getCategory(code)
        if category == None:
            category = ''
        # print data
        contactName = madInst.getContactName(code)
        contactEmail = madInst.getContactEmail(code)
        instStr += '%s,%i,%s,%f,%f,%f,%s,%s,%s\n' % (name,
                                                     code,
                                                     mnemonic,
                                                     latitude,
                                                     longitude,
                                                     altitude,
                                                     category,
                                                     str(contactName),
                                                     str(contactEmail))
        
    return render_to_response('madweb/service.html', {'text': instStr})


def get_experiments_service(request):
    """get_experiments_service runs the getExperimentsService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            code - one or more kindat values
            
            startyear, startmonth, startday, starthour, startmin, startsec
            
            endyear, endmonth, endday, endhour, endmin, endsec
            
            local (defaults to True)
            
    Returns comma-delimited data, one line for each experiment, with the following fields:

        1. experiment.id (int) Example: 10000111
        
        2. experiment.url (string) Example: 'http://www.haystack.mit.edu/cgi-bin/madtoc/1997/mlh/03dec97'
        
        3. experiment.name (string) Example: 'Wide Latitude Substorm Study'
        
        4. experiment.siteid (int) Example: 1
        
        5. experiment.sitename (string) Example: 'Millstone Hill Observatory'
        
        6. experiment.instcode (int) Code of instrument. Example: 30
        
        7. experiment.instname (string) Instrument name. Example: 'Millstone Hill Incoherent Scatter Radar'
        
        8. experiment.start year (int) year of experiment start
        
        9. experiment.start month (int) month of experiment start
        
        10. experiment.start day (int) day of experiment start
        
        11. experiment.start hour (int) hour of experiment start
        
        12. experiment.start minute (int) min of experiment start
        
        13. experiment.start second (int) sec of experiment start
        
        14. experiment.end year (int) year of experiment end
        
        15. experiment.end month (int) month of experiment end
        
        16. experiment.end day (int) day of experiment end
        
        17. experiment.end hour (int) hour of experiment end
        
        18. experiment.end minute (int) min of experiment end
        
        19. experiment.end second (int) sec of experiment end
        
        20. experiment.isLocal (int) 1 if local, 0 if not
        
        21.experiment.PI (string) Experiment PI name Example: 'Phil Erickson'

        22. experiment.PIEmail (string) Experiment PI email Example: 'perickson@haystack.mit.edu'
        
        23. utc timestamp of last update to experiment
        
        24. security value
        
    """
    codeList = request.GET.getlist('code')
    codeList = [int(code) for code in codeList]
    startyear = int(request.GET['startyear'])
    startmonth = int(request.GET['startmonth'])
    startday = int(request.GET['startday'])
    starthour = int(request.GET['starthour'])
    startmin = int(request.GET['startmin'])
    startsec = int(request.GET['startsec'])
    endyear = int(request.GET['endyear'])
    endmonth = int(request.GET['endmonth'])
    endday = int(request.GET['endday'])
    endhour = int(request.GET['endhour'])
    endmin = int(request.GET['endmin'])
    endsec = int(request.GET['endsec'])
    try:
        local = int(request.GET['local'])
    except:
        local = 1
    
    
    # if startsec or endsec in (60, 61), handle correctly
    if startsec in (60, 61):
        tmpTime = datetime.datetime(startyear,
                                    startmonth,
                                    startday,
                                    starthour,
                                    startmin,
                                    59)
        tmpTime += datetime.timedelta(0, startsec - 59)
        startyear = tmpTime.year
        startmonth = tmpTime.month
        startday = tmpTime.day
        starthour = tmpTime.hour
        startmin = tmpTime.minute
        startsec = tmpTime.second

    if endsec in (60, 61):
        tmpTime = datetime.datetime(endyear,
                                    endmonth,
                                    endday,
                                    endhour,
                                    endmin,
                                    59)
        tmpTime += datetime.timedelta(0, endsec - 59)
        endyear = tmpTime.year
        endmonth = tmpTime.month
        endday = tmpTime.day
        endhour = tmpTime.hour
        endmin = tmpTime.minute
        endsec = tmpTime.second
        
    # if codeList is empty or contains 0, change it to only contain 0
    if len(codeList) == 0 or 0 in codeList:
        codeList = [0]
        
    retStr = ''

    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # get the local site id
    localSiteId = madDBObj.getSiteID()

    # create MadrigalInstrument obj to convert kinst to instrument names
    madInstObj = madrigal.metadata.MadrigalInstrument(madDBObj)

    # create MadrigalSite obj to convert site id to site name
    madSiteObj = madrigal.metadata.MadrigalSite(madDBObj)
    
    madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
    trusted = madWebObj.isTrusted()

    # create starttime for filter, if possible
    if startyear != None:
        startTimeFilter = datetime.datetime(startyear,
                        startmonth,
                        startday,
                        starthour,
                        startmin,
                        startsec) 
    else:
        startTimeFilter = None

    # create endtime for filter, if possible
    if endyear != None:
        endTimeFilter = datetime.datetime(endyear,
                          endmonth,
                      endday,
                      endhour,
                      endmin,
                      endsec) 
    else:
        endTimeFilter = None

    # create MadrigalExperiments for local or all files
    if local == 1:
        madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)
    else:
        # use file expTabAll.txt to get all experiments
        filename = madDBObj.getMadroot()
        if filename[-1] != '/':
            filename += '/'
        filename += 'metadata/expTabAll.txt'
        madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj, filename)


    # loop through the data
    position = 0
    while 1:
        thisId = madExpObj.getExpIdByPosition(position)
        # check for end
        if thisId == None:
            break
        thisUrl = madExpObj.getExpUrlByPosition(position)
        thisName = madExpObj.getExpNameByPosition(position)
        thisSiteId = madExpObj.getExpSiteIdByPosition(position)
        thisSiteName = madSiteObj.getSiteName(thisSiteId)
        thisInstCode = madExpObj.getKinstByPosition(position)
        thisInstName =madInstObj.getInstrumentName(thisInstCode)
        thisStart = madExpObj.getExpStartDateTimeByPosition(position)
        thisEnd = madExpObj.getExpEndDateTimeByPosition(position)
        thisSecurity = madExpObj.getSecurityByPosition(position)
        if thisSiteId == localSiteId:
            thisLocal = 1
        else:
            thisLocal = 0
        thisPI = madExpObj.getPIByPosition(position)
        if thisPI in (None, ''):
            thisPI = madInstObj.getContactName(thisInstCode)
        thisPIEmail = madExpObj.getPIEmailByPosition(position)
        if thisPIEmail in (None, ''):
            thisPIEmail = madInstObj.getContactEmail(thisInstCode)
        expDir = madExpObj.getExpDirByPosition(position)
            
        position += 1

        # some experiments set the end of the day to 24:00:00 - not
        # technically correct - reset to 23:59:59
        
        if (thisStart[3] == 24 and thisStart[4] == 0 and thisStart[5] == 0):
            thisStart[3] = 23
            thisStart[4] = 59
            thisStart[5] = 59

        if (thisEnd[3] == 24 and thisEnd[4] == 0 and thisEnd[5] == 0):
            thisEnd[3] = 23
            thisEnd[4] = 59
            thisEnd[5] = 59
        
        # apply filters
        
        # first apply instrument code filter
        if codeList[0] != 0:
            if thisInstCode not in codeList:
                continue

        # apply starttime and endtime filters
        thisStartTime = datetime.datetime(thisStart[0],
                                          thisStart[1],
                                          thisStart[2],
                                          thisStart[3],
                                          thisStart[4],
                                          thisStart[5])

        thisEndTime = datetime.datetime(thisEnd[0],
                                        thisEnd[1],
                                        thisEnd[2],
                                        thisEnd[3],
                                        thisEnd[4],
                                        thisEnd[5])
        
        if startTimeFilter != None:
            if thisEndTime < startTimeFilter:
                continue

        if endTimeFilter != None:
            if thisStartTime > endTimeFilter:
                continue

        # apply local filer
        if local == 1 and thisLocal == 0:
            continue

        # apply security filter
        if trusted == 0 and thisSecurity not in (0,2):
            continue
        
        # create exp timestamp
        if local == 1:
            thisUTTimestamp = long(os.stat(expDir).st_mtime + time.timezone)
        else:
            thisUTTimestamp = 0

        # add this experiment
        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' % \
                (thisId,
                thisUrl,
                thisName,
                thisSiteId,
                thisSiteName,
                thisInstCode,
                thisInstName,
                thisStart[0],
                thisStart[1],
                thisStart[2],
                thisStart[3],
                thisStart[4],
                thisStart[5],
                thisEnd[0],
                thisEnd[1],
                thisEnd[2],
                thisEnd[3],
                thisEnd[4],
                thisEnd[5],
                thisLocal,
                str(thisPI),
                str(thisPIEmail),
                thisUTTimestamp,
                thisSecurity)
                
    return render_to_response('madweb/service.html', {'text': retStr})


def get_experiment_files_service(request):
    """get_experiment_files_service runs the getExperimentFilesService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            id - local experiment id
            
        Returns comma-delimited data, one line for each experiment file, with the following fields:

            1. file.name (string) Example '/opt/mdarigal/blah/mlh980120g.001'
            
            2. file.kindat (int) Kindat code.  Example: 3001
            
            3. file.kindat desc (string) Kindat description: Example 'Basic Derived Parameters'
            
            4. file.category (int) (1=default, 2=variant, 3=history, 4=real-time)
            
            5. file.status (string)('preliminary', 'final', or any other description)
            
            6. file.permission (int)  0 for public, 1 for private.  For now will not return private files.
        
        Returns empty string if experiment id not found
    """
    id = int(request.GET['id'])
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create MadrigalExperiments object to get full file name
    madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)

    # create Madrigal Kindat to get Kindat descriptions
    madKindatObj = madrigal.metadata.MadrigalKindat(madDBObj)

    # create Madrigal File object 
    madFileObj = madrigal.metadata.MadrigalMetaFile(madDBObj)
    
    madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
    trusted = madWebObj.isTrusted()

    # loop through the experiments to get url
    position = 0
    kinst = None
    while 1:
        thisId = madExpObj.getExpIdByPosition(position)
        # check for end
        if thisId == None:
            sys.exit(-1)
        thisId = int(thisId)
        # check for right id
        if thisId == id:
            thisUrl = madExpObj.getExpUrlByPosition(position)
            # add end of url to exp path
            index = thisUrl.find('/madtoc/')
            expPath = madDBObj.getFullPathFromPartial(thisUrl[index+8:])
            kinst = madExpObj.getKinstByPosition(position)
            break
        position += 1

    # loop though files to find all with right experiment id
    position = 0
    retStr = ''
    while 1:
        thisId = madFileObj.getExpIdByPosition(position)
        if thisId == None:
            break
        thisId = int(thisId)
        if thisId != id:
            position += 1
            continue
        # get data
        name = os.path.join(expPath, madFileObj.getFilenameByPosition(position))
        kindat = madFileObj.getKindatByPosition(position)
        kindatdesc = madKindatObj.getKindatDescription(kindat, kinst)
        category = madFileObj.getCategoryByPosition(position)
        status = madFileObj.getStatusByPosition(position)
        permission = madFileObj.getAccessByPosition(position)

        # skip private files if not trusted
        if trusted == 0 and int(permission) != 0:
            position += 1
            continue
            
        retStr += '%s,%i,%s,%i,%s,%i\n' % \
               (name,
                kindat,
                kindatdesc,
                category,
                status,
                permission)

        position += 1
    
    return render_to_response('madweb/service.html', {'text': retStr})


def get_parameters_service(request):
    """get_parameters_service runs the getParametersService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            filename=<full path to data file>
            
        Returns backslash-delimited data, one for each parameter either measured or derivable, with the following fields:

            1. parameter.mnemonic (string) Example 'dti'
            
            2. parameter.description (string) Example:
                "F10.7 Multiday average observed (Ott)"
                
            3. parameter.isError (int) 1 if error parameter, 0 if not
            
            4. parameter.units (string) Example "W/m2/Hz"
            
            5. parameter.isMeasured (int) 1 if measured, 0 if derivable
            
            6. parameter.category (string) Example: "Time Related Parameter"
            
            7. parameter.isSure (int) - 1 if parameter can be found for every record, 0 if can only be found for some.
                Not relevant to Madrigal 3, where always 1
    
            8. parameter.isAddIncrement - 1 if additional increment, 0 if normal (Added in Madrigal 2.5)
                Not relevant to Madrigal 3, where always -1
    """
    filename = request.GET['filename']
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create Madrigal File object 
    madFileObj = madrigal.data.MadrigalFile(filename, madDBObj)

    # create Madrigal Parameter object
    madParmObj = madrigal.data.MadrigalParameters(madDBObj)
    
    # create Madrigal web object 
    madWebObj = madrigal.ui.web.MadrigalWebFormat()
    

    # create lists of parameters
    measParmList = []
    derivedParmList = []
    allParmList = []
    sureParmList = []

    # use the comprehensive list of parameters to check if derivable
    parmList = madWebObj.getFormat('Comprehensive')

    # populate lists
    madFileObj.getMeasDervBothParmLists(parmList,
                                        measParmList,
                                        derivedParmList,
                                        allParmList,
                                        sureParmList)

    retStr = ''
    
    # loop through allParmList and output results
    for parm in allParmList:
        description = madParmObj.getSimpleParmDescription(parm)
        isNorm = madParmObj.getParmType(parm)
        if isNorm == 1:
            isError = 0
        else:
            isError = 1
        units = madParmObj.getParmUnits(parm)
        if parm in measParmList:
            isMeasured = 1
        else:
            isMeasured = 0
        if parm in sureParmList:
            isSure = 1
        else:
            isSure = 0
        category = madParmObj.getParmCategory(parm)
        try:
            if madParmObj.isAddIncrement(parm):
                isAddIncrement = 1
            else:
                isAddIncrement = 0
        except:
            isAddIncrement = -1
        # print out this parm
        retStr += '%s\%s\%i\%s\%i\%s\%i\%i\n' % (parm,
                                                description,
                                                isError,
                                                units,
                                                isMeasured,
                                                category,
                                                isSure,
                                                isAddIncrement)
        
    return render_to_response('madweb/service.html', {'text': retStr})



def isprint_service(request):
    """isprint_service runs the isprintService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            'file': The full path to the file to be analyzed by isprint.
            
            'parms': Multiple requested parameters.
            
            'filters': Multiple of filters desired, as in isprint command
            
            'user_fullname'     user name 
            
            'user_email'        user email
            
            'user_affiliation'  user affiliation
            
            'output' - option argument specifying output file basename.  Will be Hdf5 format if extension in
                ('hdf5', 'h5', 'hdf').  Will be netCDF4 is extension is '.nc'. Otherwise ascii. If not
                given, output is ascii.
                
            'header':  t for headers, f for no header.  Defaults to no header. Ignored if not ascii output
    
    Returns data as either column delimited ascii, Hdf5, or netCDF4.
    """
    madDB = madrigal.metadata.MadrigalDB()
    madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
    
    # get required arguments
    thisFile = request.GET['file']
    parms = request.GET.getlist('parms')
    filters = request.GET.getlist('filters')
    user_fullname = request.GET['user_fullname']
    user_email = request.GET['user_email']
    user_affiliation = request.GET['user_affiliation']
    # get optional arguments
    try:
        output = os.path.basename(request.GET['output'])
        filename, file_extension = os.path.splitext(output)
        if file_extension in ('.hdf5', '.h5', '.hdf'):
            format = 'Hdf5'
        elif file_extension in ('.nc',):
            format = 'netCDF4'
        else:
            format = 'ascii'
    except:
        format = 'ascii'
        output = None
    if not output is None:
        # we need to write to a download file
        downloadFile = os.path.join('/tmp', output)
    try:
        header = request.GET['header']
        if header not in ('t', 'f'):
            raise ValueError, 'Unknown header value <%s>' % (header)
    except:
        header = 'f'
        
    # log data access
    madWebObj.logDataAccess(thisFile, user_fullname, user_email, user_affiliation)
        
    # run isprint command
    cmd = '%s/bin/isprint file=%s ' % (madDB.getMadroot(), thisFile)
    if not output is None:
        cmd += 'output=%s ' % (downloadFile)
    delimiter = ' '
    cmd += delimiter.join(parms) + ' '
    cmd += delimiter.join(filters) + ' '
    if format == 'ascii':
        cmd += 'summary=f '
        cmd += 'header=%s ' % (header)
        
    if output is None:
        # text response
        result = subprocess.check_output(cmd.split())
        if header == 'f':
            index = result.find('\n')
            result = result[index+1:]
        return render_to_response('madweb/service.html', {'text': result})
    else:
        # file download response
        subprocess.check_call(cmd.split())
        f = open(downloadFile, 'r')
        thisFile = django.core.files.File(f)
        response = HttpResponse(thisFile, content_type='application/x-octet-stream')
        response['Content-Disposition'] = 'attachment; filename="' + os.path.basename(downloadFile) + '"'
        response['Content-Length'] = os.path.getsize(downloadFile)
        response['Set-Cookie'] = 'fileDownload=true; path=/'
        os.remove(downloadFile)
        return(response)
    
    
def get_madfile_service(request):
    """get_madfile_service runs the getMadfile.cgi service.  
    
    Inputs:
        request/url - contains arguments:
        
            'fileName': The full path to the file to be downloaded as.
            
            'fileType': -1 for ascii, -2 for Hdf5, -3 for netCDF4. No other values supported
            
            'user_fullname'     user name 
            
            'user_email'        user email
            
            'user_affiliation'  user affiliation
    
    Returns file as either column delimited ascii, Hdf5, or netCDF4.
    """
    madDB = madrigal.metadata.MadrigalDB()
    madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
    
    # get required arguments
    fileName = request.GET['fileName']
    fileType = int(request.GET['fileType'])
    user_fullname = request.GET['user_fullname']
    user_email = request.GET['user_email']
    user_affiliation = request.GET['user_affiliation']
    
    if fileType not in (-1, -2, -3):
        raise ValueError, 'fileType %i not allowed: -1 for ascii, -2 for Hdf5, -3 for netCDF4' % (fileType)
    
    # log data access
    madWebObj.logDataAccess(fileName, user_fullname, user_email, user_affiliation)
    
    if fileType in (-1, -3):
        # need to create temp file
        filepath, file_extension = os.path.splitext(fileName)
        basename = os.path.basename(filepath)
        cedarObj = madrigal.cedar.MadrigalCedarFile(fileName)
        if fileType == -1:
            tmpFile = os.path.join('/tmp', basename + '.txt')
            cedarObj.writeText(tmpFile)
        else:
            tmpFile = os.path.join('/tmp', basename + '.nc')
            cedarObj.write('netCDF4', tmpFile)
        
    else:
        tmpFile = fileName
        
    f = open(tmpFile, 'r')
    thisFile = django.core.files.File(f)
    response = HttpResponse(thisFile, content_type='application/x-octet-stream')
    response['Content-Disposition'] = 'attachment; filename="' + os.path.basename(tmpFile) + '"'
    response['Content-Length'] = os.path.getsize(tmpFile)
    response['Set-Cookie'] = 'fileDownload=true; path=/'
    if fileType in (-1, -3):
        os.remove(tmpFile)
    return(response) 
        
    
def mad_calculator_service(request):
    """mad_calculator_service runs the madCalculator service.  
    
    Inputs:
        request/url - contains arguments:
        
            year, month, day, hour, min, sec 
            
            startLat - Starting geodetic latitude, -90 to 90 (float)
            
            endLat - Ending geodetic latitude, -90 to 90 (float)
            
            stepLat - Latitude step (0.1 to 90) (float)
            
            startLong - Starting geodetic longitude, -180 to 180  (float)
            
            endLong - Ending geodetic longitude, -180 to 180 (float)
            
            stepLong - Longitude step (0.1 to 180) (float)
            
            startAlt - Starting geodetic altitude, >= 0 (float)
            
            endAlt - Ending geodetic altitude, > 0 (float)
            
            stepAlt - Altitude step (>= 0.1) (float)
            
            parms - comma delimited string of Madrigal parameters desired
            
            oneD - zero or more mnemonics,float values to set input 1D values
    
    Returns comma-delimited data, one line for each combination of lat, long, and alt,
    with the following fields:

        1. latitude
        
        2. longitude
        
        3. altitude
        
        4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    year = int(request.GET['year'])
    month = int(request.GET['month'])
    day = int(request.GET['day'])
    hour = int(request.GET['hour'])
    minute = int(request.GET['min'])
    second = int(request.GET['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    
    startLat = float(request.GET['startLat'])
    endLat = float(request.GET['endLat'])
    if startLat == endLat:
        endLat += 0.001
    elif startLat > endLat:
        raise ValueError, 'startLat cannot be greater than endLat'
    stepLat = float(request.GET['stepLat'])
    if stepLat < 0.0:
        raise ValueError, 'stepLat cannot be less than zero'
    elif stepLat == 0.0:
        stepLat = 0.001
    latList = list(numpy.arange(startLat, endLat, stepLat))
    
    startLong = float(request.GET['startLong'])
    endLong = float(request.GET['endLong'])
    if startLong == endLong:
        endLong += 0.001
    elif startLong > endLong:
        raise ValueError, 'startLong cannot be greater than endLong'
    stepLong = float(request.GET['stepLong'])
    if stepLong < 0.0:
        raise ValueError, 'stepLong cannot be less than zero'
    elif stepLong == 0.0:
        stepLong = 0.001
    lonList = list(numpy.arange(startLong, endLong, stepLong))
    
    startAlt = float(request.GET['startAlt'])
    endAlt = float(request.GET['endAlt'])
    if startAlt == endAlt:
        endAlt += 0.001
    elif startAlt > endAlt:
        raise ValueError, 'startAlt cannot be greater than endAlt'
    stepAlt = float(request.GET['stepAlt'])
    if stepAlt < 0.0:
        raise ValueError, 'stepAlt cannot be less than zero'
    elif stepAlt == 0.0:
        stepAlt = 0.01
    altList = list(numpy.arange(startAlt, endAlt, stepAlt))
    
    parms = request.GET['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = request.GET.getlist('oneD')
    oneDParmDict = {}
    for oneDStr in oneDList:
        mnem, strValue = oneDStr.encode('ascii', 'ignore').split(',')
        oneDParmDict[mnem] = [float(strValue)]
    
    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorGrid(None, desiredParmList, [dt], latList, lonList, altList, 
                                   oneDParmDict, summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})


def mad_time_calculator_service(request):
    """mad_time_calculator_service runs the madTimeCalculator service.  Input parameters must not be location dependent
    
    Inputs:
        request/url - contains arguments:
        
            1. startyear - int 
            
            2. startmonth - int 
            
            3. startday - int
            
            4. starthour - int 
            
            5. startmin - int 
            
            6. startsec - int
            
            7. endyear - int 
            
            8. endmonth - int 
            
            9. endday - int
            
            10. endhour - int 
            
            11. endmin - int 
            
            12. endsec - int
            
            13. stephours - float - number of hours per time step
            
            14. parms - comma delimited string of Madrigal parameters desired (must not depend on location)
    
    Returns comma-delimited data, one line for each year, month, day, hour, minute, and second,
    with the following fields:

        1-6: year, month, day, hour, minute, and second
        
        2. requested parm fields
    """
    startyear = int(request.GET['startyear'])
    startmonth = int(request.GET['startmonth'])
    startday = int(request.GET['startday'])
    starthour = int(request.GET['starthour'])
    startminute = int(request.GET['startmin'])
    startsecond = int(request.GET['startsec'])
    endyear = int(request.GET['endyear'])
    endmonth = int(request.GET['endmonth'])
    endday = int(request.GET['endday'])
    endhour = int(request.GET['endhour'])
    endminute = int(request.GET['endmin'])
    endsecond = int(request.GET['endsec'])
    dt1 = datetime.datetime(startyear, startmonth, startday, starthour, startminute, startsecond)
    dt2 = datetime.datetime(endyear, endmonth, endday, endhour, endminute, endsecond)
    if dt1 > dt2:
        raise ValueError, 'End Datetime %s cannot be before start datetime %s' % (str(dt2), str(dt1))
    
    stephours = float(request.GET['stephours'])
    if stephours <= 0.0:
        raise ValueError, 'stephours cannot be non-positive: %f' % (stephours)
    
    dtList = []
    while dt1 <= dt2:
        dtList.append(dt1)
        dt1 += datetime.timedelta(hours=stephours)
    
    parms = request.GET['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['year','month','day','hour','min','sec'] + parms.split(',')]
    
    # no spatial data
    latList = lonList = altList = []
    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, latList, lonList, altList, 
                                   summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})




def mad_calculator2_service(request):
    """mad_calculator2_service runs the madCalculator2 service.
    
    Differs from madCalulator in that positions are a list rather than a grid.  
    
    Inputs:
        request/url - contains arguments:
        
            year, month, day, hour, min, sec 
            
            lats - comma separated list of latitudes to analyze
            
            longs - comma separated list of longitudes to analyze. Len must == len(lats)
            
            alts - comma separated list of altitudes to analyze. Len must == len(lats)
            
            parms - comma delimited string of Madrigal parameters desired
            
            oneD - zero or more mnemonics,float values to set input 1D values
                Example:  &oneD=kinst,31.0&oneD=elm,45.0
                
            twoD - zero or more mnemonics,comma-separate float list of len(lats) to set input 2D values
                Example:  twoD=te,1000,1100,1200  twoD=ti,1000,1000,1000
                          where there are 3 lats
    
    Returns comma-delimited data, one line for each lat value,
    with the following fields:

        1. latitude
        
        2. longitude
        
        3. altitude
        
        4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    if request.method == 'POST':
        reqDict = request.POST
    else:
        reqDict = request.GET
    year = int(reqDict.get('year'))
    month = int(reqDict['month'])
    day = int(reqDict['day'])
    hour = int(reqDict['hour'])
    minute = int(reqDict['min'])
    second = int(reqDict['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    
    latsStr = reqDict['lats']
    lats = [float(item) for item in latsStr.split(',')]
    longsStr = reqDict['longs']
    longs = [float(item) for item in longsStr.split(',')]
    altsStr = reqDict['alts']
    alts = [float(item) for item in altsStr.split(',')]
    
    parms = reqDict['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = reqDict.getlist('oneD')
    oneDParmDict = {}
    for oneDStr in oneDList:
        mnem, strValue = oneDStr.encode('ascii', 'ignore').split(',')
        oneDParmDict[mnem] = [float(strValue)]
        
    twoDList = reqDict.getlist('twoD')
        
    twoDParmDict = {}
    for twoDStr in twoDList:
        items = twoDStr.encode('ascii', 'ignore').split(',')
        if len(items) != 1 + len(lats):
            raise ValueError, 'twoDstr %s not correct number of points' % (str(twoDStr))
        mnem = items[0]
        floatValues = [float(item) for item in items[1:]]
        # now we need to expand these values to be two dimensional 1 x len(lats)
        values = numpy.zeros((1,len(lats)), dtype=numpy.float)
        values[0][:] = floatValues
        twoDParmDict[mnem] = values

    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorList(None, desiredParmList, [dt], lats, longs, alts, 
                                       oneDParmDict, twoDParmDict, summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})
    
    
    


def mad_calculator3_service(request):
    """mad_calculator3_service runs the madCalculator3 service.
    
    Differs from madCalulator in that multiple times, each with a unique list of positions, can be passed in.
    
    Inputs:
      request/url - contains arguments:
      
        year - a comma-separated list of years - (required)
        
        month  - a comma-separated list of months - (required)
        
        day - a comma-separated list of days - (required)
        
        hour - a comma-separated list of hours - (required)
        
        min - a comma-separated list of minutes - (required)
        
        sec - a comma-separated list of seconds - (required)
        
        numPos - a comma-sepatated list of the number of positions for each time - (required)
        
        lats - a comma-separated list of geodetic latitudes, -90 to 90 (required).  Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        longs - a comma-separated list of longitudes (required) Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        alts - a comma-separated list of geodetic altitudes in km (required) Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        parms - comma delimited string of Madrigal parameters desired (required)
        
        oneD - string in form <parm>,<comma-separated values> This argument allows the user to
                            set any number of one-D parameters to be used in the calculation.
                            Value must be parameter name, comma, list of values as double,
                            where length of list is equal to number of times.
                            Example:  &oneD=kinst,31.0,31.0&oneD=elm,45.0,50
                            (optional - 0 or more allowed)        
                            
         twoD=<parm>,<values>  (optional - 0 or more allowed) This argument allows the user to
                            set any number of two-D parameters to be used in the calculation.
                            Value must be parameter name, comma, comma-separated values.
                            Number of values must equal the sum of numPos.  Order is
                            first time values first, then second time values, etc
                            Example:  twoD=te,1000,1100,1200,1000,1100,1200 &twoD=ti,1000,1000,1000,1000,1000,1000
                            where numPos=3,3

    Returns comma-delimited data, one line for each location.  Separate times are delimited by line

    TIME MM/DD/YYYY HH:MM:SS
    
    Data lines have the following fields:
    
    1. latitude
    
    2. longitude
    
    3. altitude
    
    4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    if request.method == 'POST':
        reqDict = request.POST
    else:
        reqDict = request.GET
    yearList = [int(item) for item in reqDict.get('year').split(',')]
    monthList = [int(item) for item in reqDict.get('month').split(',')]
    dayList = [int(item) for item in reqDict.get('day').split(',')]
    hourList = [int(item) for item in reqDict.get('hour').split(',')]
    minList = [int(item) for item in reqDict.get('min').split(',')]
    secList = [int(item) for item in reqDict.get('sec').split(',')]
    dtList = [datetime.datetime(yearList[i], monthList[i], dayList[i],
                                hourList[i], minList[i], secList[i]) for i in range(len(yearList))]
    numPosStr = reqDict['numPos']
    numPosList = [int(item) for item in numPosStr.split(',')]
    totalPos = 0
    for numPos in numPosList:
        totalPos += numPos
    latsStr = reqDict['lats']
    lats = [float(item) for item in latsStr.split(',')]
    if len(lats) != totalPos:
        raise IOError, 'wrong number of lats, expected %i' % (totalPos)
    longsStr = reqDict['longs']
    longs = [float(item) for item in longsStr.split(',')]
    if len(longs) != totalPos:
        raise IOError, 'wrong number of longs, expected %i' % (totalPos)
    altsStr = reqDict['alts']
    alts = [float(item) for item in altsStr.split(',')]
    if len(alts) != totalPos:
        raise IOError, 'wrong number of alts, expected %i' % (totalPos)
    
    parms = reqDict['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = reqDict.getlist('oneD')
    twoDList = reqDict.getlist('twoD')
    
    # since the positions can change with each call, we need to call madrigal.isprint.MadCalculatorGrid once for each time
    startIndex = 0
    endIndex = 0
    fullText = ''
    for timeIndex, numPos in enumerate(numPosList):
        startIndex = endIndex
        endIndex += numPos
        thisLats = lats[startIndex:endIndex]
        thisLongs = longs[startIndex:endIndex]
        thisAlts = alts[startIndex:endIndex]
    
        oneDParmDict = {}
        for oneDStr in oneDList:
            values = oneDStr.encode('ascii', 'ignore').split(',')
            if len(values) != 1+len(dtList):
                raise ValueError, 'wrong number of values given for 1D parm %s' % (values[0])
            oneDParmDict[values[0]] = [float(values[timeIndex+1])]
        
        twoDParmDict = {}
        
        for twoDStr in twoDList:
            values = twoDStr.encode('ascii', 'ignore').split(',')
            if len(values) != 1 + totalPos:
                raise ValueError, 'twoDstr %s not correct number of points' % (str(twoDStr))
            mnem = values[0]
            floatValues = [float(item) for item in values[1+startIndex:1+endIndex]]
            # now we need to expand these values to be two dimensional - 1,len(thisLats)
            values2D = numpy.zeros((1,len(thisLats)), dtype=numpy.float)
            values2D[0][:] = floatValues
            twoDParmDict[mnem] = values2D
            
            
    
        # capture stdout
        old_stdout = sys.stdout
        sys.stdout = mystdout = cStringIO.StringIO()
        madrigal.isprint.MadCalculatorList(None, desiredParmList, [dtList[timeIndex]], thisLats, 
                                           thisLongs, thisAlts, 
                                           oneDParmDict, twoDParmDict, summary=None)
        text = mystdout.getvalue()
        sys.stdout = old_stdout
        
        fullText += 'TIME %s\n' % (dtList[timeIndex].strftime('%m/%d/%Y %H:%M:%S'))
        fullText += text
    
    return render_to_response('madweb/service.html', {'text': fullText})
    
    
    
def geodetic_to_radar_service(request):
    """geodetic_to_radar_service runs the geodeticToRadar service.
    
    Inputs:
      request/url - contains arguments:
      
        slatgd  - radar geodetic latitude
        
        slon - radar longitude
        
        saltgd - radar geodetic altitude
        
        gdlat - a comma-separated list of geodetic latitude of point
        
        glon - a comma-separated list of longitude of point. Len must be same as gdlat
        
        gdalt - a comma-separated list of geodetic altitude of point. Len must be same as gdlat


    Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):

        1. radar azimuth in degrees (0 = north)
        
        2. radar elevation in degrees 
        
        3. radar range in km
    """
    slatgd = float(request.GET['slatgd'])
    slon = float(request.GET['slon'])
    saltgd = float(request.GET['saltgd'])
    oneDParmDict = {'GDLATR': [slatgd],
                    'GDLONR': [slon],
                    'GALTR': [saltgd]}
    gdlatStr = request.GET['gdlat']
    gdlatList = [float(item) for item in gdlatStr.split(',')]
    glonStr = request.GET['glon']
    glonList = [float(item) for item in glonStr.split(',')]
    gdaltStr = request.GET['gdalt']
    gdaltList = [float(item) for item in gdaltStr.split(',')]
    desiredParmList = ['azm', 'elm', 'range']
    dtList = [datetime.datetime(2001,1,1)] # not relevant
    if len(gdlatList) != len(glonList) or len(gdlatList) != len(gdaltList):
        raise ValueError, 'all point list lengths must be equal'
    
    fullText = ''
    
    delimiter = ','
    for i in range(len(gdlatList)):
         # capture stdout
        old_stdout = sys.stdout
        sys.stdout = mystdout = cStringIO.StringIO()
        madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, [gdlatList[i]], 
                                       [glonList[i]], [gdaltList[i]], summary=None,
                                       oneDParmDict=oneDParmDict)
        text = mystdout.getvalue()
        sys.stdout = old_stdout
        for line in text.split('\n'):
            items = line.split()
            fullText += delimiter.join(items) + '\n'
    
    return render_to_response('madweb/service.html', {'text': fullText})


def radar_to_geodetic_service(request):
    """radar_to_geodetic_service runs the radarToGeodetic service.
    
    Inputs:
      request/url - contains arguments:
      
        slatgd  - radar geodetic latitude
        
        slon - radar longitude
        
        saltgd - radar geodetic altitude
        
        azs - a comma-separated list of azimuths of point
        
        els - a comma-separated list of elevations of point. Len must be same as azs
        
        ranges - a comma-separated list of ranges to point. Len must be same as azs


    Returns comma-delimited data, one line for point in lists  (points treated as individual combinations, not grids):

        1. geodetic latitude
        
        2. longitude (-180 to 180)
        
        3. geodetic altitude in km
    """
    slatgd = float(request.GET['slatgd'])
    slon = float(request.GET['slon'])
    saltgd = float(request.GET['saltgd'])
    azStr = request.GET['az']
    azList = [float(item) for item in azStr.split(',')]
    elStr = request.GET['el']
    elList = [float(item) for item in elStr.split(',')]
    rangeStr = request.GET['range']
    rangeList = [float(item) for item in rangeStr.split(',')]
    if len(azList) != len(elList) or len(azList) != len(rangeList):
        raise ValueError, 'all point list lengths must be equal'
    
    fullText = ''
    
    for i in range(len(azList)):
        gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slatgd, slon, saltgd,
                                                            azList[i], elList[i], rangeList[i])
        fullText += '%f,%f,%f\n' % (gdlat,glon,gdalt)
        
    return render_to_response('madweb/service.html', {'text': fullText})
    
    

def list_file_times_service(request):
    """list_file_times_service runs the listFileTimes service.
    
    Inputs:
      request/url - contains arguments:
      
        Optional: expDir - experiment directory to list.  Can be absolute or relative to
            experiments[0-9]*. Default is all files in $MADROOT/experiments*

    Returns comma-delimited data, one for each file:
    
        1. Full path of file
        
        2. File modification time in form YYYY-MM-DD HH:MM:SS (UT time)
    """
    expDir = None
    try:
        expDir = request.GET['expDir']
    except:
        pass
    madDB = madrigal.metadata.MadrigalDB()
    fileList = madDB.listFileTimes(expDir)
    fullText = '\n\n'
    for filename, filetime in fileList:
        fullText += "\'%s\', %s\n" % (filename, filetime.strftime('%Y-%m-%d %H:%M:%S'))
        
    return render_to_response('madweb/service.html', {'text': django.utils.safestring.mark_safe(fullText)})


def trace_magnetic_field_service(request):
    """trace_magnetic_field_service runs the traceMagneticField service.
    
    Inputs:
      request/url - contains arguments:
      
        year, month, day, hour, min, sec
        
        inputType (0 for geodetic, 1 for GSM)
        
        outputType (0 for geodetic, 1 for GSM)
        
            The following parameter depend on inputType:
            
        in1 - a comma-separated list of geodetic altitudes or ZGSMs of starting point
        
        in2 - a comma-separated list of geodetic latitudes or XGSMs of starting point
        
        in3 - a comma-separated list of longitude or YGSM of starting point

            Length of all three lists must be the same
        
        model - 0 for Tsyganenko, 1 for IGRF
        
        qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane
        
        stopAlt - altitude in km to stop trace at, if qualifier is north_alt or south_alt.
        
        If other qualifier, this parameter is not required.

    Returns comma-delimited data, one line for point in in lists:

        1. geodetic altitude or ZGSM of ending point
        
        2. geodetic latitude or XGSM of ending point
        
        3. longitude or YGSM of ending point
    """
    year = int(request.GET['year'])
    month = int(request.GET['month'])
    day = int(request.GET['day'])
    hour = int(request.GET['hour'])
    minute = int(request.GET['min'])
    second = int(request.GET['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    inputType = int(request.GET['inputType'])
    if inputType not in (0,1):
        raise ValueError, 'inputType must be 0 or 1, not %i' % (inputType)
    outputType = int(request.GET['outputType'])
    if outputType not in (0,1):
        raise ValueError, 'outputType must be 0 or 1, not %i' % (outputType)
    in1Str = request.GET['in1']
    in1List = [float(item) for item in in1Str.split(',')]
    in2Str = request.GET['in2']
    in2List = [float(item) for item in in2Str.split(',')]
    in3Str = request.GET['in3']
    in3List = [float(item) for item in in3Str.split(',')]
    if len(in1List) != len(in2List) or len(in1List) != len(in3List):
        raise ValueError, 'All three in* lists must have same length'
    model = int(request.GET['model'])
    if model not in (0,1):
        raise ValueError, 'model must be 0 or 1, not %i' % (model)
    qualifier = int(request.GET['qualifier'])
    if qualifier not in (0,1,2,3,4):
        raise ValueError, 'model must be in 0,1,2,3,4 not %i' % (model)
    try:
        stopAlt = float(request.GET['stopAlt'])
    except:
        stopAlt = 0.0
        
    fullText = ''
    resultArr = numpy.zeros((3,), dtype='f8')
    madDB = madrigal.metadata.MadrigalDB()
    madDeriveObj = madrigal.derivation.MadrigalDerivationMethods(madDB.getMadroot())
    for i in range(len(in1List)):
        madDeriveObj.traceMagneticField(year, month, day, hour, minute, second, 
                                        inputType, outputType, in1List[i], in2List[i], in3List[i], 
                                        model, qualifier, stopAlt, resultArr)
        fullText += '%f,%f,%f\n' % (resultArr[0], resultArr[1], resultArr[2])

    return render_to_response('madweb/service.html', {'text': fullText})

Functions

def geodetic_to_radar_service(

request)

geodetic_to_radar_service runs the geodeticToRadar service.

Inputs: request/url - contains arguments:

slatgd  - radar geodetic latitude

slon - radar longitude

saltgd - radar geodetic altitude

gdlat - a comma-separated list of geodetic latitude of point

glon - a comma-separated list of longitude of point. Len must be same as gdlat

gdalt - a comma-separated list of geodetic altitude of point. Len must be same as gdlat

Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):

1. radar azimuth in degrees (0 = north)

2. radar elevation in degrees

3. radar range in km
def geodetic_to_radar_service(request):
    """geodetic_to_radar_service runs the geodeticToRadar service.
    
    Inputs:
      request/url - contains arguments:
      
        slatgd  - radar geodetic latitude
        
        slon - radar longitude
        
        saltgd - radar geodetic altitude
        
        gdlat - a comma-separated list of geodetic latitude of point
        
        glon - a comma-separated list of longitude of point. Len must be same as gdlat
        
        gdalt - a comma-separated list of geodetic altitude of point. Len must be same as gdlat


    Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):

        1. radar azimuth in degrees (0 = north)
        
        2. radar elevation in degrees 
        
        3. radar range in km
    """
    slatgd = float(request.GET['slatgd'])
    slon = float(request.GET['slon'])
    saltgd = float(request.GET['saltgd'])
    oneDParmDict = {'GDLATR': [slatgd],
                    'GDLONR': [slon],
                    'GALTR': [saltgd]}
    gdlatStr = request.GET['gdlat']
    gdlatList = [float(item) for item in gdlatStr.split(',')]
    glonStr = request.GET['glon']
    glonList = [float(item) for item in glonStr.split(',')]
    gdaltStr = request.GET['gdalt']
    gdaltList = [float(item) for item in gdaltStr.split(',')]
    desiredParmList = ['azm', 'elm', 'range']
    dtList = [datetime.datetime(2001,1,1)] # not relevant
    if len(gdlatList) != len(glonList) or len(gdlatList) != len(gdaltList):
        raise ValueError, 'all point list lengths must be equal'
    
    fullText = ''
    
    delimiter = ','
    for i in range(len(gdlatList)):
         # capture stdout
        old_stdout = sys.stdout
        sys.stdout = mystdout = cStringIO.StringIO()
        madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, [gdlatList[i]], 
                                       [glonList[i]], [gdaltList[i]], summary=None,
                                       oneDParmDict=oneDParmDict)
        text = mystdout.getvalue()
        sys.stdout = old_stdout
        for line in text.split('\n'):
            items = line.split()
            fullText += delimiter.join(items) + '\n'
    
    return render_to_response('madweb/service.html', {'text': fullText})

def get_experiment_files_service(

request)

get_experiment_files_service runs the getExperimentFilesService.py service.

Inputs: request/url - contains arguments:

    id - local experiment id

Returns comma-delimited data, one line for each experiment file, with the following fields:

    1. file.name (string) Example '/opt/mdarigal/blah/mlh980120g.001'

    2. file.kindat (int) Kindat code.  Example: 3001

    3. file.kindat desc (string) Kindat description: Example 'Basic Derived Parameters'

    4. file.category (int) (1=default, 2=variant, 3=history, 4=real-time)

    5. file.status (string)('preliminary', 'final', or any other description)

    6. file.permission (int)  0 for public, 1 for private.  For now will not return private files.

Returns empty string if experiment id not found
def get_experiment_files_service(request):
    """get_experiment_files_service runs the getExperimentFilesService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            id - local experiment id
            
        Returns comma-delimited data, one line for each experiment file, with the following fields:

            1. file.name (string) Example '/opt/mdarigal/blah/mlh980120g.001'
            
            2. file.kindat (int) Kindat code.  Example: 3001
            
            3. file.kindat desc (string) Kindat description: Example 'Basic Derived Parameters'
            
            4. file.category (int) (1=default, 2=variant, 3=history, 4=real-time)
            
            5. file.status (string)('preliminary', 'final', or any other description)
            
            6. file.permission (int)  0 for public, 1 for private.  For now will not return private files.
        
        Returns empty string if experiment id not found
    """
    id = int(request.GET['id'])
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create MadrigalExperiments object to get full file name
    madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)

    # create Madrigal Kindat to get Kindat descriptions
    madKindatObj = madrigal.metadata.MadrigalKindat(madDBObj)

    # create Madrigal File object 
    madFileObj = madrigal.metadata.MadrigalMetaFile(madDBObj)
    
    madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
    trusted = madWebObj.isTrusted()

    # loop through the experiments to get url
    position = 0
    kinst = None
    while 1:
        thisId = madExpObj.getExpIdByPosition(position)
        # check for end
        if thisId == None:
            sys.exit(-1)
        thisId = int(thisId)
        # check for right id
        if thisId == id:
            thisUrl = madExpObj.getExpUrlByPosition(position)
            # add end of url to exp path
            index = thisUrl.find('/madtoc/')
            expPath = madDBObj.getFullPathFromPartial(thisUrl[index+8:])
            kinst = madExpObj.getKinstByPosition(position)
            break
        position += 1

    # loop though files to find all with right experiment id
    position = 0
    retStr = ''
    while 1:
        thisId = madFileObj.getExpIdByPosition(position)
        if thisId == None:
            break
        thisId = int(thisId)
        if thisId != id:
            position += 1
            continue
        # get data
        name = os.path.join(expPath, madFileObj.getFilenameByPosition(position))
        kindat = madFileObj.getKindatByPosition(position)
        kindatdesc = madKindatObj.getKindatDescription(kindat, kinst)
        category = madFileObj.getCategoryByPosition(position)
        status = madFileObj.getStatusByPosition(position)
        permission = madFileObj.getAccessByPosition(position)

        # skip private files if not trusted
        if trusted == 0 and int(permission) != 0:
            position += 1
            continue
            
        retStr += '%s,%i,%s,%i,%s,%i\n' % \
               (name,
                kindat,
                kindatdesc,
                category,
                status,
                permission)

        position += 1
    
    return render_to_response('madweb/service.html', {'text': retStr})

def get_experiments_service(

request)

get_experiments_service runs the getExperimentsService.py service.

Inputs: request/url - contains arguments:

    code - one or more kindat values

    startyear, startmonth, startday, starthour, startmin, startsec

    endyear, endmonth, endday, endhour, endmin, endsec

    local (defaults to True)

Returns comma-delimited data, one line for each experiment, with the following fields:

1. experiment.id (int) Example: 10000111

2. experiment.url (string) Example: 'http://www.haystack.mit.edu/cgi-bin/madtoc/1997/mlh/03dec97'

3. experiment.name (string) Example: 'Wide Latitude Substorm Study'

4. experiment.siteid (int) Example: 1

5. experiment.sitename (string) Example: 'Millstone Hill Observatory'

6. experiment.instcode (int) Code of instrument. Example: 30

7. experiment.instname (string) Instrument name. Example: 'Millstone Hill Incoherent Scatter Radar'

8. experiment.start year (int) year of experiment start

9. experiment.start month (int) month of experiment start

10. experiment.start day (int) day of experiment start

11. experiment.start hour (int) hour of experiment start

12. experiment.start minute (int) min of experiment start

13. experiment.start second (int) sec of experiment start

14. experiment.end year (int) year of experiment end

15. experiment.end month (int) month of experiment end

16. experiment.end day (int) day of experiment end

17. experiment.end hour (int) hour of experiment end

18. experiment.end minute (int) min of experiment end

19. experiment.end second (int) sec of experiment end

20. experiment.isLocal (int) 1 if local, 0 if not

21.experiment.PI (string) Experiment PI name Example: 'Phil Erickson'

22. experiment.PIEmail (string) Experiment PI email Example: 'perickson@haystack.mit.edu'

23. utc timestamp of last update to experiment

24. security value
def get_experiments_service(request):
    """get_experiments_service runs the getExperimentsService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            code - one or more kindat values
            
            startyear, startmonth, startday, starthour, startmin, startsec
            
            endyear, endmonth, endday, endhour, endmin, endsec
            
            local (defaults to True)
            
    Returns comma-delimited data, one line for each experiment, with the following fields:

        1. experiment.id (int) Example: 10000111
        
        2. experiment.url (string) Example: 'http://www.haystack.mit.edu/cgi-bin/madtoc/1997/mlh/03dec97'
        
        3. experiment.name (string) Example: 'Wide Latitude Substorm Study'
        
        4. experiment.siteid (int) Example: 1
        
        5. experiment.sitename (string) Example: 'Millstone Hill Observatory'
        
        6. experiment.instcode (int) Code of instrument. Example: 30
        
        7. experiment.instname (string) Instrument name. Example: 'Millstone Hill Incoherent Scatter Radar'
        
        8. experiment.start year (int) year of experiment start
        
        9. experiment.start month (int) month of experiment start
        
        10. experiment.start day (int) day of experiment start
        
        11. experiment.start hour (int) hour of experiment start
        
        12. experiment.start minute (int) min of experiment start
        
        13. experiment.start second (int) sec of experiment start
        
        14. experiment.end year (int) year of experiment end
        
        15. experiment.end month (int) month of experiment end
        
        16. experiment.end day (int) day of experiment end
        
        17. experiment.end hour (int) hour of experiment end
        
        18. experiment.end minute (int) min of experiment end
        
        19. experiment.end second (int) sec of experiment end
        
        20. experiment.isLocal (int) 1 if local, 0 if not
        
        21.experiment.PI (string) Experiment PI name Example: 'Phil Erickson'

        22. experiment.PIEmail (string) Experiment PI email Example: 'perickson@haystack.mit.edu'
        
        23. utc timestamp of last update to experiment
        
        24. security value
        
    """
    codeList = request.GET.getlist('code')
    codeList = [int(code) for code in codeList]
    startyear = int(request.GET['startyear'])
    startmonth = int(request.GET['startmonth'])
    startday = int(request.GET['startday'])
    starthour = int(request.GET['starthour'])
    startmin = int(request.GET['startmin'])
    startsec = int(request.GET['startsec'])
    endyear = int(request.GET['endyear'])
    endmonth = int(request.GET['endmonth'])
    endday = int(request.GET['endday'])
    endhour = int(request.GET['endhour'])
    endmin = int(request.GET['endmin'])
    endsec = int(request.GET['endsec'])
    try:
        local = int(request.GET['local'])
    except:
        local = 1
    
    
    # if startsec or endsec in (60, 61), handle correctly
    if startsec in (60, 61):
        tmpTime = datetime.datetime(startyear,
                                    startmonth,
                                    startday,
                                    starthour,
                                    startmin,
                                    59)
        tmpTime += datetime.timedelta(0, startsec - 59)
        startyear = tmpTime.year
        startmonth = tmpTime.month
        startday = tmpTime.day
        starthour = tmpTime.hour
        startmin = tmpTime.minute
        startsec = tmpTime.second

    if endsec in (60, 61):
        tmpTime = datetime.datetime(endyear,
                                    endmonth,
                                    endday,
                                    endhour,
                                    endmin,
                                    59)
        tmpTime += datetime.timedelta(0, endsec - 59)
        endyear = tmpTime.year
        endmonth = tmpTime.month
        endday = tmpTime.day
        endhour = tmpTime.hour
        endmin = tmpTime.minute
        endsec = tmpTime.second
        
    # if codeList is empty or contains 0, change it to only contain 0
    if len(codeList) == 0 or 0 in codeList:
        codeList = [0]
        
    retStr = ''

    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # get the local site id
    localSiteId = madDBObj.getSiteID()

    # create MadrigalInstrument obj to convert kinst to instrument names
    madInstObj = madrigal.metadata.MadrigalInstrument(madDBObj)

    # create MadrigalSite obj to convert site id to site name
    madSiteObj = madrigal.metadata.MadrigalSite(madDBObj)
    
    madWebObj = madrigal.ui.web.MadrigalWeb(madDBObj)
    trusted = madWebObj.isTrusted()

    # create starttime for filter, if possible
    if startyear != None:
        startTimeFilter = datetime.datetime(startyear,
                        startmonth,
                        startday,
                        starthour,
                        startmin,
                        startsec) 
    else:
        startTimeFilter = None

    # create endtime for filter, if possible
    if endyear != None:
        endTimeFilter = datetime.datetime(endyear,
                          endmonth,
                      endday,
                      endhour,
                      endmin,
                      endsec) 
    else:
        endTimeFilter = None

    # create MadrigalExperiments for local or all files
    if local == 1:
        madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj)
    else:
        # use file expTabAll.txt to get all experiments
        filename = madDBObj.getMadroot()
        if filename[-1] != '/':
            filename += '/'
        filename += 'metadata/expTabAll.txt'
        madExpObj = madrigal.metadata.MadrigalExperiment(madDBObj, filename)


    # loop through the data
    position = 0
    while 1:
        thisId = madExpObj.getExpIdByPosition(position)
        # check for end
        if thisId == None:
            break
        thisUrl = madExpObj.getExpUrlByPosition(position)
        thisName = madExpObj.getExpNameByPosition(position)
        thisSiteId = madExpObj.getExpSiteIdByPosition(position)
        thisSiteName = madSiteObj.getSiteName(thisSiteId)
        thisInstCode = madExpObj.getKinstByPosition(position)
        thisInstName =madInstObj.getInstrumentName(thisInstCode)
        thisStart = madExpObj.getExpStartDateTimeByPosition(position)
        thisEnd = madExpObj.getExpEndDateTimeByPosition(position)
        thisSecurity = madExpObj.getSecurityByPosition(position)
        if thisSiteId == localSiteId:
            thisLocal = 1
        else:
            thisLocal = 0
        thisPI = madExpObj.getPIByPosition(position)
        if thisPI in (None, ''):
            thisPI = madInstObj.getContactName(thisInstCode)
        thisPIEmail = madExpObj.getPIEmailByPosition(position)
        if thisPIEmail in (None, ''):
            thisPIEmail = madInstObj.getContactEmail(thisInstCode)
        expDir = madExpObj.getExpDirByPosition(position)
            
        position += 1

        # some experiments set the end of the day to 24:00:00 - not
        # technically correct - reset to 23:59:59
        
        if (thisStart[3] == 24 and thisStart[4] == 0 and thisStart[5] == 0):
            thisStart[3] = 23
            thisStart[4] = 59
            thisStart[5] = 59

        if (thisEnd[3] == 24 and thisEnd[4] == 0 and thisEnd[5] == 0):
            thisEnd[3] = 23
            thisEnd[4] = 59
            thisEnd[5] = 59
        
        # apply filters
        
        # first apply instrument code filter
        if codeList[0] != 0:
            if thisInstCode not in codeList:
                continue

        # apply starttime and endtime filters
        thisStartTime = datetime.datetime(thisStart[0],
                                          thisStart[1],
                                          thisStart[2],
                                          thisStart[3],
                                          thisStart[4],
                                          thisStart[5])

        thisEndTime = datetime.datetime(thisEnd[0],
                                        thisEnd[1],
                                        thisEnd[2],
                                        thisEnd[3],
                                        thisEnd[4],
                                        thisEnd[5])
        
        if startTimeFilter != None:
            if thisEndTime < startTimeFilter:
                continue

        if endTimeFilter != None:
            if thisStartTime > endTimeFilter:
                continue

        # apply local filer
        if local == 1 and thisLocal == 0:
            continue

        # apply security filter
        if trusted == 0 and thisSecurity not in (0,2):
            continue
        
        # create exp timestamp
        if local == 1:
            thisUTTimestamp = long(os.stat(expDir).st_mtime + time.timezone)
        else:
            thisUTTimestamp = 0

        # add this experiment
        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' % \
                (thisId,
                thisUrl,
                thisName,
                thisSiteId,
                thisSiteName,
                thisInstCode,
                thisInstName,
                thisStart[0],
                thisStart[1],
                thisStart[2],
                thisStart[3],
                thisStart[4],
                thisStart[5],
                thisEnd[0],
                thisEnd[1],
                thisEnd[2],
                thisEnd[3],
                thisEnd[4],
                thisEnd[5],
                thisLocal,
                str(thisPI),
                str(thisPIEmail),
                thisUTTimestamp,
                thisSecurity)
                
    return render_to_response('madweb/service.html', {'text': retStr})

def get_instruments_service(

request)

get_instruments_service runs the getInstrumentsService.py service.

Inputs: request (ignored)

Returns comma-delimited data, one line for each experiment, with the following fields:

1. instrument.name  Example: 'Millstone Hill Incoherent Scatter Radar'

2. instrument.code Example: 30

3. instrument.mnemonic (3 char string) Example: 'mlh'

4. instrument.latitude  Example: 45.0

5. instrument.longitude  Example: 110.0

6. instrument.altitude   Example: 0.015 (km)

7. instrument.category  Example: 'Incoherent Scatter Radars'

8. contact name

9. contact email
def get_instruments_service(request):
    """get_instruments_service runs the getInstrumentsService.py service.  
    
    Inputs:
        request (ignored)
        
        Returns comma-delimited data, one line for each experiment, with the following fields:

        1. instrument.name  Example: 'Millstone Hill Incoherent Scatter Radar'

        2. instrument.code Example: 30

        3. instrument.mnemonic (3 char string) Example: 'mlh'

        4. instrument.latitude  Example: 45.0

        5. instrument.longitude  Example: 110.0

        6. instrument.altitude   Example: 0.015 (km) 
        
        7. instrument.category  Example: 'Incoherent Scatter Radars'
        
        8. contact name
        
        9. contact email
    """
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create MadrigalInstument object
    madInst = madrigal.metadata.MadrigalInstrument(madDBObj)

    # get instrument list
    instList = madInst.getInstrumentList()

    # loop through each instrument
    instStr = ''
    for inst in instList:
        name = inst[0]
        code = inst[2]
        mnemonic = inst[1]
        latitude = madInst.getLatitude(code)
        if latitude == None:
            latitude = 0.0
        longitude = madInst.getLongitude(code)
        if longitude == None:
            longitude = 0.0
        altitude = madInst.getAltitude(code)
        if altitude == None:
            altitude = 0.0
        category = madInst.getCategory(code)
        if category == None:
            category = ''
        # print data
        contactName = madInst.getContactName(code)
        contactEmail = madInst.getContactEmail(code)
        instStr += '%s,%i,%s,%f,%f,%f,%s,%s,%s\n' % (name,
                                                     code,
                                                     mnemonic,
                                                     latitude,
                                                     longitude,
                                                     altitude,
                                                     category,
                                                     str(contactName),
                                                     str(contactEmail))
        
    return render_to_response('madweb/service.html', {'text': instStr})

def get_madfile_service(

request)

get_madfile_service runs the getMadfile.cgi service.

Inputs: request/url - contains arguments:

    'fileName': The full path to the file to be downloaded as.

    'fileType': -1 for ascii, -2 for Hdf5, -3 for netCDF4. No other values supported

    'user_fullname'     user name

    'user_email'        user email

    'user_affiliation'  user affiliation

Returns file as either column delimited ascii, Hdf5, or netCDF4.

def get_madfile_service(request):
    """get_madfile_service runs the getMadfile.cgi service.  
    
    Inputs:
        request/url - contains arguments:
        
            'fileName': The full path to the file to be downloaded as.
            
            'fileType': -1 for ascii, -2 for Hdf5, -3 for netCDF4. No other values supported
            
            'user_fullname'     user name 
            
            'user_email'        user email
            
            'user_affiliation'  user affiliation
    
    Returns file as either column delimited ascii, Hdf5, or netCDF4.
    """
    madDB = madrigal.metadata.MadrigalDB()
    madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
    
    # get required arguments
    fileName = request.GET['fileName']
    fileType = int(request.GET['fileType'])
    user_fullname = request.GET['user_fullname']
    user_email = request.GET['user_email']
    user_affiliation = request.GET['user_affiliation']
    
    if fileType not in (-1, -2, -3):
        raise ValueError, 'fileType %i not allowed: -1 for ascii, -2 for Hdf5, -3 for netCDF4' % (fileType)
    
    # log data access
    madWebObj.logDataAccess(fileName, user_fullname, user_email, user_affiliation)
    
    if fileType in (-1, -3):
        # need to create temp file
        filepath, file_extension = os.path.splitext(fileName)
        basename = os.path.basename(filepath)
        cedarObj = madrigal.cedar.MadrigalCedarFile(fileName)
        if fileType == -1:
            tmpFile = os.path.join('/tmp', basename + '.txt')
            cedarObj.writeText(tmpFile)
        else:
            tmpFile = os.path.join('/tmp', basename + '.nc')
            cedarObj.write('netCDF4', tmpFile)
        
    else:
        tmpFile = fileName
        
    f = open(tmpFile, 'r')
    thisFile = django.core.files.File(f)
    response = HttpResponse(thisFile, content_type='application/x-octet-stream')
    response['Content-Disposition'] = 'attachment; filename="' + os.path.basename(tmpFile) + '"'
    response['Content-Length'] = os.path.getsize(tmpFile)
    response['Set-Cookie'] = 'fileDownload=true; path=/'
    if fileType in (-1, -3):
        os.remove(tmpFile)
    return(response) 

def get_parameters_service(

request)

get_parameters_service runs the getParametersService.py service.

Inputs: request/url - contains arguments:

    filename=<full path to data file>

Returns backslash-delimited data, one for each parameter either measured or derivable, with the following fields:

    1. parameter.mnemonic (string) Example 'dti'

    2. parameter.description (string) Example:
        "F10.7 Multiday average observed (Ott)"

    3. parameter.isError (int) 1 if error parameter, 0 if not

    4. parameter.units (string) Example "W/m2/Hz"

    5. parameter.isMeasured (int) 1 if measured, 0 if derivable

    6. parameter.category (string) Example: "Time Related Parameter"

    7. parameter.isSure (int) - 1 if parameter can be found for every record, 0 if can only be found for some.
        Not relevant to Madrigal 3, where always 1

    8. parameter.isAddIncrement - 1 if additional increment, 0 if normal (Added in Madrigal 2.5)
        Not relevant to Madrigal 3, where always -1
def get_parameters_service(request):
    """get_parameters_service runs the getParametersService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            filename=<full path to data file>
            
        Returns backslash-delimited data, one for each parameter either measured or derivable, with the following fields:

            1. parameter.mnemonic (string) Example 'dti'
            
            2. parameter.description (string) Example:
                "F10.7 Multiday average observed (Ott)"
                
            3. parameter.isError (int) 1 if error parameter, 0 if not
            
            4. parameter.units (string) Example "W/m2/Hz"
            
            5. parameter.isMeasured (int) 1 if measured, 0 if derivable
            
            6. parameter.category (string) Example: "Time Related Parameter"
            
            7. parameter.isSure (int) - 1 if parameter can be found for every record, 0 if can only be found for some.
                Not relevant to Madrigal 3, where always 1
    
            8. parameter.isAddIncrement - 1 if additional increment, 0 if normal (Added in Madrigal 2.5)
                Not relevant to Madrigal 3, where always -1
    """
    filename = request.GET['filename']
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create Madrigal File object 
    madFileObj = madrigal.data.MadrigalFile(filename, madDBObj)

    # create Madrigal Parameter object
    madParmObj = madrigal.data.MadrigalParameters(madDBObj)
    
    # create Madrigal web object 
    madWebObj = madrigal.ui.web.MadrigalWebFormat()
    

    # create lists of parameters
    measParmList = []
    derivedParmList = []
    allParmList = []
    sureParmList = []

    # use the comprehensive list of parameters to check if derivable
    parmList = madWebObj.getFormat('Comprehensive')

    # populate lists
    madFileObj.getMeasDervBothParmLists(parmList,
                                        measParmList,
                                        derivedParmList,
                                        allParmList,
                                        sureParmList)

    retStr = ''
    
    # loop through allParmList and output results
    for parm in allParmList:
        description = madParmObj.getSimpleParmDescription(parm)
        isNorm = madParmObj.getParmType(parm)
        if isNorm == 1:
            isError = 0
        else:
            isError = 1
        units = madParmObj.getParmUnits(parm)
        if parm in measParmList:
            isMeasured = 1
        else:
            isMeasured = 0
        if parm in sureParmList:
            isSure = 1
        else:
            isSure = 0
        category = madParmObj.getParmCategory(parm)
        try:
            if madParmObj.isAddIncrement(parm):
                isAddIncrement = 1
            else:
                isAddIncrement = 0
        except:
            isAddIncrement = -1
        # print out this parm
        retStr += '%s\%s\%i\%s\%i\%s\%i\%i\n' % (parm,
                                                description,
                                                isError,
                                                units,
                                                isMeasured,
                                                category,
                                                isSure,
                                                isAddIncrement)
        
    return render_to_response('madweb/service.html', {'text': retStr})

def get_version_service(

request)

get_version_service runs the getVersionService.py service.

Inputs: request (ignored)

Returns a single line of text, with the version in the form <major_version_int>.<minor_version_int>[.<sub_version_int>]
def get_version_service(request):
    """get_version_service runs the getVersionService.py service.  
    
    Inputs:
        request (ignored)
        
        Returns a single line of text, with the version in the form <major_version_int>.<minor_version_int>[.<sub_version_int>]
    """
    rePattern = r'\[[0-9\.]*\]'
    
    # create MadrigalDB obj
    madDBObj = madrigal.metadata.MadrigalDB()

    # create cmd
    f = open(os.path.join(madDBObj.getMadroot(), 'source/configure.ac'))
    lines = f.readlines()
    f.close()
    for line in lines:
        if line.find('AC_INIT') == -1:
            continue
        if line.find('Madrigal') == -1:
            continue
        result = re.findall(rePattern, line)
        if len(result) != 1:
            raise IOError, 'problem parsing MADROOT/source/configure.ac'
        version = result[0][1:-1]
        return render_to_response('madweb/service.html', {'text': version})
        
    
    # should not get here
    raise IOError, 'problem parsing MADROOT/source/configure.ac'

def isprint_service(

request)

isprint_service runs the isprintService.py service.

Inputs: request/url - contains arguments:

    'file': The full path to the file to be analyzed by isprint.

    'parms': Multiple requested parameters.

    'filters': Multiple of filters desired, as in isprint command

    'user_fullname'     user name

    'user_email'        user email

    'user_affiliation'  user affiliation

    'output' - option argument specifying output file basename.  Will be Hdf5 format if extension in
        ('hdf5', 'h5', 'hdf').  Will be netCDF4 is extension is '.nc'. Otherwise ascii. If not
        given, output is ascii.

    'header':  t for headers, f for no header.  Defaults to no header. Ignored if not ascii output

Returns data as either column delimited ascii, Hdf5, or netCDF4.

def isprint_service(request):
    """isprint_service runs the isprintService.py service.  
    
    Inputs:
        request/url - contains arguments:
        
            'file': The full path to the file to be analyzed by isprint.
            
            'parms': Multiple requested parameters.
            
            'filters': Multiple of filters desired, as in isprint command
            
            'user_fullname'     user name 
            
            'user_email'        user email
            
            'user_affiliation'  user affiliation
            
            'output' - option argument specifying output file basename.  Will be Hdf5 format if extension in
                ('hdf5', 'h5', 'hdf').  Will be netCDF4 is extension is '.nc'. Otherwise ascii. If not
                given, output is ascii.
                
            'header':  t for headers, f for no header.  Defaults to no header. Ignored if not ascii output
    
    Returns data as either column delimited ascii, Hdf5, or netCDF4.
    """
    madDB = madrigal.metadata.MadrigalDB()
    madWebObj = madrigal.ui.web.MadrigalWeb(madDB)
    
    # get required arguments
    thisFile = request.GET['file']
    parms = request.GET.getlist('parms')
    filters = request.GET.getlist('filters')
    user_fullname = request.GET['user_fullname']
    user_email = request.GET['user_email']
    user_affiliation = request.GET['user_affiliation']
    # get optional arguments
    try:
        output = os.path.basename(request.GET['output'])
        filename, file_extension = os.path.splitext(output)
        if file_extension in ('.hdf5', '.h5', '.hdf'):
            format = 'Hdf5'
        elif file_extension in ('.nc',):
            format = 'netCDF4'
        else:
            format = 'ascii'
    except:
        format = 'ascii'
        output = None
    if not output is None:
        # we need to write to a download file
        downloadFile = os.path.join('/tmp', output)
    try:
        header = request.GET['header']
        if header not in ('t', 'f'):
            raise ValueError, 'Unknown header value <%s>' % (header)
    except:
        header = 'f'
        
    # log data access
    madWebObj.logDataAccess(thisFile, user_fullname, user_email, user_affiliation)
        
    # run isprint command
    cmd = '%s/bin/isprint file=%s ' % (madDB.getMadroot(), thisFile)
    if not output is None:
        cmd += 'output=%s ' % (downloadFile)
    delimiter = ' '
    cmd += delimiter.join(parms) + ' '
    cmd += delimiter.join(filters) + ' '
    if format == 'ascii':
        cmd += 'summary=f '
        cmd += 'header=%s ' % (header)
        
    if output is None:
        # text response
        result = subprocess.check_output(cmd.split())
        if header == 'f':
            index = result.find('\n')
            result = result[index+1:]
        return render_to_response('madweb/service.html', {'text': result})
    else:
        # file download response
        subprocess.check_call(cmd.split())
        f = open(downloadFile, 'r')
        thisFile = django.core.files.File(f)
        response = HttpResponse(thisFile, content_type='application/x-octet-stream')
        response['Content-Disposition'] = 'attachment; filename="' + os.path.basename(downloadFile) + '"'
        response['Content-Length'] = os.path.getsize(downloadFile)
        response['Set-Cookie'] = 'fileDownload=true; path=/'
        os.remove(downloadFile)
        return(response)

def list_file_times_service(

request)

list_file_times_service runs the listFileTimes service.

Inputs: request/url - contains arguments:

Optional: expDir - experiment directory to list.  Can be absolute or relative to
    experiments[0-9]*. Default is all files in $MADROOT/experiments*

Returns comma-delimited data, one for each file:

1. Full path of file

2. File modification time in form YYYY-MM-DD HH:MM:SS (UT time)
def list_file_times_service(request):
    """list_file_times_service runs the listFileTimes service.
    
    Inputs:
      request/url - contains arguments:
      
        Optional: expDir - experiment directory to list.  Can be absolute or relative to
            experiments[0-9]*. Default is all files in $MADROOT/experiments*

    Returns comma-delimited data, one for each file:
    
        1. Full path of file
        
        2. File modification time in form YYYY-MM-DD HH:MM:SS (UT time)
    """
    expDir = None
    try:
        expDir = request.GET['expDir']
    except:
        pass
    madDB = madrigal.metadata.MadrigalDB()
    fileList = madDB.listFileTimes(expDir)
    fullText = '\n\n'
    for filename, filetime in fileList:
        fullText += "\'%s\', %s\n" % (filename, filetime.strftime('%Y-%m-%d %H:%M:%S'))
        
    return render_to_response('madweb/service.html', {'text': django.utils.safestring.mark_safe(fullText)})

def mad_calculator2_service(

request)

mad_calculator2_service runs the madCalculator2 service.

Differs from madCalulator in that positions are a list rather than a grid.

Inputs: request/url - contains arguments:

    year, month, day, hour, min, sec

    lats - comma separated list of latitudes to analyze

    longs - comma separated list of longitudes to analyze. Len must == len(lats)

    alts - comma separated list of altitudes to analyze. Len must == len(lats)

    parms - comma delimited string of Madrigal parameters desired

    oneD - zero or more mnemonics,float values to set input 1D values
        Example:  &oneD=kinst,31.0&oneD=elm,45.0

    twoD - zero or more mnemonics,comma-separate float list of len(lats) to set input 2D values
        Example:  twoD=te,1000,1100,1200  twoD=ti,1000,1000,1000
                  where there are 3 lats

Returns comma-delimited data, one line for each lat value, with the following fields:

1. latitude

2. longitude

3. altitude

4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
def mad_calculator2_service(request):
    """mad_calculator2_service runs the madCalculator2 service.
    
    Differs from madCalulator in that positions are a list rather than a grid.  
    
    Inputs:
        request/url - contains arguments:
        
            year, month, day, hour, min, sec 
            
            lats - comma separated list of latitudes to analyze
            
            longs - comma separated list of longitudes to analyze. Len must == len(lats)
            
            alts - comma separated list of altitudes to analyze. Len must == len(lats)
            
            parms - comma delimited string of Madrigal parameters desired
            
            oneD - zero or more mnemonics,float values to set input 1D values
                Example:  &oneD=kinst,31.0&oneD=elm,45.0
                
            twoD - zero or more mnemonics,comma-separate float list of len(lats) to set input 2D values
                Example:  twoD=te,1000,1100,1200  twoD=ti,1000,1000,1000
                          where there are 3 lats
    
    Returns comma-delimited data, one line for each lat value,
    with the following fields:

        1. latitude
        
        2. longitude
        
        3. altitude
        
        4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    if request.method == 'POST':
        reqDict = request.POST
    else:
        reqDict = request.GET
    year = int(reqDict.get('year'))
    month = int(reqDict['month'])
    day = int(reqDict['day'])
    hour = int(reqDict['hour'])
    minute = int(reqDict['min'])
    second = int(reqDict['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    
    latsStr = reqDict['lats']
    lats = [float(item) for item in latsStr.split(',')]
    longsStr = reqDict['longs']
    longs = [float(item) for item in longsStr.split(',')]
    altsStr = reqDict['alts']
    alts = [float(item) for item in altsStr.split(',')]
    
    parms = reqDict['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = reqDict.getlist('oneD')
    oneDParmDict = {}
    for oneDStr in oneDList:
        mnem, strValue = oneDStr.encode('ascii', 'ignore').split(',')
        oneDParmDict[mnem] = [float(strValue)]
        
    twoDList = reqDict.getlist('twoD')
        
    twoDParmDict = {}
    for twoDStr in twoDList:
        items = twoDStr.encode('ascii', 'ignore').split(',')
        if len(items) != 1 + len(lats):
            raise ValueError, 'twoDstr %s not correct number of points' % (str(twoDStr))
        mnem = items[0]
        floatValues = [float(item) for item in items[1:]]
        # now we need to expand these values to be two dimensional 1 x len(lats)
        values = numpy.zeros((1,len(lats)), dtype=numpy.float)
        values[0][:] = floatValues
        twoDParmDict[mnem] = values

    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorList(None, desiredParmList, [dt], lats, longs, alts, 
                                       oneDParmDict, twoDParmDict, summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})

def mad_calculator3_service(

request)

mad_calculator3_service runs the madCalculator3 service.

Differs from madCalulator in that multiple times, each with a unique list of positions, can be passed in.

Inputs: request/url - contains arguments:

year - a comma-separated list of years - (required)

month  - a comma-separated list of months - (required)

day - a comma-separated list of days - (required)

hour - a comma-separated list of hours - (required)

min - a comma-separated list of minutes - (required)

sec - a comma-separated list of seconds - (required)

numPos - a comma-sepatated list of the number of positions for each time - (required)

lats - a comma-separated list of geodetic latitudes, -90 to 90 (required).  Listed
          for first time, then second, etc.  Total must be equal to the sum
          of numPos.

longs - a comma-separated list of longitudes (required) Listed
          for first time, then second, etc.  Total must be equal to the sum
          of numPos.

alts - a comma-separated list of geodetic altitudes in km (required) Listed
          for first time, then second, etc.  Total must be equal to the sum
          of numPos.

parms - comma delimited string of Madrigal parameters desired (required)

oneD - string in form <parm>,<comma-separated values> This argument allows the user to
                    set any number of one-D parameters to be used in the calculation.
                    Value must be parameter name, comma, list of values as double,
                    where length of list is equal to number of times.
                    Example:  &oneD=kinst,31.0,31.0&oneD=elm,45.0,50
                    (optional - 0 or more allowed)

 twoD=<parm>,<values>  (optional - 0 or more allowed) This argument allows the user to
                    set any number of two-D parameters to be used in the calculation.
                    Value must be parameter name, comma, comma-separated values.
                    Number of values must equal the sum of numPos.  Order is
                    first time values first, then second time values, etc
                    Example:  twoD=te,1000,1100,1200,1000,1100,1200 &twoD=ti,1000,1000,1000,1000,1000,1000
                    where numPos=3,3

Returns comma-delimited data, one line for each location. Separate times are delimited by line

TIME MM/DD/YYYY HH:MM:SS

Data lines have the following fields:

  1. latitude

  2. longitude

  3. altitude

  4. Values for each Madrigal parameter listed in argument parms, separated by whitespace

def mad_calculator3_service(request):
    """mad_calculator3_service runs the madCalculator3 service.
    
    Differs from madCalulator in that multiple times, each with a unique list of positions, can be passed in.
    
    Inputs:
      request/url - contains arguments:
      
        year - a comma-separated list of years - (required)
        
        month  - a comma-separated list of months - (required)
        
        day - a comma-separated list of days - (required)
        
        hour - a comma-separated list of hours - (required)
        
        min - a comma-separated list of minutes - (required)
        
        sec - a comma-separated list of seconds - (required)
        
        numPos - a comma-sepatated list of the number of positions for each time - (required)
        
        lats - a comma-separated list of geodetic latitudes, -90 to 90 (required).  Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        longs - a comma-separated list of longitudes (required) Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        alts - a comma-separated list of geodetic altitudes in km (required) Listed
                  for first time, then second, etc.  Total must be equal to the sum
                  of numPos.
                  
        parms - comma delimited string of Madrigal parameters desired (required)
        
        oneD - string in form <parm>,<comma-separated values> This argument allows the user to
                            set any number of one-D parameters to be used in the calculation.
                            Value must be parameter name, comma, list of values as double,
                            where length of list is equal to number of times.
                            Example:  &oneD=kinst,31.0,31.0&oneD=elm,45.0,50
                            (optional - 0 or more allowed)        
                            
         twoD=<parm>,<values>  (optional - 0 or more allowed) This argument allows the user to
                            set any number of two-D parameters to be used in the calculation.
                            Value must be parameter name, comma, comma-separated values.
                            Number of values must equal the sum of numPos.  Order is
                            first time values first, then second time values, etc
                            Example:  twoD=te,1000,1100,1200,1000,1100,1200 &twoD=ti,1000,1000,1000,1000,1000,1000
                            where numPos=3,3

    Returns comma-delimited data, one line for each location.  Separate times are delimited by line

    TIME MM/DD/YYYY HH:MM:SS
    
    Data lines have the following fields:
    
    1. latitude
    
    2. longitude
    
    3. altitude
    
    4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    if request.method == 'POST':
        reqDict = request.POST
    else:
        reqDict = request.GET
    yearList = [int(item) for item in reqDict.get('year').split(',')]
    monthList = [int(item) for item in reqDict.get('month').split(',')]
    dayList = [int(item) for item in reqDict.get('day').split(',')]
    hourList = [int(item) for item in reqDict.get('hour').split(',')]
    minList = [int(item) for item in reqDict.get('min').split(',')]
    secList = [int(item) for item in reqDict.get('sec').split(',')]
    dtList = [datetime.datetime(yearList[i], monthList[i], dayList[i],
                                hourList[i], minList[i], secList[i]) for i in range(len(yearList))]
    numPosStr = reqDict['numPos']
    numPosList = [int(item) for item in numPosStr.split(',')]
    totalPos = 0
    for numPos in numPosList:
        totalPos += numPos
    latsStr = reqDict['lats']
    lats = [float(item) for item in latsStr.split(',')]
    if len(lats) != totalPos:
        raise IOError, 'wrong number of lats, expected %i' % (totalPos)
    longsStr = reqDict['longs']
    longs = [float(item) for item in longsStr.split(',')]
    if len(longs) != totalPos:
        raise IOError, 'wrong number of longs, expected %i' % (totalPos)
    altsStr = reqDict['alts']
    alts = [float(item) for item in altsStr.split(',')]
    if len(alts) != totalPos:
        raise IOError, 'wrong number of alts, expected %i' % (totalPos)
    
    parms = reqDict['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = reqDict.getlist('oneD')
    twoDList = reqDict.getlist('twoD')
    
    # since the positions can change with each call, we need to call madrigal.isprint.MadCalculatorGrid once for each time
    startIndex = 0
    endIndex = 0
    fullText = ''
    for timeIndex, numPos in enumerate(numPosList):
        startIndex = endIndex
        endIndex += numPos
        thisLats = lats[startIndex:endIndex]
        thisLongs = longs[startIndex:endIndex]
        thisAlts = alts[startIndex:endIndex]
    
        oneDParmDict = {}
        for oneDStr in oneDList:
            values = oneDStr.encode('ascii', 'ignore').split(',')
            if len(values) != 1+len(dtList):
                raise ValueError, 'wrong number of values given for 1D parm %s' % (values[0])
            oneDParmDict[values[0]] = [float(values[timeIndex+1])]
        
        twoDParmDict = {}
        
        for twoDStr in twoDList:
            values = twoDStr.encode('ascii', 'ignore').split(',')
            if len(values) != 1 + totalPos:
                raise ValueError, 'twoDstr %s not correct number of points' % (str(twoDStr))
            mnem = values[0]
            floatValues = [float(item) for item in values[1+startIndex:1+endIndex]]
            # now we need to expand these values to be two dimensional - 1,len(thisLats)
            values2D = numpy.zeros((1,len(thisLats)), dtype=numpy.float)
            values2D[0][:] = floatValues
            twoDParmDict[mnem] = values2D
            
            
    
        # capture stdout
        old_stdout = sys.stdout
        sys.stdout = mystdout = cStringIO.StringIO()
        madrigal.isprint.MadCalculatorList(None, desiredParmList, [dtList[timeIndex]], thisLats, 
                                           thisLongs, thisAlts, 
                                           oneDParmDict, twoDParmDict, summary=None)
        text = mystdout.getvalue()
        sys.stdout = old_stdout
        
        fullText += 'TIME %s\n' % (dtList[timeIndex].strftime('%m/%d/%Y %H:%M:%S'))
        fullText += text
    
    return render_to_response('madweb/service.html', {'text': fullText})

def mad_calculator_service(

request)

mad_calculator_service runs the madCalculator service.

Inputs: request/url - contains arguments:

    year, month, day, hour, min, sec

    startLat - Starting geodetic latitude, -90 to 90 (float)

    endLat - Ending geodetic latitude, -90 to 90 (float)

    stepLat - Latitude step (0.1 to 90) (float)

    startLong - Starting geodetic longitude, -180 to 180  (float)

    endLong - Ending geodetic longitude, -180 to 180 (float)

    stepLong - Longitude step (0.1 to 180) (float)

    startAlt - Starting geodetic altitude, >= 0 (float)

    endAlt - Ending geodetic altitude, > 0 (float)

    stepAlt - Altitude step (>= 0.1) (float)

    parms - comma delimited string of Madrigal parameters desired

    oneD - zero or more mnemonics,float values to set input 1D values

Returns comma-delimited data, one line for each combination of lat, long, and alt, with the following fields:

1. latitude

2. longitude

3. altitude

4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
def mad_calculator_service(request):
    """mad_calculator_service runs the madCalculator service.  
    
    Inputs:
        request/url - contains arguments:
        
            year, month, day, hour, min, sec 
            
            startLat - Starting geodetic latitude, -90 to 90 (float)
            
            endLat - Ending geodetic latitude, -90 to 90 (float)
            
            stepLat - Latitude step (0.1 to 90) (float)
            
            startLong - Starting geodetic longitude, -180 to 180  (float)
            
            endLong - Ending geodetic longitude, -180 to 180 (float)
            
            stepLong - Longitude step (0.1 to 180) (float)
            
            startAlt - Starting geodetic altitude, >= 0 (float)
            
            endAlt - Ending geodetic altitude, > 0 (float)
            
            stepAlt - Altitude step (>= 0.1) (float)
            
            parms - comma delimited string of Madrigal parameters desired
            
            oneD - zero or more mnemonics,float values to set input 1D values
    
    Returns comma-delimited data, one line for each combination of lat, long, and alt,
    with the following fields:

        1. latitude
        
        2. longitude
        
        3. altitude
        
        4. Values for each Madrigal parameter listed in argument parms, separated by whitespace
    """
    year = int(request.GET['year'])
    month = int(request.GET['month'])
    day = int(request.GET['day'])
    hour = int(request.GET['hour'])
    minute = int(request.GET['min'])
    second = int(request.GET['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    
    startLat = float(request.GET['startLat'])
    endLat = float(request.GET['endLat'])
    if startLat == endLat:
        endLat += 0.001
    elif startLat > endLat:
        raise ValueError, 'startLat cannot be greater than endLat'
    stepLat = float(request.GET['stepLat'])
    if stepLat < 0.0:
        raise ValueError, 'stepLat cannot be less than zero'
    elif stepLat == 0.0:
        stepLat = 0.001
    latList = list(numpy.arange(startLat, endLat, stepLat))
    
    startLong = float(request.GET['startLong'])
    endLong = float(request.GET['endLong'])
    if startLong == endLong:
        endLong += 0.001
    elif startLong > endLong:
        raise ValueError, 'startLong cannot be greater than endLong'
    stepLong = float(request.GET['stepLong'])
    if stepLong < 0.0:
        raise ValueError, 'stepLong cannot be less than zero'
    elif stepLong == 0.0:
        stepLong = 0.001
    lonList = list(numpy.arange(startLong, endLong, stepLong))
    
    startAlt = float(request.GET['startAlt'])
    endAlt = float(request.GET['endAlt'])
    if startAlt == endAlt:
        endAlt += 0.001
    elif startAlt > endAlt:
        raise ValueError, 'startAlt cannot be greater than endAlt'
    stepAlt = float(request.GET['stepAlt'])
    if stepAlt < 0.0:
        raise ValueError, 'stepAlt cannot be less than zero'
    elif stepAlt == 0.0:
        stepAlt = 0.01
    altList = list(numpy.arange(startAlt, endAlt, stepAlt))
    
    parms = request.GET['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['gdlat','glon','gdalt'] + parms.split(',')]
    
    oneDList = request.GET.getlist('oneD')
    oneDParmDict = {}
    for oneDStr in oneDList:
        mnem, strValue = oneDStr.encode('ascii', 'ignore').split(',')
        oneDParmDict[mnem] = [float(strValue)]
    
    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorGrid(None, desiredParmList, [dt], latList, lonList, altList, 
                                   oneDParmDict, summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})

def mad_time_calculator_service(

request)

mad_time_calculator_service runs the madTimeCalculator service. Input parameters must not be location dependent

Inputs: request/url - contains arguments:

    1. startyear - int

    2. startmonth - int

    3. startday - int

    4. starthour - int

    5. startmin - int

    6. startsec - int

    7. endyear - int

    8. endmonth - int

    9. endday - int

    10. endhour - int

    11. endmin - int

    12. endsec - int

    13. stephours - float - number of hours per time step

    14. parms - comma delimited string of Madrigal parameters desired (must not depend on location)

Returns comma-delimited data, one line for each year, month, day, hour, minute, and second, with the following fields:

1-6: year, month, day, hour, minute, and second

2. requested parm fields
def mad_time_calculator_service(request):
    """mad_time_calculator_service runs the madTimeCalculator service.  Input parameters must not be location dependent
    
    Inputs:
        request/url - contains arguments:
        
            1. startyear - int 
            
            2. startmonth - int 
            
            3. startday - int
            
            4. starthour - int 
            
            5. startmin - int 
            
            6. startsec - int
            
            7. endyear - int 
            
            8. endmonth - int 
            
            9. endday - int
            
            10. endhour - int 
            
            11. endmin - int 
            
            12. endsec - int
            
            13. stephours - float - number of hours per time step
            
            14. parms - comma delimited string of Madrigal parameters desired (must not depend on location)
    
    Returns comma-delimited data, one line for each year, month, day, hour, minute, and second,
    with the following fields:

        1-6: year, month, day, hour, minute, and second
        
        2. requested parm fields
    """
    startyear = int(request.GET['startyear'])
    startmonth = int(request.GET['startmonth'])
    startday = int(request.GET['startday'])
    starthour = int(request.GET['starthour'])
    startminute = int(request.GET['startmin'])
    startsecond = int(request.GET['startsec'])
    endyear = int(request.GET['endyear'])
    endmonth = int(request.GET['endmonth'])
    endday = int(request.GET['endday'])
    endhour = int(request.GET['endhour'])
    endminute = int(request.GET['endmin'])
    endsecond = int(request.GET['endsec'])
    dt1 = datetime.datetime(startyear, startmonth, startday, starthour, startminute, startsecond)
    dt2 = datetime.datetime(endyear, endmonth, endday, endhour, endminute, endsecond)
    if dt1 > dt2:
        raise ValueError, 'End Datetime %s cannot be before start datetime %s' % (str(dt2), str(dt1))
    
    stephours = float(request.GET['stephours'])
    if stephours <= 0.0:
        raise ValueError, 'stephours cannot be non-positive: %f' % (stephours)
    
    dtList = []
    while dt1 <= dt2:
        dtList.append(dt1)
        dt1 += datetime.timedelta(hours=stephours)
    
    parms = request.GET['parms']
    desiredParmList = [item.encode('ascii', 'ignore').strip() for item in ['year','month','day','hour','min','sec'] + parms.split(',')]
    
    # no spatial data
    latList = lonList = altList = []
    # capture stdout
    old_stdout = sys.stdout
    sys.stdout = mystdout = cStringIO.StringIO()
    madrigal.isprint.MadCalculatorGrid(None, desiredParmList, dtList, latList, lonList, altList, 
                                   summary=None)
    text = mystdout.getvalue()
    sys.stdout = old_stdout
    
    return render_to_response('madweb/service.html', {'text': text})

def radar_to_geodetic_service(

request)

radar_to_geodetic_service runs the radarToGeodetic service.

Inputs: request/url - contains arguments:

slatgd  - radar geodetic latitude

slon - radar longitude

saltgd - radar geodetic altitude

azs - a comma-separated list of azimuths of point

els - a comma-separated list of elevations of point. Len must be same as azs

ranges - a comma-separated list of ranges to point. Len must be same as azs

Returns comma-delimited data, one line for point in lists (points treated as individual combinations, not grids):

1. geodetic latitude

2. longitude (-180 to 180)

3. geodetic altitude in km
def radar_to_geodetic_service(request):
    """radar_to_geodetic_service runs the radarToGeodetic service.
    
    Inputs:
      request/url - contains arguments:
      
        slatgd  - radar geodetic latitude
        
        slon - radar longitude
        
        saltgd - radar geodetic altitude
        
        azs - a comma-separated list of azimuths of point
        
        els - a comma-separated list of elevations of point. Len must be same as azs
        
        ranges - a comma-separated list of ranges to point. Len must be same as azs


    Returns comma-delimited data, one line for point in lists  (points treated as individual combinations, not grids):

        1. geodetic latitude
        
        2. longitude (-180 to 180)
        
        3. geodetic altitude in km
    """
    slatgd = float(request.GET['slatgd'])
    slon = float(request.GET['slon'])
    saltgd = float(request.GET['saltgd'])
    azStr = request.GET['az']
    azList = [float(item) for item in azStr.split(',')]
    elStr = request.GET['el']
    elList = [float(item) for item in elStr.split(',')]
    rangeStr = request.GET['range']
    rangeList = [float(item) for item in rangeStr.split(',')]
    if len(azList) != len(elList) or len(azList) != len(rangeList):
        raise ValueError, 'all point list lengths must be equal'
    
    fullText = ''
    
    for i in range(len(azList)):
        gdlat,glon,gdalt = madrigal._derive.radarToGeodetic(slatgd, slon, saltgd,
                                                            azList[i], elList[i], rangeList[i])
        fullText += '%f,%f,%f\n' % (gdlat,glon,gdalt)
        
    return render_to_response('madweb/service.html', {'text': fullText})

def trace_magnetic_field_service(

request)

trace_magnetic_field_service runs the traceMagneticField service.

Inputs: request/url - contains arguments:

year, month, day, hour, min, sec

inputType (0 for geodetic, 1 for GSM)

outputType (0 for geodetic, 1 for GSM)

    The following parameter depend on inputType:

in1 - a comma-separated list of geodetic altitudes or ZGSMs of starting point

in2 - a comma-separated list of geodetic latitudes or XGSMs of starting point

in3 - a comma-separated list of longitude or YGSM of starting point

    Length of all three lists must be the same

model - 0 for Tsyganenko, 1 for IGRF

qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane

stopAlt - altitude in km to stop trace at, if qualifier is north_alt or south_alt.

If other qualifier, this parameter is not required.

Returns comma-delimited data, one line for point in in lists:

1. geodetic altitude or ZGSM of ending point

2. geodetic latitude or XGSM of ending point

3. longitude or YGSM of ending point
def trace_magnetic_field_service(request):
    """trace_magnetic_field_service runs the traceMagneticField service.
    
    Inputs:
      request/url - contains arguments:
      
        year, month, day, hour, min, sec
        
        inputType (0 for geodetic, 1 for GSM)
        
        outputType (0 for geodetic, 1 for GSM)
        
            The following parameter depend on inputType:
            
        in1 - a comma-separated list of geodetic altitudes or ZGSMs of starting point
        
        in2 - a comma-separated list of geodetic latitudes or XGSMs of starting point
        
        in3 - a comma-separated list of longitude or YGSM of starting point

            Length of all three lists must be the same
        
        model - 0 for Tsyganenko, 1 for IGRF
        
        qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane
        
        stopAlt - altitude in km to stop trace at, if qualifier is north_alt or south_alt.
        
        If other qualifier, this parameter is not required.

    Returns comma-delimited data, one line for point in in lists:

        1. geodetic altitude or ZGSM of ending point
        
        2. geodetic latitude or XGSM of ending point
        
        3. longitude or YGSM of ending point
    """
    year = int(request.GET['year'])
    month = int(request.GET['month'])
    day = int(request.GET['day'])
    hour = int(request.GET['hour'])
    minute = int(request.GET['min'])
    second = int(request.GET['sec'])
    dt = datetime.datetime(year, month, day, hour, minute, second)
    inputType = int(request.GET['inputType'])
    if inputType not in (0,1):
        raise ValueError, 'inputType must be 0 or 1, not %i' % (inputType)
    outputType = int(request.GET['outputType'])
    if outputType not in (0,1):
        raise ValueError, 'outputType must be 0 or 1, not %i' % (outputType)
    in1Str = request.GET['in1']
    in1List = [float(item) for item in in1Str.split(',')]
    in2Str = request.GET['in2']
    in2List = [float(item) for item in in2Str.split(',')]
    in3Str = request.GET['in3']
    in3List = [float(item) for item in in3Str.split(',')]
    if len(in1List) != len(in2List) or len(in1List) != len(in3List):
        raise ValueError, 'All three in* lists must have same length'
    model = int(request.GET['model'])
    if model not in (0,1):
        raise ValueError, 'model must be 0 or 1, not %i' % (model)
    qualifier = int(request.GET['qualifier'])
    if qualifier not in (0,1,2,3,4):
        raise ValueError, 'model must be in 0,1,2,3,4 not %i' % (model)
    try:
        stopAlt = float(request.GET['stopAlt'])
    except:
        stopAlt = 0.0
        
    fullText = ''
    resultArr = numpy.zeros((3,), dtype='f8')
    madDB = madrigal.metadata.MadrigalDB()
    madDeriveObj = madrigal.derivation.MadrigalDerivationMethods(madDB.getMadroot())
    for i in range(len(in1List)):
        madDeriveObj.traceMagneticField(year, month, day, hour, minute, second, 
                                        inputType, outputType, in1List[i], in2List[i], in3List[i], 
                                        model, qualifier, stopAlt, resultArr)
        fullText += '%f,%f,%f\n' % (resultArr[0], resultArr[1], resultArr[2])

    return render_to_response('madweb/service.html', {'text': fullText})
Previous: Remote access - introduction   Up: Remote access programming tutorial toc   Next: Matlab remote access