diff --git a/Code/.DS_Store b/Code/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..8f7b3328c74ea79382b39f6d9b3a74f32c351f55
Binary files /dev/null and b/Code/.DS_Store differ
diff --git a/Code/VisIVODesktop-vtk6_qt5.pro b/Code/VisIVODesktop-vtk6_qt5.pro
new file mode 100644
index 0000000000000000000000000000000000000000..777be4a5e60508aed208d308eab108e3623acb14
--- /dev/null
+++ b/Code/VisIVODesktop-vtk6_qt5.pro
@@ -0,0 +1,251 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-05-18T11:03:07
+#
+#-------------------------------------------------
+
+QT += core gui network printsupport xml widgets concurrent webkitwidgets
+#CONFIG += static
+QMAKE_MAC_SDK = macosx10.13
+CONFIG-=app_bundle
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = VisIVODesktop-vtk6_qt5
+TEMPLATE = app
+
+
+ICON = logo.icns
+#win32:RC_ICONS += your_icon.ico
+
+
+INCLUDEPATH += /opt/vtk6.20/include/vtk-6.2/
+INCLUDEPATH += /opt/cfitsio3_1_0/include/ \
+ /opt/local/include \
+ /opt/boost_1_63_0/include/
+
+INCLUDEPATH += /Users/fxbio6600/OACT/VisIVOServer_svn_locale/branches/2.3/
+INCLUDEPATH +=/opt/hdf5-1.10.0-patch1/include
+LIBS += /opt/cfitsio3_1_0/lib/libcfitsio.a
+
+
+LIBS += -L/opt/vtk6.20/lib/
+LIBS += -lvtkChartsCore-6.2 -lvtkCommonColor-6.2 -lvtkCommonComputationalGeometry-6.2 -lvtkCommonCore-6.2 -lvtkCommonDataModel-6.2 -lvtkCommonExecutionModel-6.2 -lvtkCommonMath-6.2 -lvtkCommonMisc-6.2 -lvtkCommonSystem-6.2 -lvtkCommonTransforms-6.2 -lvtkDICOMParser-6.2 -lvtkDomainsChemistry-6.2 -lvtkFiltersAMR-6.2 -lvtkFiltersCore-6.2 -lvtkFiltersExtraction-6.2 -lvtkFiltersFlowPaths-6.2 -lvtkFiltersGeneral-6.2 -lvtkFiltersGeneric-6.2 -lvtkFiltersGeometry-6.2 -lvtkFiltersHybrid-6.2 -lvtkFiltersHyperTree-6.2 -lvtkFiltersImaging-6.2 -lvtkFiltersModeling-6.2 -lvtkFiltersParallel-6.2 -lvtkFiltersParallelImaging-6.2 -lvtkFiltersProgrammable-6.2 -lvtkFiltersSMP-6.2 -lvtkFiltersSelection-6.2 -lvtkFiltersSources-6.2 -lvtkFiltersStatistics-6.2 -lvtkFiltersTexture-6.2 -lvtkFiltersVerdict-6.2 -lvtkGUISupportQt-6.2 -lvtkGUISupportQtOpenGL-6.2 -lvtkGUISupportQtSQL-6.2 -lvtkGUISupportQtWebkit-6.2 -lvtkGeovisCore-6.2 -lvtkIOAMR-6.2 -lvtkIOCore-6.2 -lvtkIOEnSight-6.2 -lvtkIOExodus-6.2 -lvtkIOExport-6.2 -lvtkIOGeometry-6.2 -lvtkIOImage-6.2 -lvtkIOImport-6.2 -lvtkIOInfovis-6.2 -lvtkIOLSDyna-6.2 -lvtkIOLegacy-6.2 -lvtkIOMINC-6.2 -lvtkIOMovie-6.2 -lvtkIONetCDF-6.2 -lvtkIOPLY-6.2 -lvtkIOParallel-6.2 -lvtkIOParallelXML-6.2 -lvtkIOSQL-6.2 -lvtkIOVideo-6.2 -lvtkIOXML-6.2 -lvtkIOXMLParser-6.2 -lvtkImagingColor-6.2 -lvtkImagingCore-6.2 -lvtkImagingFourier-6.2 -lvtkImagingGeneral-6.2 -lvtkImagingHybrid-6.2 -lvtkImagingMath-6.2 -lvtkImagingMorphological-6.2 -lvtkImagingSources-6.2 -lvtkImagingStatistics-6.2 -lvtkImagingStencil-6.2 -lvtkInfovisCore-6.2 -lvtkInfovisLayout-6.2 -lvtkInteractionImage-6.2 -lvtkInteractionStyle-6.2 -lvtkInteractionWidgets-6.2 -lvtkNetCDF-6.2 -lvtkNetCDF_cxx-6.2 -lvtkParallelCore-6.2 -lvtkRenderingAnnotation-6.2 -lvtkRenderingContext2D-6.2 -lvtkRenderingContextOpenGL-6.2 -lvtkRenderingCore-6.2 -lvtkRenderingFreeType-6.2 -lvtkRenderingFreeTypeOpenGL-6.2 -lvtkRenderingGL2PS-6.2 -lvtkRenderingImage-6.2 -lvtkRenderingLIC-6.2 -lvtkRenderingLOD-6.2 -lvtkRenderingLabel-6.2 -lvtkRenderingOpenGL-6.2 -lvtkRenderingQt-6.2 -lvtkRenderingVolume-6.2 -lvtkRenderingVolumeOpenGL-6.2 -lvtkViewsContext2D-6.2 -lvtkViewsCore-6.2 -lvtkViewsInfovis-6.2 -lvtkViewsQt-6.2 -lvtkalglib-6.2 -lvtkexoIIc-6.2 -lvtkexpat-6.2 -lvtkfreetype-6.2 -lvtkftgl-6.2 -lvtkgl2ps-6.2 -lvtkhdf5-6.2 -lvtkhdf5_hl-6.2 -lvtkjpeg-6.2 -lvtkjsoncpp-6.2 -lvtklibxml2-6.2 -lvtkmetaio-6.2 -lvtkoggtheora-6.2 -lvtkpng-6.2 -lvtkproj4-6.2 -lvtksqlite-6.2 -lvtksys-6.2 -lvtktiff-6.2 -lvtkverdict-6.2 -lvtkzlib-6.2
+#LIBS += -lvtkChartsCore-6.2 -lvtkCommonColor-6.2 -lvtkCommonComputationalGeometry-6.2 -lvtkCommonCore-6.2 -lvtkCommonDataModel-6.2 -lvtkCommonExecutionModel-6.2 -lvtkCommonMath-6.2 -lvtkCommonMisc-6.2 -lvtkCommonSystem-6.2 -lvtkCommonTransforms-6.2 -lvtkDICOMParser-6.2 -lvtkDomainsChemistry-6.2 -lvtkFiltersAMR-6.2 -lvtkFiltersCore-6.2 -lvtkFiltersExtraction-6.2 -lvtkFiltersFlowPaths-6.2 -lvtkFiltersGeneral-6.2 -lvtkFiltersGeneric-6.2 -lvtkFiltersGeometry-6.2 -lvtkFiltersHybrid-6.2 -lvtkFiltersHyperTree-6.2 -lvtkFiltersImaging-6.2 -lvtkFiltersModeling-6.2 -lvtkFiltersParallel-6.2 -lvtkFiltersParallelImaging-6.2 -lvtkFiltersProgrammable-6.2 -lvtkFiltersSMP-6.2 -lvtkFiltersSelection-6.2 -lvtkFiltersSources-6.2 -lvtkFiltersStatistics-6.2 -lvtkFiltersTexture-6.2 -lvtkFiltersVerdict-6.2 -lvtkGUISupportQt-6.2 -lvtkGUISupportQtOpenGL-6.2 -lvtkGUISupportQtSQL-6.2 -lvtkGUISupportQtWebkit-6.2 -lvtkGeovisCore-6.2 -lvtkIOAMR-6.2 -lvtkIOCore-6.2 -lvtkIOEnSight-6.2 -lvtkIOExodus-6.2 -lvtkIOExport-6.2 -lvtkIOGeometry-6.2 -lvtkIOImage-6.2 -lvtkIOImport-6.2 -lvtkIOInfovis-6.2 -lvtkIOLSDyna-6.2 -lvtkIOLegacy-6.2 -lvtkIOMINC-6.2 -lvtkIOMovie-6.2 -lvtkIONetCDF-6.2 -lvtkIOPLY-6.2 -lvtkIOParallel-6.2 -lvtkIOParallelXML-6.2 -lvtkIOSQL-6.2 -lvtkIOVideo-6.2 -lvtkIOXML-6.2 -lvtkIOXMLParser-6.2 -lvtkImagingColor-6.2 -lvtkImagingCore-6.2 -lvtkImagingFourier-6.2 -lvtkImagingGeneral-6.2 -lvtkImagingHybrid-6.2 -lvtkImagingMath-6.2 -lvtkImagingMorphological-6.2 -lvtkImagingSources-6.2 -lvtkImagingStatistics-6.2 -lvtkImagingStencil-6.2 -lvtkInfovisCore-6.2 -lvtkInfovisLayout-6.2 -lvtkInteractionImage-6.2 -lvtkInteractionStyle-6.2 -lvtkInteractionWidgets-6.2 -lvtkNetCDF-6.2 -lvtkNetCDF_cxx-6.2 -lvtkParallelCore-6.2 -lvtkRenderingAnnotation-6.2 -lvtkRenderingContext2D-6.2 -lvtkRenderingContextOpenGL-6.2 -lvtkRenderingCore-6.2 -lvtkRenderingFreeType-6.2 -lvtkRenderingFreeTypeFontConfig-6.2 -lvtkRenderingFreeTypeOpenGL-6.2 -lvtkRenderingGL2PS-6.2 -lvtkRenderingImage-6.2 -lvtkRenderingLIC-6.2 -lvtkRenderingLOD-6.2 -lvtkRenderingLabel-6.2 -lvtkRenderingOpenGL-6.2 -lvtkRenderingQt-6.2 -lvtkRenderingVolume-6.2 -lvtkRenderingVolumeOpenGL-6.2 -lvtkViewsContext2D-6.2 -lvtkViewsCore-6.2 -lvtkViewsInfovis-6.2 -lvtkViewsQt-6.2 -lvtkalglib-6.2 -lvtkexoIIc-6.2 -lvtkexpat-6.2 -lvtkfreetype-6.2 -lvtkftgl-6.2 -lvtkgl2ps-6.2 -lvtkhdf5-6.2 -lvtkhdf5_hl-6.2 -lvtkjpeg-6.2 -lvtkjsoncpp-6.2 -lvtklibxml2-6.2 -lvtkmetaio-6.2 -lvtkoggtheora-6.2 -lvtkpng-6.2 -lvtkproj4-6.2 -lvtksqlite-6.2 -lvtksys-6.2 -lvtktiff-6.2 -lvtkverdict-6.2 -lvtkzlib-6.2
+#LIBS += -L/Users/fxbio6600/OACT/develop/VisIVODesktop6/trunk/lib/ -lsamp -lVOApps -lVO -lVOTable -lVOClient
+LIBS += -lm -lc -lpthread -lcurl
+LIBS += /Users/fxbio6600/OACT/VisIVOServer_svn_locale/branches/2.3/API_LIGHT/libVisIVOApi.a
+LIBS += -L/opt/hdf5-1.10.0-patch1/lib/ -lhdf5
+LIBS += /usr/lib/libc++.dylib
+
+macx:LIBS += -framework \
+ Foundation \
+ -framework \
+ Cocoa \
+ -framework \
+ GLUT \
+ -framework \
+ QTKit \
+ -framework \
+ OpenGL \
+ -framework \
+ AGL \
+ -framework \
+ IOKit \
+ -framework \
+ QtPrintSupport
+
+
+
+SOURCES += src/main.cpp\
+ src/mainwindow.cpp \
+ src/treemodel.cpp \
+ src/treeitem.cpp \
+ src/vtkfitsreader.cpp \
+ src/vispoint.cpp \
+ src/observedobject.cpp \
+ src/operationqueue.cpp \
+ src/sednode.cpp \
+ src/sed.cpp \
+ src/pointspipe.cpp \
+ src/pipe.cpp \
+ src/vtkellipse.cpp \
+ src/base64.cpp \
+ src/astroutils.cpp \
+ src/libwcs/fitsfile.c \
+ src/libwcs/hget.c \
+ src/libwcs/fileutil.c \
+ src/libwcs/fitswcs.c \
+ src/libwcs/distort.c \
+ src/libwcs/hput.c \
+ src/libwcs/iget.c \
+ src/libwcs/imio.c \
+ src/libwcs/imhfile.c \
+ src/libwcs/dateutil.c \
+ src/libwcs/wcsinit.c \
+ src/libwcs/dsspos.c \
+ src/libwcs/wcs.c \
+ src/libwcs/wcstrig.c \
+ src/libwcs/wcscon.c \
+ src/libwcs/lin.c \
+ src/libwcs/platepos.c \
+ src/libwcs/tnxpos.c \
+ src/libwcs/wcslib.c \
+ src/libwcs/cel.c \
+ src/libwcs/proj.c \
+ src/libwcs/sph.c \
+ src/libwcs/worldpos.c \
+ src/vialacteasource.cpp \
+ src/vlkbquery.cpp \
+ src/loadingwidget.cpp \
+ src/sedvisualizerplot.cpp \
+ src/qcustomplot.cpp \
+ src/sedplotpointcustom.cpp \
+ src/sedfitgrid_thin.cpp \
+ src/sedfitgrid_thick.cpp \
+ src/luteditor.cpp \
+ src/vtktoolswidget.cpp \
+ src/color.cpp \
+ src/vtkfitstoolswidget.cpp \
+ src/higalselectedsources.cpp \
+ src/plotwindow.cpp \
+ src/vlkbquerycomposer.cpp \
+ src/vlkbtable.cpp \
+ src/fitsimagestatisiticinfo.cpp \
+ src/vlkbsimplequerycomposer.cpp \
+ src/dbquery.cpp \
+ src/xmlparser.cpp \
+ src/vialactea_fileload.cpp \
+ src/selectedsourcefieldsselect.cpp \
+ src/downloadmanager.cpp \
+ src/viewselectedsourcedataset.cpp \
+ src/vialactea.cpp \
+ src/contour.cpp \
+ src/histogram.cpp \
+ src/lutselector.cpp \
+ src/vtkwindow_new.cpp \
+ src/vtkfitstoolwidget_new.cpp \
+ src/vtkfitstoolwidgetobject.cpp \
+ src/vialacteainitialquery.cpp \
+ src/settingform.cpp \
+ src/aboutform.cpp \
+ src/selectedsourcesform.cpp \
+ src/vtklegendscaleactor.cpp \
+ src/lutcustomize.cpp \
+ src/vtkextracthistogram.cpp \
+ src/extendedglyph3d.cpp \
+ # src/vosamp.cpp \
+ src/visivoimporterdesktop.cpp \
+ src/vstabledesktop.cpp \
+ src/visivoutilsdesktop.cpp \
+ src/vsobjectdesktop.cpp \
+ src/visivofilterdesktop.cpp \
+ src/filtercustomize.cpp \
+ src/vialacteastringdictwidget.cpp
+
+
+HEADERS += src/mainwindow.h \
+ src/singleton.h \
+ src/treemodel.h \
+ src/treeitem.h \
+ src/vtkfitsreader.h \
+ src/vispoint.h \
+ src/observedobject.h \
+ src/operationqueue.h \
+ src/sednode.h \
+ src/sed.h \
+ src/pointspipe.h \
+ src/pipe.h \
+ src/vtkellipse.h \
+ src/base64.h \
+ src/astroutils.h \
+ src/libwcs/fitsfile.h \
+ src/libwcs/wcs.h \
+ src/vialacteasource.h \
+ src/vlkbquery.h \
+ src/loadingwidget.h \
+ src/sedvisualizerplot.h \
+ src/qcustomplot.h \
+ src/sedplotpointcustom.h \
+ src/sedfitgrid_thin.h \
+ src/sedfitgrid_thick.h \
+ src/luteditor.h \
+ src/vtktoolswidget.h \
+ src/color.h \
+ src/vtkfitstoolswidget.h \
+ src/higalselectedsources.h \
+ src/plotwindow.h \
+ src/vlkbquerycomposer.h \
+ src/vlkbtable.h \
+ src/fitsimagestatisiticinfo.h \
+ src/vlkbsimplequerycomposer.h \
+ src/dbquery.h \
+ src/xmlparser.h \
+ src/extendedglyph3d.h \
+ src/vialactea_fileload.h \
+ src/selectedsourcefieldsselect.h \
+ src/downloadmanager.h \
+ src/viewselectedsourcedataset.h \
+ src/vialactea.h \
+ src/contour.h \
+ src/histogram.h \
+ src/lutselector.h \
+ src/vtkwindow_new.h \
+ src/vtkfitstoolwidget_new.h \
+ src/vtkfitstoolwidgetobject.h \
+ src/vialacteainitialquery.h \
+ src/settingform.h \
+ src/aboutform.h \
+ src/selectedsourcesform.h \
+ src/vtklegendscaleactor.h \
+ src/lutcustomize.h \
+ src/vtkextracthistogram.h \
+ src/osxhelper.h \
+ # src/vosamp.h \
+ src/visivoimporterdesktop.h \
+ src/vstabledesktop.h \
+ src/visivoutilsdesktop.h \
+ src/vsobjectdesktop.h \
+ src/visivofilterdesktop.h \
+ src/filtercustomize.h \
+ src/vialacteastringdictwidget.h
+
+
+FORMS += ui/mainwindow.ui \
+ ui/operationqueue.ui \
+ ui/vtkwindow.ui \
+ ui/vlkbquery.ui \
+ ui/loadingwidget.ui \
+ ui/sedvisualizerplot.ui \
+ ui/sedfitgrid_thin.ui \
+ ui/sedfitgrid_thick.ui \
+ ui/vtktoolswidget.ui \
+ ui/vtkfitstoolswidget.ui \
+ ui/higalselectedsources.ui \
+ ui/plotwindow.ui \
+ ui/vlkbquerycomposer.ui \
+ ui/fitsimagestatisiticinfo.ui \
+ ui/vlkbsimplequerycomposer.ui \
+ ui/dbquery.ui \
+ ui/vialactea_fileload.ui \
+ ui/selectedsourcefieldsselect.ui \
+ ui/viewselectedsourcedataset.ui \
+ ui/vialactea.ui \
+ ui/contour.ui \
+ ui/vtkwindow_new.ui \
+ ui/vtkfitstoolwidget_new.ui \
+ ui/vialacteainitialquery.ui \
+ ui/settingform.ui \
+ ui/aboutform.ui \
+ ui/selectedsourcesform.ui \
+ ui/lutcustomize.ui \
+ ui/filtercustomize.ui \
+ src/vialacteastringdictwidget.ui
+
+RESOURCES += \
+ visivo.qrc
+
+DISTFILES +=
+
+OBJECTIVE_SOURCES += \
+ src/osxhelper.mm
diff --git a/Code/VisIVODesktop-vtk6_qt5.pro.user b/Code/VisIVODesktop-vtk6_qt5.pro.user
new file mode 100644
index 0000000000000000000000000000000000000000..f62c868f3582485f2a962a0a503d0234d65dccc1
--- /dev/null
+++ b/Code/VisIVODesktop-vtk6_qt5.pro.user
@@ -0,0 +1,339 @@
+
+
+
+
+
+ EnvironmentId
+ {d7bdcdd1-3e2c-4559-a568-85e4bf761de3}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop
+ {fefc9313-5518-4942-9856-e8ccfb4406bc}
+ 1
+ 0
+ 0
+
+ /Users/fxbio6600/OACT/develop/VisIVODesktop6/build-VisIVODesktop-vtk6_qt5-Desktop-Debug
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ false
+
+
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ true
+ clean
+
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ LC_NUMERIC=en_US.UTF-8
+
+ Debug
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ /Users/fxbio6600/OACT/develop/VisIVODesktop6/build-VisIVODesktop-vtk6_qt5-Desktop-Release
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+
+ false
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ false
+
+
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ true
+ clean
+
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Release
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+
+ /Users/fxbio6600/OACT/develop/VisIVODesktop6/build-VisIVODesktop-vtk6_qt5-Desktop-Profile
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ true
+
+ false
+ true
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ false
+
+
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ true
+ clean
+
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Profile
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 3
+
+
+ 0
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy locally
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+ VisIVODesktop-vtk6_qt5
+
+ Qt4ProjectManager.Qt4RunConfiguration:/Users/fxbio6600/OACT/develop/VisIVODesktop6/trunk/VisIVODesktop-vtk6_qt5.pro
+ true
+
+ VisIVODesktop-vtk6_qt5.pro
+ false
+ false
+
+ /Users/fxbio6600/OACT/develop/VisIVODesktop6/build-VisIVODesktop-vtk6_qt5-Desktop-Release
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 18
+
+
+ Version
+ 18
+
+
diff --git a/Code/VisIVODesktop-vtk6_qt5.pro.user.a9018b3 b/Code/VisIVODesktop-vtk6_qt5.pro.user.a9018b3
new file mode 100644
index 0000000000000000000000000000000000000000..6dc29e650dc877e4c7699d8e4766be0f92869ced
--- /dev/null
+++ b/Code/VisIVODesktop-vtk6_qt5.pro.user.a9018b3
@@ -0,0 +1,271 @@
+
+
+
+
+
+ EnvironmentId
+ {a9018b3b-7afd-4732-92b3-1651299ec816}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ true
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop Qt 5.4.1 clang 64bit
+ Desktop Qt 5.4.1 clang 64bit
+ qt.54.clang_64_kit
+ 1
+ 0
+ 0
+
+ /Users/fxbio6600/OACT/develop/VisIVODesktop6/build-VisIVODesktop-vtk6_qt5-Desktop_Qt_5_4_1_clang_64bit-Debug
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+ true
+
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ false
+
+
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ true
+ clean
+
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ Debug
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+ true
+
+
+ /Users/fxbio6600/OACT/develop//build-VisIVODesktop-vtk6_qt5-Desktop_Qt_5_4_1_clang_64bit-Release
+
+
+ true
+ qmake
+
+ QtProjectManager.QMakeBuildStep
+ false
+ true
+
+ false
+ false
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ false
+
+
+
+ 2
+ Build
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Make
+
+ Qt4ProjectManager.MakeStep
+
+ -w
+ -r
+
+ true
+ clean
+
+
+ 1
+ Clean
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ LC_NUMERIC=en_US.UTF-8
+
+ Release
+
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ true
+
+ 2
+
+
+ 0
+ Deploy
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Deploy locally
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ /opt/valgrind/bin/valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+ VisIVODesktop-vtk6_qt5
+
+ Qt4ProjectManager.Qt4RunConfiguration:/Users/fxbio6600/OACT/develop/VisIVODesktop6/trunk/VisIVODesktop-vtk6_qt5.pro
+
+ VisIVODesktop-vtk6_qt5.pro
+ false
+ false
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 18
+
+
+ Version
+ 18
+
+
diff --git a/Code/customprocess.cpp b/Code/customprocess.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..049202855696f1f8193ba58cd33977bfa928a77b
--- /dev/null
+++ b/Code/customprocess.cpp
@@ -0,0 +1,24 @@
+#include "customprocess.h"
+#include
+#include
+#include
+
+CustomProcess::CustomProcess()
+{
+
+
+ QProcess *process = new QProcess();
+ connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished()));
+ process->start("ls", QStringList());
+ if (!process->waitForStarted())
+ qDebug() << "error";
+
+
+
+}
+
+CustomProcess::~CustomProcess()
+{
+
+}
+
diff --git a/Code/customprocess.h b/Code/customprocess.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9cdea0b8bfd56cee46ddad2fcc5158a6e076c74
--- /dev/null
+++ b/Code/customprocess.h
@@ -0,0 +1,13 @@
+#ifndef CUSTOMPROCESS_H
+#define CUSTOMPROCESS_H
+
+#include
+
+class CustomProcess : public QObject
+{
+public:
+ CustomProcess();
+ ~CustomProcess();
+};
+
+#endif // CUSTOMPROCESS_H
diff --git a/Code/icons/.DS_Store b/Code/icons/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..24154484bd613f6e2b458b27a646d1a320b9b64b
Binary files /dev/null and b/Code/icons/.DS_Store differ
diff --git a/Code/icons/CHECK_OFF.bmp b/Code/icons/CHECK_OFF.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..29a0e4bccd08104e2c7a8d4ad6fa64a9a01b4137
Binary files /dev/null and b/Code/icons/CHECK_OFF.bmp differ
diff --git a/Code/icons/CHECK_ON.bmp b/Code/icons/CHECK_ON.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f51be532e7d0959975bcd3478cf073aa38f7ccef
Binary files /dev/null and b/Code/icons/CHECK_ON.bmp differ
diff --git a/Code/icons/CLOSE_SASH.bmp b/Code/icons/CLOSE_SASH.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b4ea916b0b3ba8b5b60f3a97a4c2caa9cd25b87c
Binary files /dev/null and b/Code/icons/CLOSE_SASH.bmp differ
diff --git a/Code/icons/DISABLED.bmp b/Code/icons/DISABLED.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..babe589514b1c1605d54a4f19216078de74d0b32
Binary files /dev/null and b/Code/icons/DISABLED.bmp differ
diff --git a/Code/icons/FILE_NEW.bmp b/Code/icons/FILE_NEW.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2f0377fdcfc37898437a817a765dcd539342e710
Binary files /dev/null and b/Code/icons/FILE_NEW.bmp differ
diff --git a/Code/icons/FILE_OPEN.bmp b/Code/icons/FILE_OPEN.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..25baa29bf17df47237ecd8c79edf7b5dbe9a72d9
Binary files /dev/null and b/Code/icons/FILE_OPEN.bmp differ
diff --git a/Code/icons/FILE_SAVE.bmp b/Code/icons/FILE_SAVE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..ddd83208b753f7857165057900284e815e0ef221
Binary files /dev/null and b/Code/icons/FILE_SAVE.bmp differ
diff --git a/Code/icons/FLYTO.bmp b/Code/icons/FLYTO.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1c2f9bdf8afb2b1b2b15a44bab17f5dc9938be4d
Binary files /dev/null and b/Code/icons/FLYTO.bmp differ
diff --git a/Code/icons/INFO.bmp b/Code/icons/INFO.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..85956128e33a0f6bf7bc0330503ef8ee598f3457
Binary files /dev/null and b/Code/icons/INFO.bmp differ
diff --git a/Code/icons/MOVIE_RECORD.bmp b/Code/icons/MOVIE_RECORD.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3aa0a925c0eaf753d4030f43b30206373d1e0549
Binary files /dev/null and b/Code/icons/MOVIE_RECORD.bmp differ
diff --git a/Code/icons/NODE_BLUE.bmp b/Code/icons/NODE_BLUE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..44498e105bf608af9c319c34e83400d564c37b02
Binary files /dev/null and b/Code/icons/NODE_BLUE.bmp differ
diff --git a/Code/icons/NODE_GRAY.bmp b/Code/icons/NODE_GRAY.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6cafe9b79e7addb008a554fe0904d64b9a09ed16
Binary files /dev/null and b/Code/icons/NODE_GRAY.bmp differ
diff --git a/Code/icons/NODE_RED.bmp b/Code/icons/NODE_RED.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..070a08503f54cdb2f435e7bef7956993eccba913
Binary files /dev/null and b/Code/icons/NODE_RED.bmp differ
diff --git a/Code/icons/NODE_YELLOW.bmp b/Code/icons/NODE_YELLOW.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..7ffb562c31c41f0941252101d36719405bad304e
Binary files /dev/null and b/Code/icons/NODE_YELLOW.bmp differ
diff --git a/Code/icons/OPAddVector.png b/Code/icons/OPAddVector.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc59ef0948a12ab106afd0775b2ab2e5e88a0e92
Binary files /dev/null and b/Code/icons/OPAddVector.png differ
diff --git a/Code/icons/OPEN_LOCAL.png b/Code/icons/OPEN_LOCAL.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d531f9cca7c4aa311cb7cd6d8c09d17e8fe4187
Binary files /dev/null and b/Code/icons/OPEN_LOCAL.png differ
diff --git a/Code/icons/OPEN_REMOTE.png b/Code/icons/OPEN_REMOTE.png
new file mode 100644
index 0000000000000000000000000000000000000000..097a3937b69219d743f47a05dfae77684f9a36c7
Binary files /dev/null and b/Code/icons/OPEN_REMOTE.png differ
diff --git a/Code/icons/OP_COPY.bmp b/Code/icons/OP_COPY.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8ca09f05a1605609dfaa158cbe8bf76491b8a2d1
Binary files /dev/null and b/Code/icons/OP_COPY.bmp differ
diff --git a/Code/icons/OP_CUT.bmp b/Code/icons/OP_CUT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..04ab372862f0652d938fbfc13c4245fdd030d999
Binary files /dev/null and b/Code/icons/OP_CUT.bmp differ
diff --git a/Code/icons/OP_MakePlot.png b/Code/icons/OP_MakePlot.png
new file mode 100644
index 0000000000000000000000000000000000000000..65079fc09bd6cb76cd810d92d7bbcd1f2262b566
Binary files /dev/null and b/Code/icons/OP_MakePlot.png differ
diff --git a/Code/icons/OP_Merger.png b/Code/icons/OP_Merger.png
new file mode 100644
index 0000000000000000000000000000000000000000..ebcaa730b528c318ba3c770ce77d9afa1ce5ce94
Binary files /dev/null and b/Code/icons/OP_Merger.png differ
diff --git a/Code/icons/OP_PASTE.bmp b/Code/icons/OP_PASTE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..10f5cae64e108c265f6444de33d80b3e554289ec
Binary files /dev/null and b/Code/icons/OP_PASTE.bmp differ
diff --git a/Code/icons/OP_Parser.png b/Code/icons/OP_Parser.png
new file mode 100644
index 0000000000000000000000000000000000000000..f13b5a6086b8746f109afc71580aae26d19aa691
Binary files /dev/null and b/Code/icons/OP_Parser.png differ
diff --git a/Code/icons/OP_REDO.bmp b/Code/icons/OP_REDO.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f2e84505e9782b7f8d826f75fda2c8b778bc9699
Binary files /dev/null and b/Code/icons/OP_REDO.bmp differ
diff --git a/Code/icons/OP_UNDO.bmp b/Code/icons/OP_UNDO.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..9431efd81b06e05e6f46acd6e3f93afdc22b7e80
Binary files /dev/null and b/Code/icons/OP_UNDO.bmp differ
diff --git a/Code/icons/PIC_BACK.bmp b/Code/icons/PIC_BACK.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..732dfa8f6a5667628e5acf763fb3edbea5d0abb2
Binary files /dev/null and b/Code/icons/PIC_BACK.bmp differ
diff --git a/Code/icons/PIC_BOTTOM.bmp b/Code/icons/PIC_BOTTOM.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d9b1d47b736f0bdaeabc2365abb53bc7b409431b
Binary files /dev/null and b/Code/icons/PIC_BOTTOM.bmp differ
diff --git a/Code/icons/PIC_FRONT.bmp b/Code/icons/PIC_FRONT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f13d3c622fb79f1d558a671aed1be0e1ce7bc2c9
Binary files /dev/null and b/Code/icons/PIC_FRONT.bmp differ
diff --git a/Code/icons/PIC_LEFT.bmp b/Code/icons/PIC_LEFT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3b41281b55b0a47a1b9a0e265f5b76ce6b1fb942
Binary files /dev/null and b/Code/icons/PIC_LEFT.bmp differ
diff --git a/Code/icons/PIC_RIGHT.bmp b/Code/icons/PIC_RIGHT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..9fcbca74f68439733c42f5e6558c81eac212446a
Binary files /dev/null and b/Code/icons/PIC_RIGHT.bmp differ
diff --git a/Code/icons/PIC_TOP.bmp b/Code/icons/PIC_TOP.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5f590c690ca3d9e773dd8f76de8c9c25ce270667
Binary files /dev/null and b/Code/icons/PIC_TOP.bmp differ
diff --git a/Code/icons/PRINT.bmp b/Code/icons/PRINT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..19cf42a415405c197075196745d9455621d6d6d1
Binary files /dev/null and b/Code/icons/PRINT.bmp differ
diff --git a/Code/icons/PRINT_PREVIEW.bmp b/Code/icons/PRINT_PREVIEW.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d21f96e87bf79ee7189fbef11689ec050e1fd935
Binary files /dev/null and b/Code/icons/PRINT_PREVIEW.bmp differ
diff --git a/Code/icons/RADIO_OFF.bmp b/Code/icons/RADIO_OFF.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4abe8cf57e50486528ed16abcb76b203c5a282ce
Binary files /dev/null and b/Code/icons/RADIO_OFF.bmp differ
diff --git a/Code/icons/RADIO_ON.bmp b/Code/icons/RADIO_ON.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..c4890794a40f18c4c37045978862326873e775d3
Binary files /dev/null and b/Code/icons/RADIO_ON.bmp differ
diff --git a/Code/icons/ROLLOUT_CLOSE.bmp b/Code/icons/ROLLOUT_CLOSE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0ab35c79f6524fa7736d69bf8a1a15d2b9d120a5
Binary files /dev/null and b/Code/icons/ROLLOUT_CLOSE.bmp differ
diff --git a/Code/icons/ROLLOUT_OPEN.bmp b/Code/icons/ROLLOUT_OPEN.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..843f233e2ac4be30f752e65102195ecb63ba4a17
Binary files /dev/null and b/Code/icons/ROLLOUT_OPEN.bmp differ
diff --git a/Code/icons/TIME_BEGIN.bmp b/Code/icons/TIME_BEGIN.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6c7270344ec273fc6b93c31ece367941c35f311c
Binary files /dev/null and b/Code/icons/TIME_BEGIN.bmp differ
diff --git a/Code/icons/TIME_END.bmp b/Code/icons/TIME_END.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..55d8382202b09ca7fdd9c42310dbc9c1d53da0d2
Binary files /dev/null and b/Code/icons/TIME_END.bmp differ
diff --git a/Code/icons/TIME_NEXT.bmp b/Code/icons/TIME_NEXT.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..54ad4c41d93b5baac5ff648a3c38e02a3c6e1291
Binary files /dev/null and b/Code/icons/TIME_NEXT.bmp differ
diff --git a/Code/icons/TIME_PLAY.bmp b/Code/icons/TIME_PLAY.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..67d0f2c9613908ce8402e172427f25d86a69ea3f
Binary files /dev/null and b/Code/icons/TIME_PLAY.bmp differ
diff --git a/Code/icons/TIME_PREV.bmp b/Code/icons/TIME_PREV.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..422d27c7017d43862c8aec58427395b88a21414f
Binary files /dev/null and b/Code/icons/TIME_PREV.bmp differ
diff --git a/Code/icons/TIME_STOP.bmp b/Code/icons/TIME_STOP.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..7d504edf208f1329f0f07109a8a797a1fdab862c
Binary files /dev/null and b/Code/icons/TIME_STOP.bmp differ
diff --git a/Code/icons/VBT_CLOUD.bmp b/Code/icons/VBT_CLOUD.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..9c812170e4de38752c430716cde81125d42420f2
Binary files /dev/null and b/Code/icons/VBT_CLOUD.bmp differ
diff --git a/Code/icons/VBT_Table.bmp b/Code/icons/VBT_Table.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6bee44e26be46b0c4c403f442ba42226a4357736
Binary files /dev/null and b/Code/icons/VBT_Table.bmp differ
diff --git a/Code/icons/VBT_Volume.bmp b/Code/icons/VBT_Volume.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0d832a990cc3c194743558c0c42374f978397fd2
Binary files /dev/null and b/Code/icons/VBT_Volume.bmp differ
diff --git a/Code/icons/VME_FEM.bmp b/Code/icons/VME_FEM.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8366b5bf00801c351c3d605f89c400c738c70a77
Binary files /dev/null and b/Code/icons/VME_FEM.bmp differ
diff --git a/Code/icons/VME_IMAGE.bmp b/Code/icons/VME_IMAGE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..11e61bc79a414c851c459cd2732ec0dc195da6dd
Binary files /dev/null and b/Code/icons/VME_IMAGE.bmp differ
diff --git a/Code/icons/VME_LANDMARK.bmp b/Code/icons/VME_LANDMARK.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8553c4d29bff7c7e82032736d17b3865bbd6f8eb
Binary files /dev/null and b/Code/icons/VME_LANDMARK.bmp differ
diff --git a/Code/icons/VME_SURFACE.bmp b/Code/icons/VME_SURFACE.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..c6b63caa295d203b73771dc97081b6d6512711e2
Binary files /dev/null and b/Code/icons/VME_SURFACE.bmp differ
diff --git a/Code/icons/VME_VOLUME.bmp b/Code/icons/VME_VOLUME.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2b595cb4705add9bf06c5ecb7c77f27d4607fb68
Binary files /dev/null and b/Code/icons/VME_VOLUME.bmp differ
diff --git a/Code/icons/VisIVODesktop.icns b/Code/icons/VisIVODesktop.icns
new file mode 100644
index 0000000000000000000000000000000000000000..f97b15c68669a362f48fc92ca99739aa56d04c52
Binary files /dev/null and b/Code/icons/VisIVODesktop.icns differ
diff --git a/Code/icons/ZOOM.bmp b/Code/icons/ZOOM.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f3fe21cf4bcea102bb5f065a3b6f38392c214e1a
Binary files /dev/null and b/Code/icons/ZOOM.bmp differ
diff --git a/Code/icons/ZOOM_ALL.bmp b/Code/icons/ZOOM_ALL.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2f05fca348522a517c58583583df398aaafe1cfb
Binary files /dev/null and b/Code/icons/ZOOM_ALL.bmp differ
diff --git a/Code/icons/ZOOM_SEL.bmp b/Code/icons/ZOOM_SEL.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..bcc0a92734adc468ffcf45ded75d00e42b074954
Binary files /dev/null and b/Code/icons/ZOOM_SEL.bmp differ
diff --git a/Code/icons/colorize.png b/Code/icons/colorize.png
new file mode 100644
index 0000000000000000000000000000000000000000..72f18df87e212a0b2da34a6b2b25fa89acc42b4d
Binary files /dev/null and b/Code/icons/colorize.png differ
diff --git a/Code/icons/ellipse-select.png b/Code/icons/ellipse-select.png
new file mode 100644
index 0000000000000000000000000000000000000000..2575584c95e6539736043a35471055ccff544944
Binary files /dev/null and b/Code/icons/ellipse-select.png differ
diff --git a/Code/icons/filter.png b/Code/icons/filter.png
new file mode 100644
index 0000000000000000000000000000000000000000..f724b68b22376f1dfbeccabea6e3349192511da3
Binary files /dev/null and b/Code/icons/filter.png differ
diff --git a/Code/icons/logo3b_vl.jpg b/Code/icons/logo3b_vl.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..da054efd443905b76edb9a71e8cfb5798d19d78b
Binary files /dev/null and b/Code/icons/logo3b_vl.jpg differ
diff --git a/Code/icons/mafVMEVector.bmp b/Code/icons/mafVMEVector.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..68bccefc578289229f947de15fd9f9bef2e8e790
Binary files /dev/null and b/Code/icons/mafVMEVector.bmp differ
diff --git a/Code/icons/rect-select.png b/Code/icons/rect-select.png
new file mode 100644
index 0000000000000000000000000000000000000000..866b602a89b6afd40aff72016d9a34e21ba66b0e
Binary files /dev/null and b/Code/icons/rect-select.png differ
diff --git a/Code/icons/visivo.png b/Code/icons/visivo.png
new file mode 100644
index 0000000000000000000000000000000000000000..552d7e3e17c132b4985acd2c4d5a71fab51d7159
Binary files /dev/null and b/Code/icons/visivo.png differ
diff --git a/Code/images/splash.png b/Code/images/splash.png
new file mode 100644
index 0000000000000000000000000000000000000000..75b3e982866f6b06a834c4e506d99641a4449d60
Binary files /dev/null and b/Code/images/splash.png differ
diff --git a/Code/lib/.DS_Store b/Code/lib/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6
Binary files /dev/null and b/Code/lib/.DS_Store differ
diff --git a/Code/lib/libVO.a b/Code/lib/libVO.a
new file mode 100644
index 0000000000000000000000000000000000000000..019a31294fe9b229a223e6804d01b183482bef58
Binary files /dev/null and b/Code/lib/libVO.a differ
diff --git a/Code/lib/libVOApps.a b/Code/lib/libVOApps.a
new file mode 100644
index 0000000000000000000000000000000000000000..44a7e6d66d27537229ca3930941446445404cd01
Binary files /dev/null and b/Code/lib/libVOApps.a differ
diff --git a/Code/lib/libVOClient.a b/Code/lib/libVOClient.a
new file mode 100644
index 0000000000000000000000000000000000000000..a2cd11104a3e02359861ddccd1cc3a5730a3e601
Binary files /dev/null and b/Code/lib/libVOClient.a differ
diff --git a/Code/lib/libVOTable.a b/Code/lib/libVOTable.a
new file mode 100644
index 0000000000000000000000000000000000000000..7d84812d0bc1a3194f21c6798deee4f3ebfefbdd
Binary files /dev/null and b/Code/lib/libVOTable.a differ
diff --git a/Code/lib/libcfitsio.a b/Code/lib/libcfitsio.a
new file mode 100644
index 0000000000000000000000000000000000000000..23bd7579ac54a1712a39a765d69a5ea77b004d6c
Binary files /dev/null and b/Code/lib/libcfitsio.a differ
diff --git a/Code/lib/libcurl.a b/Code/lib/libcurl.a
new file mode 100644
index 0000000000000000000000000000000000000000..9a6daffbeb768f402568f79f9c2e031c0830a76a
Binary files /dev/null and b/Code/lib/libcurl.a differ
diff --git a/Code/lib/libexpat.a b/Code/lib/libexpat.a
new file mode 100644
index 0000000000000000000000000000000000000000..61bfad4b2d843e48109f49b7187d91276b99a891
Binary files /dev/null and b/Code/lib/libexpat.a differ
diff --git a/Code/lib/libsamp.a b/Code/lib/libsamp.a
new file mode 100644
index 0000000000000000000000000000000000000000..274d66caa7f4dfa6151de73afeb7d4d0d63d9f3c
Binary files /dev/null and b/Code/lib/libsamp.a differ
diff --git a/Code/logo.icns b/Code/logo.icns
new file mode 100644
index 0000000000000000000000000000000000000000..6d26a11c023271a009d36cd82e4dddf99c9ff778
Binary files /dev/null and b/Code/logo.icns differ
diff --git a/Code/script_idl_mv/.DS_Store b/Code/script_idl_mv/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..1097fa5c6b6ea8ca8b3cc1039c6baa4eff2ce550
Binary files /dev/null and b/Code/script_idl_mv/.DS_Store differ
diff --git a/Code/script_idl_mv/astrolib/.idlwave_catalog b/Code/script_idl_mv/astrolib/.idlwave_catalog
new file mode 100644
index 0000000000000000000000000000000000000000..55907894aace370a30440f0e90f41a58851fb422
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/.idlwave_catalog
@@ -0,0 +1,583 @@
+;;
+;; IDLWAVE catalog for library Astrolib
+;; Automatically Generated -- do not edit.
+;; Created by idlwave_catalog on Wed May 25 13:21:39 2016
+;;
+(setq idlwave-library-catalog-libname "Astrolib")
+(setq idlwave-library-catalog-routines
+ '(("spc" fun nil (lib "factor.pro" nil "Astrolib") "Result = %s(n, text)" (nil ("character") ("help") ("notrim")))
+ ("print_fact" pro nil (lib "factor.pro" nil "Astrolib") "%s, p, n" (nil ("help")))
+ ("factor" pro nil (lib "factor.pro" nil "Astrolib") "%s, x, p, n" (nil ("debug") ("help") ("quiet") ("try")))
+ ("ad2xy" pro nil (lib "ad2xy.pro" nil "Astrolib") "%s, a, d, astr, x, y" (nil))
+ ("add_distort" pro nil (lib "add_distort.pro" nil "Astrolib") "%s, hdr, astr" (nil))
+ ("adstring" fun nil (lib "adstring.pro" nil "Astrolib") "Result = %s(ra_dec, dec, precision)" (nil ("PRECISION") ("TRUNCATE")))
+ ("adxy" pro nil (lib "adxy.pro" nil "Astrolib") "%s, hdr, a, d, x, y" (nil ("ALT") ("PRINT")))
+ ("airtovac" pro nil (lib "airtovac.pro" nil "Astrolib") "%s, wave_air, wave_vac" (nil))
+ ("aitoff" pro nil (lib "aitoff.pro" nil "Astrolib") "%s, l, b, x, y" (nil))
+ ("AITOFF_GRID" pro nil (lib "aitoff_grid.pro" nil "Astrolib") "%s, DLONG, DLAT" (nil ("_EXTRA") ("CHARSIZE") ("CHARTHICK") ("FONT") ("LABEL") ("NEW")))
+ ("altaz2hadec" pro nil (lib "altaz2hadec.pro" nil "Astrolib") "%s, alt, az, lat, ha, dec" (nil))
+ ("aper" pro nil (lib "aper.pro" nil "Astrolib") "%s, image, xc, yc, mags, errap, sky, skyerr, phpadu, apr, skyradii, badpix" (nil ("CLIPSIG") ("CONVERGE_NUM") ("EXACT") ("FLUX") ("MAXITER") ("MEANBACK") ("MINSKY") ("Nan") ("PRINT") ("READNOISE") ("SETSKYVAL") ("SILENT")))
+ ("arcbar" pro nil (lib "arcbar.pro" nil "Astrolib") "%s, hdr, arclen" (nil ("COLOR") ("DATA") ("FONT") ("LABEL") ("NORMAL") ("POSITION") ("SECONDS") ("SIZE") ("THICK")))
+ ("arrows" pro nil (lib "arrows.pro" nil "Astrolib") "%s, h, xcen, ycen" (nil ("arrowlen") ("charsize") ("color") ("Data") ("font") ("Normal") ("NotVertex") ("thick")))
+ ("asinh" fun nil (lib "asinh.pro" nil "Astrolib") "Result = %s(x)" (nil))
+ ("AstDisp" pro nil (lib "astdisp.pro" nil "Astrolib") "%s, x, y, ra, dec, DN" (nil ("Coords") ("silent")))
+ ("astro" pro nil (lib "astro.pro" nil "Astrolib") "%s, selection" (nil ("EQUINOX") ("FK4")))
+ ("ASTROLIB" pro nil (lib "astrolib.pro" nil "Astrolib") "%s" (nil))
+ ("AUTOHIST" pro nil (lib "autohist.pro" nil "Astrolib") "%s, V, ZX, ZY, XX, YY" (nil ("_EXTRA") ("NOPLOT")))
+ ("AVG" fun nil (lib "avg.pro" nil "Astrolib") "Result = %s(ARRAY, DIMENSION)" (nil ("DOUBLE") ("NAN")))
+ ("baryvel" pro nil (lib "baryvel.pro" nil "Astrolib") "%s, dje, deq, dvelh, dvelb" (nil ("JPL")))
+ ("BIWEIGHT_MEAN" fun nil (lib "biweight_mean.pro" nil "Astrolib") "Result = %s(Y, SIGMA, WEIGHTs)" (nil))
+ ("BLINK" pro nil (lib "blink.pro" nil "Astrolib") "%s, wndw, t" (nil))
+ ("BLKSHIFT" pro nil (lib "blkshift.pro" nil "Astrolib") "%s, UNIT, POS0, DELTA0" (nil ("BUFFERSIZE") ("ERRMSG") ("NOZERO") ("TO")))
+ ("BOOST_ARRAY" pro nil (lib "boost_array.pro" nil "Astrolib") "%s, DESTINATION, APPEND" (nil))
+ ("boxave" fun nil (lib "boxave.pro" nil "Astrolib") "Result = %s(array, xsize, ysize)" (nil))
+ ("Bprecess" pro nil (lib "bprecess.pro" nil "Astrolib") "%s, ra, dec, ra_1950, dec_1950" (nil ("EPOCH") ("MU_RADEC") ("PARALLAX") ("RAD_VEL")))
+ ("BREAK_PATH" fun nil (lib "break_path.pro" nil "Astrolib") "Result = %s(PATHS)" (nil ("NOCURRENT")))
+ ("Bsort" fun nil (lib "bsort.pro" nil "Astrolib") "Result = %s(Array, Asort)" (nil ("INFO") ("REVERSE")))
+ ("calz_unred" pro nil (lib "calz_unred.pro" nil "Astrolib") "%s, wave, flux, ebv, funred" (nil ("R_V")))
+ ("ccm_UNRED" pro nil (lib "ccm_unred.pro" nil "Astrolib") "%s, wave, flux, ebv, funred" (nil ("R_V")))
+ ("check_FITS" pro nil (lib "check_fits.pro" nil "Astrolib") "%s, im, hdr, dimen, idltype" (nil ("ERRMSG") ("FITS") ("NOTYPE") ("SDAS") ("SILENT") ("UPDATE")))
+ ("checksum32" pro nil (lib "checksum32.pro" nil "Astrolib") "%s, array, checksum" (nil ("FROM_IEEE") ("NOSAVE")))
+ ("cic" fun nil (lib "cic.pro" nil "Astrolib") "Result = %s(value, posx, nx, posy, ny, posz, nz)" (nil ("AVERAGE") ("ISOLATED") ("NO_MESSAGE") ("WRAPAROUND")))
+ ("cirrange" pro nil (lib "cirrange.pro" nil "Astrolib") "%s, ang" (nil ("RADIANS")))
+ ("CleanPlot" pro nil (lib "cleanplot.pro" nil "Astrolib") "%s" (nil ("ShowOnly") ("silent")))
+ ("cntrd" pro nil (lib "cntrd.pro" nil "Astrolib") "%s, img, x, y, xcen, ycen, fwhm" (nil ("DEBUG") ("EXTENDBOX") ("KeepCenter") ("SILENT")))
+ ("co_aberration" pro nil (lib "co_aberration.pro" nil "Astrolib") "%s, jd, ra, dec, d_ra, d_dec" (nil ("eps")))
+ ("co_nutate" pro nil (lib "co_nutate.pro" nil "Astrolib") "%s, jd, ra, dec, d_ra, d_dec" (nil ("d_eps") ("d_psi") ("eps")))
+ ("co_refract_forward" fun nil (lib "co_refract.pro" nil "Astrolib") "Result = %s(a)" (nil ("P") ("T")))
+ ("co_refract" fun nil (lib "co_refract.pro" nil "Astrolib") "Result = %s(a)" (nil ("altitude") ("epsilon") ("pressure") ("temperature") ("To_observed")))
+ ("compare_struct" fun nil (lib "compare_struct.pro" nil "Astrolib") "Result = %s(struct_A, struct_B, Struct_Name)" (nil ("BRIEF") ("EXCEPT") ("FULL") ("NaN") ("RECUR_A") ("RECUR_B")))
+ ("concat_dir" fun nil (lib "concat_dir.pro" nil "Astrolib") "Result = %s(dirname, filnam)" (nil))
+ ("CONS_DEC" fun nil (lib "cons_dec.pro" nil "Astrolib") "Result = %s(DEC, X, ASTR, ALPHA)" (nil))
+ ("CONS_RA" fun nil (lib "cons_ra.pro" nil "Astrolib") "Result = %s(RA, Y, ASTR, DELTA)" (nil))
+ ("convolve" fun nil (lib "convolve.pro" nil "Astrolib") "Result = %s(image, psf)" (nil ("AUTO_CORRELATION") ("CORRELATE") ("FT_IMAGE") ("FT_PSF") ("NO_FT") ("NO_PAD")))
+ ("copy_struct" pro nil (lib "copy_struct.pro" nil "Astrolib") "%s, struct_From, struct_To, NT_copied, Recur_Level" (nil ("EXCEPT_TAGS") ("RECUR_From") ("RECUR_TANDEM") ("RECUR_TO") ("SELECT_TAGS")))
+ ("copy_struct_inx" pro nil (lib "copy_struct_inx.pro" nil "Astrolib") "%s, struct_From, struct_To, NT_copied, Recur_Level" (nil ("EXCEPT_TAGS") ("INDEX_From") ("INDEX_To") ("RECUR_From") ("RECUR_TANDEM") ("RECUR_To") ("SELECT_TAGS")))
+ ("correl_images" fun nil (lib "correl_images.pro" nil "Astrolib") "Result = %s(image_A, image_B)" (nil ("MAGNIFICATION") ("MONITOR") ("NUMPIX") ("REDUCTION") ("XOFFSET_B") ("XSHIFT") ("YOFFSET_B") ("YSHIFT")))
+ ("correl_optimize" pro nil (lib "correl_optimize.pro" nil "Astrolib") "%s, image_A, image_B, xoffset_optimum, yoffset_optimum" (nil ("MAGNIFICATION") ("MONITOR") ("NUMPIX") ("PLATEAU_TRESH") ("PRINT") ("XOFF_INIT") ("YOFF_INIT")))
+ ("corrmat_analyze" pro nil (lib "corrmat_analyze.pro" nil "Astrolib") "%s, correl_mat, xoffset_optimum, yoffset_optimum, max_corr, edge, plateau" (nil ("MAGNIFICATION") ("PLATEAU_THRESH") ("PRINT") ("REDUCTION") ("XOFF_INIT") ("YOFF_INIT")))
+ ("cosmo_param" pro nil (lib "cosmo_param.pro" nil "Astrolib") "%s, Omega_m, Omega_Lambda, Omega_k, q0" (nil))
+ ("cr_reject" pro nil (lib "cr_reject.pro" nil "Astrolib") "%s, input_cube, rd_noise_dn, dark_dn, gain, mult_noise, combined_image, combined_noise, combined_npix" (nil ("BIAS") ("DFACTOR") ("DILATION") ("EXPTIME") ("INIT_MEAN") ("INIT_MED") ("INIT_MIN") ("INPUT_MASK") ("MASK_CUBE") ("MEAN_LOOP") ("MEDIAN_LOOP") ("MINIMUM_LOOP") ("NOCLEARMASK") ("NOISE_CUBE") ("NOSKYADJUST") ("NSIG") ("NULL_VALUE") ("RESTORE_SKY") ("SKYBOX") ("SKYVALS") ("TRACKING_SET") ("VERBOSE") ("WEIGHTING") ("XMEDSKY")))
+ ("create_struct" pro nil (lib "create_struct.pro" nil "Astrolib") "%s, struct, strname, tagnames, tag_descript" (nil ("CHATTER") ("DIMEN") ("NODELETE")))
+ ("cspline" fun nil (lib "cspline.pro" nil "Astrolib") "Result = %s(xx, yy, tt)" (nil ("Deriv")))
+ ("CT2LST" pro nil (lib "ct2lst.pro" nil "Astrolib") "%s, lst, lng, tz, tme, day, mon, year" (nil))
+ ("curs" pro nil (lib "curs.pro" nil "Astrolib") "%s, sel" (nil))
+ ("curval" pro nil (lib "curval.pro" nil "Astrolib") "%s, hd, im" (nil ("ALT") ("Filename") ("OFFSET") ("ZOOM")))
+ ("DAO_VALUE" fun nil (lib "dao_value.pro" nil "Astrolib") "Result = %s(XX, YY, GAUSS, PSF, DVDX, DVDY)" (nil))
+ ("daoerf" pro nil (lib "daoerf.pro" nil "Astrolib") "%s, x, y, a, f, pder" (nil))
+ ("DATE" fun nil (lib "date.pro" nil "Astrolib") "Result = %s(YEAR, DAY)" (nil))
+ ("date_conv" fun nil (lib "date_conv.pro" nil "Astrolib") "Result = %s(date, type)" (nil ("BAD_DATE")))
+ ("DAYCNV" pro nil (lib "daycnv.pro" nil "Astrolib") "%s, XJD, YR, MN, DAY, HR" (nil))
+ ("DB_ENT2EXT" pro nil (lib "db_ent2ext.pro" nil "Astrolib") "%s, ENTRY" (nil))
+ ("DB_ENT2HOST" pro nil (lib "db_ent2host.pro" nil "Astrolib") "%s, ENTRY, DBNO" (nil))
+ ("db_info" fun nil (lib "db_info.pro" nil "Astrolib") "Result = %s(request, dbname)" (nil))
+ ("db_item" pro nil (lib "db_item.pro" nil "Astrolib") "%s, items, itnum, ivalnum, idltype, sbyte, numvals, nbytes" (nil ("errmsg")))
+ ("db_item_info" fun nil (lib "db_item_info.pro" nil "Astrolib") "Result = %s(request, itnums)" (nil))
+ ("db_or" fun nil (lib "db_or.pro" nil "Astrolib") "Result = %s(list1, list2)" (nil))
+ ("db_titles" pro nil (lib "db_titles.pro" nil "Astrolib") "%s, fnames, titles" (nil))
+ ("dbbuild" pro nil (lib "dbbuild.pro" nil "Astrolib") "%s, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50" (nil ("NOINDEX") ("SILENT") ("STATUS")))
+ ("dbcircle" fun nil (lib "dbcircle.pro" nil "Astrolib") "Result = %s(ra_cen, dec_cen, radius, dis, sublist)" (nil ("COUNT") ("GALACTIC") ("SILENT") ("TO_B1950") ("TO_J2000")))
+ ("dbclose" pro nil (lib "dbclose.pro" nil "Astrolib") "%s, dummy" (nil))
+ ("dbcompare" pro nil (lib "dbcompare.pro" nil "Astrolib") "%s, list1, list2, items" (nil ("DIFF") ("TEXTOUT")))
+ ("dbcreate" pro nil (lib "dbcreate.pro" nil "Astrolib") "%s, name, newindex, newdb, maxitems" (nil ("EXTERNAL") ("Maxentry")))
+ ("dbdelete" pro nil (lib "dbdelete.pro" nil "Astrolib") "%s, list, name" (nil ("DEBUG")))
+ ("widgetedit_event" pro nil (lib "dbedit.pro" nil "Astrolib") "%s, event" (nil))
+ ("widedit" pro nil (lib "dbedit.pro" nil "Astrolib") "%s" (nil))
+ ("dbedit" pro nil (lib "dbedit.pro" nil "Astrolib") "%s, list, items" (nil ("bytenum")))
+ ("dbedit_basic" pro nil (lib "dbedit_basic.pro" nil "Astrolib") "%s, list, items" (nil))
+ ("dbext" pro nil (lib "dbext.pro" nil "Astrolib") "%s, list, items, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12" (nil))
+ ("dbext_dbf" pro nil (lib "dbext_dbf.pro" nil "Astrolib") "%s, list, dbno, sbyte, nbytes, idltype, nval, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18" (nil ("item_dbno")))
+ ("dbext_ind" pro nil (lib "dbext_ind.pro" nil "Astrolib") "%s, list, item, dbno, values" (nil))
+ ("dbfind" fun nil (lib "dbfind.pro" nil "Astrolib") "Result = %s(spar, listin)" (nil ("Count") ("errmsg") ("fullstring") ("SILENT")))
+ ("dbfind_entry" pro nil (lib "dbfind_entry.pro" nil "Astrolib") "%s, type, svals, nentries, values" (nil ("Count")))
+ ("dbfind_sort" pro nil (lib "dbfind_sort.pro" nil "Astrolib") "%s, it, type, svals, list" (nil ("COUNT") ("FULLSTRING")))
+ ("dbfparse" pro nil (lib "dbfparse.pro" nil "Astrolib") "%s, spar, items, stype, values" (nil))
+ ("dbget" fun nil (lib "dbget.pro" nil "Astrolib") "Result = %s(item, values, listin)" (nil ("Count") ("FULLSTRING") ("SILENT")))
+ ("dbhelp" pro nil (lib "dbhelp.pro" nil "Astrolib") "%s, flag" (nil ("sort") ("TEXTOUT")))
+ ("dbindex" pro nil (lib "dbindex.pro" nil "Astrolib") "%s, items" (nil))
+ ("dbindex_blk" fun nil (lib "dbindex_blk.pro" nil "Astrolib") "Result = %s(unit, nb, bsz, ofb, dtype)" (nil))
+ ("dbmatch" fun nil (lib "dbmatch.pro" nil "Astrolib") "Result = %s(item, values, listin)" (nil ("FULLSTRING")))
+ ("dbopen" pro nil (lib "dbopen.pro" nil "Astrolib") "%s, name, update" (nil ("UNAVAIL")))
+ ("dbprint" pro nil (lib "dbprint.pro" nil "Astrolib") "%s, list, items" (nil ("Adjustformat") ("FORMS") ("NoHeader") ("TEXTOUT")))
+ ("dbput" pro nil (lib "dbput.pro" nil "Astrolib") "%s, item, val, entry" (nil))
+ ("dbrd" pro nil (lib "dbrd.pro" nil "Astrolib") "%s, enum, entry, available, dbno" (nil ("noconvert")))
+ ("dbsearch" pro nil (lib "dbsearch.pro" nil "Astrolib") "%s, type, svals, values, good" (nil ("COUNT") ("FULLSTRING")))
+ ("dbsort" fun nil (lib "dbsort.pro" nil "Astrolib") "Result = %s(list, items)" (nil ("REVERSE")))
+ ("dbtarget" fun nil (lib "dbtarget.pro" nil "Astrolib") "Result = %s(target, radius, sublist)" (nil ("DIS") ("SILENT") ("TO_B1950")))
+ ("dbtitle" fun nil (lib "dbtitle.pro" nil "Astrolib") "Result = %s(c, f)" (nil))
+ ("dbupdate" pro nil (lib "dbupdate.pro" nil "Astrolib") "%s, list, items, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14" (nil ("NOINDEX")))
+ ("dbval" fun nil (lib "dbval.pro" nil "Astrolib") "Result = %s(entry, item)" (nil))
+ ("dbwrt" pro nil (lib "dbwrt.pro" nil "Astrolib") "%s, entry, index, append" (nil ("noconvert")))
+ ("dbxput" pro nil (lib "dbxput.pro" nil "Astrolib") "%s, val, entry, idltype, sbyte, nbytes" (nil))
+ ("dbxval" fun nil (lib "dbxval.pro" nil "Astrolib") "Result = %s(entry, idltype, nvalues, sbyte, nbytes)" (nil ("bswap")))
+ ("delvarx" pro nil (lib "delvarx.pro" nil "Astrolib") "%s, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9" (nil ("free_mem")))
+ ("deredd" pro nil (lib "deredd.pro" nil "Astrolib") "%s, Eby, by, m1, c1, ub, by0, m0, c0, ub0" (nil ("update")))
+ ("DETABIFY" fun nil (lib "detabify.pro" nil "Astrolib") "Result = %s(CHAR_STR)" (nil))
+ ("dist_circle" pro nil (lib "dist_circle.pro" nil "Astrolib") "%s, im, n, xcen, ycen" (nil ("DOUBLE")))
+ ("dist_ellipse" pro nil (lib "dist_ellipse.pro" nil "Astrolib") "%s, im, n, xc, yc, ratio, pos_ang" (nil ("DOUBLE")))
+ ("eci2geo" fun nil (lib "eci2geo.pro" nil "Astrolib") "Result = %s(ECI_XYZ, JDtim)" (nil))
+ ("eq2hor" pro nil (lib "eq2hor.pro" nil "Astrolib") "%s, ra, dec, jd, alt, az, ha" (nil ("_extra") ("aberration_") ("altitude") ("B1950") ("lat") ("lon") ("nutate_") ("obsname") ("precess_") ("refract_") ("verbose") ("WS")))
+ ("eqpole" pro nil (lib "eqpole.pro" nil "Astrolib") "%s, l, b, x, y" (nil ("southpole")))
+ ("EQPOLE_GRID" pro nil (lib "eqpole_grid.pro" nil "Astrolib") "%s, DLONG, DLAT" (nil ("_EXTRA") ("CHARSIZE") ("CHARTHICK") ("LABELS") ("NEW") ("SOUTHPOLE")))
+ ("EULER" pro nil (lib "euler.pro" nil "Astrolib") "%s, AI, BI, AO, BO, SELECT" (nil ("FK4") ("RADIAN") ("SELECT")))
+ ("expand_tilde" fun nil (lib "expand_tilde.pro" nil "Astrolib") "Result = %s(name)" (nil))
+ ("extast" pro nil (lib "extast.pro" nil "Astrolib") "%s, hdr, astr, noparams" (nil ("alt")))
+ ("extgrp" pro nil (lib "extgrp.pro" nil "Astrolib") "%s, hdr, par" (nil))
+ ("f_format" fun nil (lib "f_format.pro" nil "Astrolib") "Result = %s(minval, maxval, factor, length)" (nil))
+ ("al_legend" pro nil (lib "al_legend.pro" nil "Astrolib") "%s, items" (nil ("background_color") ("BOTTOM_LEGEND") ("BOX") ("BTHICK") ("CENTER_LEGEND") ("CHARSIZE") ("CHARTHICK") ("CLEAR") ("COLORS") ("CORNERS") ("DATA") ("DELIMITER") ("DEVICE") ("FILL") ("FONT") ("HELP") ("HORIZONTAL") ("LEFT_LEGEND") ("LINESTYLE") ("LINSIZE") ("MARGIN") ("NORMAL") ("NUMBER") ("OUTLINE_COLOR") ("POSITION") ("PSPACING") ("PSYM") ("RIGHT_LEGEND") ("SPACING") ("SYMSIZE") ("TEXTCOLORS") ("THICK") ("TOP_LEGEND") ("USERSYM") ("VECTORFONT") ("VERTICAL") ("WINDOW")))
+ ("fdecomp" pro nil (lib "fdecomp.pro" nil "Astrolib") "%s, filename, disk, dir, name, qual, version" (nil ("OSfamily")))
+ ("filter_image" fun nil (lib "filter_image.pro" nil "Astrolib") "Result = %s(image)" (nil ("ALL_PIXELS") ("FWHM_GAUSSIAN") ("ITERATE_SMOOTH") ("MEDIAN") ("NO_FT_CONVOL") ("PSF") ("SMOOTH")))
+ ("find" pro nil (lib "find.pro" nil "Astrolib") "%s, image, x, y, flux, sharp, roundness, hmin, fwhm, roundlim, sharplim" (nil ("MONITOR") ("PRINT") ("SILENT")))
+ ("FIND_ALL_DIR" fun nil (lib "find_all_dir.pro" nil "Astrolib") "Result = %s(PATH)" (nil ("PATH_FORMAT") ("PLUS_REQUIRED") ("RESET")))
+ ("FIND_WITH_DEF" fun nil (lib "find_with_def.pro" nil "Astrolib") "Result = %s(FILENAME, PATHS, EXTENSIONS)" (nil ("NOCURRENT") ("RESET")))
+ ("FindPro" pro nil (lib "findpro.pro" nil "Astrolib") "%s, Proc_Name" (nil ("DirList") ("NoPrint") ("ProList")))
+ ("chisq_fitexy" fun nil (lib "fitexy.pro" nil "Astrolib") "Result = %s(B_angle)" (nil))
+ ("fitexy" pro nil (lib "fitexy.pro" nil "Astrolib") "%s, x, y, A_intercept, B_slope, sigma_A_B, chi_sq, q" (nil ("TOLERANCE") ("X_SIGMA") ("Y_SIGMA")))
+ ("fits_add_checksum" pro nil (lib "fits_add_checksum.pro" nil "Astrolib") "%s, hdr, im" (nil ("FROM_IEEE") ("no_timestamp")))
+ ("fits_ascii_encode" fun nil (lib "fits_ascii_encode.pro" nil "Astrolib") "Result = %s(sum32)" (nil))
+ ("fits_cd_fix" pro nil (lib "fits_cd_fix.pro" nil "Astrolib") "%s, hdr" (nil ("REVERSE")))
+ ("fits_close" pro nil (lib "fits_close.pro" nil "Astrolib") "%s, fcb" (nil ("message") ("no_abort")))
+ ("fits_help" pro nil (lib "fits_help.pro" nil "Astrolib") "%s, file_or_fcb" (nil))
+ ("fits_info" pro nil (lib "fits_info.pro" nil "Astrolib") "%s, filename" (nil ("extname") ("N_ext") ("SILENT") ("TEXTOUT")))
+ ("fits_open" pro nil (lib "fits_open.pro" nil "Astrolib") "%s, filename, fcb" (nil ("append") ("fpack") ("hprint") ("message") ("no_abort") ("update") ("write")))
+ ("fits_read" pro nil (lib "fits_read.pro" nil "Astrolib") "%s, file_or_fcb, data, header, group_par" (nil ("data_only") ("enum") ("exten_no") ("extlevel") ("extname") ("extver") ("first") ("group") ("header_only") ("last") ("message") ("no_abort") ("no_pdu") ("no_unsigned") ("noscale") ("pdu") ("xtension")))
+ ("fits_test_checksum" fun nil (lib "fits_test_checksum.pro" nil "Astrolib") "Result = %s(hdr, data)" (nil ("ERRMSG") ("FROM_IEEE")))
+ ("fits_write" pro nil (lib "fits_write.pro" nil "Astrolib") "%s, file_or_fcb, data, header_in" (nil ("extlevel") ("extname") ("extver") ("header") ("message") ("no_abort") ("no_data") ("xtension")))
+ ("fitsdir" pro nil (lib "fitsdir.pro" nil "Astrolib") "%s, directory" (nil ("alt1_keywords") ("alt2_keywords") ("alt3_keywords") ("exten") ("Keywords") ("nosize") ("NoTelescope") ("TEXTOUT")))
+ ("FITSRGB_to_TIFF" pro nil (lib "fitsrgb_to_tiff.pro" nil "Astrolib") "%s, path, rgb_files, tiff_name" (nil ("BLUE") ("BY_PIXEL") ("GREEN") ("PREVIEW") ("RED")))
+ ("flegendre" fun nil (lib "flegendre.pro" nil "Astrolib") "Result = %s(x, m)" (nil))
+ ("flux2mag" fun nil (lib "flux2mag.pro" nil "Astrolib") "Result = %s(flux, zero_pt)" (nil ("ABwave")))
+ ("fm_unred" pro nil (lib "fm_unred.pro" nil "Astrolib") "%s, wave, flux, ebv, funred" (nil ("avglmc") ("c1") ("c2") ("c3") ("c4") ("ExtCurve") ("gamma") ("lmc2") ("R_V") ("x0")))
+ ("forprint" pro nil (lib "forprint.pro" nil "Astrolib") "%s, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18" (nil ("COMMENT") ("FORMAT") ("NoCOMMENT") ("NUMLINE") ("SILENT") ("STARTLINE") ("STDOUT") ("SUBSET") ("TEXTOUT") ("WIDTH")))
+ ("frebin" fun nil (lib "frebin.pro" nil "Astrolib") "Result = %s(image, nsout, nlout)" (nil ("total")))
+ ("ftab_delrow" pro nil (lib "ftab_delrow.pro" nil "Astrolib") "%s, filename, rows" (nil ("EXTEN_NO") ("NEWFILE")))
+ ("ftab_ext" pro nil (lib "ftab_ext.pro" nil "Astrolib") "%s, file_or_fcb, columns, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v45, v46, v47, v48, v49, v50" (nil ("EXTEN_NO") ("ROWS")))
+ ("ftab_help" pro nil (lib "ftab_help.pro" nil "Astrolib") "%s, file_or_fcb" (nil ("EXTEN_NO") ("TEXTOUT")))
+ ("ftab_print" pro nil (lib "ftab_print.pro" nil "Astrolib") "%s, filename, columns, rows" (nil ("EXTEN_NO") ("FMT") ("num_header_lines") ("nval_per_line") ("TEXTOUT")))
+ ("ftaddcol" pro nil (lib "ftaddcol.pro" nil "Astrolib") "%s, h, tab, name, idltype, tform, tunit, tscal, tzero, tnull" (nil))
+ ("ftcreate" pro nil (lib "ftcreate.pro" nil "Astrolib") "%s, MAXCOLS, MAXROWS, H, TAB" (nil))
+ ("ftdelcol" pro nil (lib "ftdelcol.pro" nil "Astrolib") "%s, h, tab, name" (nil))
+ ("ftdelrow" pro nil (lib "ftdelrow.pro" nil "Astrolib") "%s, h, tab, rows" (nil))
+ ("ftget" fun nil (lib "ftget.pro" nil "Astrolib") "Result = %s(hdr_or_ftstr, tab, field, rows, nulls)" (nil))
+ ("fthelp" pro nil (lib "fthelp.pro" nil "Astrolib") "%s, h" (nil ("TEXTOUT")))
+ ("fthmod" pro nil (lib "fthmod.pro" nil "Astrolib") "%s, h, field, parameter, value" (nil))
+ ("ftinfo" pro nil (lib "ftinfo.pro" nil "Astrolib") "%s, h, ft_str" (nil ("Count")))
+ ("ftkeeprow" pro nil (lib "ftkeeprow.pro" nil "Astrolib") "%s, h, tab, subs" (nil))
+ ("ftprint" pro nil (lib "ftprint.pro" nil "Astrolib") "%s, h, tab, columns, rows" (nil ("textout")))
+ ("ftput" pro nil (lib "ftput.pro" nil "Astrolib") "%s, h, tab, field, row, values, nulls" (nil))
+ ("ftsize" pro nil (lib "ftsize.pro" nil "Astrolib") "%s, h, tab, ncols, nrows, tfields, ncols_all, nrows_all" (nil ("ERRMSG")))
+ ("ftsort" pro nil (lib "ftsort.pro" nil "Astrolib") "%s, h, tab, hnew, tabnew, field" (nil ("reverse")))
+ ("FXADDPAR_CONTPAR" pro nil (lib "fxaddpar.pro" nil "Astrolib") "%s, VALUE, CONTINUED" (nil))
+ ("FXADDPAR_CONTWARN" pro nil (lib "fxaddpar.pro" nil "Astrolib") "%s, HEADER, NAME" (nil))
+ ("FXADDPAR" pro nil (lib "fxaddpar.pro" nil "Astrolib") "%s, HEADER, NAME, VALUE, COMMENT" (nil ("AFTER") ("BEFORE") ("ERRMSG") ("FORMAT") ("MISSING") ("NOCONTINUE") ("NOLOGICAL") ("NULL")))
+ ("FXBADDCOL" pro nil (lib "fxbaddcol.pro" nil "Astrolib") "%s, INDEX, HEADER, ARRAY, TTYPE, COMMENT" (nil ("BIT") ("DCOMPLEX") ("ERRMSG") ("LOGICAL") ("NO_TDIM") ("TCUNI") ("TDELT") ("TDESC") ("TDISP") ("TDMAX") ("TDMIN") ("TNULL") ("TROTA") ("TRPIX") ("TRVAL") ("TSCAL") ("TUNIT") ("TZERO") ("VARIABLE")))
+ ("FXBCLOSE" pro nil (lib "fxbclose.pro" nil "Astrolib") "%s, UNIT" (nil ("ERRMSG")))
+ ("FXBCOLNUM" fun nil (lib "fxbcolnum.pro" nil "Astrolib") "Result = %s(UNIT, COL)" (nil ("ERRMSG")))
+ ("FXBCREATE" pro nil (lib "fxbcreate.pro" nil "Astrolib") "%s, UNIT, FILENAME, HEADER, EXTENSION" (nil ("ERRMSG")))
+ ("FXBDIMEN" fun nil (lib "fxbdimen.pro" nil "Astrolib") "Result = %s(UNIT, COL)" (nil ("ERRMSG")))
+ ("FXBFIND" pro nil (lib "fxbfind.pro" nil "Astrolib") "%s, P1, KEYWORD, COLUMNS, VALUES, N_FOUND, DEFAULT" (nil ("COMMENTS")))
+ ("FXBFINDLUN" fun nil (lib "fxbfindlun.pro" nil "Astrolib") "Result = %s(UNIT)" (nil))
+ ("FXBFINISH" pro nil (lib "fxbfinish.pro" nil "Astrolib") "%s, UNIT" (nil ("ERRMSG")))
+ ("FXBGROW" pro nil (lib "fxbgrow.pro" nil "Astrolib") "%s, UNIT, HEADER, NROWS" (nil ("BUFFERSIZE") ("ERRMSG") ("NOZERO")))
+ ("FXBHEADER" fun nil (lib "fxbheader.pro" nil "Astrolib") "Result = %s(UNIT)" (nil))
+ ("FXBHELP" pro nil (lib "fxbhelp.pro" nil "Astrolib") "%s, UNIT" (nil))
+ ("FXBHMAKE" pro nil (lib "fxbhmake.pro" nil "Astrolib") "%s, HEADER, NROWS, EXTNAME, COMMENT" (nil ("DATE") ("ERRMSG") ("EXTLEVEL") ("EXTVER") ("INITIALIZE")))
+ ("FXBISOPEN" fun nil (lib "fxbisopen.pro" nil "Astrolib") "Result = %s(UNIT)" (nil))
+ ("FXBOPEN" pro nil (lib "fxbopen.pro" nil "Astrolib") "%s, UNIT, FILENAME0, EXTENSION, HEADER" (nil ("ACCESS") ("ERRMSG") ("NO_TDIM") ("REOPEN")))
+ ("FXBPARSE" pro nil (lib "fxbparse.pro" nil "Astrolib") "%s, ILUN, HEADER" (nil ("ERRMSG") ("NO_TDIM")))
+ ("FXBREAD" pro nil (lib "fxbread.pro" nil "Astrolib") "%s, UNIT, DATA, COL, ROW" (nil ("DIMENSIONS") ("ERRMSG") ("NANVALUE") ("NOIEEE") ("NOSCALE") ("VIRTUAL")))
+ ("FXBREADM_CONV" pro nil (lib "fxbreadm.pro" nil "Astrolib") "%s, BB, DD, CTYPE, PERROW, NROWS" (nil ("DEFAULT_FLOAT") ("NANVALUE") ("NOIEEE") ("NOSCALE") ("TNULL_FLAG") ("TNULL_VALUE") ("TSCAL") ("TZERO") ("VARICOL")))
+ ("FXBREADM" pro nil (lib "fxbreadm.pro" nil "Astrolib") "%s, UNIT, COL, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, D47" (nil ("BUFFERSIZE") ("DEFAULT_FLOAT") ("DIMENSIONS") ("ERRMSG") ("NANVALUE") ("NOIEEE") ("NOSCALE") ("PASS_METHOD") ("POINTERS") ("ROW") ("STATUS") ("VIRTUAL") ("WARNMSG")))
+ ("FXBSTATE" fun nil (lib "fxbstate.pro" nil "Astrolib") "Result = %s(UNIT)" (nil))
+ ("FXBTDIM" fun nil (lib "fxbtdim.pro" nil "Astrolib") "Result = %s(TDIM_KEYWORD)" (nil))
+ ("FXBTFORM" pro nil (lib "fxbtform.pro" nil "Astrolib") "%s, HEADER, TBCOL, IDLTYPE, FORMAT, NUMVAL, MAXVAL" (nil ("ERRMSG")))
+ ("FXBWRITE" pro nil (lib "fxbwrite.pro" nil "Astrolib") "%s, UNIT, DATA, COL, ROW" (nil ("BIT") ("ERRMSG") ("NANVALUE")))
+ ("FXBWRITM" pro nil (lib "fxbwritm.pro" nil "Astrolib") "%s, UNIT, COL, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, D32, D33, D34, D35, D36, D37, D38, D39, D40, D41, D42, D43, D44, D45, D46, D47, D48, D49" (nil ("BUFFERSIZE") ("ERRMSG") ("NANVALUE") ("NOIEEE") ("NOSCALE") ("PASS_METHOD") ("POINTERS") ("ROW") ("STATUS") ("WARNMSG")))
+ ("FXFINDEND" pro nil (lib "fxfindend.pro" nil "Astrolib") "%s, UNIT, EXTENSION" (nil))
+ ("FXHCLEAN" pro nil (lib "fxhclean.pro" nil "Astrolib") "%s, HEADER" (nil ("ERRMSG")))
+ ("FXHMAKE" pro nil (lib "fxhmake.pro" nil "Astrolib") "%s, HEADER, DATA" (nil ("DATE") ("ERRMSG") ("EXTEND") ("INITIALIZE") ("XTENSION")))
+ ("FXHMODIFY" pro nil (lib "fxhmodify.pro" nil "Astrolib") "%s, FILENAME, NAME, VALUE, COMMENT" (nil ("AFTER") ("BEFORE") ("ERRMSG") ("EXTENSION") ("FORMAT") ("NOGROW")))
+ ("FXHREAD" pro nil (lib "fxhread.pro" nil "Astrolib") "%s, UNIT, HEADER, STATUS" (nil))
+ ("FXMOVE" fun nil (lib "fxmove.pro" nil "Astrolib") "Result = %s(UNIT, EXTEN)" (nil ("ERRMSG") ("EXT_NO") ("SILENT")))
+ ("FXPAR" fun nil (lib "fxpar.pro" nil "Astrolib") "Result = %s(HDR, NAME, ABORT)" (nil ("COMMENT") ("COUNT") ("DATATYPE") ("MISSING") ("NAN") ("NOCONTINUE") ("NULL") ("POSTCHECK") ("PRECHECK") ("START")))
+ ("FXPARPOS" fun nil (lib "fxparpos.pro" nil "Astrolib") "Result = %s(KEYWRD, IEND)" (nil ("AFTER") ("BEFORE")))
+ ("FXPOSIT" fun nil (lib "fxposit.pro" nil "Astrolib") "Result = %s(XFILE, EXT_NO)" (nil ("COMPRESS") ("ERRMSG") ("EXTNUM") ("FPACK") ("HEADERONLY") ("LUNIT") ("NO_FPACK") ("readonly") ("SILENT") ("UNIXPIPE")))
+ ("FXREAD" pro nil (lib "fxread.pro" nil "Astrolib") "%s, FILENAME, DATA, HEADER, P1, P2, P3, P4, P5" (nil ("AVERAGE") ("COMPRESS") ("ERRMSG") ("EXTENSION") ("NANVALUE") ("NODATA") ("NOSCALE") ("NOUPDATE") ("PROMPT") ("YSTEP")))
+ ("FXWRITE" pro nil (lib "fxwrite.pro" nil "Astrolib") "%s, FILENAME, HEADER, DATA" (nil ("APPEND") ("ERRMSG") ("NANVALUE") ("NOUPDATE")))
+ ("GAL_FLAT" fun nil (lib "gal_flat.pro" nil "Astrolib") "Result = %s(IMAGE, ANG, INC, CEN)" (nil ("INTERP")))
+ ("gal_uvw" pro nil (lib "gal_uvw.pro" nil "Astrolib") "%s, u, v, w" (nil ("dec") ("distance") ("LSR") ("plx") ("pmdec") ("pmra") ("ra") ("vrad")))
+ ("dtdz" fun nil (lib "galage.pro" nil "Astrolib") "Result = %s(z)" (nil ("lambda0") ("q0")))
+ ("galage" fun nil (lib "galage.pro" nil "Astrolib") "Result = %s(z, zform)" (nil ("h0") ("k") ("lambda0") ("Omega_m") ("q0") ("SILENT")))
+ ("gaussian" fun nil (lib "gaussian.pro" nil "Astrolib") "Result = %s(xi, parms, pderiv)" (nil ("DOUBLE")))
+ ("gcirc" pro nil (lib "gcirc.pro" nil "Astrolib") "%s, u, ra1, dc1, ra2, dc2, dis" (nil))
+ ("gcntrd" pro nil (lib "gcntrd.pro" nil "Astrolib") "%s, img, x, y, xcen, ycen, fwhm" (nil ("DEBUG") ("keepcenter") ("maxgood") ("SILENT")))
+ ("geo2eci" fun nil (lib "geo2eci.pro" nil "Astrolib") "Result = %s(incoord, JDtim)" (nil))
+ ("geo2geodetic" fun nil (lib "geo2geodetic.pro" nil "Astrolib") "Result = %s(gcoord)" (nil ("EQUATORIAL_RADIUS") ("PLANET") ("POLAR_RADIUS")))
+ ("geo2mag" fun nil (lib "geo2mag.pro" nil "Astrolib") "Result = %s(incoord)" (nil))
+ ("geodetic2geo" fun nil (lib "geodetic2geo.pro" nil "Astrolib") "Result = %s(ecoord)" (nil ("EQUATORIAL_RADIUS") ("PLANET") ("POLAR_RADIUS")))
+ ("GET_COORDS" pro nil (lib "get_coords.pro" nil "Astrolib") "%s, Coords, PromptString, NumVals" (nil ("InString") ("Quiet")))
+ ("get_date" pro nil (lib "get_date.pro" nil "Astrolib") "%s, dte, in_date" (nil ("OLD") ("TIMETAG")))
+ ("GET_EQUINOX" fun nil (lib "get_equinox.pro" nil "Astrolib") "Result = %s(HDR, CODE)" (nil ("ALT")))
+ ("get_juldate" pro nil (lib "get_juldate.pro" nil "Astrolib") "%s, jd" (nil))
+ ("getopt" fun nil (lib "getopt.pro" nil "Astrolib") "Result = %s(input, type, numopt)" (nil ("count")))
+ ("getpro" pro nil (lib "getpro.pro" nil "Astrolib") "%s, proc_name" (nil))
+ ("getpsf" pro nil (lib "getpsf.pro" nil "Astrolib") "%s, image, xc, yc, apmag, sky, ronois, phpadu, gauss, psf, idpsf, psfrad, fitrad, psfname" (nil ("DEBUG")))
+ ("getrot" pro nil (lib "getrot.pro" nil "Astrolib") "%s, hdr, rot, cdelt" (nil ("ALT") ("DEBUG") ("SILENT")))
+ ("gettok" fun nil (lib "gettok.pro" nil "Astrolib") "Result = %s(st, char)" (nil ("exact") ("notrim")))
+ ("RHOTHETA" fun nil (lib "rhotheta.pro" nil "Astrolib") "Result = %s(P, T, e, a, i, Omega, omega2, t2)" (nil))
+ ("glactc" pro nil (lib "glactc.pro" nil "Astrolib") "%s, ra, dec, year, gl, gb, j" (nil ("degree") ("fk4") ("SuperGalactic")))
+ ("glactc_pm" pro nil (lib "glactc_pm.pro" nil "Astrolib") "%s, ra, dec, mu_ra, mu_dec, year, gl, gb, mu_gl, mu_gb, j" (nil ("degree") ("fk4") ("mustar") ("SuperGalactic")))
+ ("GROUP" pro nil (lib "group.pro" nil "Astrolib") "%s, X, Y, RCRIT, NGROUP" (nil))
+ ("GSSS_StdAst" pro nil (lib "gsss_stdast.pro" nil "Astrolib") "%s, h, xpts, ypts" (nil))
+ ("GSSSadxy" pro nil (lib "gsssadxy.pro" nil "Astrolib") "%s, gsa, ra, dec, x, y" (nil ("PRINT")))
+ ("GSSSExtAst" pro nil (lib "gsssextast.pro" nil "Astrolib") "%s, h, astr, noparams" (nil))
+ ("GSSSxyad" pro nil (lib "gsssxyad.pro" nil "Astrolib") "%s, gsa, xin, yin, ra, dec" (nil ("PRINT")))
+ ("hadec2altaz" pro nil (lib "hadec2altaz.pro" nil "Astrolib") "%s, ha, dec, lat, alt, az" (nil ("WS")))
+ ("hastrom" pro nil (lib "hastrom.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, refhd" (nil ("CUBIC") ("DEGREE") ("ERRMSG") ("INTERP") ("MISSING") ("NGRID") ("SILENT")))
+ ("hboxave" pro nil (lib "hboxave.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, box" (nil ("ERRMSG")))
+ ("hcongrid" pro nil (lib "hcongrid.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, newx, newy" (nil ("ALT") ("CUBIC") ("ERRMSG") ("HALF_HALF") ("INTERP") ("OUTSIZE")))
+ ("HEADFITS" fun nil (lib "headfits.pro" nil "Astrolib") "Result = %s(filename)" (nil ("Compress") ("ERRMSG") ("EXTEN") ("SILENT")))
+ ("HELIO" pro nil (lib "helio.pro" nil "Astrolib") "%s, JD, LIST, HRAD, HLONG, HLAT" (nil ("RADIAN")))
+ ("helio_jd" fun nil (lib "helio_jd.pro" nil "Astrolib") "Result = %s(date, ra, dec)" (nil ("B1950") ("TIME_DIFF")))
+ ("helio_rv" fun nil (lib "helio_rv.pro" nil "Astrolib") "Result = %s(HJD, T, P, V0, K, e, omega)" (nil))
+ ("hermite" fun nil (lib "hermite.pro" nil "Astrolib") "Result = %s(xx, ff, x)" (nil ("FDERIV")))
+ ("heuler" pro nil (lib "heuler.pro" nil "Astrolib") "%s, h_or_astr" (nil ("alt_in") ("alt_out") ("celestial") ("ecliptic") ("Galactic")))
+ ("hextract" pro nil (lib "hextract.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, x0, x1, y0, y1" (nil ("ALT") ("ERRMSG") ("SILENT")))
+ ("hgrep" pro nil (lib "hgrep.pro" nil "Astrolib") "%s, header, substring" (nil ("keepcase") ("linenum")))
+ ("HISTOGAUSS" pro nil (lib "histogauss.pro" nil "Astrolib") "%s, SAMPLE, A, XX, YY, GX, GY" (nil ("_EXTRA") ("CHARSIZE") ("FONT") ("NOFIT") ("NOPLOT") ("Window")))
+ ("hor2eq" pro nil (lib "hor2eq.pro" nil "Astrolib") "%s, alt, az, jd, ra, dec, ha" (nil ("_extra") ("aberration_") ("altitude") ("B1950") ("lat") ("lon") ("nutate_") ("obsname") ("precess_") ("refract_") ("verbose") ("WS")))
+ ("host_to_ieee" pro nil (lib "host_to_ieee.pro" nil "Astrolib") "%s, data" (nil ("IDLTYPE")))
+ ("HPRECESS" pro nil (lib "hprecess.pro" nil "Astrolib") "%s, HDR, YEARF" (nil))
+ ("hprint" pro nil (lib "hprint.pro" nil "Astrolib") "%s, h, firstline" (nil))
+ ("hrebin" pro nil (lib "hrebin.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, newx, newy" (nil ("ALT") ("ERRMSG") ("OUTSIZE") ("SAMPLE") ("TOTAL")))
+ ("hreverse" pro nil (lib "hreverse.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, subs" (nil ("ERRMSG") ("SILENT")))
+ ("hrot" pro nil (lib "hrot.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, angle, xc, yc, int" (nil ("CUBIC") ("ERRMSG") ("INTERP") ("MISSING") ("PIVOT")))
+ ("hrotate" pro nil (lib "hrotate.pro" nil "Astrolib") "%s, oldim, oldhd, newim, newhd, direction" (nil ("ERRMSG")))
+ ("ieee_to_host" pro nil (lib "ieee_to_host.pro" nil "Astrolib") "%s, data" (nil ("IDLTYPE")))
+ ("imcontour" pro nil (lib "imcontour.pro" nil "Astrolib") "%s, im, hdr" (nil ("_EXTRA") ("NOerase") ("OVERLAY") ("PUTINFO") ("SUBTITLE") ("TYPE") ("window") ("XDELTA") ("XMID") ("XTITLE") ("YDELTA") ("YMID") ("YTITLE")))
+ ("imdbase" pro nil (lib "imdbase.pro" nil "Astrolib") "%s, hdr, catalogue, list" (nil ("ALT") ("SILENT") ("SUBLIST") ("XPOS") ("XRANGE") ("YPOS") ("YRANGE")))
+ ("imf" fun nil (lib "imf.pro" nil "Astrolib") "Result = %s(mass, expon, mass_range)" (nil))
+ ("imlist" pro nil (lib "imlist.pro" nil "Astrolib") "%s, image, xc, yc" (nil ("DESCRIP") ("DX") ("DY") ("OFFSET") ("TEXTOUT") ("WIDTH")))
+ ("irafdir" pro nil (lib "irafdir.pro" nil "Astrolib") "%s, directory" (nil ("TEXTOUT")))
+ ("irafrd" pro nil (lib "irafrd.pro" nil "Astrolib") "%s, im, hd, filename" (nil ("SILENT")))
+ ("irafwrt" pro nil (lib "irafwrt.pro" nil "Astrolib") "%s, image, hd, filename" (nil ("PIXDIR")))
+ ("is_ieee_big" fun nil (lib "is_ieee_big.pro" nil "Astrolib") "Result = %s" (nil))
+ ("GETWRD" fun nil (lib "getwrd.pro" nil "Astrolib") "Result = %s(TXTSTR, NTH, MTH)" (nil ("delimiter") ("help") ("last") ("location") ("notrim") ("nwords")))
+ ("ismeuv" fun nil (lib "ismeuv.pro" nil "Astrolib") "Result = %s(wave, Hcol, HeIcol, HeIIcol)" (nil ("Fano")))
+ ("JDCNV" pro nil (lib "jdcnv.pro" nil "Astrolib") "%s, YR, MN, DAY, HR, JULIAN" (nil))
+ ("jplephinterp_calc" pro nil (lib "jplephinterp.pro" nil "Astrolib") "%s, info, raw, obj, t, x, y, z, vx, vy, vz" (nil ("tbase") ("velocity")))
+ ("jplephinterp_denew" pro nil (lib "jplephinterp.pro" nil "Astrolib") "%s, info, raw, obj, t, x, y, z, vx, vy, vz" (nil ("tbase") ("velocity")))
+ ("jplephinterp" pro nil (lib "jplephinterp.pro" nil "Astrolib") "%s, info, raw, t, x, y, z, vx, vy, vz" (nil ("center") ("decode_obj") ("earth") ("objectname") ("pos_vel_factor") ("posunits") ("sun") ("tbase") ("velocity") ("velunits") ("xobjnum")))
+ ("jplephpar" fun nil (lib "jplephread.pro" nil "Astrolib") "Result = %s(header, parname)" (nil ("default") ("fatal")))
+ ("jplephval" fun nil (lib "jplephread.pro" nil "Astrolib") "Result = %s(names, values, name)" (nil ("default") ("fatal")))
+ ("jplephread" pro nil (lib "jplephread.pro" nil "Astrolib") "%s, filename, info, raw, jdlimits" (nil ("errmsg") ("status")))
+ ("jplephtest" pro nil (lib "jplephtest.pro" nil "Astrolib") "%s, ephfile, testfile" (nil ("pause")))
+ ("jprecess" pro nil (lib "jprecess.pro" nil "Astrolib") "%s, ra, dec, ra_2000, dec_2000" (nil ("EPOCH") ("MU_RADEC") ("PARALLAX") ("RAD_VEL")))
+ ("JULDATE" pro nil (lib "juldate.pro" nil "Astrolib") "%s, DATE, JD" (nil ("PROMPT")))
+ ("ksone" pro nil (lib "ksone.pro" nil "Astrolib") "%s, data, func_name, d, prob" (nil ("_EXTRA") ("PLOT") ("Window")))
+ ("kstwo" pro nil (lib "kstwo.pro" nil "Astrolib") "%s, data1, data2, D, prob" (nil))
+ ("kuiperone" pro nil (lib "kuiperone.pro" nil "Astrolib") "%s, data, func_name, d, prob" (nil ("_EXTRA") ("PLOT") ("WINDOW")))
+ ("kuipertwo" pro nil (lib "kuipertwo.pro" nil "Astrolib") "%s, data1, data2, D, prob" (nil ("_EXTRA") ("PLOT") ("WINDOW")))
+ ("PERMUTE" fun nil (lib "permute.pro" nil "Astrolib") "Result = %s(N, Seed)" (nil))
+ ("isarray" fun nil (lib "isarray.pro" nil "Astrolib") "Result = %s(a)" (nil))
+ ("lineid_plot" pro nil (lib "lineid_plot.pro" nil "Astrolib") "%s, wave, flux, wline, text1, text2" (nil ("_EXTRA") ("extend") ("lcharsize") ("lcharthick") ("window")))
+ ("linmix_atanh" fun nil (lib "linmix_err.pro" nil "Astrolib") "Result = %s(x)" (nil))
+ ("linmix_robsig" fun nil (lib "linmix_err.pro" nil "Astrolib") "Result = %s(x)" (nil))
+ ("loglik_mixerr" fun nil (lib "linmix_err.pro" nil "Astrolib") "Result = %s(x, y, xvar, yvar, xycov, delta, theta, pi, mu, tausqr, Glabel)" (nil))
+ ("logprior_mixerr" fun nil (lib "linmix_err.pro" nil "Astrolib") "Result = %s(mu, mu0, tausqr, usqr, wsqr)" (nil))
+ ("linmix_metro_update" fun nil (lib "linmix_err.pro" nil "Astrolib") "Result = %s(logpost_new, logpost_old, seed, log_jrat)" (nil))
+ ("linmix_metro_results" pro nil (lib "linmix_err.pro" nil "Astrolib") "%s, arate, ngauss" (nil))
+ ("linmix_err" pro nil (lib "linmix_err.pro" nil "Astrolib") "%s, x, y, post" (nil ("delta") ("maxiter") ("metro") ("miniter") ("ngauss") ("silent") ("xsig") ("xycov") ("ysig")))
+ ("linterp" pro nil (lib "linterp.pro" nil "Astrolib") "%s, Xtab, Ytab, Xint, Yint" (nil ("MISSING") ("NoInterp")))
+ ("LIST_WITH_PATH" fun nil (lib "list_with_path.pro" nil "Astrolib") "Result = %s(FILENAME, PATHS)" (nil ("COUNT") ("NOCURRENT")))
+ ("lsf_rotate" fun nil (lib "lsf_rotate.pro" nil "Astrolib") "Result = %s(deltav, vsini)" (nil ("EPSILON") ("VELGRID")))
+ ("ldist" fun nil (lib "lumdist.pro" nil "Astrolib") "Result = %s(z)" (nil ("lambda0") ("q0")))
+ ("lumdist" fun nil (lib "lumdist.pro" nil "Astrolib") "Result = %s(z)" (nil ("h0") ("k") ("Lambda0") ("Omega_m") ("q0") ("Silent")))
+ ("mag2flux" fun nil (lib "mag2flux.pro" nil "Astrolib") "Result = %s(mag, zero_pt)" (nil ("ABwave")))
+ ("mag2geo" fun nil (lib "mag2geo.pro" nil "Astrolib") "Result = %s(incoord)" (nil))
+ ("make_2d" pro nil (lib "make_2d.pro" nil "Astrolib") "%s, x, y, xx, yy" (nil))
+ ("make_astr" pro nil (lib "make_astr.pro" nil "Astrolib") "%s, astr" (nil ("AXES") ("CD") ("CRPIX") ("CRVAL") ("CTYPE") ("DATE_OBS") ("DELTA") ("EQUINOX") ("LATPOLE") ("LONGPOLE") ("MJD_OBS") ("NAXIS") ("pv1") ("PV2") ("RADECSYS")))
+ ("match" pro nil (lib "match.pro" nil "Astrolib") "%s, a, b, suba, subb" (nil ("COUNT") ("epsilon") ("SORT")))
+ ("match2" pro nil (lib "match2.pro" nil "Astrolib") "%s, a, b, suba, subb" (nil))
+ ("max_entropy" pro nil (lib "max_entropy.pro" nil "Astrolib") "%s, data, psf, deconv, multipliers" (nil ("FT_PSF") ("LINEAR") ("LOGMIN") ("NO_FT") ("RE_CONVOL_IMAGE")))
+ ("Max_Likelihood" pro nil (lib "max_likelihood.pro" nil "Astrolib") "%s, data, psf, deconv, Re_conv" (nil ("FT_PSF") ("GAUSSIAN") ("NO_FT") ("POSITIVITY_EPS") ("UNDERFLOW_ZERO")))
+ ("MEANCLIP" pro nil (lib "meanclip.pro" nil "Astrolib") "%s, Image, Mean, Sigma" (nil ("CLIPSIG") ("CONVERGE_NUM") ("DOUBLE") ("MAXITER") ("SUBS") ("VERBOSE")))
+ ("medarr" pro nil (lib "medarr.pro" nil "Astrolib") "%s, inarr, outarr, mask, output_mask" (nil))
+ ("MEDSMOOTH" fun nil (lib "medsmooth.pro" nil "Astrolib") "Result = %s(ARRAY, WINDOW)" (nil))
+ ("minF_bracket" pro nil (lib "minf_bracket.pro" nil "Astrolib") "%s, xa, xb, xc, fa, fb, fc" (nil ("DIRECTION") ("FUNC_NAME") ("POINT_NDIM")))
+ ("minF_conj_grad" pro nil (lib "minf_conj_grad.pro" nil "Astrolib") "%s, p_min, f_min, conv_factor" (nil ("FUNC_NAME") ("INITIALIZE") ("QUADRATIC") ("TOLERANCE") ("USE_DERIV")))
+ ("call_func_deriv" fun nil (lib "minf_parabol_d.pro" nil "Astrolib") "Result = %s(func_name, x, deriv)" (nil ("DIRECTION") ("POINT_NDIM")))
+ ("minF_parabol_D" pro nil (lib "minf_parabol_d.pro" nil "Astrolib") "%s, xa, xb, xc, xmin, fmin" (nil ("DIRECTION") ("FUNC_NAME") ("MAX_ITERATIONS") ("POINT_NDIM") ("TOLERANCE")))
+ ("minF_parabolic" pro nil (lib "minf_parabolic.pro" nil "Astrolib") "%s, xa, xb, xc, xmin, fmin" (nil ("DIRECTION") ("FUNC_NAME") ("MAX_ITERATIONS") ("POINT_NDIM") ("TOLERANCE")))
+ ("minmax" fun nil (lib "minmax.pro" nil "Astrolib") "Result = %s(array, subs)" (nil ("DIMEN") ("NAN")))
+ ("mkhdr" pro nil (lib "mkhdr.pro" nil "Astrolib") "%s, header, im, naxisx" (nil ("EXTEND") ("IMAGE")))
+ ("mlinmix_chol_invert" fun nil (lib "mlinmix_err.pro" nil "Astrolib") "Result = %s(L)" (nil))
+ ("mlinmix_posdef_invert" pro nil (lib "mlinmix_err.pro" nil "Astrolib") "%s, A" (nil))
+ ("mlinmix_err" pro nil (lib "mlinmix_err.pro" nil "Astrolib") "%s, x, y, post" (nil ("delta") ("maxiter") ("miniter") ("ngauss") ("silent") ("xvar") ("xycov") ("yvar")))
+ ("mmm" pro nil (lib "mmm.pro" nil "Astrolib") "%s, sky_vector, skymod, sigma, skew" (nil ("DEBUG") ("HIGHBAD") ("INTEGER") ("MAXITER") ("MINSKY") ("Nsky") ("ReadNoise") ("SILENT")))
+ ("MODFITS" pro nil (lib "modfits.pro" nil "Astrolib") "%s, filename, data, header" (nil ("ERRMSG") ("EXTEN_NO") ("EXTNAME")))
+ ("month_cnv" fun nil (lib "month_cnv.pro" nil "Astrolib") "Result = %s(MonthInput)" (nil ("Low") ("Short") ("Up")))
+ ("MOONPOS" pro nil (lib "moonpos.pro" nil "Astrolib") "%s, jd, ra, dec, dis, geolong, geolat" (nil ("RADIAN")))
+ ("mphase" pro nil (lib "mphase.pro" nil "Astrolib") "%s, jd, k" (nil))
+ ("mrandomn" fun nil (lib "mrandomn.pro" nil "Astrolib") "Result = %s(seed, covar, nrand)" (nil ("STATUS")))
+ ("mrd_hread" pro nil (lib "mrd_hread.pro" nil "Astrolib") "%s, unit, header, status" (nil ("ERRMSG") ("FIRSTBLOCK") ("NO_BADHEADER") ("SILENT") ("SKIPDATA")))
+ ("mrd_skip" pro nil (lib "mrd_skip.pro" nil "Astrolib") "%s, unit, nskip" (nil))
+ ("mrd_struct" fun nil (lib "mrd_struct.pro" nil "Astrolib") "Result = %s(names, values, nrow)" (nil ("no_execute") ("old_struct") ("silent") ("structyp") ("tempdir")))
+ ("mrd_fxpar" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, hdr, xten, nfld, nrow, rsize, fnames, fforms, scales, offsets" (nil))
+ ("mrd_dofn" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(name, index, use_colnum)" (nil ("alias")))
+ ("mrd_doff" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, form, dim, type" (nil))
+ ("mrd_chkfn" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(name, namelist, index)" (nil ("silent")))
+ ("mrd_unsigned_offset" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(type)" (nil))
+ ("mrd_chkunsigned" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(bitpix, scale, zero)" (nil ("unsigned")))
+ ("mrd_unsignedtype" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(data)" (nil))
+ ("mrd_version" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s" (nil))
+ ("mrd_atype" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, form, type, slen" (nil))
+ ("mrd_read_ascii" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, unit, range, nbytes, nrows, nfld, typarr, posarr, lenarr, nullarr, table" (nil ("old_struct") ("rows")))
+ ("mrd_ascii" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, header, structyp, use_colnum, range, table, nbytes, nrows, nfld, typarr, posarr, lenarr, nullarr, fnames, fvalues, scales, offsets, scaling, status" (nil ("alias") ("columns") ("outalias") ("rows") ("silent")))
+ ("mrd_columns" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, table, columns, fnames, fvalues, vcls, vtpes, scales, offsets, scaling" (nil ("silent") ("structyp")))
+ ("mrd_read_image" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, unit, range, maxd, rsize, table" (nil ("rows") ("status") ("unixpipe")))
+ ("mrd_axes_trunc" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, naxis, dims, silent" (nil))
+ ("mrd_image" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, header, range, maxd, rsize, table, scales, offsets, scaling, status" (nil ("rows") ("silent") ("unsigned")))
+ ("mrd_ptrscale" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, array, scale, offset" (nil))
+ ("mrd_string" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, table, header, typarr, fnames, fvalues, nrec" (nil ("silent") ("structyp")))
+ ("mrd_scale" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, type, scales, offsets, table, header, fnames, fvalues, nrec" (nil ("dscale") ("silent") ("structyp")))
+ ("mrd_varcolumn" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, vtype, array, heap, off, siz" (nil))
+ ("mrd_fixcolumn" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, vtype, array, heap, off, siz" (nil))
+ ("mrd_read_heap" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, unit, header, range, fnames, fvalues, vcls, vtpes, table, structyp, scaling, scales, offsets, status" (nil ("columns") ("fixed_var") ("pointer_var") ("rows") ("silent")))
+ ("mrd_read_table" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, unit, range, rsize, structyp, nrows, nfld, typarr, table" (nil ("rows") ("unixpipe")))
+ ("mrd_tdim" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, header, index, flen, arrstr" (nil ("no_tdim")))
+ ("mrd_table" pro nil (lib "mrdfits.pro" nil "Astrolib") "%s, header, structyp, use_colnum, range, rsize, table, nrows, nfld, typarr, fnames, fvalues, vcls, vtpes, scales, offsets, scaling, status" (nil ("alias") ("columns") ("emptystring") ("no_tdim") ("outalias") ("rows") ("silent") ("unsigned")))
+ ("mrdfits" fun nil (lib "mrdfits.pro" nil "Astrolib") "Result = %s(file, extension, header)" (nil ("alias") ("columns") ("compress") ("dscale") ("emptystring") ("error_action") ("extnum") ("fixed_var") ("fpack") ("fscale") ("no_fpack") ("no_tdim") ("outalias") ("pointer_var") ("range") ("rows") ("silent") ("status") ("structyp") ("unsigned") ("use_colnum") ("version")))
+ ("multinom" fun nil (lib "multinom.pro" nil "Astrolib") "Result = %s(n, p, nrand)" (nil ("seed")))
+ ("multiplot" pro nil (lib "multiplot.pro" nil "Astrolib") "%s, pmulti" (nil ("default") ("doxaxis") ("doyaxis") ("gap") ("help") ("initialize") ("mtitle") ("mTitOffset") ("mTitSize") ("mxTitle") ("mxTitOffset") ("mxTitSize") ("myTitle") ("myTitOffset") ("myTitSize") ("reset") ("rowmajor") ("square") ("verbose") ("xgap") ("xtickformat") ("ygap") ("ytickformat")))
+ ("mwr_version" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s" (nil))
+ ("mwr_unsigned_offset" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s(type)" (nil))
+ ("chk_and_upd" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, header, key, value, comment" (nil ("nological")))
+ ("mwr_checktype" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s(tag)" (nil ("alias")))
+ ("mwr_ascii" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, input, siz, lun, bof, header" (nil ("alias") ("ascii") ("bscale") ("iscale") ("lscale") ("no_comment") ("no_types") ("null") ("separator") ("silent") ("terminator") ("use_colnum")))
+ ("mwr_dummy" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, lun" (nil))
+ ("mwr_validptr" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s(vtypes, nfld, index, array)" (nil))
+ ("mwr_tablehdr" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, lun, input, header, vtypes" (nil ("alias") ("bit_cols") ("logical_cols") ("nbit_cols") ("no_comment") ("no_types") ("silent") ("use_colnum")))
+ ("mwr_retable" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s(input, vtypes)" (nil))
+ ("mwr_writeheap" fun nil (lib "mwrfits.pro" nil "Astrolib") "Result = %s(lun, vtypes)" (nil))
+ ("mwr_tabledat" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, lun, input, header, vtypes" (nil))
+ ("mwr_pscale" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, grp, header" (nil ("pscale") ("pzero")))
+ ("mwr_findscale" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, flag, array, nbits, scale, offset, error" (nil))
+ ("mwr_scale" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, array, scale, offset" (nil ("bscale") ("iscale") ("lscale") ("null")))
+ ("mwr_header" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, lun, header" (nil))
+ ("mwr_groupinfix" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, data, group, hdr" (nil))
+ ("mwr_groupscale" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, maxval, group, hdr" (nil))
+ ("mwr_image" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, input, siz, lun, bof, hdr" (nil ("bscale") ("group") ("iscale") ("lscale") ("no_comment") ("null") ("pscale") ("pzero") ("silent")))
+ ("mwrfits" pro nil (lib "mwrfits.pro" nil "Astrolib") "%s, xinput, file, header" (nil ("alias") ("ascii") ("bit_cols") ("bscale") ("create") ("group") ("iscale") ("logical_cols") ("lscale") ("nbit_cols") ("no_comment") ("no_copy") ("no_types") ("null") ("pscale") ("pzero") ("separator") ("silent") ("status") ("terminator") ("use_colnum") ("version")))
+ ("N_bytes" fun nil (lib "n_bytes.pro" nil "Astrolib") "Result = %s(a)" (nil))
+ ("ngp" fun nil (lib "ngp.pro" nil "Astrolib") "Result = %s(value, posx, nx, posy, ny, posz, nz)" (nil ("AVERAGE") ("NO_MESSAGE") ("WRAPAROUND")))
+ ("nint" fun nil (lib "nint.pro" nil "Astrolib") "Result = %s(x)" (nil ("LONG")))
+ ("nstar" pro nil (lib "nstar.pro" nil "Astrolib") "%s, image, id, xc, yc, mags, sky, group, phpadu, readns, psfname, errmag, iter, chisq, peak" (nil ("DEBUG") ("PRINT") ("SILENT") ("VARSKY")))
+ ("nulltrim" fun nil (lib "nulltrim.pro" nil "Astrolib") "Result = %s(st)" (nil))
+ ("nutate" pro nil (lib "nutate.pro" nil "Astrolib") "%s, jd, nut_long, nut_obliq" (nil))
+ ("observatory" pro nil (lib "observatory.pro" nil "Astrolib") "%s, obsname, obs_struct" (nil ("print")))
+ ("one_arrow" pro nil (lib "one_arrow.pro" nil "Astrolib") "%s, xcen, ycen, angle, label" (nil ("arrowsize") ("charsize") ("color") ("data") ("font") ("linestyle") ("normal") ("thick")))
+ ("one_ray" pro nil (lib "one_ray.pro" nil "Astrolib") "%s, xcen, ycen, len, angle, terminus" (nil ("_EXTRA") ("data") ("nodraw") ("normal")))
+ ("oploterror" pro nil (lib "oploterror.pro" nil "Astrolib") "%s, x, y, xerr, yerr" (nil ("_EXTRA") ("ADDCMD") ("ERRCOLOR") ("ERRSTYLE") ("ERRTHICK") ("HATLENGTH") ("HIBAR") ("LOBAR") ("NOCLIP") ("NOHAT") ("NSKIP") ("Nsum") ("THICK") ("WINDOW")))
+ ("ordinal" fun nil (lib "ordinal.pro" nil "Astrolib") "Result = %s(num)" (nil))
+ ("partvelvec" pro nil (lib "partvelvec.pro" nil "Astrolib") "%s, velx, vely, posx, posy, x, y" (nil ("_EXTRA") ("COLOR") ("FRACTION") ("LENGTH") ("NOCLIP") ("OVER") ("VECCOLORS") ("WINDOW")))
+ ("PCA" pro nil (lib "pca.pro" nil "Astrolib") "%s, data, eigenval, eigenvect, percentages, proj_obj, proj_atr" (nil ("COVARIANCE") ("MATRIX") ("SILENT") ("SSQ") ("TEXTOUT")))
+ ("pent" fun nil (lib "pent.pro" nil "Astrolib") "Result = %s(p, t, x, m, n)" (nil))
+ ("pixcolor" pro nil (lib "pixcolor.pro" nil "Astrolib") "%s, pix_value, color" (nil))
+ ("Arc" fun nil (lib "pixwt.pro" nil "Astrolib") "Result = %s(x, y0, y1, r)" (nil))
+ ("Chord" fun nil (lib "pixwt.pro" nil "Astrolib") "Result = %s(x, y0, y1)" (nil))
+ ("Oneside" fun nil (lib "pixwt.pro" nil "Astrolib") "Result = %s(x, y0, y1, r)" (nil))
+ ("Intarea" fun nil (lib "pixwt.pro" nil "Astrolib") "Result = %s(xc, yc, r, x0, x1, y0, y1)" (nil))
+ ("Pixwt" fun nil (lib "pixwt.pro" nil "Astrolib") "Result = %s(xc, yc, r, x, y)" (nil))
+ ("pkfit" pro nil (lib "pkfit.pro" nil "Astrolib") "%s, f, scale, x, y, sky, radius, ronois, phpadu, gauss, psf, errmag, chi, sharp, niter" (nil ("DEBUG")))
+ ("planck" fun nil (lib "planck.pro" nil "Astrolib") "Result = %s(wave, temp)" (nil))
+ ("planet_coords" pro nil (lib "planet_coords.pro" nil "Astrolib") "%s, date, ra, dec" (nil ("jd") ("jpl") ("planet")))
+ ("ploterror" pro nil (lib "ploterror.pro" nil "Astrolib") "%s, x, y, xerr, yerr" (nil ("_EXTRA") ("ERRCOLOR") ("ERRSTYLE") ("ERRTHICK") ("HATLENGTH") ("NOCLIP") ("NOHAT") ("NSKIP") ("NSUM") ("TYPE") ("WINDOW") ("XLOG") ("XRANGE") ("YLOG") ("YRANGE")))
+ ("plothist" pro nil (lib "plothist.pro" nil "Astrolib") "%s, arr, xhist, yhist" (nil ("_EXTRA") ("AUTOBin") ("axiscolor") ("BIN") ("Boxplot") ("Color") ("FCOLOR") ("Fill") ("FLINE") ("FORIENTATION") ("FPATTERN") ("FSPACING") ("FTHICK") ("Halfbin") ("LINESTYLE") ("NAN") ("NOPLOT") ("OVERPLOT") ("Peak") ("PSYM") ("rotate") ("THICK") ("WINDOW") ("xlog") ("XSTYLE") ("ylog") ("yrange") ("YSTYLE")))
+ ("plotsym" pro nil (lib "plotsym.pro" nil "Astrolib") "%s, psym, psize" (nil ("Color") ("FILL") ("thick")))
+ ("poidev" fun nil (lib "poidev.pro" nil "Astrolib") "Result = %s(xm)" (nil ("SEED")))
+ ("polint" pro nil (lib "polint.pro" nil "Astrolib") "%s, xa, ya, x, y, dy" (nil))
+ ("POLREC" pro nil (lib "polrec.pro" nil "Astrolib") "%s, R, A, X, Y" (nil ("degrees") ("help")))
+ ("poly_smooth" fun nil (lib "poly_smooth.pro" nil "Astrolib") "Result = %s(data, width)" (nil ("COEFFICIENTS") ("DEGREE") ("DERIV_ORDER") ("NLEFT") ("NRIGHT")))
+ ("polyleg" fun nil (lib "polyleg.pro" nil "Astrolib") "Result = %s(x, coeff)" (nil))
+ ("POSANG" pro nil (lib "posang.pro" nil "Astrolib") "%s, u, ra1, dc1, ra2, dc2, angle" (nil))
+ ("positivity" fun nil (lib "positivity.pro" nil "Astrolib") "Result = %s(x)" (nil ("DERIVATIVE") ("EPSILON")))
+ ("precess" pro nil (lib "precess.pro" nil "Astrolib") "%s, ra, dec, equinox1, equinox2" (nil ("FK4") ("PRINT") ("RADIAN")))
+ ("PRECESS_CD" pro nil (lib "precess_cd.pro" nil "Astrolib") "%s, cd, epoch1, epoch2, crval_old, crval_new" (nil ("FK4")))
+ ("precess_xyz" pro nil (lib "precess_xyz.pro" nil "Astrolib") "%s, x, y, z, equinox1, equinox2" (nil))
+ ("premat" fun nil (lib "premat.pro" nil "Astrolib") "Result = %s(equinox1, equinox2)" (nil ("FK4")))
+ ("prime" fun nil (lib "prime.pro" nil "Astrolib") "Result = %s(n)" (nil ("help")))
+ ("print_struct" pro nil (lib "print_struct.pro" nil "Astrolib") "%s, structure, Tags_to_print, title, string_matrix" (nil ("FILE") ("FORM_FLOAT") ("FRANGE") ("LUN_OUT") ("MAX_ELEMENTS") ("NO_TITLE") ("STRINGS") ("TNUMS") ("TRANGE") ("WHICH_TO_PRINT")))
+ ("prob_ks" pro nil (lib "prob_ks.pro" nil "Astrolib") "%s, D, N_eff, probks" (nil))
+ ("prob_kuiper" pro nil (lib "prob_kuiper.pro" nil "Astrolib") "%s, D, N_eff, probks" (nil))
+ ("psf_gaussian" fun nil (lib "psf_gaussian.pro" nil "Astrolib") "Result = %s(parameters)" (nil ("CENTROID") ("DOUBLE") ("FWHM") ("NDIMENSION") ("NORMALIZE") ("NPIXEL") ("ST_DEV") ("XY_CORREL")))
+ ("putast" pro nil (lib "putast.pro" nil "Astrolib") "%s, hdr, astr, crpix, crval, ctype" (nil ("ALT") ("CD_TYPE") ("EQUINOX") ("NAXIS")))
+ ("QDCB_GRID" pro nil (lib "qdcb_grid.pro" nil "Astrolib") "%s, DLONG, DLAT" (nil ("LABELS") ("LINESTYLE")))
+ ("qget_string" fun nil (lib "qget_string.pro" nil "Astrolib") "Result = %s(dummy)" (nil))
+ ("qsimp" pro nil (lib "qsimp.pro" nil "Astrolib") "%s, func, A, B, S" (nil ("_EXTRA") ("EPS") ("MAX_ITER")))
+ ("qtrap" pro nil (lib "qtrap.pro" nil "Astrolib") "%s, func, A, B, S" (nil ("_EXTRA") ("EPS") ("MAX_ITER")))
+ ("quadterp" pro nil (lib "quadterp.pro" nil "Astrolib") "%s, xtab, ytab, xint, yint" (nil ("MISSING")))
+ ("QueryDSS" pro nil (lib "querydss.pro" nil "Astrolib") "%s, target, Image, Header" (nil ("ESO") ("IMSIZE") ("NED") ("OUTFILE") ("STSCI") ("SURVEY") ("VERBOSE")))
+ ("Querygsc" fun nil (lib "querygsc.pro" nil "Astrolib") "Result = %s(target, dis)" (nil ("BOX") ("HOURS") ("magrange") ("VERBOSE")))
+ ("QuerySimbad" pro nil (lib "querysimbad.pro" nil "Astrolib") "%s, name, ra, de, id" (nil ("CADC") ("CFA") ("ERRMSG") ("Found") ("Hmag") ("Jmag") ("Kmag") ("NED") ("parallax") ("Print") ("Server") ("SILENT") ("Verbose") ("Vmag")))
+ ("Queryvizier" fun nil (lib "queryvizier.pro" nil "Astrolib") "Result = %s(catalog, target, dis)" (nil ("ALLCOLUMNS") ("CANADA") ("CFA") ("CONSTRAINT") ("SILENT") ("VERBOSE")))
+ ("radec" pro nil (lib "radec.pro" nil "Astrolib") "%s, ra, dec, ihr, imin, xsec, ideg, imn, xsc" (nil ("hours")))
+ ("randomchi" fun nil (lib "randomchi.pro" nil "Astrolib") "Result = %s(seed, dof, nrand)" (nil))
+ ("randomdir" fun nil (lib "randomdir.pro" nil "Astrolib") "Result = %s(seed, alpha, nrand)" (nil))
+ ("randomgam" fun nil (lib "randomgam.pro" nil "Astrolib") "Result = %s(seed, alpha, beta, nrand)" (nil))
+ ("randomp" pro nil (lib "randomp.pro" nil "Astrolib") "%s, x, pow, n" (nil ("range_x") ("seed")))
+ ("randomwish" fun nil (lib "randomwish.pro" nil "Astrolib") "Result = %s(seed, dof, S, nrand)" (nil))
+ ("rdfits_struct" pro nil (lib "rdfits_struct.pro" nil "Astrolib") "%s, filename, struct" (nil ("EXTEN") ("HEADER_ONLY") ("SILENT")))
+ ("rdfloat" pro nil (lib "rdfloat.pro" nil "Astrolib") "%s, name, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19" (nil ("COLUMNS") ("DOUBLE") ("NUMLINE") ("SILENT") ("SKIPLINE")))
+ ("RESET_RDPLOT" pro nil (lib "rdplot.pro" nil "Astrolib") "%s" (nil))
+ ("RDPLOT" pro nil (lib "rdplot.pro" nil "Astrolib") "%s, x, y, WaitFlag" (nil ("ACCUMULATE") ("BACKGROUND") ("CHANGE") ("COLOR") ("CROSS") ("CURSOR_STANDARD") ("DATA") ("DEVICE") ("DOWN") ("Err") ("FULLCURSOR") ("LINESTYLE") ("NOCLIP") ("NORMAL") ("NOWAIT") ("PRINT") ("THICK") ("WAIT") ("XTITLE") ("XVALUES") ("YTITLE") ("YVALUES")))
+ ("rdpsf" pro nil (lib "rdpsf.pro" nil "Astrolib") "%s, psf, hpsf, psfname" (nil))
+ ("read_fmr" fun nil (lib "read_fmr.pro" nil "Astrolib") "Result = %s(filename)" (nil ("columns") ("help") ("missingvalue") ("use_colnum")))
+ ("read_key" fun nil (lib "read_key.pro" nil "Astrolib") "Result = %s(wait)" (nil))
+ ("readcol" pro nil (lib "readcol.pro" nil "Astrolib") "%s, name, v1, V2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50" (nil ("COMMENT") ("COMPRESS") ("COUNT") ("DEBUG") ("DELIMITER") ("FORMAT") ("NAN") ("NLINES") ("NUMLINE") ("PRESERVE_NULL") ("QUICK") ("SILENT") ("SKIPLINE") ("STRINGSKIP")))
+ ("READFITS" fun nil (lib "readfits.pro" nil "Astrolib") "Result = %s(filename, header, heap)" (nil ("CHECKSUM") ("COMPRESS") ("EXTEN_NO") ("FPACK") ("HBUFFER") ("NaNvalue") ("NO_UNSIGNED") ("NOSCALE") ("NSLICE") ("NUMROW") ("POINTLUN") ("SILENT") ("STARTROW") ("UNIXpipe")))
+ ("readfmt" pro nil (lib "readfmt.pro" nil "Astrolib") "%s, name, fmt, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25" (nil ("DEBUG") ("NUMLINE") ("SILENT") ("SKIPLINE")))
+ ("recpol" pro nil (lib "recpol.pro" nil "Astrolib") "%s, x, y, r, a" (nil ("degrees") ("help")))
+ ("rem_dup" fun nil (lib "rem_dup.pro" nil "Astrolib") "Result = %s(a, flag)" (nil))
+ ("remchar" pro nil (lib "remchar.pro" nil "Astrolib") "%s, st, char" (nil))
+ ("remove" pro nil (lib "remove.pro" nil "Astrolib") "%s, index, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25" (nil))
+ ("repchr" fun nil (lib "repchr.pro" nil "Astrolib") "Result = %s(In_String, OldChar, NewChar)" (nil))
+ ("repstr" fun nil (lib "repstr.pro" nil "Astrolib") "Result = %s(obj, in, out)" (nil))
+ ("RESISTANT_Mean" pro nil (lib "resistant_mean.pro" nil "Astrolib") "%s, Y, CUT, Mean, Sigma, Num_Rej" (nil ("dimension") ("double") ("goodvec") ("Silent") ("sumdim") ("wused")))
+ ("RINTER" fun nil (lib "rinter.pro" nil "Astrolib") "Result = %s(P, X, Y, DFDX, DFDY)" (nil ("INITIALIZE")))
+ ("ROB_CHECKFIT" fun nil (lib "rob_checkfit.pro" nil "Astrolib") "Result = %s(Y, YFIT, EPS, DEL, SIG, FRACDEV, NGOOD, W, B)" (nil ("BISQUARE_LIMIT")))
+ ("ROBUST_LINEFIT" fun nil (lib "robust_linefit.pro" nil "Astrolib") "Result = %s(XIN, YIN, YFIT, SIG, SS)" (nil ("BISECT") ("Bisquare_Limit") ("Close_Factor") ("NUMIT")))
+ ("ROBUST_POLY_FIT" fun nil (lib "robust_poly_fit.pro" nil "Astrolib") "Result = %s(X, Y, NDEG, YFIT, SIG)" (nil ("DOUBLE") ("NUMIT")))
+ ("ROBUST_SIGMA" fun nil (lib "robust_sigma.pro" nil "Astrolib") "Result = %s(Y)" (nil ("GOODVEC") ("ZERO")))
+ ("select_w_event" pro nil (lib "select_w.pro" nil "Astrolib") "%s, event" (nil))
+ ("select_w" pro nil (lib "select_w.pro" nil "Astrolib") "%s, items, iselected, comments, command_line, only_one" (nil ("columns") ("Count") ("GROUP_LEADER") ("selectin") ("y_scroll_size")))
+ ("get_pipe_filesize" pro nil (lib "get_pipe_filesize.pro" nil "Astrolib") "%s, unit, nbytes" (nil ("buffer")))
+ ("sigma_filter" fun nil (lib "sigma_filter.pro" nil "Astrolib") "Result = %s(image, box_width)" (nil ("ALL_PIXELS") ("DEVIATION_IMAGE") ("ITERATE") ("KEEP_OUTLIERS") ("MONITOR") ("N_CHANGE") ("N_SIGMA") ("RADIUS") ("VARIANCE_IMAGE")))
+ ("SIGRANGE" fun nil (lib "sigrange.pro" nil "Astrolib") "Result = %s(ARRAY)" (nil ("FRACTION") ("MISSING") ("RANGE")))
+ ("sixlin" pro nil (lib "sixlin.pro" nil "Astrolib") "%s, xx, yy, a, siga, b, sigb" (nil ("weight")))
+ ("sixty" fun nil (lib "sixty.pro" nil "Astrolib") "Result = %s(scalar)" (nil ("Trailsign")))
+ ("sky" pro nil (lib "sky.pro" nil "Astrolib") "%s, image, skymode, skysig" (nil ("_EXTRA") ("CIRCLERAD") ("MEANBACK") ("NAN") ("SILENT")))
+ ("EXTRAP" pro nil (lib "skyadj_cube.pro" nil "Astrolib") "%s, Deg, X, Y, Y2" (nil ("LIMS")))
+ ("SKYADJ_CUBE" pro nil (lib "skyadj_cube.pro" nil "Astrolib") "%s, Datacube, Skyvals, Totsky" (nil ("EDEGREE") ("EXTRAPR") ("INPUT_MASK") ("NOEDIT") ("REGION") ("SELECT") ("VERBOSE") ("XMEDSKY")))
+ ("spec_dir" fun nil (lib "spec_dir.pro" nil "Astrolib") "Result = %s(filename, extension)" (nil))
+ ("sphdist" fun nil (lib "sphdist.pro" nil "Astrolib") "Result = %s(long1, lat1, long2, lat2)" (nil ("degrees") ("help")))
+ ("srcor" pro nil (lib "srcor.pro" nil "Astrolib") "%s, x1in, y1in, x2in, y2in, dcr, ind1, ind2" (nil ("count") ("magnitude") ("option") ("silent") ("spherical")))
+ ("st_diskread" pro nil (lib "st_diskread.pro" nil "Astrolib") "%s, infiles" (nil ("DUMP")))
+ ("st_disk_data" pro nil (lib "st_diskread.pro" nil "Astrolib") "%s, unit, h, data, name, gcount, dimen, opsize, nbytes, itype" (nil))
+ ("st_disk_table" pro nil (lib "st_diskread.pro" nil "Astrolib") "%s, unit, h, data, table_available" (nil))
+ ("st_disk_geis" pro nil (lib "st_diskread.pro" nil "Astrolib") "%s, h, data, htab, tab, table_available, name, gcount, dimen, opsize, nbytes_g, itype" (nil))
+ ("starast" pro nil (lib "starast.pro" nil "Astrolib") "%s, ra, dec, x, y, cd" (nil ("hdr") ("projection") ("righthanded")))
+ ("STORE_ARRAY" pro nil (lib "store_array.pro" nil "Astrolib") "%s, DESTINATION, INSERT, INDEX" (nil))
+ ("STR_INDEX" fun nil (lib "str_index.pro" nil "Astrolib") "Result = %s(str, substr, offset)" (nil))
+ ("strcompress2" fun nil (lib "strcompress2.pro" nil "Astrolib") "Result = %s(str, chars)" (nil))
+ ("strn" fun nil (lib "strn.pro" nil "Astrolib") "Result = %s(number)" (nil ("FORMAT") ("LENGTH") ("PADCHAR") ("PADTYPE")))
+ ("strnumber" fun nil (lib "strnumber.pro" nil "Astrolib") "Result = %s(st, val)" (nil ("hex") ("L64") ("NaN")))
+ ("substar" pro nil (lib "substar.pro" nil "Astrolib") "%s, image, x, y, mag, id, psfname" (nil ("VERBOSE")))
+ ("sunpos" pro nil (lib "sunpos.pro" nil "Astrolib") "%s, jd, ra, dec, longmed, oblt" (nil ("RADIAN")))
+ ("sunsymbol" fun nil (lib "sunsymbol.pro" nil "Astrolib") "Result = %s" (nil ("FONT")))
+ ("sxaddhist" pro nil (lib "sxaddhist.pro" nil "Astrolib") "%s, history, header" (nil ("blank") ("comment") ("location") ("pdu")))
+ ("sxaddpar" pro nil (lib "sxaddpar.pro" nil "Astrolib") "%s, Header, Name, Value, Comment, Location" (nil ("after") ("before") ("format") ("missing") ("null") ("pdu") ("savecomment")))
+ ("sxdelpar" pro nil (lib "sxdelpar.pro" nil "Astrolib") "%s, h, parname" (nil))
+ ("sxginfo" pro nil (lib "sxginfo.pro" nil "Astrolib") "%s, h, par, type, sbyte, nbytes" (nil))
+ ("sxgpar" fun nil (lib "sxgpar.pro" nil "Astrolib") "Result = %s(h, par, name, type, sbyte, nbytes)" (nil))
+ ("sxgread" fun nil (lib "sxgread.pro" nil "Astrolib") "Result = %s(unit, group)" (nil))
+ ("sxhcopy" pro nil (lib "sxhcopy.pro" nil "Astrolib") "%s, h, keyword1, keyword2, hout" (nil))
+ ("sxhmake" pro nil (lib "sxhmake.pro" nil "Astrolib") "%s, data, groups, header" (nil))
+ ("sxhread" pro nil (lib "sxhread.pro" nil "Astrolib") "%s, name, header" (nil))
+ ("sxhwrite" pro nil (lib "sxhwrite.pro" nil "Astrolib") "%s, name, h" (nil))
+ ("sxmake" pro nil (lib "sxmake.pro" nil "Astrolib") "%s, unit, File, Data, Par, Groups, Header" (nil ("PSIZE")))
+ ("SXOPEN" pro nil (lib "sxopen.pro" nil "Astrolib") "%s, unit, fname, header, history, access" (nil))
+ ("SXPAR" fun nil (lib "sxpar.pro" nil "Astrolib") "Result = %s(hdr, name, abort)" (nil ("COMMENT") ("COUNT") ("IFound") ("MISSING") ("NAN") ("NoContinue") ("NULL") ("SILENT")))
+ ("sxread" fun nil (lib "sxread.pro" nil "Astrolib") "Result = %s(unit, group, par)" (nil))
+ ("SXWRITE" pro nil (lib "sxwrite.pro" nil "Astrolib") "%s, Unit, Data, Par" (nil))
+ ("ymd2dn" fun nil (lib "ymd2dn.pro" nil "Astrolib") "Result = %s(yr, m, d)" (nil ("help")))
+ ("t_aper" pro nil (lib "t_aper.pro" nil "Astrolib") "%s, image, fitsfile, apr, skyrad, badpix" (nil ("EXACT") ("NEWTABLE") ("PRINT") ("SETSKYVAL") ("SILENT")))
+ ("t_find" pro nil (lib "t_find.pro" nil "Astrolib") "%s, image, im_hdr, fitsfile, hmin, fwhm, sharplim, roundlim" (nil ("PRINT") ("SILENT")))
+ ("t_getpsf" pro nil (lib "t_getpsf.pro" nil "Astrolib") "%s, image, fitsfile, idpsf, psfrad, fitrad, psfname" (nil ("DEBUG") ("NEWTABLE")))
+ ("t_group" pro nil (lib "t_group.pro" nil "Astrolib") "%s, fitsfile, rmax" (nil ("NEWTABLE") ("xpar") ("ypar")))
+ ("t_nstar" pro nil (lib "t_nstar.pro" nil "Astrolib") "%s, image, fitsfile, psfname, groupsel" (nil ("DEBUG") ("NEWTABLE") ("PRINT") ("SILENT") ("VARSKY")))
+ ("t_substar" pro nil (lib "t_substar.pro" nil "Astrolib") "%s, image, fitsfile, id, psfname" (nil ("NOPSF") ("VERBOSE")))
+ ("sip_eval" fun nil (lib "sip_eval.pro" nil "Astrolib") "Result = %s(xy)" (nil))
+ ("file_launch" pro nil (lib "file_launch.pro" nil "Astrolib") "%s, file" (nil ("bUseJava") ("Nowait") ("ojDesktop") ("quiet")))
+ ("TPV_eval" fun nil (lib "tpv_eval.pro" nil "Astrolib") "Result = %s(xy)" (nil))
+ ("TNX_eval" fun nil (lib "tnx_eval.pro" nil "Astrolib") "Result = %s(xy)" (nil))
+ ("xi_solve_tpv" fun nil (lib "solve_astro.pro" nil "Astrolib") "Result = %s(xpixel, ypixel, pv1)" (nil ("TPVINFO")))
+ ("eta_solve_tpv" fun nil (lib "solve_astro.pro" nil "Astrolib") "Result = %s(xpixel, ypixel, pv2)" (nil ("TPVINFO")))
+ ("eta_solve_tnx" fun nil (lib "solve_astro.pro" nil "Astrolib") "Result = %s(xpixel, ypixel, params)" (nil ("TNXINFO")))
+ ("xi_solve_tnx" fun nil (lib "solve_astro.pro" nil "Astrolib") "Result = %s(xpixel, ypixel, params)" (nil ("TNXINFO")))
+ ("solve_astro" fun nil (lib "solve_astro.pro" nil "Astrolib") "Result = %s(radeg, decdeg, xpixel, ypixel)" (nil ("CRVAL") ("DISTORT") ("ETAORDER") ("ETARESID") ("ETARMS") ("n_tpvterms") ("NAXIS1") ("NAXIS2") ("NITER") ("NORTERMS") ("NREJ") ("REJECT") ("SUCCESS") ("VERBOSE") ("WFIT") ("XIORDER") ("XIRESID") ("XIRMS") ("XTERMS")))
+ ("TABINV" pro nil (lib "tabinv.pro" nil "Astrolib") "%s, XARR, X, IEFF" (nil ("FAST")))
+ ("tag_exist" fun nil (lib "tag_exist.pro" nil "Astrolib") "Result = %s(str, tag)" (nil ("index") ("quiet") ("recurse") ("top_level")))
+ ("tbdelcol" pro nil (lib "tbdelcol.pro" nil "Astrolib") "%s, h, tab, name" (nil))
+ ("tbdelrow" pro nil (lib "tbdelrow.pro" nil "Astrolib") "%s, h, tab, rows" (nil))
+ ("tbget" fun nil (lib "tbget.pro" nil "Astrolib") "Result = %s(hdr_or_tbstr, tab, field, rows, nulls)" (nil ("CONTINUE") ("NOSCALE")))
+ ("tbhelp" pro nil (lib "tbhelp.pro" nil "Astrolib") "%s, h" (nil ("TEXTOUT")))
+ ("tbinfo" pro nil (lib "tbinfo.pro" nil "Astrolib") "%s, h, tb_str" (nil ("errmsg") ("NOSCALE")))
+ ("tbprint" pro nil (lib "tbprint.pro" nil "Astrolib") "%s, hdr_or_tbstr, tab, columns, rows" (nil ("fmt") ("num_header_lines") ("nval_per_line") ("textout")))
+ ("tbsize" pro nil (lib "tbsize.pro" nil "Astrolib") "%s, h, tab, ncols, nrows, tfields, ncols_all, nrows_all" (nil))
+ ("tdb2tdt_calc" fun nil (lib "tdb2tdt.pro" nil "Astrolib") "Result = %s(jd)" (nil ("deriv") ("tbase")))
+ ("tdb2tdt" fun nil (lib "tdb2tdt.pro" nil "Astrolib") "Result = %s(jd)" (nil ("deriv") ("tbase")))
+ ("ten" fun nil (lib "ten.pro" nil "Astrolib") "Result = %s(dd, mm, ss)" (nil))
+ ("tenv" fun nil (lib "tenv.pro" nil "Astrolib") "Result = %s(dd, mm, ss)" (nil))
+ ("textclose" pro nil (lib "textclose.pro" nil "Astrolib") "%s" (nil ("textout")))
+ ("TEXTOPEN" pro nil (lib "textopen.pro" nil "Astrolib") "%s, PROGRAM" (nil ("MORE_SET") ("SILENT") ("STDOUT") ("TEXTOUT") ("WIDTH")))
+ ("tic_one" pro nil (lib "tic_one.pro" nil "Astrolib") "%s, min, pixx, incr, min2, tic1" (nil ("RA")))
+ ("ticlabels" pro nil (lib "ticlabels.pro" nil "Astrolib") "%s, minval, numtics, incr, ticlabs" (nil ("DELTA") ("FONT") ("RA")))
+ ("ticpos" pro nil (lib "ticpos.pro" nil "Astrolib") "%s, deglen, pixlen, ticsize, incr, units" (nil))
+ ("tics" pro nil (lib "tics.pro" nil "Astrolib") "%s, radec_min, radec_max, numx, ticsize, incr" (nil ("RA")))
+ ("TO_HEX" fun nil (lib "to_hex.pro" nil "Astrolib") "Result = %s(D, NCHAR)" (nil))
+ ("transform_coeff" fun nil (lib "transform_coeff.pro" nil "Astrolib") "Result = %s(coeff, alpha, beta)" (nil))
+ ("trapzd" pro nil (lib "trapzd.pro" nil "Astrolib") "%s, func, a, b, s, step" (nil ("_EXTRA")))
+ ("tsc" fun nil (lib "tsc.pro" nil "Astrolib") "Result = %s(value, posx, nx, posy, ny, posz, nz)" (nil ("AVERAGE") ("ISOLATED") ("NO_MESSAGE") ("WRAPAROUND")))
+ ("TSUM" fun nil (lib "tsum.pro" nil "Astrolib") "Result = %s(X, Y, IMIN, IMAX)" (nil ("NAN")))
+ ("tvbox" pro nil (lib "tvbox.pro" nil "Astrolib") "%s, width, x, y, color" (nil ("_EXTRA") ("ANGLE") ("Color") ("DATA") ("DEVICE") ("SQUARE")))
+ ("Tvcircle" pro nil (lib "tvcircle.pro" nil "Astrolib") "%s, radius, xc, yc, color" (nil ("_Extra") ("COLOR") ("DATA") ("Device") ("FILL")))
+ ("tvellipse" pro nil (lib "tvellipse.pro" nil "Astrolib") "%s, rmax, rmin, xc, yc, pos_ang, color" (nil ("_Extra") ("COLOR") ("DATA") ("DEVICE") ("FILL") ("MAJOR") ("MINOR") ("NPOINTS")))
+ ("TVLASER" pro nil (lib "tvlaser.pro" nil "Astrolib") "%s, hdr, Image" (nil ("BARPOS") ("BOTTOMDW") ("CARROWS") ("CLABELS") ("COLORPS") ("COMMENTS") ("CSIZE") ("CTITLE") ("DX") ("DY") ("ENCAP") ("FILENAME") ("HEADER") ("HELP") ("IMAGEOut") ("INTERP") ("MAGNIFY") ("NCOLORSDW") ("NO_PERS_INFO") ("NoClose") ("NODELETE") ("NOEIGHT") ("NOPRINT") ("NORETAIN") ("PORTRAIT") ("PRINTER") ("REVERSE") ("SCALE") ("TITLE") ("TrueColor") ("XDIM") ("XSTART") ("YDIM") ("YSTART")))
+ ("tvlist" pro nil (lib "tvlist.pro" nil "Astrolib") "%s, image, dx, dy" (nil ("OFFSET") ("TEXTOUT") ("ZOOM")))
+ ("unzoom_xy" pro nil (lib "unzoom_xy.pro" nil "Astrolib") "%s, xtv, ytv, xim, yim" (nil ("OFFSET") ("ZOOM")))
+ ("update_distort" pro nil (lib "update_distort.pro" nil "Astrolib") "%s, distort, xcoeff, ycoeff" (nil))
+ ("uvbybeta" pro nil (lib "uvbybeta.pro" nil "Astrolib") "%s, xby, xm1, xc1, xHbeta, xn, Te, MV, eby, delm0, radius" (nil ("eby_in") ("name") ("print") ("prompt") ("TEXTOUT")))
+ ("vactoair" pro nil (lib "vactoair.pro" nil "Astrolib") "%s, wave_vac, wave_air" (nil))
+ ("valid_num" fun nil (lib "valid_num.pro" nil "Astrolib") "Result = %s(string, value)" (nil ("INTEGER")))
+ ("VECT" fun nil (lib "vect.pro" nil "Astrolib") "Result = %s(vctr, form)" (nil ("delim") ("Format")))
+ ("VSYM" pro nil (lib "vsym.pro" nil "Astrolib") "%s, Nvert" (nil ("FILL") ("POLYGON") ("ROT") ("SKELETON") ("STAR") ("THICK")))
+ ("wcssph2xy_plot" pro nil (lib "wcs_demo.pro" nil "Astrolib") "%s, file_unit, map, param1, param2" (nil))
+ ("inversion_error" pro nil (lib "wcs_demo.pro" nil "Astrolib") "%s, file_unit, map, param1, param2" (nil))
+ ("wcs_rot" pro nil (lib "wcs_demo.pro" nil "Astrolib") "%s, file_unit, map, param1, param2" (nil))
+ ("wcs_demo" pro nil (lib "wcs_demo.pro" nil "Astrolib") "%s" (nil))
+ ("WCS_GETPOLE" pro nil (lib "wcs_getpole.pro" nil "Astrolib") "%s, crval, lonpole, theta0, alpha_p, delta_p" (nil ("AT_POLE") ("LATPOLE")))
+ ("wcs_rotate" pro nil (lib "wcs_rotate.pro" nil "Astrolib") "%s, longitude, latitude, phi, theta, crval" (nil ("LATPOLE") ("LONGPOLE") ("ORIGIN") ("PV1") ("REVERSE") ("THETA0")))
+ ("wcssph2xy" pro nil (lib "wcssph2xy.pro" nil "Astrolib") "%s, longitude, latitude, x, y, map_type" (nil ("badindex") ("crval") ("crxy") ("ctype") ("face") ("latpole") ("longpole") ("north_offset") ("pv1") ("pv2") ("south_offset")))
+ ("wcsxy2sph" pro nil (lib "wcsxy2sph.pro" nil "Astrolib") "%s, x, y, longitude, latitude, map_type" (nil ("crval") ("crxy") ("ctype") ("face") ("Latpole") ("longpole") ("pv1") ("pv2")))
+ ("MimeType" pro nil (lib "webget.pro" nil "Astrolib") "%s, Header, Class, Type, Length" (nil))
+ ("webget" fun nil (lib "webget.pro" nil "Astrolib") "Result = %s(url)" (nil ("COPYFILE") ("HTTP10") ("POST") ("SILENT") ("timeout")))
+ ("wfpc2_metric" pro nil (lib "wfpc2_metric.pro" nil "Astrolib") "%s, xin, yin, xout, yout, chip" (nil ("FILTER") ("GLOBAL") ("Header") ("RADec") ("YEAR")))
+ ("wfpc2_read" pro nil (lib "wfpc2_read.pro" nil "Astrolib") "%s, filename, chip1, header1, chip2, header2, chip3, header3, chip4, header4" (nil ("batwing") ("num_chip") ("path") ("trim")))
+ ("where_Tag" fun nil (lib "where_tag.pro" nil "Astrolib") "Result = %s(Struct, Nfound)" (nil ("ISELECT") ("NOPRINT") ("RANGE") ("TAG_NAME") ("TAG_NUMBER") ("VALUES")))
+ ("WHERENAN" fun nil (lib "wherenan.pro" nil "Astrolib") "Result = %s(ARRAY, COUNT)" (nil))
+ ("writefits" pro nil (lib "writefits.pro" nil "Astrolib") "%s, filename, data, header, heap" (nil ("Append") ("CheckSum") ("compress") ("NaNValue")))
+ ("XDISPSTR_EVENT" pro nil (lib "xdispstr.pro" nil "Astrolib") "%s, Event" (nil))
+ ("XDISPSTR_CLEANUP" pro nil (lib "xdispstr.pro" nil "Astrolib") "%s, Id" (nil))
+ ("XDISPSTR" pro nil (lib "xdispstr.pro" nil "Astrolib") "%s, Array" (nil ("BLOCK") ("FONT") ("GROUP_LEADER") ("HEIGHT") ("POS") ("TITLE") ("top_line") ("WIDTH")))
+ ("XMEDSKY" pro nil (lib "xmedsky.pro" nil "Astrolib") "%s, Image, Bkg" (nil ("CLIP") ("Nsig")))
+ ("xy2ad" pro nil (lib "xy2ad.pro" nil "Astrolib") "%s, x, y, astr, a, d" (nil))
+ ("xyad" pro nil (lib "xyad.pro" nil "Astrolib") "%s, hdr, x, y, a, d" (nil ("ALT") ("CELESTIAL") ("ECLIPTIC") ("GALACTIC") ("PRECISION") ("PRINT")))
+ ("xyxy" pro nil (lib "xyxy.pro" nil "Astrolib") "%s, hdra, hdrb, xa, ya, xb, yb" (nil))
+ ("xyz" pro nil (lib "xyz.pro" nil "Astrolib") "%s, date, x, y, z, xvel, yvel, zvel" (nil ("equinox")))
+ ("YDN2MD" pro nil (lib "ydn2md.pro" nil "Astrolib") "%s, YR, DY, M, D" (nil ("help")))
+ ("zang" fun nil (lib "zang.pro" nil "Astrolib") "Result = %s(dl, z)" (nil ("h0") ("k") ("Lambda0") ("Omega_m") ("q0") ("SILENT")))
+ ("ZBRENT" fun nil (lib "zbrent.pro" nil "Astrolib") "Result = %s(x1, x2)" (nil ("_EXTRA") ("FUNC_NAME") ("MAX_ITERATIONS") ("TOLERANCE")))
+ ("ZENPOS" pro nil (lib "zenpos.pro" nil "Astrolib") "%s, date, ra, dec" (nil))
+ ("zoom_xy" pro nil (lib "zoom_xy.pro" nil "Astrolib") "%s, xim, yim, xtv, ytv" (nil ("OFFSET") ("ZOOM")))
+ ("zparcheck" pro nil (lib "zparcheck.pro" nil "Astrolib") "%s, progname, parameter, parnum, types, dimens, message" (nil))
+ ("al_legendtest" pro nil (lib "al_legendtest.pro" nil "Astrolib") "%s" (nil))
+ ("wcs_check_ctype" pro nil (lib "wcs_check_ctype.pro" nil "Astrolib") "%s, ctype, projection_type, coord_type" (nil))
+ ("query_irsa_cat" fun nil (lib "query_irsa_cat.pro" nil "Astrolib") "Result = %s(targetname_OR_coords)" (nil ("catalog") ("change_null") ("DEBUG") ("outfile") ("radius") ("radunits")))
+ ("read_ipac_table" fun nil (lib "read_ipac_table.pro" nil "Astrolib") "Result = %s(filename)" (nil ("change_null") ("debug")))
+ ("read_ipac_var" fun nil (lib "read_ipac_var.pro" nil "Astrolib") "Result = %s(textvar)" (nil ("change_null") ("debug")))
+ ("write_ipac_table" pro nil (lib "write_ipac_table.pro" nil "Astrolib") "%s, in_struct, outfile" (nil ("exact_format") ("format") ("short_format")))
+ ("errtype" fun nil (lib "safe_correlate.pro" nil "Astrolib") "Result = %s(err, bad_err_msg)" (nil))
+ ("vet_err" pro nil (lib "safe_correlate.pro" nil "Astrolib") "%s, err, errtype, n, bad_err_msg" (nil))
+ ("generate_data" fun nil (lib "safe_correlate.pro" nil "Astrolib") "Result = %s(v, err, type, n, nsim, dbl, seed)" (nil))
+ ("safe_correlate" fun nil (lib "safe_correlate.pro" nil "Astrolib") "Result = %s(x, y, xerr, yerr)" (nil ("nsim") ("seed")))))
diff --git a/Code/script_idl_mv/astrolib/ad2xy.pro b/Code/script_idl_mv/astrolib/ad2xy.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ef148b0c390e238c3c4843d4c09bce4c957a32bb
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ad2xy.pro
@@ -0,0 +1,326 @@
+pro ad2xy, a, d, astr, x, y
+;+
+; NAME:
+; AD2XY
+; PURPOSE:
+; Compute X and Y from native coordinates and a FITS astrometry structure
+; EXPLANATION:
+; If a WCS projection (Calabretta & Greisen 2002, A&A, 395, 1077) is
+; present, then the procedure WCSXY2SPH is used to compute native
+; coordinates. If distortion is present then this is corrected.
+; In all cases, the inverse of the CD matrix is applied and offset
+; from the reference pixel to obtain X and Y.
+;
+; AD2XY is generally meant to be used internal to other procedures. For
+; interactive purposes, use ADXY.
+;
+; CALLING SEQUENCE:
+; AD2XY, a ,d, astr, x, y
+;
+; INPUTS:
+; A - R.A. or longitude in DEGREES, scalar or vector.
+; D - Dec. or longitude in DEGREES, scalar or vector
+; If the input A and D are arrays with 2 or more dimensions,
+; they will be converted to a 1-D vectors.
+; ASTR - astrometry structure, output from EXTAST procedure containing:
+; .CD - 2 x 2 array containing the astrometry parameters CD1_1 CD1_2
+; in DEGREES/PIXEL CD2_1 CD2_2
+; .CDELT - 2 element vector giving increment at reference point in
+; DEGREES/PIXEL
+; .CRPIX - 2 element vector giving X and Y coordinates of reference pixel
+; (def = NAXIS/2) in FITS convention (first pixel is 1,1)
+; .CRVAL - 2 element vector giving coordinates of the reference pixel
+; in DEGREES
+; .CTYPE - 2 element vector giving projection types
+; .LONGPOLE - scalar longitude of north pole (default = 180)
+; .PV2 - Vector of additional parameter (e.g. PV2_1, PV2_2) needed in
+; some projections
+;
+; Fields added for version 2:
+; .PV1 - Vector of projection parameters associated with longitude axis
+; .AXES - 2 element integer vector giving the FITS-convention axis
+; numbers associated with astrometry, in ascending order.
+; Default [1,2].
+; .REVERSE - byte, true if first astrometry axis is Dec/latitude
+; .COORDSYS - 1 or 2 character code giving coordinate system, including
+; 'C' = RA/Dec, 'G' = Galactic, 'E' = Ecliptic, 'X' = unknown.
+; .RADECSYS - String giving RA/Dec system e.g. 'FK4', 'ICRS' etc.
+; .EQUINOX - Double giving the epoch of the mean equator and equinox
+; .DATEOBS - Text string giving (start) date/time of observations
+; .MJDOBS - Modified julian date of start of observations.
+; .X0Y0 - Implied offset in intermediate world coordinates if user has
+; specified a non-standard fiducial point via PV1 and also
+; has set PV1_0a =/ 0 to indicate that the offset should be
+; applied in order to place CRVAL at the IWC origin.
+; Should be *added* to the IWC derived from application of
+; CRPIX, CDELT, CD to the pixel coordinates.
+;
+; .DISTORT - Optional substructure specifying distortion parameters
+;
+; OUTPUTS:
+; X - row position in pixels, scalar or vector
+; Y - column position in pixels, scalar or vector
+;
+; X,Y will be in the standard IDL convention (first pixel is 0), and
+; *not* the FITS convention (first pixel is 1)
+; NOTES:
+; AD2XY tests for presence of WCS coordinates by the presence of a dash
+; in the 5th character position in the value of CTYPE (e.g 'DEC--SIN').
+; COMMON BLOCKS:
+; BROYDEN_COMMON - Used when solving for a reverse distortion tranformation
+; (either SIP or TGV) by iterating on the forward transformation.
+; PROCEDURES USED:
+; CGErrorMsg (from Coyote Library)
+; TAG_EXIST(), WCSSPH2XY
+; REVISION HISTORY:
+; Converted to IDL by B. Boothman, SASC Tech, 4/21/86
+; Use astrometry structure, W. Landsman Jan. 1994
+; Do computation correctly in degrees W. Landsman Dec. 1994
+; Only pass 2 CRVAL values to WCSSPH2XY W. Landsman June 1995
+; Don't subscript CTYPE W. Landsman August 1995
+; Understand reversed X,Y (X-Dec, Y-RA) axes, W. Landsman October 1998
+; Consistent conversion between CROTA and CD matrix W. Landsman October 2000
+; No special case for tangent projection W. Landsman June 2003
+; Work for non-WCS coordinate transformations W. Landsman Oct 2004
+; Use CRVAL reference point for non-WCS transformation W.L. March 2007
+; Use post V6.0 notation W.L. July 2009
+; Allows use of Version 2 astrometry structure & optimised for
+; large input arrays. Wrap test for cylindrical coords. J. P. Leahy July 2013
+; Wrap test failed for 2d input arrays
+; T. Ellsworth-Bowers/W.Landsman July 2013
+; Tweaked to restore shape of arrays on exit JPL Aug 2013.
+; ..and make them scalars if input is scalar JPL Aug 2013
+; Iterate when forward SIP coefficients are supplied but not the reverse
+; coefficients. Don't compute poles if not a cylindrical system
+; W. Landsman Dec 2013
+; Evaluate TPV distortion (SCAMP) if present W. Landsman Jan 2014
+; Support IRAF TNX projection M. Sullivan U. of Southhamptom Mar 2014
+; No longer check that CDELT[0] differs from 1 W. Landsman Apr 2015
+;
+;-
+
+ compile_opt idl2
+ common broyden_coeff, xcoeff, ycoeff
+
+
+ if N_params() lT 4 then begin
+ print,'Syntax -- AD2XY, a, d, astr, x, y'
+ return
+ endif
+
+ Catch, theError
+ IF theError NE 0 then begin
+ Catch,/Cancel
+ void = cgErrorMsg(/quiet)
+ RETURN
+ ENDIF
+
+ if tag_exist(astr,'DISTORT') && ((astr.distort.name EQ 'TPV') || (astr.distort.name EQ 'TNX')) then $
+ ctype = strmid(astr.ctype,0,4) + '-TAN' else ctype = astr.ctype
+ crval = astr.crval
+
+ testing = 0B
+ size_a = SIZE(a)
+ ndima = size_a[0]
+
+ astr2 = TAG_EXIST(astr,'AXES') ; version 2 astrometry structure
+ IF astr2 THEN reverse = astr.reverse ELSE BEGIN
+ coord = strmid(ctype,0,4)
+ reverse = ((coord[0] EQ 'DEC-') && (coord[1] EQ 'RA--')) || $
+ ((coord[0] EQ 'GLAT') && (coord[1] EQ 'GLON')) || $
+ ((coord[0] EQ 'ELAT') && (coord[1] EQ 'ELON'))
+ ENDELSE
+ if reverse then crval = rotate(crval,2) ;Invert CRVAL?
+
+ if (ctype[0] EQ '') then begin
+ ctype = ['RA---TAN','DEC--TAN']
+ message,'No CTYPE specified - assuming TANgent projection',/INF
+ endif
+
+ spherical = strmid(astr.ctype[0],4,1) EQ '-'
+ if spherical then begin
+ IF astr2 THEN BEGIN
+ cylin = WHERE(astr.projection EQ ['CYP','CAR','MER','CEA','HPX'],Ncyl)
+ IF Ncyl GT 0 THEN BEGIN
+ testing = 1
+ size_d = SIZE(d)
+ ndimd = size_d[0]
+ IF ndima GT 1 THEN a = REFORM(a, size_a[ndima+2], /OVERWRITE)
+ IF ndimd GT 1 THEN d = REFORM(d, size_d[ndimd+2], /OVERWRITE)
+ a0 = [a, 0d0,180d0] & d0 = [d, 0d0, 0d0] ; test points
+ wcssph2xy, a0, d0, xsi, eta, CTYPE = ctype, PV1 = astr.pv1, $
+ PV2 = astr.pv2, CRVAL = crval, CRXY = astr.x0y0
+ ENDIF ELSE BEGIN
+ pv1 = astr.pv1
+ pv2 = astr.pv2
+ if tag_exist(astr,'DISTORT') then $
+ if astr.distort.name EQ 'TPV' then begin
+ pv1 = [0.0d,0,90.0d,180d,90d] ;Tangent projection
+ pv2 = [0.0,0.0]
+ ENDIF
+ wcssph2xy, a, d, xsi, eta, CTYPE = ctype, PV1 = pv1, $
+ PV2 = pv2, CRVAL = crval, CRXY = astr.x0y0
+ ENDELSE
+ ENDIF ELSE wcssph2xy, a, d, xsi, eta, CTYPE = ctype, PV2 = astr.pv2, $
+ LONGPOLE = astr.longpole, CRVAL = crval, LATPOLE = astr.latpole
+ endif else begin
+ xsi = a - crval[0] & eta = d - crval[1]
+ endelse
+ cd = astr.cd
+ cdelt = astr.cdelt
+
+ cd[0,0] *= cdelt[0] & cd[0,1] *= cdelt[0]
+ cd[1,1] *= cdelt[1] & cd[1,0] *= cdelt[1]
+
+ if reverse then begin
+ temp = TEMPORARY(xsi) & xsi = TEMPORARY(eta) & eta = TEMPORARY(temp)
+ endif
+
+ if tag_exist(astr,'DISTORT') && (astr.distort.name EQ 'TPV') then begin
+ ctype = strmid(astr.ctype,0,4) + '-TAN'
+ xcoeff = astr.pv1
+ ycoeff = astr.pv2
+ x0 = xcoeff[0]
+ y0 = ycoeff[0]
+ for i=0, N_elements(xsi)-1 do begin
+ xcoeff[0] = x0 - xsi[i]
+ ycoeff[0] = y0 - eta[i]
+ res = broyden([xsi[i],eta[i]], 'TPV_EVAL' )
+ xsi[i] = res[0]
+ eta[i] = res[1]
+ endfor
+ ENDIF
+ if tag_exist(astr,'DISTORT') && (astr.distort.name EQ 'TNX') then begin
+ ctype = strmid(astr.ctype,0,4) + '-TAN'
+ xcoeff = astr.distort.lngcor
+ ycoeff = astr.distort.latcor
+ x0 = xcoeff.coeff[0]
+ y0 = ycoeff.coeff[0]
+ for i=0, N_elements(xsi)-1 do begin
+ xcoeff.coeff[0] = x0 - xsi[i]
+ ycoeff.coeff[0] = y0 - eta[i]
+ res = broyden([xsi[i],eta[i]], 'TNX_EVAL' )
+ xsi[i] = res[0]
+ eta[i] = res[1]
+ endfor
+ ENDIF
+
+ crpix = astr.crpix - 1
+
+ cdinv = invert(cd)
+ x = ( cdinv[0,0]*xsi + cdinv[0,1]*eta )
+ y = ( cdinv[1,0]*TEMPORARY(xsi) + cdinv[1,1]*TEMPORARY(eta) )
+
+ if tag_exist(astr,'DISTORT') && ( astr.distort.name EQ 'SIP') then begin
+ distort = astr.distort
+ ap = distort.ap
+ bp = distort.bp
+ na = ((size(ap,/dimen))[0])
+; If reverse SIP coefficients are not supplied we iterate on the forward
+; coefficients (using BROYDEN).
+ if na LE 1 then begin
+ xcoeff = distort.a
+ ycoeff = distort.b
+ x0 = xcoeff[0]
+ y0 = ycoeff[0]
+ for i=0, N_elements(x)-1 do begin
+ xcoeff[0] = x0 - x[i]
+ ycoeff[0] = y0 - y[i]
+ res = broyden([x[i],y[i]], 'SIP_EVAL' )
+ x[i] = res[0]
+ y[i] = res[1]
+ endfor
+ endif else begin
+ xdif1 = x
+ ydif1 = y
+ for i=0,na-1 do begin
+ for j=0,na-1 do begin
+ if ap[i,j] NE 0.0 then xdif1 += x^i*y^j*ap[i,j]
+ if bp[i,j] NE 0.0 then ydif1 += x^i*y^j*bp[i,j]
+ endfor
+ endfor
+
+ x = xdif1
+ y = ydif1
+ ENDELSE
+ ENDIF
+
+ x += crpix[0]
+ y += crpix[1]
+
+; Check for wrapping in cylindrical projections: since the same phi
+; appears at regular intervals in (x,y), depending on the location of
+; the reference point on the pixel grid, some of the returned pixel
+; values may be offset by 360 degrees from the ones we want.
+;
+; The pixel grid may be rotated relative to intermediate world coords,
+; so the offset may have both x and y components in pixel space.
+;
+; Doesn't try if native and astronomical poles are misaligned
+; as this fix doesn't work in that case.
+
+ IF testing THEN BEGIN
+ npt = N_ELEMENTS(a)
+ x0 = x[npt:npt+1] & y0 = y[npt:npt+1]
+ x = x[0:npt-1] & y = y[0:npt-1]
+
+ crval = astr.crval
+ IF astr.reverse THEN crval = REVERSE(crval)
+ WCS_GETPOLE, crval, astr.pv1[3]-astr.pv1[1], astr.pv1[2], $
+ alpha_p, delta_p, $
+ LATPOLE = astr.pv1[4], AT_POLE = at_pole
+ IF at_pole THEN BEGIN
+ naxis = astr.naxis
+ offmap = WHERE(x LT 0 OR y LT 0 OR $
+ x GT naxis[0] OR y GT naxis[1], noff)
+ IF offmap[0] NE -1 THEN BEGIN
+ ; 360 degree shift
+ x360 = 2d0*(x0[1] - x0[0])
+ y360 = 2d0*(y0[1] - y0[0])
+ IF x360 LT 0 THEN BEGIN
+ x360 *= -1d0
+ y360 *= -1d0
+ ENDIF
+ xshift = x360 NE 0d0
+ yshift = y360 NE 0d0
+ ; Figure out which direction shift is
+ IF xshift THEN BEGIN
+ IF (MIN(x[offmap],/NAN) LT 0) THEN BEGIN
+ x[offmap] += x360
+ IF yshift THEN y[offmap] += y360
+ ENDIF ELSE IF MAX(x[offmap],/NAN) GT naxis[0] THEN BEGIN
+ x[offmap] -= x360
+ IF yshift THEN y[offmap] -= y360
+ ENDIF
+ ENDIF ELSE BEGIN
+ IF y360 LT 0 THEN BEGIN
+ x360 *= -1d0
+ y360 *= -1d0
+ ENDIF
+ IF (MIN(y[offmap],/NAN) LT 0) THEN BEGIN
+ IF xshift THEN x[offmap] += x360
+ y[offmap] += y360
+ ENDIF ELSE BEGIN
+ IF xshift THEN x[offmap] -= x360
+ y[offmap] -= y360
+ ENDELSE
+ ENDELSE
+ ENDIF
+ ENDIF
+ ENDIF
+
+
+ IF ndima GT 1 THEN BEGIN
+ a = REFORM(a, size_a[1:ndima], /OVERWRITE)
+ d = REFORM(d, size_a[1:ndima], /OVERWRITE)
+ x = REFORM(x, size_a[1:ndima], /OVERWRITE)
+ y = REFORM(y, size_a[1:ndima], /OVERWRITE)
+ ENDIF ELSE if ndima EQ 0 THEN BEGIN
+ a = a[0]
+ d = d[0]
+ x = x[0]
+ y = y[0]
+ ENDIF
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/add_distort.pro b/Code/script_idl_mv/astrolib/add_distort.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ca871fddb88e5a93bb3eecf4e80611d7fae716bc
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/add_distort.pro
@@ -0,0 +1,161 @@
+ pro add_distort, hdr, astr
+; NAME:
+; ADD_DISTORT
+; PURPOSE:
+; Add the distortion parameters in an astrometry structure to a FITS header.
+; EXPLANATION:
+; Called by PUTAST to add SIP (http://fits.gsfc.nasa.gov/registry/sip.html )
+; or TNX ( http://fits.gsfc.nasa.gov/registry/tnx.html ) distortion
+; parameters in an astrometry structure to a FITS header
+;
+; Prior to April 2012, PUTAST did not add distortion parameters so one
+; had to call ADD_DISTORT after PUTAST.
+;
+; IDL> putast,h ,astr0
+; IDL> add_distort,h,astr0
+;
+; CALLING SEQUENCE:
+; add_distort, hdr, astr
+;
+; INPUTS:
+; HDR - FITS header, string array. HDR will be updated to contain
+; the supplied astrometry.
+; ASTR - IDL structure containing values of the astrometry parameters
+; CDELT, CRPIX, CRVAL, CTYPE, LONGPOLE, PV2, and DISTORT
+; See EXTAST.PRO for more info about the structure definition
+;
+; PROCEDURES USED:
+; SXADDPAR, TAG_EXIST()
+; REVISION HISTORY:
+; Written by W. Landsman May 2005
+; Enforce i+j = n for ij coefficients of order n W. Landsman April 2012
+; Support IRAF TNX distortion M. Sullivan March 2014
+;;-
+ npar = N_params()
+
+ if ( npar LT 2 ) then begin ;Was header supplied?
+ print,'Syntax: ADD_DISTORT, Hdr, astr'
+ return
+ endif
+
+ add_distort = tag_exist(astr,'distort')
+ IF(~ add_distort)THEN RETURN
+
+ IF(astr.distort.name EQ 'SIP') then begin
+
+ sxaddpar,hdr,'CTYPE1','RA---TAN-SIP'
+ sxaddpar,hdr,'CTYPE2','DEC--TAN-SIP'
+ distort = astr.distort
+ a_dimen = size(distort.a,/dimen)
+ b_dimen = size(distort.b,/dimen)
+ ap_dimen = size(distort.ap,/dimen)
+ bp_dimen = size(distort.bp,/dimen)
+
+ if a_dimen[0] GT 0 then begin
+ a_order = a_dimen[0]-1
+ sxaddpar, hdr, 'A_ORDER', a_order, /savec, $
+ 'polynomial order, axis 1, detector to sky '
+ for i=0, a_order do begin
+ for j = 0, a_order-i do begin
+ aij = distort.a[i,j]
+ if aij NE 0.0 then $
+ sxaddpar, hdr, 'A_' + strtrim(i,2)+ '_' + strtrim(j,2), aij, $
+ ' distortion coefficient', /savec
+ endfor
+ endfor
+ endif
+
+ if b_dimen[0] GT 0 then begin
+ b_order = b_dimen[0]-1
+ sxaddpar, hdr, 'B_ORDER', a_order, /savec , $
+ 'polynomial order, axis 2, detector to sky'
+ for i=0, b_order do begin
+ for j = 0, b_order-i do begin
+ bij = distort.b[i,j]
+ if bij NE 0.0 then $
+ sxaddpar, hdr, 'B_' + strtrim(i,2)+ '_' + strtrim(j,2), bij, $
+ ' distortion coefficient', /savec
+ endfor
+ endfor
+ endif
+
+ if ap_dimen[0] GT 0 then begin
+ ap_order = ap_dimen[0]-1
+ sxaddpar, hdr, 'AP_ORDER', a_order, /savec, $
+ ' polynomial order, axis 1, sky to detector '
+ for i=0, ap_order do begin
+ for j = 0, ap_order-i do begin
+ apij = distort.ap[i,j]
+ if apij NE 0.0 then $
+ sxaddpar, hdr, 'AP_' + strtrim(i,2)+ '_' + strtrim(j,2), apij, $
+ ' distortion coefficient', /savec
+ endfor
+ endfor
+ endif
+
+
+ if bp_dimen[0] GT 0 then begin
+ bp_order = bp_dimen[0]-1
+ sxaddpar, hdr, 'BP_ORDER', a_order, /savec, $
+ ' polynomial order, axis 2, sky to detector '
+ for i=0, bp_order do begin
+ for j = 0, bp_order-i do begin
+ bpij = distort.bp[i,j]
+ if bpij NE 0.0 then $
+ sxaddpar, hdr, 'BP_' + strtrim(i,2)+ '_' + strtrim(j,2), bpij, $
+ ' distortion coefficient', /savec
+ endfor
+ endfor
+ endif
+
+ ENDIF ELSE IF(astr.distort.name EQ 'TNX')THEN BEGIN
+
+ sxaddpar, hdr,'WAT0_001','system=image'
+
+ string1='wtype=tnx axtype=ra lngcor = "3.'
+ string1+= ' '+STRN(astr.distort.lngcor.xiorder,FORMAT='(F2.0)')
+ string1+= ' '+STRN(astr.distort.lngcor.etaorder,FORMAT='(F2.0)')
+ string1+= ' '+STRN(astr.distort.lngcor.xterms,FORMAT='(F2.0)')
+ string1+= ' '+STRN(astr.distort.lngcor.ximin,FORMAT='(F19.16)')
+ string1+= ' '+STRN(astr.distort.lngcor.ximax,FORMAT='(F19.16)')
+ string1+= ' '+STRN(astr.distort.lngcor.etamin,FORMAT='(F19.16)')
+ string1+= ' '+STRN(astr.distort.lngcor.etamax,FORMAT='(F19.16)')
+ FOR i=0,N_ELEMENTS(astr.distort.lngcor.coeff)-1 DO BEGIN
+ string1+=' '+STRN(astr.distort.lngcor.coeff[i],FORMAT='(F19.16)')
+ ENDFOR
+ string1+= '"'
+
+ string2='wtype=tnx axtype=dec latcor = "3. '
+ string2+= ' '+STRN(astr.distort.latcor.xiorder,FORMAT='(F2.0)')
+ string2+= ' '+STRN(astr.distort.latcor.etaorder,FORMAT='(F2.0)')
+ string2+= ' '+STRN(astr.distort.latcor.xterms,FORMAT='(F2.0)')
+ string2+= ' '+STRN(astr.distort.latcor.ximin,FORMAT='(F19.16)')
+ string2+= ' '+STRN(astr.distort.latcor.ximax,FORMAT='(F19.16)')
+ string2+= ' '+STRN(astr.distort.latcor.etamin,FORMAT='(F19.16)')
+ string2+= ' '+STRN(astr.distort.latcor.etamax,FORMAT='(F19.16)')
+ FOR i=0,N_ELEMENTS(astr.distort.latcor.coeff)-1 DO BEGIN
+ string2+= ' '+STRN(astr.distort.latcor.coeff[i],FORMAT='(F19.16)')
+ ENDFOR
+ string2+= '"'
+
+ len1=STRLEN(string1)
+ n1=len1/70
+ IF(len1 MOD 68 GT 0)THEN n1++
+ FOR i=0,n1-1 DO BEGIN
+ s=STRMID(string1,i*68,68)
+; PRINT,'WAT1_'+STRN(i+1,FORMAT='(I3.3)'),' ',s
+ sxaddpar, hdr,'WAT1_'+STRN(i+1,FORMAT='(I3.3)'),s
+ ENDFOR
+ len2=STRLEN(string2)
+ n2=len2/70
+ IF(len2 MOD 68 GT 0)THEN n2++
+ FOR i=0,n2-1 DO BEGIN
+ s=STRMID(string2,i*68,68)
+; PRINT,'WAT1_'+STRN(i+1,FORMAT='(I3.3)'),' ',s
+ sxaddpar, hdr,'WAT2_'+STRN(i+1,FORMAT='(I3.3)'),s
+ ENDFOR
+
+ ENDIF
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/adstring.pro b/Code/script_idl_mv/astrolib/adstring.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3e0ba1332ea861078cea8b845d7714053ef302db
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/adstring.pro
@@ -0,0 +1,208 @@
+Function adstring,ra_dec,dec,precision, TRUNCATE = truncate,PRECISION=prec
+;+
+; NAME:
+; ADSTRING
+; PURPOSE:
+; Return RA and Dec as character string(s) in sexagesimal format.
+; EXPLANATION:
+; RA and Dec may be entered as either a 2 element vector or as
+; two separate vectors (or scalars). One can also specify the precision
+; of the declination in digits after the decimal point.
+;
+; CALLING SEQUENCE
+; result = ADSTRING( ra_dec, precision, /TRUNCATE )
+; or
+; result = ADSTRING( ra,dec,[ precision, /TRUNCATE ] )
+; or
+; result = ADSTRING( dec, [ PRECISION= ]
+;
+; INPUTS:
+; RA_DEC - 2 element vector giving the Right Ascension and declination
+; in decimal degrees.
+; or
+; RA - Right ascension in decimal degrees, numeric scalar or vector
+; DEC - Declination in decimal degrees, numeric scalar or vector
+;
+; If only one parameter is supplied then it must be either a scalar (which
+; is converted to sexagesimal) or a two element [RA, Dec] vector.
+; OPTIONAL INPUT:
+; PRECISION - Integer scalar (0-4) giving the number of digits after the
+; decimal of DEClination. The RA is automatically 1 digit more.
+; This parameter may either be the third parameter after RA,DEC
+; or the second parameter after [RA,DEC]. If only DEC is supplied
+; then precision must be supplied as a keyword parameter. If no
+; PRECISION parameter or keyword is passed, a precision of 1 for
+; both RA and DEC is returned to maintain compatibility with past
+; ADSTRING versions. Values of precision larger than 4 will
+; be truncated to 4. If PRECISION is 3 or 4, then RA and Dec
+; should be input as double precision.
+; OPTIONAL INPUT KEYWORD:
+; /TRUNCATE - if set, then the last displayed digit in the output is
+; truncated in precision rather than rounded. This option is
+; useful if ADSTRING() is used to form an official IAU name
+; (see http://vizier.u-strasbg.fr/Dic/iau-spec.htx) with
+; coordinate specification. The IAU name will typically be
+; be created by applying STRCOMPRESS/REMOVE) after the ADSTRING()
+; call, e.g.
+; strcompress( adstring(ra,dec,0,/truncate), /remove) ;IAU format
+; PRECISION = Alternate method of supplying the precision parameter,
+; OUTPUT:
+; RESULT - Character string(s) containing HR,MIN,SEC,DEC,MIN,SEC formatted
+; as ( 2I3,F5.(p+1),2I3,F4.p ) where p is the PRECISION
+; parameter. If only a single scalar is supplied it is
+; converted to a sexagesimal string (2I3,F5.1).
+;
+; EXAMPLE:
+; (1) Display CRVAL coordinates in a FITS header, H
+;
+; IDL> crval = sxpar(h,'CRVAL*') ;Extract 2 element CRVAL vector (degs)
+; IDL> print, adstring(crval) ;Print CRVAL vector sexagesimal format
+;
+; (2) print,adstring(30.42,-1.23,1) ==> ' 02 01 40.80 -01 13 48.0'
+; print,adstring(30.42,+0.23) ==> ' 02 01 40.8 +00 13 48.0'
+; print,adstring(+0.23) ==> '+00 13 48.0'
+;
+; (3) The first two calls in (2) can be combined in a single call using
+; vector input
+; print,adstring([30.42,30.42],[-1.23,0.23], 1)
+; PROCEDURES CALLED:
+; RADEC, SIXTY()
+;
+; REVISION HISTORY:
+; Written W. Landsman June 1988
+; Addition of variable precision and DEC seconds precision fix.
+; ver. Aug. 1990 [E. Deutsch]
+; Output formatting spiffed up October 1991 [W. Landsman]
+; Remove ZPARCHECK call, accept 1 element vector April 1992 [W. Landsman]
+; Call ROUND() instead of NINT() February 1996 [W. Landsman]
+; Check roundoff past 60s October 1997 [W. Landsman]
+; Work for Precision =4 November 1997 [W. Landsman]
+; Major rewrite to allow vector inputs W. Landsman February 2000
+; Fix possible error in seconds display when Precision=0
+; P. Broos/W. Landsman April 2002
+; Added /TRUNCATE keyword, put leading zeros in seconds display
+; P. Broos/W. Landsman September 2002
+; Fix declination zero values under vector processing W.Landsman Feb 2004
+; Fix possible problem in leading zero display W. Landsman June 2004
+; Assume since V5.4, omit fstring() call W. Landsman April 2006
+; Fix significant bug when round a declination with -199.99 W. L. Sep 2012
+;-
+ On_error,2
+ compile_opt idl2
+
+ Npar = N_params()
+
+
+ case N_elements(ra_dec) of
+
+ 1: if ( Npar EQ 1 ) then dec = ra_dec else ra = ra_dec
+ 2: begin
+ if (N_elements(dec) LT 2) then begin
+ ra = ra_dec[0] mod 360.
+ if N_elements(dec) EQ 1 then begin
+ precision = dec & Npar=3 & endif
+ dec = ra_dec[1]
+ endif else ra = ra_dec
+ end
+ else: begin
+ If (Npar Eq 1) then message, $
+ 'ERROR - first parameter must be either a scalar or 2 element vector'
+ ra = ra_dec
+ end
+ endcase
+
+ if N_elements(prec) EQ 1 then precision = prec
+
+ if ( Npar GE 2 ) then $
+ if N_elements(dec) NE N_elements(ra) then message, $
+ 'ERROR - RA and Declination do not have equal number of elements'
+
+ if N_elements(ra) EQ N_elements(dec) then begin
+
+ badrange = where( (dec LT -90.) or (dec GT 90.), Nbad)
+ if Nbad GT 0 then message, /INF, $
+ 'WARNING - Some declination values are out of valid range (-90 < dec <90)'
+ radec, ra, dec, ihr, imin, xsec, ideg, imn, xsc
+ if N_elements(precision) EQ 0 then precision = 0
+ precision = precision > 0 < 4 ;No more than 4 decimal places
+ if ~keyword_set(truncate) then begin
+ roundsec = [59.5,59.95,59.995,59.9995,59.99995,59.999995]
+ carry = where(xsec GT roundsec[precision+1], Ncarry)
+ if Ncarry GT 0 then begin
+ imin[carry] = imin[carry] + 1
+ xsec[carry] = 0.0
+ mcarry = where(imin[carry] EQ 60, Nmcarry)
+ if Nmcarry GT 0 then begin
+ ic = carry[mcarry]
+ ihr[ic] = (ihr[ic] + 1) mod 24
+ imin[ic] = 0
+ endif
+ endif
+ endif else xsec = (long(xsec*10L^(precision+1)))/10.0d^(precision+1)
+
+ secfmt = '(F0' + string( 3+precision+1,'(I1)' ) + '.' + $
+ string( precision+1,'(I1)' ) + ')'
+ result = string(ihr,'(I3.2)') + string(imin,'(I3.2)') + ' ' +$
+ strtrim(string(xsec,secfmt),2) + ' '
+ if N_elements(precision) EQ 0 then precision = 1
+
+ endif else begin
+
+ x = sixty(dec)
+ if N_elements(precision) EQ 0 then precision = 1
+ ideg = fix(x[0]) & imn = fix(x[1]) & xsc = x[2]
+ result = ''
+
+ endelse
+
+ imn = abs(imn) & xsc = abs(xsc)
+ if ( precision EQ 0 ) then begin
+ secfmt = '(I03.2)'
+ if ~keyword_set(truncate) then begin
+ xsc = round(xsc)
+ carry = where(xsc EQ 60, Ncarry)
+ if Ncarry GT 0 then begin ;Updated April 2002
+ xsc[carry] = 0
+ imn[carry] = imn[carry] + 1
+ endif
+ endif
+ endif else begin
+
+ secfmt = '(F0' + string( 3+precision,'(I1)') + '.' + $
+ string( precision,'(I1)') + ')'
+
+ if ~keyword_set(truncate) then begin
+ ixsc = fix(xsc + 0.5/10^precision)
+ carry = where(ixsc GE 60, Ncarry)
+ if Ncarry GT 0 then begin
+ xsc[carry] = 0.
+ imn[carry] = imn[carry] + 1
+ endif
+ endif else $
+ xsc = (long(xsc*10^precision))/10.0d^precision
+ endelse
+
+ pos = dec GE 0
+ carry = where(imn EQ 60, Ncarry)
+ if Ncarry GT 0 then begin
+ ideg[carry] = ideg[carry] -1 + 2*pos[carry]
+ imn[carry] = 0
+ endif
+
+ deg = string(ideg,'(I+3.2)')
+ big = where(abs(ideg) ge 100, Nbig)
+ if Nbig GT 0 then deg[big] = string(ideg[big],'(I+4.3)')
+ zero = where(ideg EQ 0, Nzero)
+ if Nzero GT 0 then begin
+ negzero = where( dec[zero] LT 0, Nneg)
+ if Nneg GT 0 then deg[zero[negzero]] = '-00'
+ endif
+
+
+ return, result + deg + string(imn,'(I3.2)') + ' ' + $
+ strtrim(string(xsc,secfmt),2)
+
+ end
diff --git a/Code/script_idl_mv/astrolib/adxy.pro b/Code/script_idl_mv/astrolib/adxy.pro
new file mode 100644
index 0000000000000000000000000000000000000000..736a772d934ce31e155988ff57b4ce22c93b922b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/adxy.pro
@@ -0,0 +1,139 @@
+pro adxy, hdr, a, d, x, y, PRINT = print, ALT = alt ;Ra, Dec to X,Y
+;+
+; NAME:
+; ADXY
+; PURPOSE:
+; Use a FITS header to convert astronomical to pixel coordinates
+; EXPLANATION:
+; Use an image header to compute X and Y positions, given the
+; RA and Dec (or longitude, latitude) in decimal degrees.
+;
+; CALLING SEQUENCE:
+; ADXY, HDR ;Prompt for Ra and DEC
+; ADXY, hdr, a, d, x, y, [ /PRINT, ALT= ]
+;
+; INPUTS:
+; HDR - FITS Image header containing astrometry parameters
+;
+; OPTIONAL INPUTS:
+; A - Right ascension in decimal DEGREES, scalar or vector
+; D - Declination in decimal DEGREES, scalar or vector
+;
+; If A and D are not supplied, user will be prompted to supply
+; them in either decimal degrees or HR,MIN,SEC,DEG,MN,SC format.
+;
+; OPTIONAL OUTPUT:
+; X - row position in pixels, same number of elements as A and D
+; Y - column position in pixels
+;
+; X and Y will be in standard IDL convention (first pixel is 0) and not
+; the FITS convention (first pixel is 1). As in FITS an integral
+; value corresponds to the center of a pixel.
+; OPTIONAL KEYWORD INPUT:
+; /PRINT - If this keyword is set and non-zero, then results are displayed
+; at the terminal.
+; ALT - single character 'A' through 'Z' or ' ' specifying an alternate
+; astrometry system present in the FITS header. The default is
+; to use the primary astrometry or ALT = ' '. If /ALT is set,
+; then this is equivalent to ALT = 'A'. See Section 3.3 of
+; Greisen & Calabretta (2002, A&A, 395, 1061) for information about
+; alternate astrometry keywords.
+;
+; OPERATIONAL NOTES:
+; If less than 5 parameters are supplied, or if the /PRINT keyword is
+; set, then the X and Y positions are displayed at the terminal.
+;
+; If the procedure is to be used repeatedly with the same header,
+; then it would be faster to use AD2XY.
+;
+; PROCEDURES CALLED:
+; AD2XY, ADSTRING(), EXTAST, GETOPT(), TEN()
+;
+; REVISION HISTORY:
+; W. Landsman HSTX January, 1988
+; Use astrometry structure W. Landsman January, 1994
+; Changed default ADSTRING format W. Landsman September, 1995
+; Check if latitude/longitude reversed in CTYPE keyword W. L. Feb. 2004
+; Added ALT keyword W. Landsman September 2004
+; Work for non-spherical coordinate transformation W. Landsman May 2005
+; More informative error message if astrometry missing W.L. Feb 2008
+; Cosmetic updates W.L. July 2011
+; Use version 2 astrometry structure J. P. Leahy July 2013
+;-
+ Compile_opt idl2
+ On_error,2
+
+ npar = N_params()
+
+ if ( npar EQ 0 ) then begin
+ print,'Syntax - ADXY, hdr, [a, d, x, y, /PRINT, ALT= ]'
+ print,'If supplied, A and D must be in decimal DEGREES'
+ return
+ endif
+
+ extast, hdr, astr, noparams, ALT = alt ;Extract astrometry from FITS header
+ if ( noparams LT 0 ) then begin
+ if alt EQ '' then $
+ message,'ERROR - No astrometry info in supplied FITS header' $
+ else message, $
+ 'ERROR - No alt=' + alt + ' astrometry info in supplied FITS header'
+ endif
+
+ astr2 = TAG_EXIST(astr,'AXES') ; Version 2 structure
+
+ if npar lt 3 then begin
+ RD: print,'Coordinates must be entered in either decimal (2 parameter) '
+ print,' or sexagesimal (6 parameter) format'
+ inp = ''
+ read,'ADXY: Enter coordinates: ',inp
+ radec = getopt(inp,'F')
+ case N_elements(radec) of
+ 2: begin
+ a = radec[0] & d = radec[1]
+ end
+ 6: begin
+ a = ten(radec[0:2]*15.) & d = ten(radec[3:5])
+ end
+ else: begin
+ print,'ADXY: ERROR - Either 2 or 6 parameters must be entered'
+ return
+ end
+ endcase
+ endif
+
+ case strmid( astr.ctype[0], 5,3) of
+ 'GSS': gsssadxy, astr, a, d, x, y ;HST Guide star astrometry
+ else: ad2xy, a, d, astr, x, y ;All other cases
+ endcase
+
+ if (npar lt 5) || keyword_set( PRINT ) then begin
+ npts = N_elements(a)
+ tit = strmid(astr.ctype,0,4)
+ spherical = strmid(astr.ctype[0],4,1) EQ '-'
+ if spherical then begin
+ fmt = '(2F9.4,A,2X,2F8.2)'
+ str = adstring(a,d,1)
+ tit = strmid(astr.ctype,0,4)
+ tit = repchr(tit,'-',' ')
+ flip = astr2 ? astr.reverse : $
+ (tit[0] EQ 'DEC ') || (tit[0] EQ 'ELAT') || (tit[0] EQ 'GLAT')
+ if flip then tit = rotate(tit,2)
+ print,' ' + tit[0] + ' ' + tit[1] + ' ' + tit[0] + $
+ ' ' + tit[1] + ' X Y'
+ for i = 0l, npts-1 do $
+ print,FORMAT = fmt, a[i], d[i], str[i], x[i], y[i]
+ endif else begin
+ unit1 = strtrim( sxpar( hdr, 'CUNIT1'+alt,count = N_unit1),2)
+ if N_unit1 EQ 0 then unit1 = ''
+ unit2 = strtrim( sxpar( hdr, 'CUNIT2'+alt,count = N_unit2),2)
+ if N_unit2 EQ 0 then unit2 = ''
+ print,' ' + tit[0] + ' ' + tit[1] + ' X Y'
+ if (N_unit1 GT 0) || (N_unit2 GT 0) then $
+ print,unit1 ,unit2,f='(t5,a,t14,a)'
+ for i=0l, npts-1 do $
+ print, a[i], d[i], x[i], y[i], f='(2F9.4,2X,2F8.2)'
+ endelse
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/airtovac.pro b/Code/script_idl_mv/astrolib/airtovac.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1cbdd01d0f443f0970928ce0b08d6d0cf98ac40e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/airtovac.pro
@@ -0,0 +1,67 @@
+pro airtovac,wave_air, wave_vac
+;+
+; NAME:
+; AIRTOVAC
+; PURPOSE:
+; Convert air wavelengths to vacuum wavelengths
+; EXPLANATION:
+; Wavelengths are corrected for the index of refraction of air under
+; standard conditions. Wavelength values below 2000 A will not be
+; altered. Uses relation of Ciddor (1996).
+;
+; CALLING SEQUENCE:
+; AIRTOVAC, WAVE_AIR, [ WAVE_VAC]
+;
+; INPUT/OUTPUT:
+; WAVE_AIR - Wavelength in Angstroms, scalar or vector
+; If this is the only parameter supplied, it will be updated on
+; output to contain double precision vacuum wavelength(s).
+; OPTIONAL OUTPUT:
+; WAVE_VAC - Vacuum wavelength in Angstroms, same number of elements as
+; WAVE_AIR, double precision
+;
+; EXAMPLE:
+; If the air wavelength is W = 6056.125 (a Krypton line), then
+; AIRTOVAC, W yields an vacuum wavelength of W = 6057.8019
+;
+; METHOD:
+; Formula from Ciddor 1996, Applied Optics 62, 958
+;
+; NOTES:
+; Take care within 1 A of 2000 A. Wavelengths below 2000 A *in air* are
+; not altered.
+; REVISION HISTORY
+; Written W. Landsman November 1991
+; Use Ciddor (1996) formula for better accuracy in the infrared
+; Added optional output vector, W Landsman Mar 2011
+; Iterate for better precision W.L./D. Schlegel Mar 2011
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() EQ 0 then begin
+ print,'Syntax - AIRTOVAC, WAVE_AIR, [WAVE_VAC]'
+ print,'WAVE_AIR (Input) is the air wavelength in Angstroms'
+ return
+ endif
+
+ wave_vac = double(wave_air)
+ g = where(wave_vac GE 2000, Ng) ;Only modify above 2000 A
+
+ if Ng GT 0 then begin
+
+ for iter=0, 1 do begin
+ sigma2 = (1d4/double(wave_vac[g]) )^2. ;Convert to wavenumber squared
+
+; Compute conversion factor
+ fact = 1.D + 5.792105D-2/(238.0185D0 - sigma2) + $
+ 1.67917D-3/( 57.362D0 - sigma2)
+
+
+ wave_vac[g] = wave_air[g]*fact ;Convert Wavelength
+ endfor
+ if N_params() EQ 1 then wave_air = wave_vac
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/aitoff.pro b/Code/script_idl_mv/astrolib/aitoff.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6e7fbee43321e80eab083cc72b7915d3670001d5
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/aitoff.pro
@@ -0,0 +1,56 @@
+pro aitoff,l,b,x,y
+;+
+; NAME:
+; AITOFF
+; PURPOSE:
+; Convert longitude, latitude to X,Y using an AITOFF projection.
+; EXPLANATION:
+; This procedure can be used to create an all-sky map in Galactic
+; coordinates with an equal-area Aitoff projection. Output map
+; coordinates are zero longitude centered.
+;
+; CALLING SEQUENCE:
+; AITOFF, L, B, X, Y
+;
+; INPUTS:
+; L - longitude - scalar or vector, in degrees
+; B - latitude - same number of elements as L, in degrees
+;
+; OUTPUTS:
+; X - X coordinate, same number of elements as L. X is normalized to
+; be between -180 and 180
+; Y - Y coordinate, same number of elements as L. Y is normalized to
+; be between -90 and 90.
+;
+; NOTES:
+; See AIPS memo No. 46, page 4, for details of the algorithm. This
+; version of AITOFF assumes the projection is centered at b=0 degrees.
+;
+; REVISION HISTORY:
+; Written W.B. Landsman STX December 1989
+; Modified for Unix:
+; J. Bloch LANL SST-9 5/16/91 1.1
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ if N_params() ne 4 then begin
+ print,'Syntax - AITOFF, L, B, X, Y'
+ return
+ endif
+
+ sa = l
+ if N_elements(sa) eq 1 then sa = fltarr(1) + sa
+ x180 = where (sa gt 180.0)
+ if x180[0] ne -1 then sa[x180] = sa[x180] - 360.
+ alpha2 = sa/(2*!RADEG)
+ delta = b/!RADEG
+ r2 = sqrt(2.)
+ f = 2*r2/!PI
+ cdec = cos(delta)
+ denom =sqrt(1. + cdec*cos(alpha2))
+ x = cdec*sin(alpha2)*2.*r2/denom
+ y = sin(delta)*r2/denom
+ x = x*!radeg/f
+ y = y*!radeg/f
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/aitoff_grid.pro b/Code/script_idl_mv/astrolib/aitoff_grid.pro
new file mode 100644
index 0000000000000000000000000000000000000000..62e45f91499c2de56cf260567d2d2ae0b71f8e5e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/aitoff_grid.pro
@@ -0,0 +1,144 @@
+;+
+; NAME:
+; AITOFF_GRID
+;
+; PURPOSE:
+; Produce an overlay of latitude and longitude lines over a plot or image
+; EXPLANATION:
+; The grid is plotted on the current graphics device. AITOFF_GRID
+; assumes that the ouput plot coordinates span the x-range of
+; -180 to 180 and the y-range goes from -90 to 90.
+;
+; CALLING SEQUENCE:
+;
+; AITOFF_GRID [,DLONG,DLAT, LABEL=, /NEW, CHARTHICK=, CHARSIZE=,
+; FONT=, _EXTRA=]
+;
+; OPTIONAL INPUTS:
+;
+; DLONG = Optional input longitude line spacing in degrees. If left
+; out, defaults to 30.
+; DLAT = Optional input latitude line spacing in degrees. If left
+; out, defaults to 30.
+;
+; OPTIONAL INPUT KEYWORDS:
+;
+; LABEL = Optional keyword specifying that the latitude and
+; longitude lines on the prime meridian and the
+; equator should be labeled in degrees. If LABELS is
+; given a value of 2, i.e. LABELS=2, then the longitude
+; labels will be in hours instead of degrees.
+; CHARSIZE = If /LABEL is set, then CHARSIZE specifies the size
+; of the label characters (passed to XYOUTS)
+; CHARTHICK = If /LABEL is set, then CHARTHICK specifies the
+; thickness of the label characters (passed to XYOUTS)
+; FONT = scalar font graphics keyword (-1,0 or 1) for text
+; /NEW = If this keyword is set, then AITOFF_GRID will create
+; a new plot grid, rather than overlay an existing plot.
+;
+; Any valid keyword to OPLOT such as COLOR, LINESTYLE, THICK can be
+; passed to AITOFF_GRID (though the _EXTRA facility) to to specify the
+; color, style, or thickness of the grid lines.
+; OUTPUTS:
+; Draws grid lines on current graphics device.
+;
+; EXAMPLE:
+; Create a labeled Aitoff grid of the Galaxy, and overlay stars at
+; specified Galactic longitudes, glong and latitudes, glat
+;
+; IDL> aitoff_grid,/label,/new ;Create labeled grid
+; IDL> aitoff, glong, glat, x,y ;Convert to X,Y coordinates
+; IDL> plots,x,y,psym=2 ;Overlay "star" positions
+;
+; PROCEDURES USED:
+; AITOFF
+; NOTES:
+; If labeling in hours (LABEL=2) then the longitude spacing should be
+; a multiple of 15 degrees
+;
+; AUTHOR AND MODIFICATIONS:
+;
+; J. Bloch 1.2 6/2/91
+; Converted to IDL V5.0 W. Landsman September 1997
+; Create default plotting coords, if needed W. Landsman August 2000
+; Added _EXTRA, CHARTHICK, CHARSIZE keywords W. Landsman March 2001
+; Several tweaks, plot only hours not minutes W. Landsman January 2002
+; Allow FONT keyword to be passed to XYOUTS. T. Robishaw Apr. 2006
+;-
+PRO AITOFF_GRID,DLONG,DLAT,LABEL=LABEL, NEW = new, _EXTRA= E, $
+ CHARSIZE = charsize, CHARTHICK =charthick, FONT=font
+
+ if N_elements(dlong) EQ 0 then dlong = 30.0
+ if N_elements(dlat) EQ 0 then dlat = 30.0
+ if N_elements(font) EQ 0 then font = !p.font
+
+; If no plotting axis has been defined, then create a default one
+
+ new = keyword_set(new)
+ if not new then new = (!X.crange[0] EQ 0) and (!X.crange[1] EQ 0)
+ if new then plot,[-180,180],[-90,90],/nodata,xsty=5,ysty=5
+;
+; Do lines of constant longitude
+;
+ lat=findgen(181)-90
+ lng=fltarr(181,/nozero)
+ lngtot = long(180.0/dlong)
+
+ for i=0,lngtot do begin
+ replicate_inplace, lng, -180.0 + (i*dlong)
+ aitoff,lng,lat,x,y
+ oplot,x,y,_extra=e
+ oplot,-x,y,_extra=e
+ endfor
+;
+; Do lines of constant latitude
+;
+ lng = findgen(361)-180.0
+ lat = fltarr(361,/nozero)
+ lattot=long(180.0/dlat)
+ for i=1,lattot do begin
+ replicate_inplace, lat, -90. + (i*dlat)
+ aitoff,lng,lat,x,y
+ oplot,x,y,_extra=e
+ endfor
+;
+; Do labeling if requested
+;
+ if keyword_set(label) then begin
+
+;
+; Label equator
+;
+ if (!d.name eq 'PS') and (font eq 0) then hr = '!Uh!N' else hr='h'
+ xoff = 2*dlong/30.
+ for i=0,2*lngtot-1 do begin
+ lng = (180 + (i*dlong)) mod 360
+ if (lng ne 0.0) and (lng ne 180.0) then begin
+ aitoff,lng,0.0,x,y
+ if label eq 1 then xyouts,x[0]+xoff,y[0]+1,$
+ strcompress(string(lng,format="(I4)"),/remove_all), $
+ charsize = charsize, charthick = charthick,font=font $
+ else begin
+ tmp = lng/15.
+ xyouts,round(x[0])+xoff,round(y[0])+1,string(tmp[0],$
+ format='(I2)') + hr, font=font,$
+ charsize = charsize, charthick = charthick
+ endelse
+ endif
+ endfor
+;
+; Label prime meridian
+;
+ lat = -90 + (indgen(lattot-1)+1)*dlat
+ aitoff,fltarr(lattot-1),lat,x,y
+ slat = strtrim(round(lat),2)
+ pos = where(lat GT 0, Npos)
+ if Npos GT 0 then slat[pos] = '+' + slat[pos]
+ for i=0,lattot-2 do begin
+ xyouts,x[i]+2,y[i]+1, slat[i], font=font, $
+ charsize = charsize, charthick = charthick
+ endfor
+ endif
+
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/al_legend.pro b/Code/script_idl_mv/astrolib/al_legend.pro
new file mode 100644
index 0000000000000000000000000000000000000000..74c02f60e5f167b61d8163a5cadfcff9b5b549ae
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/al_legend.pro
@@ -0,0 +1,572 @@
+;+
+; NAME:
+; AL_LEGEND
+; PURPOSE:
+; Create an annotation legend for a plot.
+; EXPLANATION:
+;
+; This procedure makes a legend for a plot. The legend can contain
+; a mixture of symbols, linestyles, Hershey characters (vectorfont),
+; and filled polygons (usersym). A test procedure, al_legendtest.pro,
+; shows legend's capabilities. Placement of the legend is controlled
+; with keywords like /right, /top, and /center or by using a position
+; keyword for exact placement (position=[x,y]) or via mouse (/position).
+;
+; The procedure CGLEGEND in the Coyote library provides a similar
+; capability. https://www.idlcoyote.com/idldoc/cg/cglegend.html
+; CALLING SEQUENCE:
+; AL_LEGEND [,items][,keyword options]
+; EXAMPLES:
+; The call:
+; al_legend,['Plus sign','Asterisk','Period'],psym=[1,2,3]
+; produces:
+; -----------------
+; | |
+; | + Plus sign |
+; | * Asterisk |
+; | . Period |
+; | |
+; -----------------
+; Each symbol is drawn with a cgPlots command, so they look OK.
+; Other examples are given in optional output keywords.
+;
+; lines = indgen(6) ; for line styles
+; items = 'linestyle '+strtrim(lines,2) ; annotations
+; al_legend,items,linestyle=lines ; vertical legend---upper left
+; items = ['Plus sign','Asterisk','Period']
+; sym = [1,2,3]
+; al_legend,items,psym=sym ; ditto except using symbols
+; al_legend,items,psym=sym,/horizontal ; horizontal format
+; al_legend,items,psym=sym,box=0 ; sans border
+; al_legend,items,psym=sym,delimiter='=' ; embed '=' betw psym & text
+; al_legend,items,psym=sym,margin=2 ; 2-character margin
+; al_legend,items,psym=sym,position=[x,y] ; upper left in data coords
+; al_legend,items,psym=sym,pos=[x,y],/norm ; upper left in normal coords
+; al_legend,items,psym=sym,pos=[x,y],/device ; upper left in device coords
+; al_legend,items,psym=sym,/position ; interactive position
+; al_legend,items,psym=sym,/right ; at upper right
+; al_legend,items,psym=sym,/bottom ; at lower left
+; al_legenditems,psym=sym,/center ; approximately near center
+; al_legend,items,psym=sym,number=2 ; plot two symbols, not one
+; Plot 3 filled colored squares
+; al_legend,items,/fill,psym=[8,8,8],colors=['red','green','blue']
+;
+; Another example of the use of AL_LEGEND can be found at
+; http://www.idlcoyote.com/cg_tips/al_legend.php
+; INPUTS:
+; items = text for the items in the legend, a string array.
+; For example, items = ['diamond','asterisk','square'].
+; You can omit items if you don't want any text labels. The
+; text can include many LaTeX symbols (e.g. $\leq$) for a less
+; than equals symbol) as described in cgsymbol.pro.
+; OPTIONAL INPUT KEYWORDS:
+;
+; linestyle = array of linestyle numbers If linestyle[i] < 0, then omit
+; ith symbol or line to allow a multi-line entry. If
+; linestyle = -99 then text will be left-justified.
+; psym = array of plot symbol numbers or names. If psym[i] is negative,
+; then a line connects pts for ith item. If psym[i] = 8, then the
+; procedure USERSYM is called with vertices defined in the
+; keyword usersym. If psym[i] = 88, then use the previously
+; defined user symbol. If 11 <= psym[i] <= 46 then David
+; Fanning's function CGSYMCAT() will be used for additional
+; symbols. Note that PSYM=10 (histogram plot mode) is not
+; allowed since it cannot be used with the cgPlots command.
+; vectorfont = vector-drawn characters for the sym/line column, e.g.,
+; ['!9B!3','!9C!3','!9D!3'] produces an open square, a checkmark,
+; and a partial derivative, which might have accompanying items
+; ['BOX','CHECK','PARTIAL DERIVATIVE'].
+; There is no check that !p.font is set properly, e.g., -1 for
+; X and 0 for PostScript. This can produce an error, e.g., use
+; !20 with PostScript and !p.font=0, but allows use of Hershey
+; *AND* PostScript fonts together.
+; N. B.: Choose any of linestyle, psym, and/or vectorfont. If none is
+; present, only the text is output. If more than one
+; is present, all need the same number of elements, and normal
+; plot behaviour occurs.
+; By default, if psym is positive, you get one point so there is
+; no connecting line. If vectorfont[i] = '',
+; then cgPlots is called to make a symbol or a line, but if
+; vectorfont[i] is a non-null string, then cgText is called.
+; /help = flag to print header
+; /horizontal = flag to make the legend horizontal
+; /vertical = flag to make the legend vertical (D=vertical)
+; background_color - color name or number to fill the legend box.
+; Automatically sets /clear. (D = -1)
+; box = flag to include/omit box around the legend (D=include)
+; outline_color = color of box outline (D = !P.color)
+; bthick = thickness of the legend box (D = !P.thick)
+; charsize = just like !p.charsize for plot labels
+; charthick = just like !p.charthick for plot labels
+; clear = flag to clear the box area before drawing the legend
+; colors = array of colors names or numbers for plot symbols/lines
+; See cgCOLOR for list of color names. Default is 'Opposite'
+; If you are using index colors (0-255), then supply color as a byte,
+; integer or string, but not as a long, which will be interpreted as
+; a decomposed color. See http://www.idlcoyote.com/cg_tips/legcolor.php
+; delimiter = embedded character(s) between symbol and text (D=none)
+; font = scalar font graphics keyword (-1,0 or 1) for text
+; linsize = Scale factor for line length (0-1), default = 1
+; Set to 0 to give a dot, 0.5 give half default line length
+; margin = margin around text measured in characters and lines
+; number = number of plot symbols to plot or length of line (D=1)
+; spacing = line spacing (D=bit more than character height)
+; position = data coordinates of the /top (D) /left (D) of the legend
+; pspacing = psym spacing (D=3 characters) (when number of symbols is
+; greater than 1)
+; textcolors = array of color names or numbers for text. See cgCOLOR
+; for a list of color names. Default is 'Opposite' of background
+; thick = array of line thickness numbers (D = !P.thick), if used, then
+; linestyle must also be specified
+; normal = use normal coordinates for position, not data
+; device = use device coordinates for position, not data
+; /window - if set then send legend to a resizeable graphics window
+; usersym = 2-D array of vertices, cf. usersym in IDL manual.
+; (/USERSYM =square, default is to use existing USERSYM definition)
+; /fill = flag to fill the usersym
+; /left_legend = flag to place legend snug against left side of plot
+; window (D)
+; /right_legend = flag to place legend snug against right side of plot
+; window. If /right,pos=[x,y], then x is position of RHS and
+; text runs right-to-left.
+; /top_legend = flag to place legend snug against top of plot window (D)
+; /bottom = flag to place legend snug against bottom of plot window
+; /top,pos=[x,y] and /bottom,pos=[x,y] produce same positions.
+;
+; If LINESTYLE, PSYM, VECTORFONT, SYMSIZE, THICK, COLORS, or
+; TEXTCOLORS are supplied as scalars, then the scalar value is set for
+; every line or symbol in the legend.
+; Outputs:
+; legend to current plot device
+; OPTIONAL OUTPUT KEYWORDS:
+; corners = 4-element array, like !p.position, of the normalized
+; coords for the box (even if box=0): [llx,lly,urx,ury].
+; Useful for multi-column or multi-line legends, for example,
+; to make a 2-column legend, you might do the following:
+; c1_items = ['diamond','asterisk','square']
+; c1_psym = [4,2,6]
+; c2_items = ['solid','dashed','dotted']
+; c2_line = [0,2,1]
+; al_legend,c1_items,psym=c1_psym,corners=c1,box=0
+; al_legend,c2_items,line=c2_line,corners=c2,box=0,pos=[c1[2],c1[3]]
+; c = [c1[0]c2[2],c1[3]>c2[3]]
+; cgplots,[c[0],c[0],c[2],c[2],c[0]],[c[1],c[3],c[3],c[1],c[1]],/norm
+;
+; Useful also to place the legend. Here's an automatic way to place
+; the legend in the lower right corner. The difficulty is that the
+; legend's width is unknown until it is plotted. In this example,
+; the legend is plotted twice: the first time in the upper left, the
+; second time in the lower right.
+;
+; al_legend,['1','22','333','4444'],linestyle=indgen(4),corners=corners
+; ; BOGUS LEGEND---FIRST TIME TO REPORT CORNERS
+; xydims = [corners[2]-corners[0],corners[3]-corners[1]]
+; ; SAVE WIDTH AND HEIGHT
+; chdim=[!d.x_ch_size/float(!d.x_size),!d.y_ch_size/float(!d.y_size)]
+; ; DIMENSIONS OF ONE CHARACTER IN NORMALIZED COORDS
+; pos = [!x.window[1]-chdim[0]-xydims[0] $
+; ,!y.window[0]+chdim[1]+xydims[1]]
+; ; CALCULATE POSITION FOR LOWER RIGHT
+; cgplot,findgen(10) ; SIMPLE PLOT; YOU DO WHATEVER YOU WANT HERE.
+; al_legend,['1','22','333','4444'],linestyle=indgen(4),pos=pos
+; ; REDO THE LEGEND IN LOWER RIGHT CORNER
+; You can modify the pos calculation to place the legend where you
+; want. For example to place it in the upper right:
+; pos = [!x.window[1]-chdim[0]-xydims[0],!y.window[1]-xydims[1]]
+; Common blocks:
+; none
+; Procedure:
+; If keyword help is set, call doc_library to print header.
+; See notes in the code. Much of the code deals with placement of the
+; legend. The main problem with placement is not being
+; able to sense the length of a string before it is output. Some crude
+; approximations are used for centering.
+; Restrictions:
+; Here are some things that aren't implemented.
+; - An orientation keyword would allow lines at angles in the legend.
+; - An array of usersyms would be nice---simple change.
+; - An order option to interchange symbols and text might be nice.
+; - Somebody might like double boxes, e.g., with box = 2.
+; - Another feature might be a continuous bar with ticks and text.
+; - There are no guards to avoid writing outside the plot area.
+; - There is no provision for multi-line text, e.g., '1st line!c2nd line'
+; Sensing !c would be easy, but !c isn't implemented for PostScript.
+; A better way might be to simply output the 2nd line as another item
+; but without any accompanying symbol or linestyle. A flag to omit
+; the symbol and linestyle is linestyle[i] = -1.
+; - There is no ability to make a title line containing any of titles
+; for the legend, for the symbols, or for the text.
+; Notes:
+; This procedure was originally named LEGEND, but a distinct LEGEND()
+; function was introduced into IDL V8.0. Therefore, the
+; original LEGEND procedure was renamed to AL_LEGEND to avoid conflict.
+;
+; Modification history:
+; write, 24-25 Aug 92, F K Knight (knight@ll.mit.edu)
+; allow omission of items or omission of both psym and linestyle, add
+; corners keyword to facilitate multi-column legends, improve place-
+; ment of symbols and text, add guards for unequal size, 26 Aug 92, FKK
+; add linestyle(i)=-1 to suppress a single symbol/line, 27 Aug 92, FKK
+; add keyword vectorfont to allow characters in the sym/line column,
+; 28 Aug 92, FKK
+; add /top, /bottom, /left, /right keywords for automatic placement at
+; the four corners of the plot window. The /right keyword forces
+; right-to-left printing of menu. 18 Jun 93, FKK
+; change default position to data coords and add normal, data, and
+; device keywords, 17 Jan 94, FKK
+; add /center keyword for positioning, but it is not precise because
+; text string lengths cannot be known in advance, 17 Jan 94, FKK
+; add interactive positioning with /position keyword, 17 Jan 94, FKK
+; allow a legend with just text, no plotting symbols. This helps in
+; simply describing a plot or writing assumptions done, 4 Feb 94, FKK
+; added thick, symsize, and clear keyword Feb 96, W. Landsman HSTX
+; David Seed, HR Wallingford, d.seed@hrwallingford.co.uk
+; allow scalar specification of keywords, Mar 96, W. Landsman HSTX
+; added charthick keyword, June 96, W. Landsman HSTX
+; Made keyword names left,right,top,bottom,center longer,
+; Aug 16, 2000, Kim Tolbert
+; Added ability to have regular text lines in addition to plot legend
+; lines in legend. If linestyle is -99 that item is left-justified.
+; Previously, only option for no sym/line was linestyle=-1, but then text
+; was lined up after sym/line column. 10 Oct 2000, Kim Tolbert
+; Make default value of thick = !P.thick W. Landsman Jan. 2001
+; Don't overwrite existing USERSYM definition W. Landsman Mar. 2002
+; Added outline_color BT 24 MAY 2004
+; Pass font keyword to cgText commands. M. Fitzgerald, Sep. 2005
+; Default spacing, pspacing should be relative to charsize. M. Perrin, July 2007
+; Don't modify position keyword A. Kimball/ W. Landsman Jul 2007
+; Small update to Jul 2007 for /NORMAL coords. W. Landsman Aug 2007
+; Use SYMCAT() plotting symbols for 11<=PSYM<=46 W. Landsman Nov 2009
+; Make a sharper box edge T. Robishaw/W.Landsman July 2010
+; Added BTHICK keyword W. Landsman October 2010
+; Added BACKGROUND_COLOR keyword W. Landsman February 2011
+; Incorporate Coyote graphics W. Landsman February 2011
+; Added LINSIZE keyword W.L./V.Gonzalez May 2011
+; Fixed a small problem with Convert_Coord when the Window keyword is set.
+; David Fanning, May 2011.
+; Fixed problem when /clear and /Window are set J. Bailin/WL May 2011
+; CGQUERY was called instead of CGCONTROL W.L. June 2011
+; Fixed typo preventing BTHICK keyword from working W.L. Dec 2011
+; Remove call to SYMCAT() W.L. Dec 2011
+; Changed the way the WINDOW keyword adds commands to cgWindow, and
+; now default to BACKGROUND for background color. 1 Feb 2012 David Fanning
+; Allow 1 element SYMSIZE for vector input, WL Apr 2012.
+; Allow to specify symbols by cgSYMCAT() name WL Aug 2012
+; Fixed bug when linsize, /right called simultaneously, Dec 2012, K.Stewart
+; Added a check for embedded symbols in the items string array. March 2013. David Fanning
+;
+;-
+pro al_legend, items, BOTTOM_LEGEND=bottom, BOX = box, CENTER_LEGEND=center, $
+ CHARTHICK=charthick, CHARSIZE = charsize, CLEAR = clear, COLORS = colorsi, $
+ CORNERS = corners, DATA=data, DELIMITER=delimiter, DEVICE=device, $
+ FILL=fill, HELP = help, HORIZONTAL=horizontal,LEFT_LEGEND=left, $
+ LINESTYLE=linestylei, MARGIN=margin, NORMAL=normal, NUMBER=number, $
+ POSITION=position,PSPACING=pspacing, PSYM=psymi, RIGHT_LEGEND=right, $
+ SPACING=spacing, SYMSIZE=symsizei, TEXTCOLORS=textcolorsi, THICK=thicki, $
+ TOP_LEGEND=top, USERSYM=usersym, VECTORFONT=vectorfonti, $
+ VERTICAL=vertical,OUTLINE_COLOR = outline_color, FONT = font, $
+ BTHICK=bthick, background_color = bgcolor, WINDOW=window,LINSIZE = linsize
+;
+; =====>> HELP
+;
+compile_opt idl2
+;On_error,2
+if keyword_set(help) then begin & doc_library,'al_legend' & return & endif
+; Should this commnad be added to a resizeable graphics window?
+IF (Keyword_Set(window)) && ((!D.Flags AND 256) NE 0) THEN BEGIN
+
+ cgWindow, 'al_legend', items, BOTTOM_LEGEND=bottom, BOX = box, CENTER_LEGEND=center, $
+ CHARTHICK=charthick, CHARSIZE = charsize, CLEAR = clear, COLORS = colorsi, $
+ CORNERS = corners, DATA=data, DELIMITER=delimiter, DEVICE=device, $
+ FILL=fill, HELP = help, HORIZONTAL=horizontal,LEFT_LEGEND=left, $
+ LINESTYLE=linestylei, MARGIN=margin, NORMAL=normal, NUMBER=number, $
+ POSITION=position,PSPACING=pspacing, PSYM=psymi, RIGHT_LEGEND=right, $
+ SPACING=spacing, SYMSIZE=symsizei, TEXTCOLORS=textcolorsi, THICK=thicki, $
+ TOP_LEGEND=top, USERSYM=usersym, VECTORFONT=vectorfonti, $
+ VERTICAL=vertical,OUTLINE_COLOR = outline_color, FONT = font, $
+ BTHICK=thick, background_color = bgcolor, LINSIZE = linsize, ADDCMD=1
+
+ RETURN
+ ENDIF
+ ;
+
+;
+; =====>> SET DEFAULTS FOR SYMBOLS, LINESTYLES, AND ITEMS.
+;
+ ni = n_elements(items)
+ np = n_elements(psymi)
+ nl = n_elements(linestylei)
+ nth = n_elements(thicki)
+ nsym = n_elements(symsizei)
+ nv = n_elements(vectorfonti)
+ nlpv = max([np,nl,nv])
+ n = max([ni,np,nl,nv]) ; NUMBER OF ENTRIES
+strn = strtrim(n,2) ; FOR ERROR MESSAGES
+if n eq 0 then message,'No inputs! For help, type al_legend,/help.'
+if ni eq 0 then begin
+ items = replicate('',n) ; DEFAULT BLANK ARRAY
+endif else begin
+ if size(items,/TNAME) NE 'STRING' then message, $
+ 'First parameter must be a string array. For help, type al_legend,/help.'
+ if ni ne n then message,'Must have number of items equal to '+strn
+endelse
+
+items = cgCheckForSymbols(items) ; Check for embedded symbols in the items array.
+symline = (np ne 0) || (nl ne 0) ; FLAG TO PLOT SYM/LINE
+ if (np ne 0) && (np ne n) && (np NE 1) then message, $
+ 'Must have 0, 1 or '+strn+' elements in PSYM array.'
+ if (nl ne 0) && (nl ne n) && (nl NE 1) then message, $
+ 'Must have 0, 1 or '+strn+' elements in LINESTYLE array.'
+ if (nth ne 0) && (nth ne n) && (nth NE 1) then message, $
+ 'Must have 0, 1 or '+strn+' elements in THICK array.'
+
+ case nl of
+ 0: linestyle = intarr(n) ;Default = solid
+ 1: linestyle = intarr(n) + linestylei
+ else: linestyle = linestylei
+ endcase
+
+ case nsym of
+ 0: symsize = replicate(!p.symsize,n) ;Default = !P.SYMSIZE
+ 1: symsize = intarr(n) + symsizei
+ else: symsize = symsizei
+ endcase
+
+
+ case nth of
+ 0: thick = replicate(!p.thick,n) ;Default = !P.THICK
+ 1: thick = intarr(n) + thicki
+ else: thick = thicki
+ endcase
+
+ if size(psymi,/TNAME) EQ 'STRING' then begin
+ psym = intarr(n)
+ for i=0,N_elements(psymi)-1 do psym[i] = cgsymcat(psymi[i])
+ endif else begin
+
+ case np of ;Get symbols
+ 0: psym = intarr(n) ;Default = solid
+ 1: psym = intarr(n) + psymi
+ else: psym = psymi
+ endcase
+ endelse
+
+ case nv of
+ 0: vectorfont = replicate('',n)
+ 1: vectorfont = replicate(vectorfonti,n)
+ else: vectorfont = vectorfonti
+ endcase
+;
+; =====>> CHOOSE VERTICAL OR HORIZONTAL ORIENTATION.
+;
+if n_elements(horizontal) eq 0 then $ ; D=VERTICAL
+ setdefaultvalue, vertical, 1 else $
+ setdefaultvalue, vertical, ~horizontal
+
+;
+; =====>> SET DEFAULTS FOR OTHER OPTIONS.
+;
+ setdefaultvalue, box, 1
+ if N_elements(bgcolor) NE 0 then clear = 1
+ setdefaultvalue, bgcolor, 'BACKGROUND'
+ setdefaultvalue, clear, 0
+ setdefaultvalue, linsize, 1.
+ setdefaultvalue, margin, 0.5
+ setdefaultvalue, delimiter, ''
+ setdefaultvalue, charsize, !p.charsize
+ setdefaultvalue, charthick, !p.charthick
+ if charsize eq 0 then charsize = 1
+ setdefaultvalue, number, 1
+; Default color is opposite the background color
+ case N_elements(colorsi) of
+ 0: colors = replicate('opposite',n)
+ 1: colors = replicate(colorsi,n)
+ else: colors = colorsi
+ endcase
+
+ case N_elements(textcolorsi) of
+ 0: textcolors = replicate('opposite',n)
+ 1: textcolors = replicate(textcolorsi,n)
+ else: textcolors = textcolorsi
+ endcase
+ fill = keyword_set(fill)
+if n_elements(usersym) eq 1 then usersym = 2*[[0,0],[0,1],[1,1],[1,0],[0,0]]-1
+
+;
+; =====>> INITIALIZE SPACING
+;
+setdefaultvalue, spacing, 1.2*charsize
+setdefaultvalue, pspacing , 3*charsize
+xspacing = !d.x_ch_size/float(!d.x_size) * (spacing > charsize)
+yspacing = !d.y_ch_size/float(!d.y_size) * (spacing > charsize)
+ltor = 1 ; flag for left-to-right
+if n_elements(left) eq 1 then ltor = left eq 1
+if n_elements(right) eq 1 then ltor = right ne 1
+ttob = 1 ; flag for top-to-bottom
+if n_elements(top) eq 1 then ttob = top eq 1
+if n_elements(bottom) eq 1 then ttob = bottom ne 1
+xalign = ltor ne 1 ; x alignment: 1 or 0
+yalign = -0.5*ttob + 1 ; y alignment: 0.5 or 1
+xsign = 2*ltor - 1 ; xspacing direction: 1 or -1
+ysign = 2*ttob - 1 ; yspacing direction: 1 or -1
+if ~ttob then yspacing = -yspacing
+if ~ltor then xspacing = -xspacing
+;
+; =====>> INITIALIZE POSITIONS: FIRST CALCULATE X OFFSET FOR TEXT
+;
+xt = 0
+if nlpv gt 0 then begin ; SKIP IF TEXT ITEMS ONLY.
+if vertical then begin ; CALC OFFSET FOR TEXT START
+ for i = 0,n-1 do begin
+ if (psym[i] eq 0) and (vectorfont[i] eq '') then num = (number + 1) > 3 else num = number
+ if psym[i] lt 0 then num = number > 2 ; TO SHOW CONNECTING LINE
+ if psym[i] eq 0 then expand = linsize else expand = 2
+ thisxt = (expand*pspacing*(num-1)*xspacing)
+ if ltor then xt = thisxt > xt else xt = thisxt < xt
+ endfor
+endif ; NOW xt IS AN X OFFSET TO ALIGN ALL TEXT ENTRIES.
+endif
+;
+; =====>> INITIALIZE POSITIONS: SECOND LOCATE BORDER
+;
+
+if !x.window[0] eq !x.window[1] then begin
+ cgplot,/nodata,xstyle=4,ystyle=4,[0],/noerase
+endif
+; next line takes care of weirdness with small windows
+pos = [min(!x.window),min(!y.window),max(!x.window),max(!y.window)]
+
+case n_elements(position) of
+ 0: begin
+ if ltor then px = pos[0] else px = pos[2]
+ if ttob then py = pos[3] else py = pos[1]
+ if keyword_set(center) then begin
+ if ~keyword_set(right) && ~keyword_set(left) then $
+ px = (pos[0] + pos[2])/2. - xt
+ if ~keyword_set(top) && ~keyword_set(bottom) then $
+ py = (pos[1] + pos[3])/2. + n*yspacing
+ endif
+ nposition = [px,py] + [xspacing,-yspacing]
+ end
+ 1: begin ; interactive
+ message,/inform,'Place mouse at upper left corner and click any mouse button.'
+ cursor,x,y,/normal
+ nposition = [x,y]
+ end
+ 2: begin ; convert upper left corner to normal coordinates
+
+ ; if keyword window is set, get the current graphics window.
+ if keyword_set(window) then begin
+ wid = cgQuery(/current)
+ WSet, wid
+ endif
+ if keyword_set(data) then $
+ nposition = convert_coord(position,/to_norm) $
+ else if keyword_set(device) then $
+ nposition = convert_coord(position,/to_norm,/device) $
+ else if ~keyword_set(normal) then $
+ nposition = convert_coord(position,/to_norm) else nposition= position
+ end
+ else: message,'Position keyword can have 0, 1, or 2 elements only. Try al_legend,/help.'
+endcase
+
+yoff = 0.25*yspacing*ysign ; VERT. OFFSET FOR SYM/LINE.
+
+x0 = nposition[0] + (margin)*xspacing ; INITIAL X & Y POSITIONS
+y0 = nposition[1] - margin*yspacing + yalign*yspacing ; WELL, THIS WORKS!
+;
+; =====>> OUTPUT TEXT FOR LEGEND, ITEM BY ITEM.
+; =====>> FOR EACH ITEM, PLACE SYM/LINE, THEN DELIMITER,
+; =====>> THEN TEXT---UPDATING X & Y POSITIONS EACH TIME.
+; =====>> THERE ARE A NUMBER OF EXCEPTIONS DONE WITH IF STATEMENTS.
+;
+for iclr = 0,clear do begin
+ y = y0 ; STARTING X & Y POSITIONS
+ x = x0
+ if ltor then xend = 0 else xend = 1 ; SAVED WIDTH FOR DRAWING BOX
+
+ if ttob then ii = [0,n-1,1] else ii = [n-1,0,-1]
+
+ for i = ii[0],ii[1],ii[2] do begin
+ if vertical then x = x0 else y = y0 ; RESET EITHER X OR Y
+ x = x + xspacing ; UPDATE X & Y POSITIONS
+ y = y - yspacing
+ if nlpv eq 0 then goto,TEXT_ONLY ; FLAG FOR TEXT ONLY
+ num = number
+ if (psym[i] eq 0) && (vectorfont[i] eq '') then num = (number + 1) > 3
+ if psym[i] lt 0 then num = number > 2 ; TO SHOW CONNECTING LINE
+ if psym[i] eq 0 then expand = 1 else expand = 2
+ xp = x + expand*pspacing*indgen(num)*xspacing
+ if (psym[i] gt 0) && (num eq 1) && vertical then xp = x + xt/2.
+ yp = y + intarr(num)
+ if vectorfont[i] eq '' then yp += yoff
+ if psym[i] eq 0 then begin
+ if ltor eq 1 then xp = [min(xp),max(xp) -(max(xp)-min(xp))*(1.-linsize)]
+ if ltor ne 1 then xp = [min(xp) +(max(xp)-min(xp))*(1.-linsize),max(xp)]
+ yp = [min(yp),max(yp)] ; DITTO
+ endif
+ if (psym[i] eq 8) && (N_elements(usersym) GT 1) then $
+ usersym,usersym,fill=fill,color=colors[i]
+;; extra by djseed .. psym=88 means use the already defined usersymbol
+ if psym[i] eq 88 then p_sym =8 else $
+ if psym[i] EQ 10 then $
+ message,'PSYM=10 (histogram mode) not allowed to al_legend.pro' $
+ else p_sym= psym[i]
+
+ if vectorfont[i] ne '' then begin
+; if (num eq 1) && vertical then xp = x + xt/2 ; IF 1, CENTERED.
+ cgText,xp,yp,vectorfont[i],width=width,color=colors[i], $
+ size=charsize,align=xalign,charthick = charthick,/norm,font=font
+ xt = xt > width
+ xp = xp + width/2.
+ endif else begin
+ if symline and (linestyle[i] ge 0) then cgPlots,xp,yp,color=colors[i] $
+ ,/normal,linestyle=linestyle[i],psym=p_sym,symsize=symsize[i], $
+ thick=thick[i]
+ endelse
+
+ if vertical then x += xt else if ltor then x = max(xp) else x = min(xp)
+ if symline then x += xspacing
+
+ TEXT_ONLY:
+ if vertical && (vectorfont[i] eq '') && symline && (linestyle[i] eq -99) then x=x0 + xspacing
+ cgText,x,y,delimiter,width=width,/norm,color=textcolors[i], $
+ size=charsize,align=xalign,charthick = charthick,font=font
+ x += width*xsign
+ if width ne 0 then x += 0.5*xspacing
+ cgText,x,y,items[i],width=width,/norm,color=textcolors[i],size=charsize, $
+ align=xalign,charthick=charthick,font=font
+ x += width*xsign
+ if ~vertical && (i lt (n-1)) then x += 2*xspacing; ADD INTER-ITEM SPACE
+ xfinal = (x + xspacing*margin)
+ if ltor then xend = xfinal > xend else xend = xfinal < xend ; UPDATE END X
+ endfor
+
+ if (iclr lt clear ) then begin
+; =====>> CLEAR AREA
+ x = nposition[0]
+ y = nposition[1]
+ if vertical then bottom = n else bottom = 1
+ ywidth = - (2*margin+bottom-0.5)*yspacing
+ corners = [x,y+ywidth,xend,y]
+ cgColorfill,[x,xend,xend,x,x],y + [0,0,ywidth,ywidth,0],/norm, $
+ color=bgcolor
+; cgPlots,[x,xend,xend,x,x],y + [0,0,ywidth,ywidth,0], $
+; thick=2
+ endif else begin
+
+;
+; =====>> OUTPUT BORDER
+;
+ x = nposition[0]
+ y = nposition[1]
+ if vertical then bottom = n else bottom = 1
+ ywidth = - (2*margin+bottom-0.5)*yspacing
+ corners = [x,y+ywidth,xend,y]
+ if box then cgPlots,[x,xend,xend,x,x,xend],y + [0,0,ywidth,ywidth,0,0],$
+ /norm, color = outline_color,thick=bthick
+ return
+ endelse
+endfor
+
+end
diff --git a/Code/script_idl_mv/astrolib/al_legendtest.pro b/Code/script_idl_mv/astrolib/al_legendtest.pro
new file mode 100644
index 0000000000000000000000000000000000000000..55e33be9fedd4d5f03659a82533e858c81914095
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/al_legendtest.pro
@@ -0,0 +1,85 @@
+
+;+
+; NAME:
+; AL_LEGENDTEST
+; PURPOSE:
+; Demo program to show capabilities of the al_legend procedure.
+; CALLING SEQUENCE:
+; al_legendtest
+; INPUTS:
+; none
+; OPTIONAL INPUTS:
+; none
+; KEYWORDS:
+; none
+; OUTPUTS:
+; legends of note
+; COMMON BLOCKS:
+; none
+; SIDE EFFECTS:
+; Sets !20 font to symbol if PostScript and !p.font=0.
+; RESTRICTIONS:
+; With the vectorfont test, you'll get different results for PostScript
+; depending on the value of !p.font.
+; MODIFICATION HISTORY:
+; write, 27 Aug 92, F.K.Knight (knight@ll.mit.edu)
+; add test of /left,/right,/top,/bottom keywords, 21 June 93, FKK
+; update based on recent changes to legend, 7 Feb 94, FKK
+; Fix ambiguous CHAR keyword W. Landsman Sep 2007
+; Use Coyote graphics routines W. Landsman Jan 2011
+;-
+pro al_legendtest
+if (!d.name eq 'PS') && (!p.font eq 0) then device,/Symbol,font_index=20
+items = ['diamond','asterisk','square']
+explanation = ['The al_legend procedure annotates plots---' $
+ ,' either using text alone,' $
+ ,' or text with plot symbols, lines, and special characters.' $
+ ,'The following are some examples.' $
+ ,'Hit return to continue.']
+psym = [4,2,6]
+lineitems = ['solid','dotted','DASHED']
+linestyle = [0,1,2]
+citems = 'color '+strtrim(string(indgen(8)),2)
+colors = ['red','blue','violet','green','yellow','brown','black','cyan']
+usersym,[-1,1,1,-1,-1],[-1,-1,1,1,-1],/fill
+z = ['al_legend,explanation,charsize=1.5' $
+ ,'al_legend,items,psym=[4,2,6]' $
+ ,'cgplot,findgen(10) & al_legend,items,psym=[4,2,6] & al_legend,items,psym=[4,2,6],/bottom,/right' $
+ ,'al_legend,lineitems,linestyle=linestyle,/right,/bottom' $
+ ,'al_legend,items,psym=psym,/horizontal,chars=1.5 ; horizontal format' $
+ ,'al_legend,[items,lineitems],psym=[psym,0,0,0],line=[0,0,0,linestyle],/center,box=0 ; sans border' $
+ ,'al_legend,items,psym=psym,margin=1,spacing=2,chars=2,delimiter="=",/top,/center; delimiter & larger margin' $
+ ,'al_legend,lineitems,line=linestyle,pos=[.3,.5],/norm,chars=2,number=4 ; position of legend' $
+ ,'al_legend,items,psym=-psym,number=2,line=linestyle,/right; plot two symbols, not one' $
+ ,'al_legend,citems,/fill,psym=15+intarr(8),colors=colors,chars=2; 8 filled squares' $
+ ,'al_legend,[citems[0:4],lineitems],/fill,psym=[15+intarr(5),0*psym],line=[intarr(5),linestyle],colors=colors,chars=2,text=colors' $
+ ,"al_legend,['Absurd','Sun Lover','Lucky Lady','Fishtail Palm'],vector=['ab!9r!3','!9nu!3','!9Wf!3','!9cN!20K!3'],charsize=2,/pos,psp=3"$
+ ]
+prompt = 'Hit return to continue:'
+for i = 0,n_elements(z) - 1 do begin
+ cgerase
+ stat = execute(z[i])
+ cgtext,.01,.15,'COMMAND TO MAKE LEGEND:',charsize=1.7,/norm
+ cgtext,.01,.05,z[i],/norm,charsize=1.2
+ print,'Command: ',z[i]
+ print,prompt,format='($,a)'
+ a = get_kbrd(1)
+ print
+ endfor
+;stop
+cgerase
+!p.charsize=2
+c1_items = ['Plus','Asterisk','Period','Diamond','Triangle','Square','X']
+c1_psym = indgen(7)+1
+c2_items = ['Solid','Dotted','Dashed','Dash Dot','Dash Dot Dot Dot','Long Dashes']
+c2_line = indgen(6)
+al_legend,c1_items,psym=c1_psym,corners=c1,box=0
+al_legend,c2_items,line=c2_line,corners=c2,box=0,pos=[c1[2],c1[3]],/norm
+c = [c1[0]c2[2],c1[3]>c2[3]]
+cgplots,[c[0],c[0],c[2],c[2],c[0]],[c[1],c[3],c[3],c[1],c[1]],/norm
+!p.charsize=0
+cgtext,.01,.05,$
+ 'Multiple columns---type "al_legend,/help" for details.',/norm,charsize=1.2
+return
+end
+
diff --git a/Code/script_idl_mv/astrolib/altaz2hadec.pro b/Code/script_idl_mv/astrolib/altaz2hadec.pro
new file mode 100644
index 0000000000000000000000000000000000000000..96d543b33baedc546e9f2ea80f05d6f3503984fa
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/altaz2hadec.pro
@@ -0,0 +1,69 @@
+PRO altaz2hadec, alt, az, lat, ha, dec
+;+
+; NAME:
+; ALTAZ2HADEC
+; PURPOSE:
+; Convert Horizon (Alt-Az) coordinates to Hour Angle and Declination.
+; EXPLANATION::
+; Can deal with the NCP singularity. Intended mainly to be used by
+; program hor2eq.pro
+; CALLING SEQUENCE:
+; ALTAZ2HADEC, alt, az, lat, ha, dec
+;
+; INPUTS
+; alt - the local apparent altitude, in DEGREES, scalar or vector
+; az - the local apparent azimuth, in DEGREES, scalar or vector,
+; measured EAST of NORTH!!! If you have measured azimuth west-of-south
+; (like the book MEEUS does), convert it to east of north via:
+; az = (az + 180) mod 360
+;
+; lat - the local geodetic latitude, in DEGREES, scalar or vector.
+;
+; OUTPUTS
+; ha - the local apparent hour angle, in DEGREES. The hour angle is the
+; time that right ascension of 0 hours crosses the local meridian.
+; It is unambiguously defined.
+; dec - the local apparent declination, in DEGREES.
+;
+; EXAMPLE:
+; Arcturus is observed at an apparent altitude of 59d,05m,10s and an
+; azimuth (measured east of north) of 133d,18m,29s while at the
+; latitude of +43.07833 degrees.
+; What are the local hour angle and declination of this object?
+;
+; IDL> altaz2hadec, ten(59,05,10), ten(133,18,29), 43.07833, ha, dec
+; ===> Hour angle ha = 336.683 degrees
+; Declination, dec = 19.1824 degrees
+;
+; The widely available XEPHEM code gets:
+; Hour Angle = 336.683
+; Declination = 19.1824
+;
+; REVISION HISTORY:
+; Written Chris O'Dell Univ. of Wisconsin-Madison May 2002
+;-
+
+ if N_params() LT 4 then begin
+ print,'Syntax - ALTAZ2HADEC, alt, az, lat, ha, dec'
+ return
+ endif
+ d2r = !dpi/180.0d
+ alt_r = alt*d2r
+ az_r = az*d2r
+ lat_r = lat*d2r
+
+;******************************************************************************
+; find local HOUR ANGLE (in degrees, from 0. to 360.)
+ ha = atan( -sin(az_r)*cos(alt_r), $
+ -cos(az_r)*sin(lat_r)*cos(alt_r)+sin(alt_r)*cos(lat_r))
+ ha = ha / d2r
+ w = where(ha LT 0.)
+ if w[0] ne -1 then ha[w] = ha[w] + 360.
+ ha = ha mod 360.
+
+; Find declination (positive if north of Celestial Equator, negative if south)
+ sindec = sin(lat_r)*sin(alt_r) + cos(lat_r)*cos(alt_r)*cos(az_r)
+ dec = asin(sindec)/d2r ; convert dec to degrees
+
+
+END
diff --git a/Code/script_idl_mv/astrolib/aper.pro b/Code/script_idl_mv/astrolib/aper.pro
new file mode 100644
index 0000000000000000000000000000000000000000..940bb0cf0a97d91d5ad986949a0f3a509433cb8b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/aper.pro
@@ -0,0 +1,476 @@
+pro aper,image,xc,yc,mags,errap,sky,skyerr,phpadu,apr,skyradii,badpix, $
+ SETSKYVAL = setskyval,PRINT = print, SILENT = silent, FLUX=flux, $
+ EXACT = exact, Nan = nan, READNOISE = readnoise, MEANBACK = meanback, $
+ CLIPSIG=clipsig, MAXITER=maxiter,CONVERGE_NUM=converge_num, $
+ MINSKY = minsky
+;+
+; NAME:
+; APER
+; PURPOSE:
+; Compute concentric aperture photometry (adapted from DAOPHOT)
+; EXPLANATION:
+; APER can compute photometry in several user-specified aperture radii.
+; A separate sky value is computed for each source using specified inner
+; and outer sky radii.
+;
+; CALLING SEQUENCE:
+; APER, image, xc, yc, [ mags, errap, sky, skyerr, phpadu, apr, skyrad,
+; badpix, /NAN, /EXACT, /FLUX, PRINT = , /SILENT,
+; /MEANBACK, MINSKY=, SETSKYVAL = ]
+; INPUTS:
+; IMAGE - input image array
+; XC - vector of x coordinates.
+; YC - vector of y coordinates
+;
+; OPTIONAL INPUTS:
+; PHPADU - Photons per Analog Digital Units, numeric scalar. Converts
+; the data numbers in IMAGE to photon units. (APER assumes
+; Poisson statistics.)
+; APR - Vector of up to 12 REAL photometry aperture radii.
+; SKYRAD - Two element vector giving the inner and outer radii
+; to be used for the sky annulus. Ignored if the SETSKYVAL
+; keyword is set.
+; BADPIX - Two element vector giving the minimum and maximum value
+; of a good pixel. If badpix is not supplied or if BADPIX[0] is
+; equal to BADPIX[1] then it is assumed that there are no bad
+; pixels. Note that fluxes will not be computed for any star
+; with a bad pixel within the aperture area, but that bad pixels
+; will be simply ignored for the sky computation. The BADPIX
+; parameter is ignored if the /NAN keyword is set.
+;
+; OPTIONAL KEYWORD INPUTS:
+; CLIPSIG - if /MEANBACK is set, then this is the number of sigma at which
+; to clip the background. Default=3
+; CONVERGE_NUM: if /MEANBACK is set then if the proportion of
+; rejected pixels is less than this fraction, the iterations stop.
+; Default=0.02, i.e., iteration stops if fewer than 2% of pixels
+; excluded.
+; /EXACT - By default, APER counts subpixels, but uses a polygon
+; approximation for the intersection of a circular aperture with
+; a square pixel (and normalizes the total area of the sum of the
+; pixels to exactly match the circular area). If the /EXACT
+; keyword, then the intersection of the circular aperture with a
+; square pixel is computed exactly. The /EXACT keyword is much
+; slower and is only needed when small (~2 pixels) apertures are
+; used with very undersampled data.
+; /FLUX - By default, APER uses a magnitude system where a magnitude of
+; 25 corresponds to 1 flux unit. If set, then APER will keep
+; results in flux units instead of magnitudes.
+; MAXITER if /MEANBACK is set then this is the ceiling on number of
+; clipping iterations of the background. Default=5
+; /MEANBACK - if set, then the background is computed using the 3 sigma
+; clipped mean (using meanclip.pro) rather than using the mode
+; computed with mmm.pro. This keyword is useful for the Poisson
+; count regime or where contamination is known to be minimal.
+; MINSKY - Integer giving mininum number of sky values to be used with MMM
+; APER will not compute a flux if fewer valid sky elements are
+; within the sky annulus. Default = 20.
+; /NAN - If set then APER will check for NAN values in the image. /NAN
+; takes precedence over the BADPIX parameter. Note that fluxes
+; will not be computed for any star with a NAN pixel within the
+; aperture area, but that NAN pixels will be simply ignored for
+; the sky computation.
+; PRINT - if set and non-zero then APER will also write its results to
+; a file aper.prt. One can specify the output file name by
+; setting PRINT = 'filename'.
+; READNOISE - Scalar giving the read noise (or minimum noise for any
+; pixel. This value is passed to the procedure mmm.pro when
+; computing the sky, and is only need for images where
+; the noise is low, and pixel values are quantized.
+; /SILENT - If supplied and non-zero then no output is displayed to the
+; terminal.
+; SETSKYVAL - Use this keyword to force the sky to a specified value
+; rather than have APER compute a sky value. SETSKYVAL
+; can either be a scalar specifying the sky value to use for
+; all sources, or a 3 element vector specifying the sky value,
+; the sigma of the sky value, and the number of elements used
+; to compute a sky value. The 3 element form of SETSKYVAL
+; is needed for accurate error budgeting.
+;
+; OUTPUTS:
+; MAGS - NAPER by NSTAR array giving the magnitude for each star in
+; each aperture. (NAPER is the number of apertures, and NSTAR
+; is the number of stars). If the /FLUX keyword is not set, then
+; a flux of 1 digital unit is assigned a zero point magnitude of
+; 25.
+; ERRAP - NAPER by NSTAR array giving error for each star. If a
+; magnitude could not be determined then ERRAP = 9.99 (if in
+; magnitudes) or ERRAP = !VALUES.F_NAN (if /FLUX is set).
+; SKY - NSTAR element vector giving sky value for each star in
+; flux units
+; SKYERR - NSTAR element vector giving error in sky values
+;
+; EXAMPLE:
+; Determine the flux and error for photometry radii of 3 and 5 pixels
+; surrounding the position 234.2,344.3 on an image array, im. Compute
+; the partial pixel area exactly. Assume that the flux units are in
+; Poisson counts, so that PHPADU = 1, and the sky value is already known
+; to be 1.3, and that the range [-32767,80000] for bad low and bad high
+; pixels
+;
+;
+; IDL> aper, im, 234.2, 344.3, flux, eflux, sky,skyerr, 1, [3,5], -1, $
+; [-32767,80000],/exact, /flux, setsky = 1.3
+;
+; PROCEDURES USED:
+; GETOPT, MMM, PIXWT(), STRN(), STRNUMBER()
+; NOTES:
+; Reasons that a valid magnitude cannot be computed include the following:
+; (1) Star position is too close (within 0.5 pixels) to edge of the frame
+; (2) Less than 20 valid pixels available for computing sky
+; (3) Modal value of sky could not be computed by the procedure MMM
+; (4) *Any* pixel within the aperture radius is a "bad" pixel
+; (5) The total computed flux is negative. In this case the negative
+; flux and error are returned.
+;
+;
+; For the case where the source is fainter than the background, APER will
+; return negative fluxes if /FLUX is set, but will otherwise give
+; invalid data (since negative fluxes can't be converted to magnitudes)
+;
+; APER was modified in June 2000 in two ways: (1) the /EXACT keyword was
+; added (2) the approximation of the intersection of a circular aperture
+; with square pixels was improved (i.e. when /EXACT is not used)
+; REVISON HISTORY:
+; Adapted to IDL from DAOPHOT June, 1989 B. Pfarr, STX
+; FLUX keyword added J. E. Hollis, February, 1996
+; SETSKYVAL keyword, increase maxsky W. Landsman, May 1997
+; Work for more than 32767 stars W. Landsman, August 1997
+; Don't abort for insufficient sky pixels W. Landsman May 2000
+; Added /EXACT keyword W. Landsman June 2000
+; Allow SETSKYVAL = 0 W. Landsman December 2000
+; Set BADPIX[0] = BADPIX[1] to ignore bad pixels W. L. January 2001
+; Fix chk_badpixel problem introduced Jan 01 C. Ishida/W.L. February 2001
+; Set bad fluxes and error to NAN if /FLUX is set W. Landsman Oct. 2001
+; Remove restrictions on maximum sky radius W. Landsman July 2003
+; Added /NAN keyword W. Landsman November 2004
+; Set badflux=0 if neither /NAN nor badpix is set M. Perrin December 2004
+; Added READNOISE keyword W. Landsman January 2005
+; Added MEANBACK keyword W. Landsman October 2005
+; Correct typo when /EXACT and multiple apertures used. W.L. Dec 2005
+; Remove VMS-specific code W.L. Sep 2006
+; Add additional keywords if /MEANBACK is set W.L Nov 2006
+; Allow negative fluxes if /FLUX is set W.L. Mar 2008
+; Previous update would crash if first star was out of range W.L. Mar 2008
+; Fix floating equality test for bad magnitudes W.L./J.van Eyken Jul 2009
+; Added MINSKY keyword W.L. Dec 2011
+; Don't ever modify input skyrad variable W. Landsman Aug 2013
+; Avoid integer overflow for very big images W. Landsman/R. Gutermuth Mar 2016
+;-
+ COMPILE_OPT IDL2
+ On_error,2
+; Set parameter limits
+ ;Smallest number of pixels from which the sky may be determined
+ if N_elements(minsky) EQ 0 then minsky = 20
+ maxsky = 10000 ;Maximum number of pixels allowed in the sky annulus.
+;
+if N_params() LT 3 then begin ;Enough parameters supplied?
+ print, $
+ 'Syntax - APER, image, xc, yc, [ mags, errap, sky, skyerr, phpadu, apr, '
+ print,' skyrad, badpix, /EXACT, /FLUX, SETSKYVAL = ,PRINT=, ]'
+ print,' /SILENT, /NAN, MINSKY='
+ return
+endif
+
+ s = size(image)
+ if ( s[0] NE 2 ) then message, $
+ 'ERROR - Image array (first parameter) must be 2 dimensional'
+ ncol = s[1] & nrow = s[2] ;Number of columns and rows in image array
+
+ silent = keyword_set(SILENT)
+
+ if ~keyword_set(nan) then begin
+ if (N_elements(badpix) NE 2) then begin ;Bad pixel values supplied
+GET_BADPIX:
+ ans = ''
+ print,'Enter low and high bad pixel values, [RETURN] for defaults'
+ read,'Low and high bad pixel values [none]: ',ans
+ if ans EQ '' then badpix = [0,0] else begin
+ badpix = getopt(ans,'F')
+ if ( N_elements(badpix) NE 2 ) then begin
+ message,'Expecting 2 scalar values',/continue
+ goto,GET_BADPIX
+ endif
+ endelse
+ endif
+
+ chk_badpix = badpix[0] LT badpix[1] ;Ignore bad pixel checks?
+ endif
+
+ if ( N_elements(apr) LT 1 ) then begin ;Read in aperture sizes?
+ apr = fltarr(10)
+ read, 'Enter first aperture radius: ',ap
+ apr[0] = ap
+ ap = 'aper'
+ for i = 1,9 do begin
+GETAP:
+ read,'Enter another aperture radius, [RETURN to terminate]: ',ap
+ if ap EQ '' then goto,DONE
+ result = strnumber(ap,val)
+ if result EQ 1 then apr[i] = val else goto, GETAP
+ endfor
+DONE:
+ apr = apr[0:i-1]
+ endif
+
+
+ if N_elements(SETSKYVAL) GT 0 then begin
+ if N_elements( SETSKYVAL ) EQ 1 then setskyval = [setskyval,0.,1.]
+ if N_elements( SETSKYVAL ) NE 3 then message, $
+ 'ERROR - Keyword SETSKYVAL must contain 1 or 3 elements'
+ skyrad = [ 0., max(apr) + 1]
+ endif else begin
+ if N_elements(skyradii) NE 2 then begin
+ skyrad = fltarr(2)
+ read,'Enter inner and outer sky radius (pixel units): ',skyrad
+ endif else skyrad = float(skyradii)
+ endelse
+
+ if ( N_elements(phpadu) LT 1 ) then $
+ read,'Enter scale factor in Photons per Analog per Digital Unit: ',phpadu
+
+ Naper = N_elements( apr ) ;Number of apertures
+ Nstars = min([ N_elements(xc), N_elements(yc) ]) ;Number of stars to measure
+
+ ms = strarr( Naper ) ;String array to display mag for each aperture
+ if keyword_set(flux) then $
+ fmt = '(F8.1,1x,A,F7.1)' else $ ;Flux format
+ fmt = '(F9.3,A,F5.3)' ;Magnitude format
+ fmt2 = '(I5,2F8.2,F7.2,1x,3A,3(/,28x,4A,:))' ;Screen format
+ fmt3 = '(I4,5F8.2,1x,6A,2(/,44x,9A,:))' ;Print format
+
+ mags = fltarr( Naper, Nstars) & errap = mags ;Declare arrays
+ sky = fltarr( Nstars ) & skyerr = sky
+ area = !PI*apr*apr ;Area of each aperture
+
+ if keyword_set(EXACT) then begin
+ bigrad = apr + 0.5
+ smallrad = apr/sqrt(2) - 0.5
+ endif
+
+
+ if N_elements(SETSKYVAL) EQ 0 then begin
+
+ rinsq = (skyrad[0]> 0.)^2
+ routsq = skyrad[1]^2
+ endif
+
+ if keyword_set(PRINT) then begin ;Open output file and write header info?
+ if size(PRINT,/TNAME) NE 'STRING' then file = 'aper.prt' $
+ else file = print
+ message,'Results will be written to a file ' + file,/INF
+ openw,lun,file,/GET_LUN
+ printf,lun,'Program: APER: '+ systime(), ' User: ', $
+ getenv('USER'),' Host: ',getenv('HOST')
+ for j = 0, Naper-1 do printf,lun, $
+ format='(a,i2,a,f4.1)','Radius of aperture ',j,' = ',apr[j]
+ if N_elements(SETSKYVAL) EQ 0 then begin
+ printf,lun,f='(/a,f4.1)','Inner radius for sky annulus = ',skyrad[0]
+ printf,lun,f='(a,f4.1)', 'Outer radius for sky annulus = ',skyrad[1]
+ endif else printf,lun,'Sky values fixed at ', strtrim(setskyval[0],2)
+ if keyword_set(FLUX) then begin
+ printf,lun,f='(/a)', $
+ 'Star X Y Sky SkySig SkySkw Fluxes'
+ endif else printf,lun,f='(/a)', $
+ 'Star X Y Sky SkySig SkySkw Magnitudes'
+ endif
+ print = keyword_set(PRINT)
+
+; Print header
+ if ~SILENT then begin
+ if KEYWORD_SET(FLUX) then begin
+ print, format="(/1X,'Star',5X,'X',7X,'Y',6X,'Sky',8X,'Fluxes')"
+ endif else print, $
+ format="(/1X,'Star',5X,'X',7X,'Y',6X,'Sky',8X,'Magnitudes')"
+ endif
+
+; Compute the limits of the submatrix. Do all stars in vector notation.
+
+ lx = long(xc-skyrad[1]) > 0 ;Lower limit X direction
+ ux = long(xc+skyrad[1]) < (ncol-1) ;Upper limit X direction
+ nx = ux-lx+1 ;Number of pixels X direction
+ ly = long(yc-skyrad[1]) > 0 ;Lower limit Y direction
+ uy = long(yc+skyrad[1]) < (nrow-1); ;Upper limit Y direction
+ ny = uy-ly +1 ;Number of pixels Y direction
+ dx = xc-lx ;X coordinate of star's centroid in subarray
+ dy = yc-ly ;Y coordinate of star's centroid in subarray
+
+ edge = (dx-0.5) < (nx+0.5-dx) < (dy-0.5) < (ny+0.5-dy) ;Closest edge to array
+ badstar = ((xc LT 0.5) or (xc GT ncol-1.5) $ ;Stars too close to the edge
+ or (yc LT 0.5) or (yc GT nrow-1.5))
+;
+ badindex = where( badstar, Nbad) ;Any stars outside image
+ if ( Nbad GT 0 ) then message, /INF, $
+ 'WARNING - ' + strn(nbad) + ' star positions outside image'
+ if keyword_set(flux) then begin
+ badval = !VALUES.F_NAN
+ baderr = badval
+ endif else begin
+ badval = 99.999
+ baderr = 9.999
+ endelse
+
+ for i = 0L, Nstars-1 do begin ;Compute magnitudes for each star
+ apmag = replicate(badval, Naper) & magerr = replicate(baderr, Naper)
+ skymod = 0. & skysig = 0. & skyskw = 0. ;Sky mode sigma and skew
+ if badstar[i] then goto, BADSTAR
+ error1=apmag & error2 = apmag & error3 = apmag
+
+ rotbuf = image[ lx[i]:ux[i], ly[i]:uy[i] ] ;Extract subarray from image
+; RSQ will be an array, the same size as ROTBUF containing the square of
+; the distance of each pixel to the center pixel.
+
+
+ dxsq = ( findgen( nx[i] ) - dx[i] )^2
+ rsq = fltarr( nx[i], ny[i], /NOZERO )
+ for ii = 0, ny[i]-1 do rsq[0,ii] = dxsq + (ii-dy[i])^2
+
+
+ if keyword_set(exact) then begin
+ nbox = lindgen(nx[i]*ny[i])
+ xx = reform( (nbox mod nx[i]), nx[i], ny[i])
+ yy = reform( (nbox/nx[i]),nx[i],ny[i])
+ x1 = abs(xx-dx[i])
+ y1 = abs(yy-dy[i])
+ endif else begin
+ r = sqrt(rsq) - 0.5 ;2-d array of the radius of each pixel in the subarray
+ endelse
+
+; Select pixels within sky annulus, and eliminate pixels falling
+; below BADLO threshold. SKYBUF will be 1-d array of sky pixels
+ if N_elements(SETSKYVAL) EQ 0 then begin
+
+ skypix = ( rsq GE rinsq ) and ( rsq LE routsq )
+ if keyword_set(nan) then skypix = skypix and finite(rotbuf) $
+ else if chk_badpix then skypix = skypix and ( rotbuf GT badpix[0] ) and $
+ (rotbuf LT badpix[1] )
+ sindex = where(skypix, Nsky)
+ Nsky = Nsky < maxsky ;Must be less than MAXSKY pixels
+ if ( nsky LT minsky ) then begin ;Sufficient sky pixels?
+ if ~silent then $
+ message,'There aren''t enough valid pixels in the sky annulus.',/con
+ goto, BADSTAR
+ endif
+ skybuf = rotbuf[ sindex[0:nsky-1] ]
+
+ if keyword_set(meanback) then $
+ meanclip,skybuf,skymod,skysig, $
+ CLIPSIG=clipsig, MAXITER=maxiter, CONVERGE_NUM=converge_num else $
+ mmm, skybuf, skymod, skysig, skyskw, readnoise=readnoise,minsky=minsky
+
+
+
+; Obtain the mode, standard deviation, and skewness of the peak in the
+; sky histogram, by calling MMM.
+
+ skyvar = skysig^2 ;Variance of the sky brightness
+ sigsq = skyvar/nsky ;Square of standard error of mean sky brightness
+
+;If the modal sky value could not be determined, then all apertures for this
+; star are bad
+
+ if ( skysig LT 0.0 ) then goto, BADSTAR
+
+ skysig = skysig < 999.99 ;Don't overload output formats
+ skyskw = skyskw >(-99)<999.9
+ endif else begin
+ skymod = setskyval[0]
+ skysig = setskyval[1]
+ nsky = setskyval[2]
+ skyvar = skysig^2
+ sigsq = skyvar/nsky
+ skyskw = 0
+endelse
+
+
+
+ for k = 0,Naper-1 do begin ;Find pixels within each aperture
+
+ if ( edge[i] GE apr[k] ) then begin ;Does aperture extend outside the image?
+ if keyword_set(EXACT) then begin
+ mask = fltarr(nx[i],ny[i])
+ good = where( ( x1 LT smallrad[k] ) and (y1 LT smallrad[k] ), Ngood)
+ if Ngood GT 0 then mask[good] = 1.0
+ bad = where( (x1 GT bigrad[k]) or (y1 GT bigrad[k] )) ;Fix 05-Dec-05
+ mask[bad] = -1
+
+ gfract = where(mask EQ 0.0, Nfract)
+ if Nfract GT 0 then mask[gfract] = $
+ PIXWT(dx[i],dy[i],apr[k],xx[gfract],yy[gfract]) > 0.0
+ thisap = where(mask GT 0.0)
+ thisapd = rotbuf[thisap]
+ fractn = mask[thisap]
+ endif else begin
+;
+ thisap = where( r LT apr[k] ) ;Select pixels within radius
+ thisapd = rotbuf[thisap]
+ thisapr = r[thisap]
+ fractn = (apr[k]-thisapr < 1.0 >0.0 ) ;Fraction of pixels to count
+ full = fractn EQ 1.0
+ gfull = where(full, Nfull)
+ gfract = where(1 - full)
+ factor = (area[k] - Nfull ) / total(fractn[gfract])
+ fractn[gfract] = fractn[gfract]*factor
+ endelse
+
+; If the pixel is bad, set the total counts in this aperture to a large
+; negative number
+;
+ if keyword_set(NaN) then $
+ badflux = min(finite(thisapd)) EQ 0 $
+ else if chk_badpix then begin
+ minthisapd = min(thisapd, max = maxthisapd)
+ badflux = (minthisapd LE badpix[0] ) or ( maxthisapd GE badpix[1])
+ endif else badflux = 0
+
+ if ~badflux then $
+ apmag[k] = total(thisapd*fractn) ;Total over irregular aperture
+ endif
+endfor ;k
+ if keyword_set(flux) then g = where(finite(apmag), Ng) else $
+ g = where(abs(apmag - badval) GT 0.01, Ng)
+ if Ng GT 0 then begin
+ apmag[g] = apmag[g] - skymod*area[g] ;Subtract sky from the integrated brightnesses
+
+; Add in quadrature 3 sources of error: (1) random noise inside the star
+; aperture, including readout noise and the degree of contamination by other
+; stars in the neighborhood, as estimated by the scatter in the sky values
+; (this standard error increases as the square root of the area of the
+; aperture); (2) the Poisson statistics of the observed star brightness;
+; (3) the uncertainty of the mean sky brightness (this standard error
+; increases directly with the area of the aperture).
+
+ error1[g] = area[g]*skyvar ;Scatter in sky values
+ error2[g] = (apmag[g] > 0)/phpadu ;Random photon noise
+ error3[g] = sigsq*area[g]^2 ;Uncertainty in mean sky brightness
+ magerr[g] = sqrt(error1[g] + error2[g] + error3[g])
+
+ if ~keyword_set(FLUX) then begin
+ good = where (apmag GT 0.0, Ngood) ;Are there any valid integrated fluxes?
+ if ( Ngood GT 0 ) then begin ;If YES then compute errors
+ magerr[good] = 1.0857*magerr[good]/apmag[good] ;1.0857 = log(10)/2.5
+ apmag[good] = 25.-2.5*alog10(apmag[good])
+ endif
+ endif
+ endif
+
+ BADSTAR:
+
+;Print out magnitudes for this star
+
+ for ii = 0,Naper-1 do $ ;Concatenate mags into a string
+
+ ms[ii] = string( apmag[ii],'+-',magerr[ii], FORM = fmt)
+ if PRINT then printf,lun, $ ;Write results to file?
+ form = fmt3, i, xc[i], yc[i], skymod, skysig, skyskw, ms
+ if ~SILENT then print,form = fmt2, $ ;Write results to terminal?
+ i,xc[i],yc[i],skymod,ms
+
+ sky[i] = skymod & skyerr[i] = skysig ;Store in output variable
+ mags[0,i] = apmag & errap[0,i]= magerr
+ endfor ;i
+
+ if PRINT then free_lun, lun ;Close output file
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/arcbar.pro b/Code/script_idl_mv/astrolib/arcbar.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b331d29c44f576baeb412474ccf922230956169f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/arcbar.pro
@@ -0,0 +1,155 @@
+Pro arcbar, hdr, arclen, LABEL = label, SIZE = size, THICK = thick, DATA =data, $
+ COLOR = color, POSITION = position, NORMAL = normal, $
+ SECONDS=SECONDS, FONT=font
+;+
+; NAME:
+; ARCBAR
+; PURPOSE:
+; Draw an arc bar on an image showing the astronomical plate scale
+;
+; CALLING SEQUENCE:
+; ARCBAR, hdr, arclen,[ COLOR= , /DATA, LABEL= , /NORMAL, POSITION=,
+; /SECONDS, SIZE=, THICK=, FONT= ]
+;
+; INPUTS:
+; hdr - image FITS header with astrometry, string array
+; OPTIONAL INPUT:
+; arclen - numeric scalar giving length of bar in arcminutes (default)
+; or arcseconds (if /SECONDS is set). Default is 1 arcminute
+;
+; OPTIONAL KEYWORD INPUTS:
+; COLOR - name or integer scalar specifying the color to draw the arcbar
+; See cgColor for a list of available color names
+; /DATA - if set and non-zero, then the POSITION keyword and the arc
+; length is given in data units
+; LABEL - string giving user defined label for bar. Default label is size
+; of bar in arcminutes
+; /NORMAL - if this keyword is set and non-zero, then POSITION is given in
+; normalized units
+; POSITION - 2 element vector giving the (X,Y) position in device units
+; (or normalized units if /NORMAL is set, or data units if /DATA
+; is set) at which to place the scale bar. If not supplied,
+; then the user will be prompted to place the cursor at the
+; desired position
+; /SECONDS - if set, then arlen is specified in arcseconds rather than
+; arcminutes
+; SIZE - scalar specifying character size of label, default = 1.0
+; THICK - Character thickness of the label, default = !P.THICK
+; FONT - scalar font graphics keyword (-1,0 or 1) for text
+;
+; EXAMPLE:
+; Suppose one has an image array, IM, and FITS header, HDR, with
+; astrometry. Display the image and place a 3' arc minute scale bar
+; at position 300,200 of the current image window
+;
+; IDL> cgimage, IM, /scale,/save ;Use /SAVE to set data coordinates
+; IDL> arcbar, HDR, 3, pos = [300,200],/data
+;
+; RESTRICTIONS:
+; When using using a device with scalable pixels (e.g. postscript)
+; the data coordinate system must be established before calling ARCBAR.
+; If data coordinates are not set, then ARCBAR assumes that the displayed
+; image size is given by the NAXIS1 keyword in the FITS header.
+; PROCEDURE CALLS:
+; AD2XY, EXTAST, GSSSADXY, SXPAR(), SETDEFAULTVALUE, cgPlot, cgText
+; REVISON HISTORY:
+; written by L. Taylor (STX) from ARCBOX (Boothman)
+; modified for Version 2 IDL, B. Pfarr, STX, 4/91
+; New ASTROMETRY structures W.Landsman, HSTX, Jan 94
+; Recognize a GSSS header W. Landsman June 94
+; Added /NORMAL keyword W. Landsman Feb. 96
+; Use NAXIS1 for postscript if data coords not set, W. Landsman Aug 96
+; Fixed typo for postscript W. Landsman Oct. 96
+; Account for zeropoint offset in postscript W. Landsman Apr 97
+; Added /DATA, /SECONDS keywords W. Landsman July 1998
+; Use device-independent label offset W. Landsman August 2001
+; Allow font keyword to be passed. T. Robishaw Apr. 2006
+; Remove obsolete TVCURSOR command W. Landsman Jul 2007
+; Use Coyote Graphics W. Landsman February 2011
+; Fix problem using data coordinates when not in postscript
+; W. Landsman January 2013
+;-
+;
+ compile_opt idl2
+ On_error,2 ;Return to caller
+
+ if N_params() LT 1 then begin
+ print, 'Syntax - ARCBAR, hdr,[ arclen, COLOR= '
+ print, ' /DATA, LABEL=, /NORM, POS=, /SECONDS, SIZE=, THICK= ]'
+ return
+ endif
+
+ extast, hdr, bastr, noparams ;extract astrom params in deg.
+
+ if N_params() LT 2 then arclen = 1 ;default size = 1 arcmin
+
+ setdefaultvalue, size, 1.0
+ setdefaultvalue, thick, !P.THICK
+ setdefaultvalue, font, !P.FONT
+
+ a = bastr.crval[0]
+ d = bastr.crval[1]
+ if keyword_set(seconds) then factor = 3600.0d else factor = 60.0
+ d1 = d + (1/factor) ;compute x,y of crval + 1 arcmin
+
+ proj = strmid(bastr.ctype[0],5,3)
+
+ case proj of
+ 'GSS': gsssadxy, bastr, [a,a], [d,d1], x, y
+ else: ad2xy, [a,a], [d,d1], bastr, x, y
+ endcase
+
+ dmin = sqrt( (x[1]-x[0])^2 + (y[1]-y[0])^2 ) ;det. size in pixels of 1 arcmin
+
+ if ((!D.FLAGS AND 1) EQ 1) || keyword_set(data) then begin ;Device have scalable pixels?
+ if !X.s[1] NE 0 then begin
+ dmin = convert_coord( dmin, 0, /DATA, /TO_DEVICE) - $
+ convert_coord( 0, 0, /DATA, /TO_DEVICE) ;Fixed Apr 97
+ dmin = dmin[0]
+ endif else dmin = dmin/sxpar(hdr, 'NAXIS1' ) ;Fixed Oct. 96
+ endif
+
+ dmini2 = round(dmin * arclen)
+
+ if ~keyword_set( POSITION) then begin
+ print,'Position the cursor where you want the bar to begin'
+ print,'Hit right mouse button when ready'
+ cursor,xi,yi,1,/device
+ endif else begin
+ if keyword_set(NORMAL) then begin
+ posn = convert_coord(position,/NORMAL, /TO_DEVICE)
+ xi = posn[0] & yi = posn[1]
+ endif else if keyword_set(DATA) then begin
+ posn = convert_coord(position,/DATA, /TO_DEVICE)
+ xi = posn[0] & yi = posn[1]
+ endif else begin
+ xi = position[0] & yi = position[1]
+ endelse
+ endelse
+
+ xf = xi + dmini2
+ dmini3 = dmini2/10 ;Height of vertical end bars = total length/10.
+
+ cgPlots,[xi,xf],[yi,yi], COLOR=color, /DEV, THICK=thick
+ cgPlots,[xf,xf],[ yi+dmini3, yi-dmini3 ], COLOR=color, /DEV, THICK=thick
+ cgPlots,[xi,xi],[ yi+dmini3, yi-dmini3 ], COLOR=color, /DEV, THICK=thick
+
+ if ~keyword_set(Seconds) then begin
+ if (!D.NAME EQ 'PS') && (FONT EQ 0) then $ ;Postscript Font?
+ arcsym='!9'+string(162B)+'!X' else arcsym = "'"
+ endif else begin
+ if (!D.NAME EQ 'PS') && (FONT EQ 0) then $ ;Postscript Font?
+ arcsym = '!9'+string(178B)+'!X' else arcsym = "''"
+ endelse
+ if ~keyword_set( LABEL) then begin
+ if (arclen LT 1) then arcstr = string(arclen,format='(f4.2)') $
+ else arcstr = string(arclen)
+ label = strtrim(arcstr,2) + arcsym
+ endif
+
+ yoffset = round(!D.Y_CH_SIZE/2.)
+ cgTEXT,(xi+xf)/2, yi+yoffset, label, SIZE = size,COLOR=color,/DEV, $
+ alignment=0.5, CHARTHICK=thick, FONT=font
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/arrows.pro b/Code/script_idl_mv/astrolib/arrows.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1c785420831bfaaac74552794cb0cef3b44a130
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/arrows.pro
@@ -0,0 +1,138 @@
+pro arrows,h,xcen,ycen,thick=thick,charsize=charsize,arrowlen=arrowlen, $
+ color=color,NotVertex=NotVertex,Normal = normal,Data=data,font=font
+;+
+; NAME:
+; ARROWS
+; PURPOSE:
+; To display "weathervane" directional arrows on an astronomical image
+; EXPLANATION:
+; Overlays a graphic showing orientation of North and East.
+;
+; CALLING SEQUENCE:
+; ARROWS,h, [ xcen, ycen, ARROWLEN= , CHARSIZE= COLOR= , /DATA
+; FONT=, /NORMAL, /NOTVERTEX, THICK= ]
+;
+; INPUTS:
+; h - FITS header array, must include astrometry
+;
+; OPTIONAL INPUTS:
+; xcen,ycen - numeric scalars, specifying the center position of
+; arrows. Position in device units unless the /NORMALIZED
+; keyword is specified. If not supplied, then ARROWS
+; will prompt for xcen and ycen
+;
+; OPTIONAL KEYWORD INPUTS:
+; arrowlen - length of arrows in terms of normal Y size of vector-drawn
+; character, default = 3.5, floating point scalar
+; charsize - character size, default = 2.0, floating point scalar
+; color - color name or number for the arrows and NE letters. See
+; cgCOLOR() for a list of color names.
+; Data - if this keyword is set and nonzero, the input center (xcen,
+; ycen) is understood to be in data coordinates
+; font - IDL vector font number (1-20) to use to display NE letters.
+; For example, set font=13 to use complex italic font.
+; NotVertex - Normally (historically) the specified xcen,ycen indicated
+; the position of the vertex of the figure. If this
+; keyword is set, the xcen,ycen coordinates refer to a sort
+; of 'center of mass' of the figure. This allows the
+; figure to always appear with the area irregardless of
+; the rotation angle.
+; Normal - if this keyword is set and nonzero, the input center
+; (xcen,ycen) is taken to be in normalized coordinates. The
+; default is device coordinates.
+; thick - line thickness, default = 2.0, floating point scalar
+; OUTPUTS:
+; none
+; EXAMPLE:
+; Draw a weathervane at (400,100) on the currently active window,
+; showing the orientation of the image associated with a FITS header, hdr
+;
+; IDL> arrows, hdr, 400, 100
+;
+; METHOD:
+; Uses EXTAST to EXTract ASTrometry from the FITS header. The
+; directions of North and East are computed and the procedure
+; ONE_ARROW called to create the "weathervane".
+;
+; PROCEDURES USED:
+; GETROT - Computes rotation from the FITS header
+; ONE_ARROW - Draw a labeled arrow
+; ZPARCHECK
+; REVISON HISTORY:
+; written by B. Boothman 2/5/86
+; Recoded with new procedures ONE_ARROW, ONE_RAY. R.S.Hill,HSTX,5/20/92
+; Added separate determination for N and E arrow to properly display
+; arrows irregardless of handedness or other peculiarities and added
+; /NotVertex keyword to improve positioning of figure. E.Deutsch 1/10/93
+; Added /DATA and /NORMAL keywords W. Landsman July 1993
+; Recognize GSSS header W. Landsman June 1993
+; Added /FONT keyword W. Landsman April 1995
+; Modified to work correctly for COLOR=0 J.Wm.Parker, HITC 1995 May 25
+; Work correctly for negative CDELT values W. Landsman Feb. 1996
+; Use GETROT to compute rotation W. Landsman June 2003
+; Restored /NotVertex keyword which was not working after June 2003 change
+; W. Landsman January 2004
+;-
+
+ On_error,2 ;Return to caller
+
+ if (N_params() LT 1) then begin
+ print,'Syntax - ' + $
+ 'ARROWS, hdr, [ xcen, ycen, ARROWLEN= , CHARSIZE= COLOR= , /DATA'
+ print,' FONT=, /NORMAL, /NotVertex, THICK= ]'
+ print,' hdr - FITS header with astrometry'
+ return
+ endif else zparcheck,'ARROWS',h,1,7,1,'FITS header array'
+
+ if ( N_params() LT 3 ) then $
+ read,'Enter x, y values for center of arrows: ',xcen,ycen
+
+ setdefaultvalue, thick, 2.0
+ setdefaultvalue, charsize, 2.0
+ setdefaultvalue, arrowlen, 3.5
+ setdefaultvalue, NotVertex, 0
+
+; Derive Position Angles for North and East separately
+
+ getrot,h,npa, cdelt,/SILENT
+ sgn = 1 - 2*(cdelt[0]*cdelt[1] GT 0)
+ epa = npa + sgn*90
+
+; Make arrows reasonable size depending on device
+
+ arrowlen_dev = arrowlen*!D.y_ch_size
+ arrowsize = [arrowlen_dev, arrowlen_dev/3.5, 35.0] ; See one_arrow.pro
+
+ if keyword_set( NORMAL) then begin
+ newcen = convert_coord( xcen, ycen, /NORMAL, /TO_DEVICE)
+ xcent = newcen[0]
+ ycent = newcen[1]
+ endif else if keyword_set( DATA) then begin
+ newcen = convert_coord( xcen, ycen, /DATA, /TO_DEVICE)
+ xcent = newcen[0]
+ ycent = newcen[1]
+ endif else begin
+ xcent=xcen & ycent=ycen
+ endelse
+
+; Adjust Center to 'Center of Mass' if NotVertex set
+ if NotVertex then begin
+ rot = npa/!RADEG
+ dRAdX = cdelt[0]*cos(rot)
+ dRAdY = cdelt[1]*sin(rot)
+ dDECdX = cdelt[0]*sin(rot)
+ dDECdY = cdelt[1]*cos(rot)
+ RAnorm = sqrt( dRAdX^2 + dRAdY^2 )
+ DECnorm = sqrt(dDECdX^2 + dDECdY^2 )
+ xcent = xcen - (dRAdX+dDECdX)/2/RAnorm*arrowsize[0]
+ ycent = ycen - (dRAdY+dDECdY)/2/DECnorm*arrowsize[0]
+ endif
+
+; Draw arrows
+ one_arrow, xcent, ycent, 90+NPA, 'N', font= font, $
+ charsize=charsize, thick=thick, color=color, arrowsize=arrowsize
+ one_arrow, xcent, ycent, 90+EPA, 'E', font = font, $
+ charsize=charsize, thick=thick, color=color, arrowsize=arrowsize
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/asinh.pro b/Code/script_idl_mv/astrolib/asinh.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0083d4645276de605bfea43f59ad3ed181ccade6
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/asinh.pro
@@ -0,0 +1,40 @@
+function asinh, x
+;+
+; NAME:
+; ASINH
+; PURPOSE:
+; Return the inverse hyperbolic sine of the argument
+; EXPLANATION:
+; The inverse hyperbolic sine is used for the calculation of asinh
+; magnitudes, see Lupton et al. (1999, AJ, 118, 1406)
+;
+; CALLING SEQUENCE
+; result = asinh( x)
+; INPUTS:
+; X - hyperbolic sine, numeric scalar or vector or multidimensional array
+; (not complex)
+;
+; OUTPUT:
+; result - inverse hyperbolic sine, same number of elements as X
+; double precision if X is double, otherwise floating pt.
+;
+; METHOD:
+; Expression given in Numerical Recipes, Press et al. (1992), eq. 5.6.7
+; Note that asinh(-x) = -asinh(x) and that asinh(0) = 0. and that
+; if y = asinh(x) then x = sinh(y).
+;
+; REVISION HISTORY:
+; Written W. Landsman February, 2001
+; Work for multi-dimensional arrays W. Landsman August 2002
+; Simplify coding, and work for scalars again W. Landsman October 2003
+;-
+ On_error,2
+
+ y = alog( abs(x) + sqrt( x^2 + 1.0) )
+
+ index = where(x LT 0 ,count)
+ if count GT 0 then y[index] = -y[index]
+
+ return, y
+
+ end
diff --git a/Code/script_idl_mv/astrolib/astdisp.pro b/Code/script_idl_mv/astrolib/astdisp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1521c0585e739e3b8f2aca963bf3220bb4313315
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/astdisp.pro
@@ -0,0 +1,98 @@
+pro AstDisp, x, y, ra, dec, DN, Coords=Coords, silent=silent
+;+
+; NAME:
+; ASTDISP
+;
+; PURPOSE:
+; Print astronomical and pixel coordinates in a standard format
+; EXPLANATION:
+; This procedure (ASTrometry DISPlay) prints the astronomical and
+; pixel coordinates in a standard format. X,Y must be supplied. RA,DEC
+; may also be supplied, and a data number (DN) may also be
+; supplied. With use of the Coords= keyword, a string containing the
+; formatted data can be returned in addition or instead (with /silent)
+; of printing.
+;
+; CALLING SEQUENCE:
+; ASTDISP, x, y, [Ra, Dec, DN, COORD = , /SILENT ]
+;
+; INPUT:
+; X - The X pixel coordinate(s), scalar or vector
+; Y - The Y pixel coordinate(s), scalar or vector
+;
+; OPTIONAL INPUTS:
+; RA - Right Ascension in *degrees*, scalar or vector
+; DEC - DEClination in *degrees*, scalar or vector (if RA is supplied, DEC must also be supplied)
+; DN - Data Number or Flux values
+;
+; Each of the inputs X,Y, RA, DEC, DN should have the same number of
+; elements
+; OPTIONAL INPUT KEYWORDS:
+; SILENT Prevents printing. Only useful when used with Coords=
+; OUTPUT:
+; Printed positions in both degrees and sexagesimal format
+; All passed variables remain unchanged
+; OPTIONAL KEYWORD OUTPUT:
+; COORDS Returns the formatted coordinates in a string
+; PROCEDURES CALLED:
+; ADSTRING - used to format the RA and Dec
+; HISTORY:
+; 10-AUG-90 Version 1 written by Eric W. Deutsch
+; 20-AUG-91 Converted to standard header. Vectorized Code. E. Deutsch
+; 20-NOV-92 Added Coords= and /silent. E.Deutsch
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ On_error,2
+
+ arg = N_params()
+ if (arg lt 2) then begin
+ print,'Call: IDL> AstDisp,x_pixel,y_pixel,[RA,DEC],[DN],[/silent,coords=]'
+ print,'e.g.: IDL> AstDisp,x,y,ra,dec'
+ return
+ endif
+
+ if (arg eq 3) then message,'ERROR - Both RA and Dec values must be supplied'
+
+ silent = keyword_set(SILENT)
+
+; X and Y must be supplied
+
+ hdr = ' X Y'
+ fmt = '(f8.2,1x,f8.2'
+ if (arg le 2) then begin & type=0 & goto,PRN & endif
+
+; Ra and Dec can be optionally supplied
+
+ hdr = hdr+' RA DEC RA DEC'
+ fmt = fmt+',2x,F9.4,1x,F9.4,2x,A'
+ if (arg le 4) then begin & type=1 & goto,PRN & endif
+
+; A data number can be optionally supplied
+
+ hdr = hdr+' DN'
+ fmt = fmt+',3x,f9.3'
+ type = 2
+
+PRN:
+ if not SILENT then print,hdr
+ Coords = strarr( N_elements(x)+1 )
+ Coords[0] = hdr
+
+ for i = 0, N_elements(x)-1 do begin
+
+ case type of
+
+ 0: out = string(format=fmt+')',x[i],y[i],/print)
+ 1: out = string(format=fmt+')',x[i],y[i],ra[i],dec[i], $
+ adstring(ra[i],dec[i],2),/print)
+ 2: out = string(format=fmt+')',x[i],y[i],ra[i],dec[i], $
+ adstring(ra[i],dec[i],2),DN[i],/print)
+ endcase
+
+ if not SILENT then print,out
+ Coords[i+1] = out
+
+ endfor
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/astro.pro b/Code/script_idl_mv/astrolib/astro.pro
new file mode 100644
index 0000000000000000000000000000000000000000..994a68d1079e99119a7be017b383492109c075bc
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/astro.pro
@@ -0,0 +1,175 @@
+pro astro, selection, EQUINOX = equinox, FK4 = FK4
+;+
+; NAME:
+; ASTRO
+; PURPOSE:
+; Interactive utility for precession and coordinate conversion.
+;
+; CALLING SEQUENCE:
+; ASTRO, [ selection, EQUINOX =, /FK4]
+;
+; OPTIONAL INPUT:
+; SELECTION - Scalar Integer (0-6) giving the the particular astronomical
+; utility to be used. (0) Precession, (1) RA, Dec (2000) to Galactic
+; coordinates, (2) Galactic to RA,Dec (2000) (3) RA,Dec (2000) to
+; Ecliptic, (4) Ecliptic to RA, Dec, (5) Ecliptic to Galactic, (6) Galactic
+; to Ecliptic. Program will prompt for SELECTION if this
+; parameter is omitted.
+;
+; OPTIONAL KEYWORD INPUT:
+; EQUINOX - numeric scalar specifying the equinox to use when converting
+; between celestial and other coordinates. If not supplied,
+; then the RA and Dec will be assumed to be in EQUINOX J2000.
+; This keyword is ignored by the precession utility. For
+; example, to convert from RA and DEC (J1975) to Galactic
+; coordinates:
+;
+; IDL> astro, 1, E=1975
+; /FK4 - If this keyword is set and nonzero, then calculations are done
+; in the FK4 system. For example, to convert from RA and Dec
+; (B1975) to Galactic coordinates
+;
+; IDL> astro,1, E=1975,/FK4
+; METHOD:
+; ASTRO uses PRECESS to compute precession, and EULER to compute
+; coordinate conversions. The procedure GET_COORDS is used to
+; read the coordinates, and ADSTRING to format the RA,Dec output.
+;
+; NOTES:
+; (1) ASTRO temporarily sets !QUIET to suppress compilation messages and
+; keep a pretty screen display.
+;
+; (2) ASTRO was changed in December 1998 to use J2000 as the default
+; equinox, **and may be incompatible with earlier calls.***
+;
+; (3) A nice online page for coordinate conversions is available at
+; http://heasarc.gsfc.nasa.gov/cgi-bin/Tools/convcoord/convcoord.pl
+; PROCEDURES USED:
+; Procedures: GET_COORDS, EULER Function: ADSTRING
+; REVISION HISTORY
+; Written, W. Landsman November 1987
+; Code cleaned up W. Landsman October 1991
+; Added Equinox keyword, call to GET_COORDS, W. Landsman April, 1992
+; Allow floating point equinox input J. Parker/W. Landsman July 1996
+; Make FK5 the default, add FK4 keyword
+;-
+ On_error,2 ;Return to caller
+
+ input_type = [0,0,1,0,2,2,1] ;0= RA,Dec 1= Galactic 2 = Ecliptic
+ output_type = [0,1,0,2,0,1,2]
+
+ sv_quiet = !quiet & !quiet = 1 ;Don't display compiled procedures
+
+
+ if keyword_set(FK4) then begin
+ if not keyword_set(EQUINOX) then equinox = 1950
+ fk = 'B'
+ ref_year = 1950
+ yeari = 1950 & yearf = 1950
+ endif else begin
+ if not keyword_set(EQUINOX) then equinox = 2000
+ fk = 'J'
+ ref_year = 2000
+ yeari = 2000 & yearf = 2000
+ endelse
+ eqname = fk + string(equinox,f='(f6.1)') + ')'
+
+ select = ['(0) Precession: (RA, Dec)', $
+ '(1) Conversion: (RA, Dec ' + eqname + ' --> Galactic', $
+ '(2) Conversion: Galactic --> (RA, Dec ' + eqname, $
+ '(3) Conversion: (RA, Dec ' + eqname + ' --> Ecliptic', $
+ '(4) Conversion: Ecliptic --> (RA, Dec ' + eqname, $
+ '(5) Conversion: Ecliptic --> Galactic', $
+ '(6) Conversion: Galactic --> Ecliptic']
+
+ npar = N_params()
+
+ SELECTOR: if (npar EQ 0 ) then begin
+
+ print,'Select astronomical utility'
+ for i = 0,6 do print, select[i]
+ selection = 0
+ print,' '
+ read,'Enter Utility Number: ',selection
+ print,' '
+
+ endif
+
+ if ( selection LT 0 ) or ( selection GT 6 ) then begin
+
+ print,selection,' is not an available option'
+ npar = 0
+ goto, SELECTOR
+
+ endif
+
+ print, select[selection]
+
+ if keyword_set(EQUINOX) and (input_type[selection] EQ 0) then yeari =equinox
+ if keyword_set(EQUINOX) and (output_type[selection] EQ 0) then yearf = equinox
+
+ if ( selection EQ 0 ) then read, $
+ 'Enter initial and final equinox (e.g. 1975,2000): ',yeari,yearf
+
+
+ case output_type[selection] of
+
+ 0: OutName = " RA Dec (" + fk + string( yearf, f= "(F6.1)" ) + "): "
+ 1: OutName = " Galactic longitude and latitude: "
+ 2: OutName = " Ecliptic longitude and latitude: (" + $
+ fk + string( yearf, f= "(F6.1)" ) + ")"
+ endcase
+
+ case input_type[selection] of
+
+ 0: InName = "RA Dec (" + fk + string(yeari ,f ='(F6.1)' ) + ')'
+ 1: InName = "Galactic longitude and latitude: "
+ 2: InName = "Ecliptic longitude and latitude: (" + fk + $
+ string(yeari ,f ='(F6.1)' ) + ')'
+
+ endcase
+
+ HELP_INP: if ( input_type[selection] EQ 0 ) then begin
+
+ print,format='(/A)',' Enter RA, DEC with either 2 or 6 parameters '
+ print,format='(A/)',' Either RA, DEC (degrees) or HR, MIN, SEC, DEG, MIN SEC'
+
+ endif
+
+ READ_INP:
+
+ get_coords,coords,'Enter '+ InName, Numcoords
+
+ if ( coords[0] EQ -999 ) then begin ;Normal Return
+ print,' '
+ if Numcoords GT 0 then goto, READ_INP
+ !quiet = sv_quiet
+ return
+ endif
+
+ ra = coords[0] & dec = coords[1]
+ if Numcoords EQ 6 then ra = ra*15.
+
+ if ( selection EQ 0 ) then begin
+
+ precess, ra , dec , yeari, yearf, FK4 = fk4 ;Actual Calculations
+ newra = ra & newdec = dec
+
+ endif else begin
+ if yeari NE ref_year then precess, ra, dec, yeari, ref_year,FK4=fk4
+ euler, ra, dec, newra, newdec, selection, fk4 = FK4
+ if yearf NE ref_year then precess, newra,newdec, ref_year, yearf,FK4=fk4
+ endelse
+
+ if newra LT 0 then newra = newra + 360.
+
+ if output_type[selection] EQ 0 then $
+ print, outname + adstring( [newra,newdec], 1) $
+
+ else print, FORM = '(A,2F7.2,A,F7.2 )', $
+ outname, newra, newdec
+
+ print,' '
+ goto, READ_INP
+
+ end
diff --git a/Code/script_idl_mv/astrolib/astrolib.pro b/Code/script_idl_mv/astrolib/astrolib.pro
new file mode 100644
index 0000000000000000000000000000000000000000..99d61f92e72880d13af85c8f6b922d8a40a3f63e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/astrolib.pro
@@ -0,0 +1,51 @@
+PRO ASTROLIB
+;+
+; NAME:
+; ASTROLIB
+; PURPOSE:
+; Add the non-standard system variables used by the IDL Astronomy Library
+; EXPLANATION:
+; Also defines the environment variable ASTRO_DATA pointing to the
+; directory containing data files associated with the IDL Astronomy
+; library (system dependent -- user must edit the third line in the
+; program below).
+;
+; CALLING SEQUENCE:
+; ASTROLIB
+;
+; INPUTS:
+; None.
+;
+; OUTPUTS:
+; None.
+;
+; METHOD:
+; The non-standard system variables !PRIV, !TEXTUNIT, and
+; !TEXTOUT are added using DEFSYSV.
+;
+; REVISION HISTORY:
+; Written, Wayne Landsman, July 1986.
+; Use DEFSYSV instead of ADDSYSVAR December 1990
+; Test for system variable existence before definition July 2001
+; Assume since V55, remove VMS support W. Landsman Sep 2006
+; Remove !Debug, comment out ASTRO_DATA definition WL Jan 2009
+;-
+ On_error,2
+ compile_opt idl2
+
+; User should edit the folowing line and uncomment it to give the location of
+; ASTRO_DATA on their own system (or define it in their .cshrc or .bashrc file).
+; setenv,'ASTRO_DATA=/export/home/ftp/pub/data/'
+
+ defsysv, '!PRIV', exist = exist
+ if ~exist then defsysv, '!PRIV', 0
+ defsysv, '!TEXTUNIT', exist = exist
+ if ~exist then defsysv, '!TEXTUNIT', 0
+ defsysv, '!TEXTOUT', exist = exist
+ if ~exist then defsysv, '!TEXTOUT', 1
+
+ message,'Astronomy Library system variables have been added',/INF
+
+ return
+ end
+
diff --git a/Code/script_idl_mv/astrolib/autohist.pro b/Code/script_idl_mv/astrolib/autohist.pro
new file mode 100644
index 0000000000000000000000000000000000000000..66bff440abc69fd2804aec7b8f404aaf80fa1ece
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/autohist.pro
@@ -0,0 +1,106 @@
+PRO AUTOHIST,V, ZX,ZY,XX,YY, NOPLOT=whatever,_EXTRA = _extra
+;
+;+
+; NAME:
+; AUTOHIST
+;
+; PURPOSE:
+; Draw a histogram using automatic bin-sizing.
+; EXPLANATION
+; AUTOHIST chooses a number of bins (initially, SQRT(2*N). If this leads
+; to a histogram in which > 1/5 of the central 50% of the bins are empty,
+; it decreases the number of bins and tries again. The minimum # bins is
+; 5. The max=199. Called by HISTOGAUSS and HALFAGAUSS.
+;
+; CALLING SEQUENCE:
+; AUTOHIST, Sample, XLines, Ylines, XCenters, YCenters, [/NOPLOT, ]
+; ...Plotting Keywords
+; INPUT:
+; Sample = the vector to be histogrammed
+;
+; OUTPUT:
+; XLINES = vector of x coordinates of the points that trace the rectangular
+; histogram bins
+; YLINES = vector of y coordinates. To draw the histogram plot YLINES vs
+; XLINES
+; XCENTERS = the x values of the bin centers
+; YCENTERS = the corresponding y values
+;
+; OPTIONAL INPUT KEYWORDS:
+; /NOPLOT If set, nothing is drawn
+;
+; Any plotting keywords (e.g. XTITLE) may be supplied to AUTOHIST through
+; the _EXTRA facility.
+; REVISION HISTORY:
+; Written, H. Freudenreich, STX, 1/91
+; 1998 March 17 - Changed shading of histogram. RSH, RSTX
+; V5.0 update, _EXTRA keywords W. Landsman April 2002
+; Added NOCLIP keyword for POLYFILL call C. Paxson/W. Landsman July 2003
+; Use Coyote graphics W. Landsman Feb 2011
+;-
+
+ ON_ERROR,2
+ compile_opt idl2
+
+ if N_params() LT 1 then begin
+ print,'Syntax - AUTOHIST, Sample, XLines, Ylines, XCenters, YCenters, [ '
+ print,' /NOPLOT, Plotting keywords... ]'
+ return
+ endif
+
+ MINBIN=5
+
+ N = N_ELEMENTS(V)
+ NB = FIX(SQRT(2.*N)) < 199
+ NB = NB > MINBIN
+
+ X1 = MIN(V, MAX = X2)
+
+tryagain:
+
+ DX = (X2-X1)/NB
+ XX = FINDGEN(NB)*DX + DX/2. + X1
+
+ IND = (V-X1)/DX > 0 <(NB-1)
+
+; Compute the histogram for the current binning
+
+ YY = HISTOGRAM(IND,MIN=0,MAX = NB-1)
+
+; Count the fraction of empty bins in the middle half of the histogram:
+ X14 = (XX[NB-1]-XX[0])/4.+X1
+ X34 = XX[NB-1]-(XX[NB-1]-XX[0])/4.
+ Q=WHERE( (YY EQ 0.) AND (XX GT X14) AND (XX LT X34), COUNT )
+ IF (COUNT GT NB/10) AND (NB GT MINBIN) THEN BEGIN ; 20% EMPTY
+ NB = 3*NB/4
+ IF NB LT (2*N) THEN GOTO,tryagain
+ENDIF
+
+; Fill in ZX,ZY:
+ MB = 2*NB+2
+ ZX = FLTARR(MB) & ZY = FLTARR(MB)
+ IT = INDGEN(NB)*2 + 1
+
+ ZY[IT] = YY & ZY[IT+1] = YY
+
+ ZX[0] = X1
+ ZX[IT] = XX - DX/2. & ZX[IT+1] = XX + DX/2.
+ ZX[MB-1] = X2
+
+IF KEYWORD_SET(WHATEVER) THEN RETURN
+
+; Plot, then fill, the bins:
+ YTOP = MAX(YY[1:NB-2])
+ YY[0] = YY[0] < YTOP
+ YY[NB-1] = YY[NB-1] < YTOP
+ cgPLOT,XX,YY,XRAN=[X1-DX,X2+DX],YRAN=[0.,1.1*YTOP],PSYM=10,_EXTRA=_extra
+ FOR J=0,NB-1 DO BEGIN
+ IF YY[J] GT 0 THEN BEGIN
+ A=[XX[J]-DX/2.,XX[J]+DX/2.,XX[J]+DX/2.,XX[J]-DX/2.]
+ B=[0.,0.,YY[J],YY[J]]
+ cgcolorFILL,A,B,orientation=45,noclip=0
+ ENDIF
+ENDFOR
+
+RETURN
+END
diff --git a/Code/script_idl_mv/astrolib/avg.pro b/Code/script_idl_mv/astrolib/avg.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8f1a242d64891ea858b7861f925248ca7d29a6e7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/avg.pro
@@ -0,0 +1,111 @@
+FUNCTION AVG,ARRAY,DIMENSION, NAN = NAN, DOUBLE = DOUBLE
+;+
+; NAME:
+; AVG
+; PURPOSE:
+; Return the average value of an array, or 1 dimension of an array
+; EXPLANATION:
+; Calculate the average value of an array, or calculate the average
+; value over one dimension of an array as a function of all the other
+; dimensions.
+;
+; In 2009, a DIMENSION keyword was added to the IDL MEAN() function,
+; giving it the same capability as AVG(). Thus, the use of AVG() is now
+; **deprecated** in favor of the MEAN() function.
+; CALLING SEQUENCE:
+; RESULT = AVG( ARRAY, [ DIMENSION, /NAN, /DOUBLE ] )
+;
+; INPUTS:
+; ARRAY = Input array. May be any type except string.
+;
+; OPTIONAL INPUT PARAMETERS:
+; DIMENSION = Optional dimension to do average over, integer scalar
+;
+; OPTIONAL KEYWORD INPUT:
+; /NAN - Set this keyword to cause the routine to check for occurrences of
+; the IEEE floating-point value NaN in the input data. Elements with
+; the value NaN are treated as missing data.
+; /DOUBLE - By default, if the input Array is double-precision, complex,
+; or double complex, the result is of the same type; 64 bit
+; integers are also returned as double. Otherwise the result
+; the result is floating-point. Use of the /DOUBLE keyword
+; forces a double precision output. Note that internal
+; computations are always done in double precision.
+; OUTPUTS:
+; The average value of the array when called with one parameter.
+;
+; If DIMENSION is passed, then the result is an array with all the
+; dimensions of the input array except for the dimension specified,
+; each element of which is the average of the corresponding vector
+; in the input array.
+;
+; For example, if A is an array with dimensions of (3,4,5), then the
+; command B = AVG(A,1) is equivalent to
+;
+; B = FLTARR(3,5)
+; FOR J = 0,4 DO BEGIN
+; FOR I = 0,2 DO BEGIN
+; B[I,J] = TOTAL( A[I,*,J] ) / 4.
+; ENDFOR
+; ENDFOR
+;
+; RESTRICTIONS:
+; Dimension specified must be valid for the array passed; otherwise the
+; input array is returned as the output array.
+; PROCEDURE:
+; AVG(ARRAY) = TOTAL(ARRAY, /DOUBLE)/N_ELEMENTS(ARRAY) when called with
+; one parameter.
+; MODIFICATION HISTORY:
+; William Thompson Applied Research Corporation
+; July, 1986 8201 Corporate Drive
+; Landover, MD 20785
+; Converted to Version 2 July, 1990
+; Replace SUM call with TOTAL W. Landsman May, 1992
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added /NAN keyword W. Landsman July 2000
+; Accept a scalar input value W. Landsman/jimm@berkeley November 2000
+; Internal calculations always in double precision W. Landsman March 2002
+; Return NAN if all values in array are NAN W. Landsman April 2002
+; Fixed coding bug if all values in array are NAN W. Landsman Jan 2004
+;-
+ ON_ERROR,2
+ S = SIZE(ARRAY,/STR)
+ IF S.N_ELEMENTS EQ 1 THEN RETURN, array[0]
+ IF S.N_ELEMENTS EQ 0 THEN $
+ MESSAGE,'Variable must be an array, name= ARRAY'
+;
+ IF N_PARAMS() EQ 1 THEN BEGIN
+ IF KEYWORD_SET(NAN) THEN NPTS = TOTAL(FINITE(ARRAY) ) $
+ ELSE NPTS = N_ELEMENTS(ARRAY)
+ IF NPTS EQ 0 THEN AVERAGE = !VALUES.F_NAN ELSE $
+ AVERAGE = TOTAL(ARRAY, NAN=NAN,/DOUBLE) / NPTS
+ ENDIF ELSE BEGIN
+ IF ((DIMENSION GE 0) AND (DIMENSION LT S.N_DIMENSIONS)) THEN BEGIN
+ AVERAGE = TOTAL(ARRAY,DIMENSION+1,NAN=NAN,/DOUBLE)
+; Install a bug workaround since TOTAL(A,/NAN) returns 0 rather than NAN if
+; all A values are NAN.
+ IF KEYWORD_SET(NAN) THEN BEGIN
+ NPTS = TOTAL(FINITE(ARRAY),DIMENSION+1 )
+ BAD = WHERE(NPTS EQ 0, NBAD)
+ AVERAGE = AVERAGE/(NPTS>1)
+ IF NBAD GT 0 THEN AVERAGE[BAD] = !VALUES.D_NAN
+ ENDIF ELSE AVERAGE = AVERAGE/S.DIMENSIONS[DIMENSION]
+
+ END ELSE $
+ MESSAGE,'*** Dimension out of range, name= ARRAY'
+ ENDELSE
+
+; Convert to floating point unless of type double, complex, or L64, or
+; if /DOUBLE is set.
+
+ IF ~KEYWORD_SET(DOUBLE) THEN BEGIN
+ CASE S.TYPE OF
+ 5: RETURN, AVERAGE
+ 6: RETURN, COMPLEXARR( FLOAT(AVERAGE), FLOAT(IMAGINARY(AVERAGE)) )
+ 9: RETURN, AVERAGE
+ 14: RETURN, AVERAGE
+ 15: RETURN, AVERAGE
+ ELSE: RETURN, FLOAT(AVERAGE)
+ ENDCASE
+ ENDIF ELSE RETURN, AVERAGE
+ END
diff --git a/Code/script_idl_mv/astrolib/baryvel.pro b/Code/script_idl_mv/astrolib/baryvel.pro
new file mode 100644
index 0000000000000000000000000000000000000000..132532e044b02788cb93dc77cb453a69bca01fcc
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/baryvel.pro
@@ -0,0 +1,340 @@
+pro baryvel, dje, deq, dvelh, dvelb, JPL = JPL
+;+
+; NAME:
+; BARYVEL
+; PURPOSE:
+; Calculates heliocentric and barycentric velocity components of Earth.
+;
+; EXPLANATION:
+; BARYVEL takes into account the Earth-Moon motion, and is useful for
+; radial velocity work to an accuracy of ~1 m/s.
+;
+; CALLING SEQUENCE:
+; BARYVEL, dje, deq, dvelh, dvelb, [ JPL = ]
+;
+; INPUTS:
+; DJE - (scalar) Julian ephemeris date.
+; DEQ - (scalar) epoch of mean equinox of dvelh and dvelb. If deq=0
+; then deq is assumed to be equal to dje.
+; OUTPUTS:
+; DVELH: (vector(3)) heliocentric velocity component. in km/s
+; DVELB: (vector(3)) barycentric velocity component. in km/s
+;
+; The 3-vectors DVELH and DVELB are given in a right-handed coordinate
+; system with the +X axis toward the Vernal Equinox, and +Z axis
+; toward the celestial pole.
+;
+; OPTIONAL KEYWORD SET:
+; JPL - if /JPL set, then BARYVEL will call the procedure JPLEPHINTERP
+; to compute the Earth velocity using the full JPL ephemeris.
+; The JPL ephemeris FITS file JPLEPH.405 must exist in either the
+; current directory, or in the directory specified by the
+; environment variable ASTRO_DATA. Alternatively, the JPL keyword
+; can be set to the full path and name of the ephemeris file.
+; A copy of the JPL ephemeris FITS file is available in
+; http://idlastro.gsfc.nasa.gov/ftp/data/
+; PROCEDURES CALLED:
+; Function PREMAT() -- computes precession matrix
+; JPLEPHREAD, JPLEPHINTERP, TDB2TDT - if /JPL keyword is set
+; NOTES:
+; Algorithm taken from FORTRAN program of Stumpff (1980, A&A Suppl, 41,1)
+; Stumpf claimed an accuracy of 42 cm/s for the velocity. A
+; comparison with the JPL FORTRAN planetary ephemeris program PLEPH
+; found agreement to within about 65 cm/s between 1986 and 1994
+;
+; If /JPL is set (using JPLEPH.405 ephemeris file) then velocities are
+; given in the ICRS system; otherwise in the FK4 system.
+; EXAMPLE:
+; Compute the radial velocity of the Earth toward Altair on 15-Feb-1994
+; using both the original Stumpf algorithm and the JPL ephemeris
+;
+; IDL> jdcnv, 1994, 2, 15, 0, jd ;==> JD = 2449398.5
+; IDL> baryvel, jd, 2000, vh, vb ;Original algorithm
+; ==> vh = [-17.07243, -22.81121, -9.889315] ;Heliocentric km/s
+; ==> vb = [-17.08083, -22.80471, -9.886582] ;Barycentric km/s
+; IDL> baryvel, jd, 2000, vh, vb, /jpl ;JPL ephemeris
+; ==> vh = [-17.07236, -22.81126, -9.889419] ;Heliocentric km/s
+; ==> vb = [-17.08083, -22.80484, -9.886409] ;Barycentric km/s
+;
+; IDL> ra = ten(19,50,46.77)*15/!RADEG ;RA in radians
+; IDL> dec = ten(08,52,3.5)/!RADEG ;Dec in radians
+; IDL> v = vb[0]*cos(dec)*cos(ra) + $ ;Project velocity toward star
+; vb[1]*cos(dec)*sin(ra) + vb[2]*sin(dec)
+;
+; REVISION HISTORY:
+; Jeff Valenti, U.C. Berkeley Translated BARVEL.FOR to IDL.
+; W. Landsman, Cleaned up program sent by Chris McCarthy (SfSU) June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added /JPL keyword W. Landsman July 2001
+; Documentation update W. Landsman Dec 2005
+;-
+ On_Error,2
+ compile_opt idl2
+
+ if N_params() LT 4 then begin
+ print,'Syntax: BARYVEL, dje, deq, dvelh, dvelb'
+ print,' dje - input Julian ephemeris date'
+ print,' deq - input epoch of mean equinox of dvelh and dvelb'
+ print,' dvelh - output vector(3) heliocentric velocity comp in km/s'
+ print,' dvelb - output vector(3) barycentric velocity comp in km/s'
+ return
+ endif
+
+ if keyword_set(JPL) then begin
+ if size(jpl,/TNAME) EQ 'STRING' then jplfile = jpl else $
+ jplfile = find_with_def('JPLEPH.405','ASTRO_DATA')
+ if jplfile EQ '' then message,'ERROR - Cannot find JPL ephemeris file'
+ JPLEPHREAD,jplfile, pinfo, pdata, [long(dje), long(dje)+1]
+ JPLEPHINTERP, pinfo, pdata, dje, x,y,z,vx,vy,vz, /EARTH,/VELOCITY, $
+ VELUNITS = 'KM/S'
+ dvelb = [vx,vy,vz]
+ JPLEPHINTERP, pinfo, pdata, dje, x,y,z,vx,vy,vz, /SUN,/VELOCITY, $
+ VELUNITS = 'KM/S'
+ dvelh = dvelb - [vx,vy,vz]
+ if deq NE 2000 then begin
+ if deq EQ 0 then begin
+ DAYCNV, dje , year, month, day, hour
+ deq = year + month/12.d + day/365.25d + hour/8766.0d
+ endif
+ prema = premat(2000.0d,deq )
+ dvelh = prema # dvelh
+ dvelb = prema # dvelb
+ endif
+ return
+ endif
+
+;Define constants
+ dc2pi = 2*!DPI
+ cc2pi = 2*!PI
+ dc1 = 1.0D0
+ dcto = 2415020.0D0
+ dcjul = 36525.0D0 ;days in Julian year
+ dcbes = 0.313D0
+ dctrop = 365.24219572D0 ;days in tropical year (...572 insig)
+ dc1900 = 1900.0D0
+ AU = 1.4959787D8
+
+;Constants dcfel(i,k) of fast changing elements.
+ dcfel = [1.7400353D00, 6.2833195099091D02, 5.2796D-6 $
+ ,6.2565836D00, 6.2830194572674D02, -2.6180D-6 $
+ ,4.7199666D00, 8.3997091449254D03, -1.9780D-5 $
+ ,1.9636505D-1, 8.4334662911720D03, -5.6044D-5 $
+ ,4.1547339D00, 5.2993466764997D01, 5.8845D-6 $
+ ,4.6524223D00, 2.1354275911213D01, 5.6797D-6 $
+ ,4.2620486D00, 7.5025342197656D00, 5.5317D-6 $
+ ,1.4740694D00, 3.8377331909193D00, 5.6093D-6 ]
+ dcfel = reform(dcfel,3,8)
+
+;constants dceps and ccsel(i,k) of slowly changing elements.
+ dceps = [4.093198D-1, -2.271110D-4, -2.860401D-8 ]
+ ccsel = [1.675104E-2, -4.179579E-5, -1.260516E-7 $
+ ,2.220221E-1, 2.809917E-2, 1.852532E-5 $
+ ,1.589963E00, 3.418075E-2, 1.430200E-5 $
+ ,2.994089E00, 2.590824E-2, 4.155840E-6 $
+ ,8.155457E-1, 2.486352E-2, 6.836840E-6 $
+ ,1.735614E00, 1.763719E-2, 6.370440E-6 $
+ ,1.968564E00, 1.524020E-2, -2.517152E-6 $
+ ,1.282417E00, 8.703393E-3, 2.289292E-5 $
+ ,2.280820E00, 1.918010E-2, 4.484520E-6 $
+ ,4.833473E-2, 1.641773E-4, -4.654200E-7 $
+ ,5.589232E-2, -3.455092E-4, -7.388560E-7 $
+ ,4.634443E-2, -2.658234E-5, 7.757000E-8 $
+ ,8.997041E-3, 6.329728E-6, -1.939256E-9 $
+ ,2.284178E-2, -9.941590E-5, 6.787400E-8 $
+ ,4.350267E-2, -6.839749E-5, -2.714956E-7 $
+ ,1.348204E-2, 1.091504E-5, 6.903760E-7 $
+ ,3.106570E-2, -1.665665E-4, -1.590188E-7 ]
+ ccsel = reform(ccsel,3,17)
+
+;Constants of the arguments of the short-period perturbations.
+ dcargs = [5.0974222D0, -7.8604195454652D2 $
+ ,3.9584962D0, -5.7533848094674D2 $
+ ,1.6338070D0, -1.1506769618935D3 $
+ ,2.5487111D0, -3.9302097727326D2 $
+ ,4.9255514D0, -5.8849265665348D2 $
+ ,1.3363463D0, -5.5076098609303D2 $
+ ,1.6072053D0, -5.2237501616674D2 $
+ ,1.3629480D0, -1.1790629318198D3 $
+ ,5.5657014D0, -1.0977134971135D3 $
+ ,5.0708205D0, -1.5774000881978D2 $
+ ,3.9318944D0, 5.2963464780000D1 $
+ ,4.8989497D0, 3.9809289073258D1 $
+ ,1.3097446D0, 7.7540959633708D1 $
+ ,3.5147141D0, 7.9618578146517D1 $
+ ,3.5413158D0, -5.4868336758022D2 ]
+ dcargs = reform(dcargs,2,15)
+
+;Amplitudes ccamps(n,k) of the short-period perturbations.
+ ccamps = $
+ [-2.279594E-5, 1.407414E-5, 8.273188E-6, 1.340565E-5, -2.490817E-7 $
+ ,-3.494537E-5, 2.860401E-7, 1.289448E-7, 1.627237E-5, -1.823138E-7 $
+ , 6.593466E-7, 1.322572E-5, 9.258695E-6, -4.674248E-7, -3.646275E-7 $
+ , 1.140767E-5, -2.049792E-5, -4.747930E-6, -2.638763E-6, -1.245408E-7 $
+ , 9.516893E-6, -2.748894E-6, -1.319381E-6, -4.549908E-6, -1.864821E-7 $
+ , 7.310990E-6, -1.924710E-6, -8.772849E-7, -3.334143E-6, -1.745256E-7 $
+ ,-2.603449E-6, 7.359472E-6, 3.168357E-6, 1.119056E-6, -1.655307E-7 $
+ ,-3.228859E-6, 1.308997E-7, 1.013137E-7, 2.403899E-6, -3.736225E-7 $
+ , 3.442177E-7, 2.671323E-6, 1.832858E-6, -2.394688E-7, -3.478444E-7 $
+ , 8.702406E-6, -8.421214E-6, -1.372341E-6, -1.455234E-6, -4.998479E-8 $
+ ,-1.488378E-6, -1.251789E-5, 5.226868E-7, -2.049301E-7, 0.E0 $
+ ,-8.043059E-6, -2.991300E-6, 1.473654E-7, -3.154542E-7, 0.E0 $
+ , 3.699128E-6, -3.316126E-6, 2.901257E-7, 3.407826E-7, 0.E0 $
+ , 2.550120E-6, -1.241123E-6, 9.901116E-8, 2.210482E-7, 0.E0 $
+ ,-6.351059E-7, 2.341650E-6, 1.061492E-6, 2.878231E-7, 0.E0 ]
+ ccamps = reform(ccamps,5,15)
+
+;Constants csec3 and ccsec(n,k) of the secular perturbations in longitude.
+ ccsec3 = -7.757020E-8
+ ccsec = [1.289600E-6, 5.550147E-1, 2.076942E00 $
+ ,3.102810E-5, 4.035027E00, 3.525565E-1 $
+ ,9.124190E-6, 9.990265E-1, 2.622706E00 $
+ ,9.793240E-7, 5.508259E00, 1.559103E01 ]
+ ccsec = reform(ccsec,3,4)
+
+;Sidereal rates.
+ dcsld = 1.990987D-7 ;sidereal rate in longitude
+ ccsgd = 1.990969E-7 ;sidereal rate in mean anomaly
+
+;Constants used in the calculation of the lunar contribution.
+ cckm = 3.122140E-5
+ ccmld = 2.661699E-6
+ ccfdi = 2.399485E-7
+
+;Constants dcargm(i,k) of the arguments of the perturbations of the motion
+; of the moon.
+ dcargm = [5.1679830D0, 8.3286911095275D3 $
+ ,5.4913150D0, -7.2140632838100D3 $
+ ,5.9598530D0, 1.5542754389685D4 ]
+ dcargm = reform(dcargm,2,3)
+
+;Amplitudes ccampm(n,k) of the perturbations of the moon.
+ ccampm = [ 1.097594E-1, 2.896773E-7, 5.450474E-2, 1.438491E-7 $
+ ,-2.223581E-2, 5.083103E-8, 1.002548E-2, -2.291823E-8 $
+ , 1.148966E-2, 5.658888E-8, 8.249439E-3, 4.063015E-8 ]
+ ccampm = reform(ccampm,4,3)
+
+;ccpamv(k)=a*m*dl,dt (planets), dc1mme=1-mass(earth+moon)
+ ccpamv = [8.326827E-11, 1.843484E-11, 1.988712E-12, 1.881276E-12]
+ dc1mme = 0.99999696D0
+
+;Time arguments.
+ dt = (dje - dcto) / dcjul
+ tvec = [1d0, dt, dt*dt]
+
+;Values of all elements for the instant(aneous?) dje.
+ temp = (tvec # dcfel) mod dc2pi
+ dml = temp[0]
+ forbel = temp[1:7]
+ g = forbel[0] ;old fortran equivalence
+
+ deps = total(tvec*dceps) mod dc2pi
+ sorbel = (tvec # ccsel) mod dc2pi
+ e = sorbel[0] ;old fortran equivalence
+
+;Secular perturbations in longitude.
+dummy=cos(2.0)
+ sn = sin((tvec[0:1] # ccsec[1:2,*]) mod cc2pi)
+
+;Periodic perturbations of the emb (earth-moon barycenter).
+ pertl = total(ccsec[0,*] * sn) + dt*ccsec3*sn[2]
+ pertld = 0.0
+ pertr = 0.0
+ pertrd = 0.0
+ for k=0,14 do begin
+ a = (dcargs[0,k]+dt*dcargs[1,k]) mod dc2pi
+ cosa = cos(a)
+ sina = sin(a)
+ pertl = pertl + ccamps[0,k]*cosa + ccamps[1,k]*sina
+ pertr = pertr + ccamps[2,k]*cosa + ccamps[3,k]*sina
+ if k lt 11 then begin
+ pertld = pertld + (ccamps[1,k]*cosa-ccamps[0,k]*sina)*ccamps[4,k]
+ pertrd = pertrd + (ccamps[3,k]*cosa-ccamps[2,k]*sina)*ccamps[4,k]
+ endif
+ endfor
+
+;Elliptic part of the motion of the emb.
+ phi = (e*e/4d0)*(((8d0/e)-e)*sin(g) +5*sin(2*g) +(13/3d0)*e*sin(3*g))
+ f = g + phi
+ sinf = sin(f)
+ cosf = cos(f)
+ dpsi = (dc1 - e*e) / (dc1 + e*cosf)
+ phid = 2*e*ccsgd*((1 + 1.5*e*e)*cosf + e*(1.25 - 0.5*sinf*sinf))
+ psid = ccsgd*e*sinf / sqrt(dc1 - e*e)
+
+;Perturbed heliocentric motion of the emb.
+ d1pdro = dc1+pertr
+ drd = d1pdro * (psid + dpsi*pertrd)
+ drld = d1pdro*dpsi * (dcsld+phid+pertld)
+ dtl = (dml + phi + pertl) mod dc2pi
+ dsinls = sin(dtl)
+ dcosls = cos(dtl)
+ dxhd = drd*dcosls - drld*dsinls
+ dyhd = drd*dsinls + drld*dcosls
+
+;Influence of eccentricity, evection and variation on the geocentric
+; motion of the moon.
+ pertl = 0.0
+ pertld = 0.0
+ pertp = 0.0
+ pertpd = 0.0
+ for k = 0,2 do begin
+ a = (dcargm[0,k] + dt*dcargm[1,k]) mod dc2pi
+ sina = sin(a)
+ cosa = cos(a)
+ pertl = pertl + ccampm[0,k]*sina
+ pertld = pertld + ccampm[1,k]*cosa
+ pertp = pertp + ccampm[2,k]*cosa
+ pertpd = pertpd - ccampm[3,k]*sina
+ endfor
+
+;Heliocentric motion of the earth.
+ tl = forbel[1] + pertl
+ sinlm = sin(tl)
+ coslm = cos(tl)
+ sigma = cckm / (1.0 + pertp)
+ a = sigma*(ccmld + pertld)
+ b = sigma*pertpd
+ dxhd = dxhd + a*sinlm + b*coslm
+ dyhd = dyhd - a*coslm + b*sinlm
+ dzhd= -sigma*ccfdi*cos(forbel[2])
+
+;Barycentric motion of the earth.
+ dxbd = dxhd*dc1mme
+ dybd = dyhd*dc1mme
+ dzbd = dzhd*dc1mme
+ for k=0,3 do begin
+ plon = forbel[k+3]
+ pomg = sorbel[k+1]
+ pecc = sorbel[k+9]
+ tl = (plon + 2.0*pecc*sin(plon-pomg)) mod cc2pi
+ dxbd = dxbd + ccpamv[k]*(sin(tl) + pecc*sin(pomg))
+ dybd = dybd - ccpamv[k]*(cos(tl) + pecc*cos(pomg))
+ dzbd = dzbd - ccpamv[k]*sorbel[k+13]*cos(plon - sorbel[k+5])
+
+ endfor
+
+;Transition to mean equator of date.
+ dcosep = cos(deps)
+ dsinep = sin(deps)
+ dyahd = dcosep*dyhd - dsinep*dzhd
+ dzahd = dsinep*dyhd + dcosep*dzhd
+ dyabd = dcosep*dybd - dsinep*dzbd
+ dzabd = dsinep*dybd + dcosep*dzbd
+
+;Epoch of mean equinox (deq) of zero implies that we should use
+; Julian ephemeris date (dje) as epoch of mean equinox.
+ if deq eq 0 then begin
+ dvelh = AU * ([dxhd, dyahd, dzahd])
+ dvelb = AU * ([dxbd, dyabd, dzabd])
+ return
+ endif
+
+;General precession from epoch dje to deq.
+ deqdat = (dje-dcto-dcbes) / dctrop + dc1900
+ prema = premat(deqdat,deq,/FK4)
+
+ dvelh = AU * ( prema # [dxhd, dyahd, dzahd] )
+ dvelb = AU * ( prema # [dxbd, dyabd, dzabd] )
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/biweight_mean.pro b/Code/script_idl_mv/astrolib/biweight_mean.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2ecd438b16a90b12ae9b28890e3f08b4298b7724
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/biweight_mean.pro
@@ -0,0 +1,88 @@
+FUNCTION BIWEIGHT_MEAN,Y,SIGMA, WEIGHTs
+;
+;+
+; NAME:
+; BIWEIGHT_MEAN
+;
+; PURPOSE:
+; Calculate the center and dispersion (like mean and sigma) of a
+; distribution using bisquare weighting.
+;
+; CALLING SEQUENCE:
+; Mean = BIWEIGHT_MEAN( Vector, [ Sigma, Weights ] )
+;
+; INPUTS:
+; Vector = Distribution in vector form
+;
+; OUTPUT:
+; Mean - The location of the center.
+;
+; OPTIONAL OUTPUT ARGUMENTS:
+;
+; Sigma = An outlier-resistant measure of the dispersion about the
+; center, analogous to the standard deviation.
+;
+; Weights = The weights applied to the data in the last iteration,
+; floating point vector
+;
+; NOTES:
+; Since a sample mean scaled by sigma/sqrt(N), has a Student's T
+; distribution, the half-width of the 95% confidence interval for
+; the sample mean can be determined as follows:
+; ABS( T_CVF( .975, .7*(N-1) )*SIGMA/SQRT(N) )
+; where N = number of points, and 0.975 = 1 - (1 - 0.95)/2.
+; PROCEDURES USED:
+; ROBUST_SIGMA()
+; REVISION HISTORY
+; Written, H. Freudenreich, STX, 12/89
+; Modified 2/94, H.T.F.: use a biweighted standard deviation rather than
+; median absolute deviation.
+; Modified 2/94, H.T.F.: use the fractional change in SIGMA as the
+; convergence criterion rather than the change in center/SIGMA.
+; Modified May 2002 Use MEDIAN(/EVEN)
+; Modified October 2002, Faster computation of weights
+; Corrected documentation on 95% confidence interval of mean
+; P.Broos/W. Landsman July 2003
+;-
+
+ ON_ERROR,2
+ maxit = 20 ; Allow 20 iterations, this should nearly always be sufficient
+ eps = 1.0e-24
+
+ n = n_elements(y)
+ close_enough =.03*sqrt(.5/(n-1)) ; compare to fractional change in width
+
+ diff = 1.0e30
+ itnum = 0
+
+; As an initial estimate of the center, use the median:
+ y0=median(y,/even)
+
+; Calculate the weights:
+ dev = y-y0
+ sigma = ROBUST_SIGMA( dev )
+
+ if sigma lt EPS then begin
+; The median is IT. Do we need the weights?
+ if arg_present(weights) then begin
+; Flag any value away from the median:
+ limit=3.*sigma
+ weights = float(abs(dev) LE limit)
+ endif
+ diff = 0. ; (skip rest of routine)
+ endif
+
+; Repeat:
+ while( (diff gt close_enough) and (itnum lt maxit) )do begin
+ itnum = itnum + 1
+ uu = ( (y-y0)/(6.*sigma) )^2
+ uu = uu < 1.
+ weights=(1.-uu)^2 & weights=weights/total(weights)
+ y0 = total( weights*y )
+ dev = y-y0
+ prev_sigma = sigma & sigma = robust_sigma( dev,/zero )
+ if sigma gt eps then diff=abs(prev_sigma-sigma)/prev_sigma else diff=0.
+ endwhile
+
+return,y0
+end
diff --git a/Code/script_idl_mv/astrolib/blink.pro b/Code/script_idl_mv/astrolib/blink.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0fd34c24b7b893db5937b449878c1a59168a049e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/blink.pro
@@ -0,0 +1,114 @@
+PRO BLINK, wndw, t
+;+
+; NAME:
+; BLINK
+; PURPOSE:
+; To allow the user to alternatively examine two or more windows within
+; a single window.
+;
+; CALLING SEQUENCE:
+; BLINK, Wndw [, T]
+;
+; INPUTS:
+; Wndw A vector containing the indices of the windows to blink.
+; T The time to wait, in seconds, between blinks. This is optional
+; and set to 1 if not present.
+;
+; OUTPUTS:
+; None.
+;
+; PROCEDURE:
+; The images contained in the windows given are written to a pixmap.
+; The contents of the the windows are copied to a display window, in
+; order, until a key is struck.
+;
+; EXAMPLE:
+; Blink windows 0 and 2 with a wait time of 3 seconds
+;
+; IDL> blink, [0,2], 3
+;
+; MODIFICATION HISTORY:
+; Written by Michael R. Greason, STX, 2 May 1990.
+; Allow different size windows Wayne Landsman August, 1991
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+; Check the parameters.
+;
+On_error,2 ;Return to caller
+n = n_params(0)
+cflg = 0
+IF (n LT 2) THEN BEGIN
+ IF (n LT 1) THEN cflg = 1
+ t = 1.0
+ENDIF
+IF (cflg NE 1) THEN BEGIN
+ s = size(wndw)
+ cflg = 2
+ IF (s[0] GT 0) THEN BEGIN
+ IF (s[1] GT 1) THEN cflg = 0
+ n_wndw = s[1]
+ ENDIF
+ENDIF
+;
+; Check to see if a window is open. If so, save the
+; index for later use.
+;
+IF (cflg EQ 0) THEN BEGIN
+ whld = !d.window
+ IF (whld LT 0) THEN cflg = 3
+ENDIF
+;
+; If not enough or incorrect parameters were given,
+; complain and return.
+;
+IF (cflg NE 0) THEN BEGIN
+ IF (cflg EQ 1) THEN BEGIN
+ print, " Insufficient parameters given to BLINK."
+ print, " Syntax: BLINK, WIN_INDICES [, TIME]"
+ ENDIF
+ IF (cflg EQ 2) THEN print, " The array of window indices is invalid."
+ IF (cflg EQ 3) THEN print, " No windows are open."
+ENDIF ELSE BEGIN
+;
+;
+; Get the size of each window in the array.
+;
+device, window = opnd
+ncol = intarr(n_wndw)
+nrow = ncol
+for i=0,n_wndw-1 do begin
+ if ~opnd[wndw[i]] then $
+ message,'ERROR - Window '+ strtrim(wndw[i],2) + ' is not open'
+ wset, wndw[i]
+ ncol[i] = !d.x_vsize
+ nrow[i] = !d.y_vsize
+endfor
+;
+; Write a message explaining how to terminate BLINK.
+;
+ print, " "
+ print, "To exit BLINK, strike any key."
+ print, " "
+;
+; Create the display window and display the images.
+;
+ window, /free, retain=2, xsize = max(ncol), ysize=max(nrow), $
+ xpos=0, ypos=0, $
+ title="Blink window - Press any key to exit"
+ whd = !d.window
+ i = 0L
+ WHILE (get_kbrd(0) EQ '') DO BEGIN
+ device, copy=[0, 0, ncol[i], nrow[i], 0, 0, wndw[i]]
+ i = (i + 1) mod n_wndw
+ wait, t
+ ENDWHILE
+;
+; Clear up and terminate. Close windows/pixmaps and
+; restore the originally active window.
+;
+ wdelete, whd
+ wset, whld
+ENDELSE
+;
+RETURN
+END
diff --git a/Code/script_idl_mv/astrolib/blkshift.pro b/Code/script_idl_mv/astrolib/blkshift.pro
new file mode 100644
index 0000000000000000000000000000000000000000..faa8234c0d47e508478bf73868ffc83ed496ad49
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/blkshift.pro
@@ -0,0 +1,231 @@
+;+
+; NAME:
+; BLKSHIFT
+;
+; PURPOSE:
+; Shift a block of data to a new position in a file (possibly overlapping)
+;
+; CALLING SEQUENCE:
+;
+; BLKSHIFT, UNIT, POS, [ DELTA, TO=TO, /NOZERO, ERRMSG=ERRMSG,
+; BUFFERSIZE=BUFFERSIZE ]
+;
+; DESCRIPTION:
+;
+; BLKSHIFT moves a block of data forward or backward, to a new
+; position in a data file. The old and new positions of the block
+; can overlap safely.
+;
+; The new position can be specified with either the DELTA parameter,
+; which gives the number of bytes to move forward (positive delta) or
+; backward (negative delta); or the TO keyword, which give the new
+; absolute starting position of the block.
+;
+; The block can be moved beyond the current end of file point, in
+; which case the intervening gap is filled with zeros (optionally).
+; The gap left at the old position of the block is also optionally
+; zero-filled. If a set of data up to the end of the file is being
+; moved forward (thus making the file smaller) then
+; the file is truncated at the new end.using TRUNCATE_LUN.
+;
+; INPUTS:
+;
+; UNIT - a logical unit number, opened for reading and writing.
+;
+; POS - POS[0] is the position of the block in the file, in bytes,
+; before moving. POS[1], if present, is the size of the block
+; in bytes. If POS[1] is not given, then the block is from
+; POS[0] to the end of the file.
+;
+; DELTA - the (optional) offset in bytes between the old and new
+; positions, from the start of the block. Positive values
+; indicate moving the data forward (toward the end of file),
+; and negative values indicate moving the data backward
+; (toward the beginning of the file). One of DELTA and TO
+; must be specified; DELTA overrides the TO keyword.
+;
+; Attempts to move the block beyond the end of the file will
+; succeed. A block can never be moved beyond the beginning
+; of the file; it will be moved to the beginning instead.
+;
+; KEYWORD PARAMETERS:
+;
+; TO - the absolute file offset in bytes for the new start of the
+; block. One of DELTA and TO must be specified; DELTA
+; overrides the TO keyword.
+;
+; /NOZERO - if set, then newly created gaps will not be explicitly
+; zeroed. Note that in same systems (e.g. MacOS) the gaps will
+; always be zeroed whether or not /NOZERO is set.
+;
+; ERRMSG - If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors
+; are encountered, then a null string is returned.
+;
+; BLKSHIFT, UNIT, POS, DElTA, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; BUFFERSIZE - the maximum buffer size for transfers, in bytes.
+; Larger values of this keyword impose larger memory
+; requirements on the application; smaller values will
+; lead to more transfer operations.
+; Default: 32768 (bytes)
+;
+; ORIGINAL AUTHOR:
+; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
+; craig.markwardt@nasa.gov
+;
+; MODIFICATION HISTORY:
+;
+; Written, CM, Apr 2000
+; Documented and re-written, CM, 20 Jul 2000
+; Renamed from FXSHIFT to BLKSHIFT, CM, 21 Jul 2000
+; Documentation, CM, 12 Dec 2002
+; Truncate if moving data block forward from the end of file
+; using TRUNCATE_LUN W. Landsman Feb. 2005
+; Assume since V5.5, remove VMS support W. Landsman Sep 2006
+; Assume since V5.6, TRUNCATE_LUN available W. Landsman Sep 2006
+; MacOS can point beyond EOF W. Landsman Aug 2009
+; Use V6.0 notation W. Landsman Aprl 2014
+;-
+PRO BLKSHIFT, UNIT, POS0, DELTA0, NOZERO=NOZERO0, ERRMSG=ERRMSG, $
+ BUFFERSIZE=BUFFERSIZE0, TO=TO0
+
+ ;; Default error handling
+ compile_opt idl2
+ on_error, 2
+ on_ioerror, IO_FINISH
+ if n_params() LT 3 then begin
+ message = 'BLKSHIFT, UNIT, POS, DELTA'
+ goto, ERRMSG_OUT
+ endif
+
+ ;; Make sure file is open for writing, and begin parameter
+ ;; processing
+ fs = fstat(unit)
+ if fs.open EQ 0 OR fs.write EQ 0 then begin
+ message = 'File '+fs.name+' is not open for writing'
+ goto, ERRMSG_OUT
+ endif
+ nozero = keyword_set(nozero0)
+ pos_beg = floor(pos0[0])
+ if n_elements(pos0) GT 1 then pos_fin = floor(pos0[1])
+ if n_elements(pos_fin) EQ 0 then pos_fin = fs.size - 1L
+
+ if pos_beg GE fs.size then goto, GOOD_FINISH
+ if n_elements(to0) EQ 0 AND n_elements(delta0) EQ 0 then begin
+ message = 'Must specify DELTA or TO'
+ goto, ERRMSG_OUT
+ endif
+
+ ;; Parse the delta value, and enforce the file positioning
+ if n_elements(delta0) GT 0 then begin
+ delta = floor(delta0[0])
+ ;; Can't move beyond beginning of file
+ delta = ((pos_beg + delta) > 0L) - pos_beg
+ endif else begin
+ delta = (floor(to0[0]) > 0L) - pos_beg
+ endelse
+
+ if delta EQ 0 then goto, GOOD_FINISH
+ if pos_fin GE fs.size then pos_fin = fs.size - 1L
+ if pos_fin LT pos_beg then goto, GOOD_FINISH
+
+ if n_elements(buffersize0) EQ 0 then buffersize0 = 32768L
+ buffersize = long(buffersize0[0])
+ if buffersize LE 0 then buffersize = 32768L
+
+ ;; Seek to end of file and add zeroes (if needed)
+ pos_fin += 1L
+
+ ;; Unless /Nozero set, the zeroes will be explicitly written
+ if (delta GT 0) && (nozero EQ 0) && (pos_fin+delta GT fs.size) then begin
+ point_lun, unit, fs.size
+ nleft = (pos_fin-fs.size) + delta
+ while nleft GT 0 do begin
+ ntrans = nleft < buffersize
+ if n_elements(bb0) NE ntrans then bb0 = bytarr(ntrans)
+ writeu, unit, bb0, transfer_count=cc
+ if cc EQ 0 then goto, IO_FINISH
+ nleft -= cc
+ endwhile
+ endif
+
+ ;; Now shift the data forward or backward
+ if delta GT 0 then begin
+
+ ;; Shift forward (toward end of file)
+ edat = pos_fin ;; End of to-be-copied data segment
+ while edat GT pos_beg do begin
+ ntrans = (edat - pos_beg) < buffersize
+ if n_elements(bb0) NE ntrans then bb0 = bytarr(ntrans)
+ point_lun, unit, edat - ntrans
+ readu, unit, bb0, transfer_count=cc
+ if cc NE ntrans then goto, IO_FINISH
+ point_lun, unit, edat - ntrans + delta
+ writeu, unit, bb0, transfer_count=cc
+ if cc NE ntrans then goto, IO_FINISH
+ edat -= ntrans
+ endwhile
+ endif else begin
+
+ ;; Shift backward (toward beginning of file)
+ bdat = pos_beg ;; Beginning of to-be-copied data segment
+ while bdat LT pos_fin do begin
+ ntrans = (pos_fin - bdat) < buffersize
+ if n_elements(bb0) NE ntrans then bb0 = bytarr(ntrans)
+ point_lun, unit, bdat
+ readu, unit, bb0, transfer_count=cc
+ if cc NE ntrans then goto, IO_FINISH
+ point_lun, unit, bdat - abs(delta)
+ writeu, unit, bb0, transfer_count=cc
+ if cc NE ntrans then goto, IO_FINISH
+ bdat += ntrans
+ endwhile
+ if pos_fin EQ fs.size then begin
+ Truncate_Lun, unit
+ goto, GOOD_FINISH
+ endif
+ endelse
+ bb0 = [0b] & dummy = temporary(bb0)
+
+ ;; Finally, zero out the gap we created
+ if nozero EQ 0 then begin
+ if delta GT 0 then begin
+ point_lun, unit, pos_beg ;; also, to be sure data is flushed
+ z_fin = pos_fin < (pos_beg + delta)
+ nleft = (z_fin - pos_beg)
+ endif else begin
+ z_beg = (pos_fin - abs(delta)) > pos_beg
+ nleft = (pos_fin - z_beg)
+ point_lun, unit, z_beg
+ endelse
+ while nleft GT 0 do begin
+ i = nleft < buffersize
+ if n_elements(bb0) NE i then bb0 = bytarr(i)
+ writeu, unit, bb0, transfer_count=cc
+ if cc EQ 0 then goto, IO_FINISH
+ nleft -= cc
+ endwhile
+ endif
+ point_lun, unit, pos_beg ;; again, to be sure data is flushed
+
+ GOOD_FINISH:
+ if arg_present(errmsg) then errmsg = ''
+ return
+
+ IO_FINISH:
+ on_ioerror, NULL
+ message = 'ERROR: BLKSHIFT operation failed because of an I/O error'
+ ;; fallthrough...
+
+ ;; Error message processing. Control does not pass through here.
+ ERRMSG_OUT:
+ if arg_present(errmsg) then begin
+ errmsg = message
+ return
+ endif
+ message, message
+END
+
diff --git a/Code/script_idl_mv/astrolib/boost_array.pro b/Code/script_idl_mv/astrolib/boost_array.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d12290335d43bf20ef58de28d32267b6c64e117d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/boost_array.pro
@@ -0,0 +1,130 @@
+ PRO BOOST_ARRAY, DESTINATION, APPEND
+;+
+; NAME:
+; BOOST_ARRAY
+; PURPOSE:
+; Append one array onto a destination array
+; EXPLANATION:
+; Add array APPEND to array DESTINATION, allowing the dimensions of
+; DESTINATION to adjust to accommodate it. If both input arrays have the
+; same number of dimensions, then the output array will have one
+; additional dimension. Otherwise, the last dimension of DESTINATION
+; will be incremented by one.
+; CATEGORY:
+; Utility
+; CALLING SEQUENCE:
+; BOOST_ARRAY, DESTINATION, APPEND
+; INPUT:
+; DESTINATION = Array to be expanded.
+; APPEND = Array to append to DESTINATION.
+; OUTPUTS:
+; DESTINATION = Expanded output array.
+; RESTRICTIONS:
+; DESTINATION and APPEND have to be either both of type string or both of
+; numerical types.
+;
+; APPEND cannot have more dimensions than DESTINATION.
+;
+; MODIFICATION HISTOBY:
+; Written Aug'88 (DMZ, ARC)
+; Modified Sep'89 to handle byte arrays (DMZ)
+; Modifed to version 2, Paul Hick (ARC), Feb 1991
+; Removed restriction to 2D arrays, William Thompson (ARC), Feb 1992.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR, 2 ;On error, return to caller
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN MESSAGE, $
+ 'Syntax: BOOST_ARRAY, DESTINATION, APPEND'
+;
+; Make sure APPEND is defined.
+;
+ IF N_ELEMENTS(APPEND) EQ 0 THEN MESSAGE, $
+ 'Array to be appended (APPEND) not defined'
+;
+; If DESTINATION is not defined, then set it equal to APPEND.
+;
+ IF N_ELEMENTS(DESTINATION) EQ 0 THEN BEGIN
+ DESTINATION = APPEND
+ RETURN
+ ENDIF
+;
+; Get the array types and dimensions of DESTINATION and APPEND.
+;
+ SD = SIZE(DESTINATION)
+ SA = SIZE(APPEND)
+ D_NDIM = SD[0]
+ A_NDIM = SA[0]
+ IF D_NDIM EQ 0 THEN D_DIM = 1 ELSE D_DIM = SD[1:D_NDIM]
+ IF A_NDIM EQ 0 THEN A_DIM = 1 ELSE A_DIM = SA[1:A_NDIM]
+ D_TYPE = SD[N_ELEMENTS(SD)-2]
+ A_TYPE = SA[N_ELEMENTS(SA)-2]
+;
+; Treat scalars as one-dimensional arrays.
+;
+ D_NDIM = D_NDIM > 1
+ A_NDIM = A_NDIM > 1
+;
+; Check to see if both arrays are of type string or numeric.
+;
+ IF D_TYPE EQ 7 THEN D_STRING = 1 ELSE D_STRING = 0
+ IF A_TYPE EQ 7 THEN A_STRING = 1 ELSE A_STRING = 0
+ IF D_STRING NE A_STRING THEN MESSAGE, $
+ 'Data arrays should be either both string or both non-string'
+;
+; Calculate the number of dimensions in the output array. If both arrays have
+; the same number of dimensions, then create a new array with an extra
+; dimension of two. Otherwise, make sure that DESTINATION has more dimensions
+; than APPEND.
+;
+ IF D_NDIM EQ A_NDIM THEN BEGIN
+ R_DIM = [D_DIM > A_DIM, 2]
+ END ELSE IF D_NDIM LT A_NDIM THEN BEGIN
+ MESSAGE,'APPEND has more dimensions than DESTINATION'
+;
+; Otherwise, merge the dimensions of DESTINATION and APPEND, and add one to
+; the final dimension.
+;
+ END ELSE BEGIN
+ R_DIM = D_DIM
+ FOR I = 0,A_NDIM-1 DO R_DIM[I] = D_DIM[I] > A_DIM[I]
+ R_DIM[D_NDIM-1] = R_DIM[D_NDIM-1] + 1
+ ENDELSE
+;
+; Create the output array with the correct number of elements, and the greater
+; of the types of DESTINATION and APPEND.
+;
+ OUTPUT = MAKE_ARRAY(DIMENSION=R_DIM, TYPE=(D_TYPE > A_TYPE))
+;
+; Store DESTINATION in the output array.
+;
+ R_NDIM = N_ELEMENTS(R_DIM)
+ CASE R_NDIM OF
+ 2: OUTPUT[0,0] = DESTINATION
+ 3: OUTPUT[0,0,0] = DESTINATION
+ 4: OUTPUT[0,0,0,0] = DESTINATION
+ 5: OUTPUT[0,0,0,0,0] = DESTINATION
+ 6: OUTPUT[0,0,0,0,0,0] = DESTINATION
+ 7: OUTPUT[0,0,0,0,0,0,0] = DESTINATION
+ ENDCASE
+;
+; Add APPEND at the end.
+;
+ LAST = R_DIM[R_NDIM-1] - 1
+ CASE R_NDIM OF
+ 2: OUTPUT[0,LAST] = APPEND
+ 3: OUTPUT[0,0,LAST] = APPEND
+ 4: OUTPUT[0,0,0,LAST] = APPEND
+ 5: OUTPUT[0,0,0,0,LAST] = APPEND
+ 6: OUTPUT[0,0,0,0,0,LAST] = APPEND
+ 7: OUTPUT[0,0,0,0,0,0,LAST] = APPEND
+ ENDCASE
+;
+; Replace DESTINATION with OUTPUT, and return.
+;
+ DESTINATION = OUTPUT
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/boxave.pro b/Code/script_idl_mv/astrolib/boxave.pro
new file mode 100644
index 0000000000000000000000000000000000000000..899de45a515a0d98aba165b1735abe2d17d584b6
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/boxave.pro
@@ -0,0 +1,128 @@
+function boxave, array, xsize, ysize
+;+
+; NAME:
+; BOXAVE
+; PURPOSE:
+; Box-average a 1 or 2 dimensional array.
+; EXPLANATION:
+; This procedure differs from the intrinsic REBIN function in the follow
+; 2 ways:
+;
+; (1) the box size parameter is specified rather than the output
+; array size
+; (2) for INTEGER arrays, BOXAVE computes intermediate steps using REAL*4
+; (or REAL*8 for 64bit integers) arithmetic. This is
+; considerably slower than REBIN but avoids integer truncation
+;
+; CALLING SEQUENCE:
+; result = BOXAVE( Array, Xsize,[ Ysize ] )
+;
+; INPUTS:
+; ARRAY - Two dimensional input Array to be box-averaged. Array may be
+; one or 2 dimensions and of any type except character.
+;
+; OPTIONAL INPUTS:
+; XSIZE - Size of box in the X direction, over which the array is to
+; be averaged. If omitted, program will prompt for this
+; parameter.
+; YSIZE - For 2 dimensional arrays, the box size in the Y direction.
+; If omitted, then the box size in the X and Y directions are
+; assumed to be equal
+;
+; OUTPUT:
+; RESULT - Output array after box averaging. If the input array has
+; dimensions XDIM by YDIM, then RESULT has dimensions
+; XDIM/NBOX by YDIM/NBOX. The type of RESULT is the same as
+; the input array. However, the averaging is always computed
+; using REAL arithmetic, so that the calculation should be exact.
+; If the box size did not exactly divide the input array, then
+; then not all of the input array will be boxaveraged.
+;
+; PROCEDURE:
+; BOXAVE boxaverages all points simultaneously using vector subscripting
+;
+; NOTES:
+; If im_int is a 512 x 512 integer (16 bit) array, then the two statements
+;
+; IDL> im = fix(round(rebin(float(im_int), 128, 128)))
+; IDL> im = boxave( im_int,4)
+;
+; give equivalent results. The use of REBIN is faster, but BOXAVE is
+; is less demanding on virtual memory, since one does not need to make
+; a floating point copy of the entire array.
+;
+; REVISION HISTORY:
+; Written, W. Landsman, October 1986
+; Call REBIN for REAL*4 and REAL*8 input arrays, W. Landsman Jan, 1992
+; Removed /NOZERO in output array definition W. Landsman 1995
+; Fixed occasional integer overflow problem W. Landsman Sep. 1995
+; Allow unsigned data types W. Landsman Jan. 2000
+; Assume since V5.4, Allow 64bit integers W. Landsman Apr 2006
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() EQ 0 then $
+ message,'Syntax - out = BOXAVE( array, xsize, [ysize ])',/NoName
+
+ s = size(array)
+ if ( s[0] NE 1 ) and ( s[0] NE 2 ) then $
+ message,'Input array (first parameter) must be 1 or 2 dimensional'
+
+ if N_elements(xsize) EQ 0 then read,'BOXAVE: Enter box size: ',xsize
+ if N_elements(ysize) EQ 0 then ysize = xsize
+
+ s = size(array)
+ ninx = s[1]
+ noutx = ninx/xsize
+ type = s[ s[0] + 1]
+ integer = (type LT 4) or (type GE 12)
+
+ if s[0] EQ 1 then begin ; 1 dimension?
+
+ if integer then begin
+
+ if xsize LT 2 then return, array
+ counter = lindgen(noutx)*xsize
+ output = array[counter]
+ for i=1,xsize-1 do output = output + array[counter + i]
+ if type GE 14 then nboxsq = double(xsize) else nboxsq = float(xsize)
+
+ endif else return, rebin( array, noutx) ;Use REBIN if not integer
+
+ endif else begin ; 2 dimensions
+
+ niny = s[2]
+ nouty = niny/ysize
+ if integer then begin ;Byte, Integer, or Long
+
+ if type GE 14 then begin
+ nboxsq = double( xsize*ysize )
+ output = dblarr( noutx, nouty) ;Create output array
+ endif else begin
+ nboxsq = float( xsize*ysize )
+ output = fltarr( noutx, nouty) ;Create output array
+ endelse
+ counter = lindgen( noutx*nouty )
+ counter = xsize*(counter mod noutx) + $
+ (ysize*ninx)*long((counter/noutx))
+
+ for i = 0L,xsize-1 do $
+ for j = 0L,ysize-1 do $
+ output = output + array[counter + (i + j*ninx)]
+
+ endif else $
+ return, rebin( array, noutx, nouty) ;Use REBIN if not integer
+ endelse
+
+ case type of
+ 12: return, uint(round( output/nboxsq )) ;Unsigned Integer
+ 13: return, ulong( round(output/nboxsq)) ;Unsigned Long
+ 14: return, round(output/nboxsq, /L64) ;64bit integer
+ 15: return, ulong64(round(output/nboxsq,/L64)) ;Unsigned 64bit
+ 2: return, fix( round( output/ nboxsq )) ;Integer
+ 3: return, round( output / nboxsq ) ;Long
+ 1: return, byte( round( output/nboxsq) ) ;Byte
+ endcase
+
+ end
diff --git a/Code/script_idl_mv/astrolib/bprecess.pro b/Code/script_idl_mv/astrolib/bprecess.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cf812a62a2db89ad8d18ddae67a347d7748d28ca
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/bprecess.pro
@@ -0,0 +1,219 @@
+pro Bprecess, ra, dec, ra_1950, dec_1950, MU_RADEC = mu_radec, $
+ PARALLAX = parallax, RAD_VEL = rad_vel, EPOCH = epoch
+;+
+; NAME:
+; BPRECESS
+; PURPOSE:
+; Precess positions from J2000.0 (FK5) to B1950.0 (FK4)
+; EXPLANATION:
+; Calculates the mean place of a star at B1950.0 on the FK4 system from
+; the mean place at J2000.0 on the FK5 system.
+;
+; CALLING SEQUENCE:
+; bprecess, ra, dec, ra_1950, dec_1950, [ MU_RADEC = , PARALLAX =
+; RAD_VEL =, EPOCH = ]
+;
+; INPUTS:
+; RA,DEC - Input J2000 right ascension and declination in *degrees*.
+; Scalar or N element vector
+;
+; OUTPUTS:
+; RA_1950, DEC_1950 - The corresponding B1950 right ascension and
+; declination in *degrees*. Same number of elements as
+; RA,DEC but always double precision.
+;
+; OPTIONAL INPUT-OUTPUT KEYWORDS
+; MU_RADEC - 2xN element double precision vector containing the proper
+; motion in seconds of arc per tropical *century* in right
+; ascension and declination.
+; PARALLAX - N_element vector giving stellar parallax (seconds of arc)
+; RAD_VEL - N_element vector giving radial velocity in km/s
+;
+; The values of MU_RADEC, PARALLAX, and RADVEL will all be modified
+; upon output to contain the values of these quantities in the
+; B1950 system. The parallax and radial velocity will have a very
+; minor influence on the B1950 position.
+;
+; EPOCH - scalar giving epoch of original observations, default 2000.0d
+; This keyword value is only used if the MU_RADEC keyword is not set.
+; NOTES:
+; The algorithm is taken from the Explanatory Supplement to the
+; Astronomical Almanac 1992, page 186.
+; Also see Aoki et al (1983), A&A, 128,263
+;
+; BPRECESS distinguishes between the following two cases:
+; (1) The proper motion is known and non-zero
+; (2) the proper motion is unknown or known to be exactly zero (i.e.
+; extragalactic radio sources). In this case, the reverse of
+; the algorithm in Appendix 2 of Aoki et al. (1983) is used to
+; ensure that the output proper motion is exactly zero. Better
+; precision can be achieved in this case by inputting the EPOCH
+; of the original observations.
+;
+; The error in using the IDL procedure PRECESS for converting between
+; B1950 and J1950 can be up to 12", mainly in right ascension. If
+; better accuracy than this is needed then BPRECESS should be used.
+;
+; An unsystematic comparison of BPRECESS with the IPAC precession
+; routine (http://nedwww.ipac.caltech.edu/forms/calculator.html) always
+; gives differences less than 0.15".
+; EXAMPLE:
+; The SAO2000 catalogue gives the J2000 position and proper motion for
+; the star HD 119288. Find the B1950 position.
+;
+; RA(2000) = 13h 42m 12.740s Dec(2000) = 8d 23' 17.69''
+; Mu(RA) = -.0257 s/yr Mu(Dec) = -.090 ''/yr
+;
+; IDL> mu_radec = 100D* [ -15D*.0257, -0.090 ]
+; IDL> ra = ten(13, 42, 12.740)*15.D
+; IDL> dec = ten(8, 23, 17.69)
+; IDL> bprecess, ra, dec, ra1950, dec1950, mu_radec = mu_radec
+; IDL> print, adstring(ra1950, dec1950,2)
+; ===> 13h 39m 44.526s +08d 38' 28.63"
+;
+; REVISION HISTORY:
+; Written, W. Landsman October, 1992
+; Vectorized, W. Landsman February, 1994
+; Treat case where proper motion not known or exactly zero November 1994
+; Handling of arrays larger than 32767 Lars L. Christensen, march, 1995
+; Fixed bug where A term not initialized for vector input
+; W. Landsman February 2000
+; Use V6.0 notation W. Landsman Mar 2011
+;
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 4 then begin
+ print,'Syntax - BPRECESS, ra,dec, ra_1950, dec_1950, [MU_RADEC ='
+ print,' PARALLAX = , RAD_VEL = ]'
+ print,' Input RA and Dec should be given in DEGREES for J2000'
+ print,' Proper motion, MU_RADEC, (optional) in arc seconds per *century*'
+ print,' Parallax (optional) in arc seconds'
+ print,' Radial Velocity (optional) in km/s'
+ return
+
+ endif
+
+ N = N_elements( ra )
+ if N EQ 0 then message,'ERROR - First parameter (RA vector) is undefined'
+
+ if ~keyword_set( RAD_VEL) then rad_vel = dblarr(N) else begin
+ rad_vel = rad_vel*1.
+ if N_elements( RAD_VEL) NE N then message, $
+ 'ERROR - RAD_VEL keyword vector must contain ' + strtrim(N,2) +' values'
+ endelse
+
+ if keyword_set( MU_RADEC) then begin
+ if (N_elements( mu_radec) NE 2*N ) then message, $
+ 'ERROR - MU_RADEC keyword (proper motion) be dimensioned (2,' + $
+ strtrim(N,2) + ')'
+ mu_radec = mu_radec*1.
+ endif
+
+ if ~keyword_set( Parallax) then parallax = dblarr(N) else $
+ parallax = parallax*1.
+
+ if ~keyword_set(Epoch) then epoch = 2000.0d0
+
+ radeg = 180.D/!DPI
+ sec_to_radian = 1.d0/radeg/3600.d0
+
+ M = [ [+0.9999256795D, -0.0111814828D, -0.0048590040D, $
+ -0.000551D, -0.238560D, +0.435730D ], $
+ [ +0.0111814828D, +0.9999374849D, -0.0000271557D, $
+ +0.238509D, -0.002667D, -0.008541D ], $
+ [ +0.0048590039D, -0.0000271771D, +0.9999881946D , $
+ -0.435614D, +0.012254D, +0.002117D ], $
+ [ -0.00000242389840D, +0.00000002710544D, +0.00000001177742D, $
+ +0.99990432D, -0.01118145D, -0.00485852D ], $
+ [ -0.00000002710544D, -0.00000242392702D, +0.00000000006585D, $
+ +0.01118145D, +0.99991613D, -0.00002716D ], $
+ [ -0.00000001177742D, +0.00000000006585D,-0.00000242404995D, $
+ +0.00485852D, -0.00002717D, +0.99996684D] ]
+
+ A_dot = 1D-3*[1.244D, -1.579D, -0.660D ] ;in arc seconds per century
+
+ ra_rad = ra/radeg & dec_rad = dec/radeg
+ cosra = cos( ra_rad ) & sinra = sin( ra_rad )
+ cosdec = cos( dec_rad ) & sindec = sin( dec_rad )
+
+ dec_1950 = dec*0.
+ ra_1950 = ra*0.
+
+ for i = 0L, N-1 do begin
+
+; Following statement moved inside loop in Feb 2000.
+ A = 1D-6*[ -1.62557D, -0.31919D, -0.13843D] ;in radians
+
+ r0 = [ cosra[i]*cosdec[i], sinra[i]*cosdec[i], sindec[i] ]
+
+ if keyword_set(mu_radec) then begin
+
+ mu_a = mu_radec[ 0, i ]
+ mu_d = mu_radec[ 1, i ]
+ r0_dot = [ -mu_a*sinra[i]*cosdec[i] - mu_d*cosra[i]*sindec[i] , $ ;Velocity vector
+ mu_a*cosra[i]*cosdec[i] - mu_d*sinra[i]*sindec[i] , $
+ mu_d*cosdec[i] ] + 21.095d * rad_vel[i] * parallax[i] * r0
+
+ endif else r0_dot = [0.0d0, 0.0d0, 0.0d0]
+
+ R_0 = [ r0, r0_dot ]
+ R_1 = M # R_0
+
+ ; Include the effects of the E-terms of aberration to form r and r_dot.
+
+ r1 = R_1[0:2]
+ r1_dot = R_1[3:5]
+
+ if ~keyword_set(Mu_radec) then begin
+ r1 = r1 + sec_to_radian * r1_dot * (epoch - 1950.0d)/100.
+ A = A + sec_to_radian * A_dot * (epoch - 1950.0d)/100.
+ endif
+
+ x1 = R_1[0] & y1 = R_1[1] & z1 = R_1[2]
+ rmag = sqrt( x1^2 + y1^2 + z1^2 )
+
+
+ s1 = r1/rmag & s1_dot = r1_dot/rmag
+
+ s = s1
+ for j = 0,2 do begin
+ r = s1 + A - (total(s * A))*s
+ s = r/rmag
+ endfor
+ x = r[0] & y = r[1] & z = r[2]
+ r2 = x^2 + y^2 + z^2
+ rmag = sqrt( r2 )
+
+ if keyword_set(Mu_radec) then begin
+ r_dot = s1_dot + A_dot - ( total( s * A_dot))*s
+ x_dot = r_dot[0] & y_dot= r_dot[1] & z_dot = r_dot[2]
+ mu_radec[0,i] = ( x*y_dot - y*x_dot) / ( x^2 + y^2)
+ mu_radec[1,i] = ( z_dot* (x^2 + y^2) - z*(x*x_dot + y*y_dot) ) / $
+ ( r2*sqrt( x^2 + y^2) )
+ endif
+
+ dec_1950[i] = asin( z / rmag)
+ ra_1950[i] = atan( y, x)
+
+ if parallax[i] GT 0. then begin
+ rad_vel[i] = ( x*x_dot + y*y_dot + z*z_dot )/ (21.095*Parallax[i]*rmag)
+ parallax[i] = parallax[i] / rmag
+ endif
+ endfor
+
+ neg = where( ra_1950 LT 0, NNeg )
+ if Nneg GT 0 then ra_1950[neg] = ra_1950[neg] + 2.D*!DPI
+
+ ra_1950 = ra_1950*radeg & dec_1950 = dec_1950*radeg
+
+; Make output scalar if input was scalar
+
+ sz = size(ra)
+ if sz[0] EQ 0 then begin
+ ra_1950 = ra_1950[0] & dec_1950 = dec_1950[0]
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/break_path.pro b/Code/script_idl_mv/astrolib/break_path.pro
new file mode 100644
index 0000000000000000000000000000000000000000..703c381a6ec31ae5d2263836870fa5f490f52d3a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/break_path.pro
@@ -0,0 +1,140 @@
+ FUNCTION BREAK_PATH, PATHS, NOCURRENT=NOCURRENT
+;+
+; NAME:
+; BREAK_PATH()
+;
+; PURPOSE:
+; Breaks up a path string into its component directories.
+;
+; CALLING SEQUENCE:
+; Result = BREAK_PATH( PATHS [ /NoCurrent])
+;
+; INPUTS:
+; PATHS = A string containing one or more directory paths. The
+; individual paths are separated by commas, although in UNIX,
+; colons can also be used. In other words, PATHS has the same
+; format as !PATH, except that commas can be used as a separator
+; regardless of operating system.
+;
+; A leading $ can be used in any path to signal that what follows
+; is an environmental variable, but the $ is not necessary.
+; Environmental variables can themselves contain multiple paths.
+;
+; OUTPUT:
+; The result of the function is a string array of directories.
+; Unless the NOCURRENT keyword is set, the first element of the array is
+; always the null string, representing the current directory. All the
+; other directories will end in the correct separator character for the
+; current operating system.
+;
+; OPTIONAL INPUT KEYWORD:
+; /NOCURRENT = If set, then the current directory (represented by
+; the null string) will not automatically be prepended to the
+; output.
+;
+; PROCEDURE CALLS:
+; None.
+;
+; REVISION HISTORY:
+; Version 1, William Thompson, GSFC, 6 May 1993.
+; Added IDL for Windows compatibility.
+; Version 2, William Thompson, GSFC, 16 May 1995
+; Added keyword NOCURRENT
+; Version 3, William Thompson, GSFC, 29 August 1995
+; Modified to use OS_FAMILY
+; Version 4, Zarro, GSFC, 4 August 1997
+; Added trim to input
+; Fix directory character on Macintosh system A. Ferro February 2000
+; Use STRSPLIT instead of STR_SEP() W. Landsman July 2002
+; Remove VMS support W. Landsman September 2006
+;-
+;
+ ON_ERROR, 2
+;
+; Check the number of parameters:
+;
+ IF SIZE(PATHS,/TNAME) NE 'STRING' THEN MESSAGE, $
+ 'Syntax: Result = BREAK_PATH( PATHS )'
+;
+; Reformat PATHS into an array. The first element is the null string. In
+; Unix, both the comma and colon character can be separators, so two passes
+; are needed to extract everything. The same is true for Microsoft Windows
+; and semi-colons.
+;
+ sep = path_sep(/SEARCH_PATH)
+ PATH = ['',STRSPLIT(PATHS,SEP + ',',/EXTRACT)]
+;
+; For each path, see if it is really an environment variable. If so, then
+; decompose the environmental variable into its constituent paths.
+;
+ I = 0
+ WHILE I LT N_ELEMENTS(PATH) DO BEGIN
+;
+; First, try the path by itself. Remove any trailing "/", "\", or ":"
+; characters.
+
+ CHAR = STRMID(PATH[I],STRLEN(PATH[I])-1,1)
+ IF (CHAR EQ '/') OR (CHAR EQ '\') OR (CHAR EQ ':') THEN $
+ PATH[I] = STRMID(PATH[I],0,STRLEN(PATH[I])-1)
+ TEMP = PATH[I]
+ TEST = GETENV(TEMP)
+;
+; If that doesn't yield anything, and the path begins with the $ prompt, then
+; try what follows after the $.
+;
+ IF TEST EQ '' THEN IF STRMID(PATH[I],0,1) EQ '$' THEN BEGIN
+ FOLLOWING = STRMID(TEMP,1,STRLEN(TEMP)-1)
+ TEST = GETENV(FOLLOWING)
+ ENDIF
+;
+;
+; If something was found, then decompose this into whatever paths it may
+; contain.
+;
+ IF TEST NE '' THEN BEGIN
+ PTH = STRSPLIT(TEST,SEP+',',/EXTRACT)
+;
+; Insert this sublist into the main path list.
+;
+ IF N_ELEMENTS(PATH) EQ 1 THEN BEGIN
+ PATH = PTH
+ END ELSE IF I EQ 0 THEN BEGIN
+ PATH = [PTH,PATH[1:*]]
+ END ELSE IF I EQ N_ELEMENTS(PATH)-1 THEN BEGIN
+ PATH = [PATH[0:I-1],PTH]
+ END ELSE BEGIN
+ PATH = [PATH[0:I-1],PTH,PATH[I+1:*]]
+ ENDELSE
+;
+; Otherwise, check whether or not the path ends in the correct character.
+; In Unix, if the path does not end in "/" then append it. Do the same with
+; the "\" character in Microsoft Windows. This step is only taken once the
+; routine has completely decomposed this part of the path list.
+;
+ END ELSE BEGIN
+ IF PATH[I] NE '' THEN BEGIN
+ LAST = STRMID(PATH[I], STRLEN(PATH[I])-1, 1)
+ CASE !VERSION.OS_FAMILY OF
+ 'Windows': IF LAST NE '\' THEN $
+ PATH[I] = PATH[I] + '\'
+ 'MacOS': IF LAST NE ':' THEN $
+ PATH[I] = PATH[I] + ':'
+ ELSE: IF LAST NE '/' THEN $
+ PATH[I] = PATH[I] + '/'
+ ENDCASE
+ ENDIF
+;
+; Advance to the next path, and continue.
+;
+ I = I + 1
+ ENDELSE
+ ENDWHILE
+;
+; If the NOCURRENT keyword was set, then remove the first element which
+; represents the current directory
+;
+ IF KEYWORD_SET(NOCURRENT) AND (N_ELEMENTS(PATH) GT 1) THEN $
+ PATH = PATH[1:*]
+;
+ RETURN, PATH
+ END
diff --git a/Code/script_idl_mv/astrolib/bsort.pro b/Code/script_idl_mv/astrolib/bsort.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b420f0a1c2f43f8dd642e6538df979e36421ab3e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/bsort.pro
@@ -0,0 +1,103 @@
+function Bsort, Array, Asort, INFO=info, REVERSE = rev
+;+
+; NAME:
+; BSORT
+; PURPOSE:
+; Function to sort data into ascending order, like a simple bubble sort.
+; EXPLANATION:
+; Original subscript order is maintained when values are equal (stable sort).
+; (This differs from the IDL SORT routine alone, which may rearrange
+; order for equal values)
+;
+; A faster algorithm (radix sort) for numeric data is described at
+; http://idldatapoint.com/2012/04/19/an-lsd-radix-sort-algorithm-in-idl/
+; and available at
+; https://github.com/mgalloy/mglib/blob/master/src/analysis/mg_sort.pro
+; CALLING SEQUENCE:
+; result = bsort( array, [ asort, /INFO, /REVERSE ] )
+;
+; INPUT:
+; Array - array to be sorted
+;
+; OUTPUT:
+; result - sort subscripts are returned as function value
+;
+; OPTIONAL OUTPUT:
+; Asort - sorted array
+;
+; OPTIONAL KEYWORD INPUTS:
+; /REVERSE - if this keyword is set, and non-zero, then data is sorted
+; in descending order instead of ascending order.
+; /INFO = optional keyword to cause brief message about # equal values.
+;
+; HISTORY
+; written by F. Varosi Oct.90:
+; uses WHERE to find equal clumps, instead of looping with IF ( EQ ).
+; compatible with string arrays, test for degenerate array
+; 20-MAY-1991 JKF/ACC via T AKE- return indexes if the array to
+; be sorted has all equal values.
+; Aug - 91 Added REVERSE keyword W. Landsman
+; Always return type LONG W. Landsman August 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ N = N_elements( Array )
+ if N lt 1 then begin
+ print,'Input to BSORT must be an array'
+ return, [0L]
+ endif
+
+ if N lt 2 then begin
+ asort = array ;MDM added 24-Sep-91
+ return,[0L] ;Only 1 element
+ end
+;
+; sort array (in descending order if REVERSE keyword specified )
+;
+ subs = sort( Array )
+ if keyword_set( REV ) then subs = rotate(subs,5)
+ Asort = Array[subs]
+;
+; now sort subscripts into ascending order
+; when more than one Asort has same value
+;
+ weq = where( (shift( Asort, -1 ) eq Asort) , Neq )
+
+ if keyword_set( info ) then $
+ message, strtrim( Neq, 2 ) + " equal values Located",/CON,/INF
+
+ if (Neq EQ n) then return,lindgen(n) ;Array is degenerate equal values
+
+ if (Neq GT 0) then begin
+
+ if (Neq GT 1) then begin ;find clumps of equality
+
+ wclump = where( (shift( weq, -1 ) - weq) GT 1, Nclump )
+ Nclump++
+
+ endif else Nclump = 1
+
+ if (Nclump LE 1) then begin
+ Clump_Beg = 0
+ Clump_End = Neq-1
+ endif else begin
+ Clump_Beg = [0,wclump+1]
+ Clump_End = [wclump,Neq-1]
+ endelse
+
+ weq_Beg = weq[ Clump_Beg ] ;subscript ranges
+ weq_End = weq[ Clump_End ] + 1 ; of Asort equalities.
+
+ if keyword_set( info ) then message, strtrim( Nclump, 2 ) + $
+ " clumps of equal values Located",/CON,/INF
+
+ for ic = 0L, Nclump-1 do begin ;sort each clump.
+
+ subic = subs[ weq_Beg[ic] : weq_End[ic] ]
+ subs[ weq_Beg[ic] ] = subic[ sort( subic ) ]
+ endfor
+
+ if N_params() GE 2 then Asort = Array[subs] ;resort array.
+ endif
+
+return, subs
+end
diff --git a/Code/script_idl_mv/astrolib/calz_unred.pro b/Code/script_idl_mv/astrolib/calz_unred.pro
new file mode 100644
index 0000000000000000000000000000000000000000..de407895da29eb563ebab20e2b49d0a3e9e37615
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/calz_unred.pro
@@ -0,0 +1,79 @@
+pro calz_unred, wave, flux, ebv, funred, R_V = R_V
+;+
+; NAME:
+; CALZ_UNRED
+; PURPOSE:
+; Deredden a galaxy spectrum using the Calzetti et al. (2000) recipe
+; EXPLANATION:
+; Calzetti et al. (2000, ApJ 533, 682) developed a recipe for dereddening
+; the spectra of galaxies where massive stars dominate the radiation output,
+; valid between 0.12 to 2.2 microns. (CALZ_UNRED extrapolates between
+; 0.12 and 0.0912 microns.)
+;
+; CALLING SEQUENCE:
+; CALZ_UNRED, wave, flux, ebv, [ funred, R_V = ]
+; INPUT:
+; WAVE - wavelength vector (Angstroms)
+; FLUX - calibrated flux vector, same number of elements as WAVE
+; If only 3 parameters are supplied, then this vector will
+; updated on output to contain the dereddened flux.
+; EBV - color excess E(B-V), scalar. If a negative EBV is supplied,
+; then fluxes will be reddened rather than deredenned.
+; Note that the supplied color excess should be that derived for
+; the stellar continuum, EBV(stars), which is related to the
+; reddening derived from the gas, EBV(gas), via the Balmer
+; decrement by EBV(stars) = 0.44*EBV(gas)
+;
+; OUTPUT:
+; FUNRED - unreddened flux vector, same units and number of elements
+; as FLUX. FUNRED values will be zeroed outside valid domain
+; Calz_unred (0.0912 - 2.2 microns).
+;
+; OPTIONAL INPUT KEYWORD:
+; R_V - Ratio of total to selective extinction, default = 4.05.
+; Calzetti et al. (2000) estimate R_V = 4.05 +/- 0.80 from optical
+; -IR observations of 4 starbursts.
+; EXAMPLE:
+; Estimate how a flat galaxy spectrum (in wavelength) between 1200 A
+; and 3200 A is altered by a reddening of E(B-V) = 0.1.
+;
+; IDL> w = 1200 + findgen(40)*50 ;Create a wavelength vector
+; IDL> f = w*0 + 1 ;Create a "flat" flux vector
+; IDL> calz_unred, w, f, -0.1, fnew ;Redden (negative E(B-V)) flux vector
+; IDL> plot,w,fnew
+;
+; NOTES:
+; Use the 4 parameter calling sequence if you wish to save the
+; original flux vector.
+; PROCEDURE CALLS:
+; POLY()
+; REVISION HISTORY:
+; Written W. Landsman Raytheon ITSS December, 2000
+;-
+ On_error, 2
+
+ if N_params() LT 3 then begin
+ print,'Syntax: CALZ_UNRED, wave, flux, ebv, [ funred, R_V=]'
+ return
+ endif
+
+ if N_elements(R_V) EQ 0 then R_V = 4.05
+ w1 = where((wave GE 6300) AND (wave LE 22000), c1)
+ w2 = where((wave GE 912) AND (wave LT 6300), c2)
+ x = 10000.0/wave ;Wavelength in inverse microns
+
+ IF (c1 + c2) NE N_elements(wave) THEN message,/INF, $
+ 'Warning - some elements of wavelength vector outside valid domain'
+
+ klam = 0.0*flux
+
+ IF c1 GT 0 THEN $
+ klam[w1] = 2.659*(-1.857 + 1.040*x[w1]) + R_V
+
+ IF c2 GT 0 THEN $
+ klam[w2] = 2.659*(poly(x[w2], [-2.156, 1.509d0, -0.198d0, 0.011d0])) + R_V
+
+ funred = flux*10.0^(0.4*klam*ebv)
+ if N_params() EQ 3 then flux = funred
+
+ end
diff --git a/Code/script_idl_mv/astrolib/ccm_unred.pro b/Code/script_idl_mv/astrolib/ccm_unred.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7aacc109c24ff300fe275f52be9ad62c74d64e1b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ccm_unred.pro
@@ -0,0 +1,147 @@
+pro ccm_UNRED, wave, flux, ebv, funred, R_V = r_v
+;+
+; NAME:
+; CCM_UNRED
+; PURPOSE:
+; Deredden a flux vector using the CCM 1989 parameterization
+; EXPLANATION:
+; The reddening curve is that of Cardelli, Clayton, and Mathis (1989 ApJ.
+; 345, 245), including the update for the near-UV given by O'Donnell
+; (1994, ApJ, 422, 158). Parameterization is valid from the IR to the
+; far-UV (3.5 microns to 0.1 microns).
+;
+; Users might wish to consider using the alternate procedure FM_UNRED
+; which uses the extinction curve of Fitzpatrick (1999).
+; CALLING SEQUENCE:
+; CCM_UNRED, wave, flux, ebv, funred, [ R_V = ]
+; or
+; CCM_UNRED, wave, flux, ebv, [ R_V = ]
+; INPUT:
+; WAVE - wavelength vector (Angstroms)
+; FLUX - calibrated flux vector, same number of elements as WAVE
+; If only 3 parameters are supplied, then this vector will
+; updated on output to contain the dereddened flux.
+; EBV - color excess E(B-V), scalar. If a negative EBV is supplied,
+; then fluxes will be reddened rather than deredenned.
+;
+; OUTPUT:
+; FUNRED - unreddened flux vector, same units and number of elements
+; as FLUX
+;
+; OPTIONAL INPUT KEYWORD
+; R_V - scalar specifying the ratio of total selective extinction
+; R(V) = A(V) / E(B - V). If not specified, then R_V = 3.1
+; Extreme values of R(V) range from 2.75 to 5.3
+;
+; EXAMPLE:
+; Determine how a flat spectrum (in wavelength) between 1200 A and 3200 A
+; is altered by a reddening of E(B-V) = 0.1. Assume an "average"
+; reddening for the diffuse interstellar medium (R(V) = 3.1)
+;
+; IDL> w = 1200 + findgen(40)*50 ;Create a wavelength vector
+; IDL> f = w*0 + 1 ;Create a "flat" flux vector
+; IDL> ccm_unred, w, f, -0.1, fnew ;Redden (negative E(B-V)) flux vector
+; IDL> plot,w,fnew
+;
+; NOTES:
+; (1) The CCM curve shows good agreement with the Savage & Mathis (1979)
+; ultraviolet curve shortward of 1400 A, but is probably
+; preferable between 1200 and 1400 A.
+; (2) Many sightlines with peculiar ultraviolet interstellar extinction
+; can be represented with a CCM curve, if the proper value of
+; R(V) is supplied.
+; (3) Curve is extrapolated between 912 and 1000 A as suggested by
+; Longo et al. (1989, ApJ, 339,474)
+; (4) Use the 4 parameter calling sequence if you wish to save the
+; original flux vector.
+; (5) Valencic et al. (2004, ApJ, 616, 912) revise the ultraviolet CCM
+; curve (3.3 -- 8.0 um-1). But since their revised curve does
+; not connect smoothly with longer and shorter wavelengths, it is
+; not included here.
+;
+; REVISION HISTORY:
+; Written W. Landsman Hughes/STX January, 1992
+; Extrapolate curve for wavelengths between 900 and 1000 A Dec. 1993
+; Use updated coefficients for near-UV from O'Donnell Feb 1994
+; Allow 3 parameter calling sequence April 1998
+; Converted to IDLV5.0 April 1998
+;-
+
+ On_error, 2
+
+ if N_params() LT 3 then begin
+ print,'Syntax: CCM_UNRED, wave, flux, ebv, funred,[ R_V = ]'
+ return
+ endif
+
+ if not keyword_set(R_V) then R_V = 3.1
+
+ x = 10000./ wave ; Convert to inverse microns
+ npts = N_elements( x )
+ a = fltarr(npts)
+ b = fltarr(npts)
+;******************************
+
+ good = where( (x GT 0.3) and (x LT 1.1), Ngood ) ;Infrared
+ if Ngood GT 0 then begin
+ a[good] = 0.574 * x[good]^(1.61)
+ b[good] = -0.527 * x[good]^(1.61)
+ endif
+
+;******************************
+
+ good = where( (x GE 1.1) and (x LT 3.3) ,Ngood) ;Optical/NIR
+ if Ngood GT 0 then begin ;Use new constants from O'Donnell (1994)
+ y = x[good] - 1.82
+; c1 = [ 1. , 0.17699, -0.50447, -0.02427, 0.72085, $ ;Original
+; 0.01979, -0.77530, 0.32999 ] ;coefficients
+; c2 = [ 0., 1.41338, 2.28305, 1.07233, -5.38434, $ ;from CCM89
+; -0.62251, 5.30260, -2.09002 ]
+ c1 = [ 1. , 0.104, -0.609, 0.701, 1.137, $ ;New coefficients
+ -1.718, -0.827, 1.647, -0.505 ] ;from O'Donnell
+ c2 = [ 0., 1.952, 2.908, -3.989, -7.985, $ ;(1994)
+ 11.102, 5.491, -10.805, 3.347 ]
+
+ a[good] = poly( y, c1)
+ b[good] = poly( y, c2)
+ endif
+;******************************
+
+ good = where( (x GE 3.3) and (x LT 8) ,Ngood) ;Mid-UV
+ if Ngood GT 0 then begin
+
+ y = x[good]
+ F_a = fltarr(Ngood) & F_b = fltarr(Ngood)
+ good1 = where( (y GT 5.9), Ngood1 )
+ if Ngood1 GT 0 then begin
+ y1 = y[good1] - 5.9
+ F_a[ good1] = -0.04473 * y1^2 - 0.009779 * y1^3
+ F_b[ good1] = 0.2130 * y1^2 + 0.1207 * y1^3
+ endif
+
+ a[good] = 1.752 - 0.316*y - (0.104 / ( (y-4.67)^2 + 0.341 )) + F_a
+ b[good] = -3.090 + 1.825*y + (1.206 / ( (y-4.62)^2 + 0.263 )) + F_b
+ endif
+
+; *******************************
+
+ good = where( (x GE 8) and (x LE 11), Ngood ) ;Far-UV
+ if Ngood GT 0 then begin
+ y = x[good] - 8.
+ c1 = [ -1.073, -0.628, 0.137, -0.070 ]
+ c2 = [ 13.670, 4.257, -0.420, 0.374 ]
+ a[good] = poly(y, c1)
+ b[good] = poly(y, c2)
+ endif
+
+; *******************************
+
+; Now apply extinction correction to input flux vector
+
+ A_V = R_V * EBV
+ A_lambda = A_V * (a + b/R_V)
+ if N_params() EQ 3 then flux = flux * 10.^(0.4*A_lambda) else $
+ funred = flux * 10.^(0.4*A_lambda) ;Derive unreddened flux
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/check_fits.pro b/Code/script_idl_mv/astrolib/check_fits.pro
new file mode 100644
index 0000000000000000000000000000000000000000..000bffa2545abc7ea33875483918444766bbee46
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/check_fits.pro
@@ -0,0 +1,227 @@
+pro check_FITS, im, hdr, dimen, idltype, UPDATE = update, NOTYPE = notype, $
+ SDAS = sdas, FITS = fits, SILENT = silent, ERRMSG = errmsg
+;+
+; NAME:
+; CHECK_FITS
+; PURPOSE:
+; Check that keywords in a FITS header array match the associated data
+; EXPLANATION:
+; Given a FITS array IM, and a associated FITS header HDR, this
+; procedure will check that
+; (1) HDR is a string array, and IM is defined and numeric
+; (2) The NAXISi values in HDR are appropriate to the dimensions
+; of IM
+; (3) The BITPIX value in HDR is appropriate to the datatype of IM
+; If the /UPDATE keyword is present, then the FITS header will be
+; modified, if necessary, to force agreement with the image array
+;
+; CALLING SEQUENCE:
+; check_FITS, im, hdr, [ dimen, idltype, /UPDATE, /NOTYPE, /SILENT
+; ERRMSG = ]'
+;
+; INPUT PARAMETERS:
+; IM - FITS array, e.g. as read by READFITS
+; HDR - FITS header (string array) associated with IM
+;
+; OPTIONAL OUTPUTS:
+; dimen - vector containing actual array dimensions
+; idltype- data type of the FITS array as specified in the IDL SIZE
+; function (1 for BYTE, 2 for INTEGER*2, 3 for INTEGER*4, etc.)
+;
+; OPTIONAL KEYWORD INPUTS:
+; /NOTYPE - If this keyword is set, then only agreement of the array
+; dimensions with the FITS header are checked, and not the
+; data type.
+; /UPDATE - If this keyword is set then the BITPIX, NAXIS and NAXISi
+; FITS keywords will be updated to agree with the array
+; /FITS, /SDAS - these are obsolete keywords that now do nothing
+; /SILENT - If keyword is set and nonzero, the informational messages
+; will not be printed
+; OPTIONAL KEYWORD OUTPUT:
+; ERRMSG = If this keyword is present, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned.
+;
+; PROCEDURE:
+; Program checks the NAXIS and NAXISi keywords in the header to
+; see if they match the image array dimensions, and checks whether
+; the BITPIX keyword agrees with the array type.
+;
+; PROCEDURE CALLS:
+; FXADDPAR, FXPAR(), SXDELPAR
+; MODIFICATION HISTORY:
+; Written, December 1991 W. Landsman Hughes/STX to replace CHKIMHD
+; No error returned if NAXIS=0 and IM is a scalar W. Landsman Feb 93
+; Fixed bug for REAL*8 STSDAS data W. Landsman July 93
+; Make sure NAXIS agrees with NAXISi W. Landsman October 93
+; Converted to IDL V5.0 W. Landsman September 1997
+; Allow unsigned data types W. Landsman December 1999
+; Allow BZERO = 0 for unsigned data types W. Landsman January 2000
+; Added ERRMSG keyword, W. Landsman February 2000
+; Use FXADDPAR to put NAXISi in proper order W. Landsman August 2000
+; Improper FXADDPAR call for DATATYPE keyword W. Landsman December 2000
+; Remove explicit setting of obsolete !err W. Landsman February 2004
+; Remove SDAS support W. Landsman November 2006
+; Fix dimension errors introduced Nov 2006
+; Work again for null arrays W. Landsman/E. Hivon May 2007
+; Use V6.0 notation W.L. Feb. 2011
+;-
+ compile_opt idl2
+ On_error,2
+
+ if N_params() LT 2 then begin
+ print,'Syntax - CHECK_FITS, im, hdr, dimen, idltype, '
+ print,' [ /UPDATE, /NOTYPE, ERRMSG=, /SILENT ]'
+ return
+ endif
+
+ if arg_present(errmsg) then errmsg = ''
+
+ if size(hdr,/TNAME) NE 'STRING' then begin ;Is hdr of string type?
+ message= 'FITS header is not a string array'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message, 'ERROR - ' + message, /CON
+ return
+ endif
+
+ im_info = size(im,/struc)
+ ndimen = im_info.n_dimensions
+ if ndimen GT 0 then dimen = im_info.dimensions[0:ndimen-1]
+ idltype = im_info.type
+
+
+ nax = fxpar( hdr, 'NAXIS', Count = N_naxis )
+ if N_naxis EQ 0 then begin
+ message = 'FITS header missing NAXIS keyword'
+ if N_elements(errmsg) GT 0 then errmsg = message else $
+ message,'ERROR - ' + message,/CON
+ return
+ endif
+
+ if ndimen EQ 0 then $ ;Null primary array
+ if nax EQ 0 then return else begin
+ message = 'FITS array is not defined'
+ if N_elements(errmsg) GT 0 then errmsg = message else $
+ message,'ERROR - ' +message,/con
+ return
+ endelse
+
+
+ naxis = fxpar( hdr, 'NAXIS*')
+ naxi = N_elements( naxis )
+ if nax GT naxi then begin ;Does NAXIS agree with # of NAXISi?
+ if keyword_set( UPDATE) then begin
+ fxaddpar, hdr, 'NAXIS', naxi
+ if ~keyword_set(SILENT) then message, /INF, $
+ 'NAXIS changed from ' + strtrim(nax,2) + ' to ' + strtrim(naxi,2)
+ endif else begin
+ message = 'FITS header has NAXIS = ' + strtrim(nax,2) + $
+ ', but only ' + strtrim(naxi, 2) + ' axes defined'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message, 'ERROR - ' + message
+ return
+ endelse
+ endif
+
+ last = naxi-1 ;Remove degenerate dimensions
+ while ( (naxis[last] EQ 1) && (last GE 1) ) do last--
+ if last NE nax-1 then begin
+ naxis = naxis[ 0:last]
+ endif
+
+ if ( ndimen NE last + 1 ) then begin
+ if ~keyword_set( UPDATE) THEN begin
+ message = $
+ '# of NAXISi keywords does not match # of array dimensions'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message,'ERROR - ' + message,/CON
+ return
+
+ endif else goto, DIMEN_ERROR
+ endif
+
+ for i = 0,last do begin
+ if naxis[i] NE dimen[i] then begin
+ if ~keyword_set( UPDATE ) then begin
+ message = 'Invalid NAXIS' + strtrim( i+1,2 ) + $
+ ' keyword value in header'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message,'ERROR - ' + message,/CON
+ return
+ endif else goto, DIMEN_ERROR
+ endif
+ endfor
+
+BITPIX:
+
+ if ~keyword_set( NOTYPE ) then begin
+
+
+ bitpix = fxpar( hdr, 'BITPIX')
+
+ case idltype of
+
+ 1: if bitpix NE 8 then goto, BITPIX_ERROR
+ 2: if bitpix NE 16 then goto, BITPIX_ERROR
+ 4: if bitpix NE -32 then goto, BITPIX_ERROR
+ 3: if bitpix NE 32 then goto, BITPIX_ERROR
+ 5: if bitpix NE -64 then goto, BITPIX_ERROR
+ 12:if bitpix NE 16 then goto, BITPIX_ERROR
+ 13: if bitpix NE 32 then goto, BITPIX_ERROR
+
+ else: begin
+ message = 'Data array is not a valid FITS datatype'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message,'ERROR - ' + message,/CON
+ return
+ end
+
+ endcase
+
+ endif
+
+ return
+
+BITPIX_ERROR:
+ if keyword_set( UPDATE ) then begin
+ bpix = [0, 8, 16, 32, -32, -64, 32, 0, 0, 0, 0, 0, 16,32 ]
+ comm = ['',' Character or unsigned binary integer', $
+ ' 16-bit twos complement binary integer', $
+ ' 32-bit twos complement binary integer', $
+ ' IEEE single precision floating point', $
+ ' IEEE double precision floating point', $
+ ' 32-bit twos complement binary integer','','','','','', $
+ ' 16-bit unsigned binary integer', $
+ ' 32-bit unsigned binary integer' ]
+ bitpix = bpix[idltype]
+ comment = comm[idltype]
+ if ~keyword_set(SILENT) then message, /INF, $
+ 'BITPIX value of ' + strtrim(bitpix,2) + ' added to FITS header'
+ fxaddpar, hdr, 'BITPIX', bitpix, comment
+ return
+
+ endif else begin
+ message = 'BITPIX value of ' + strtrim(bitpix,2) + $
+ ' in FITS header does not match array'
+ if N_elements(ERRMSG) GT 0 then errmsg = message else $
+ message,'ERROR - ' + message,/CON
+ return
+ endelse
+
+DIMEN_ERROR:
+ if keyword_set( UPDATE ) then begin
+ fxaddpar, hdr, 'NAXIS', ndimen, before = 'NAXIS1'
+ naxis = 'NAXIS' + strtrim(indgen(ndimen)+1,2)
+ for i = 1, ndimen do fxaddpar, hdr, naxis[i-1], dimen[i-1], $
+ 'Number of positions along axis ' + strtrim(i,2), $
+ after = 'NAXIS' + strtrim(i-1,2)
+ if naxi GT ndimen then begin
+ for i = ndimen+1, naxi do sxdelpar, hdr, 'NAXIS'+strtrim(i,2)
+ endif
+ if ~keyword_set(SILENT) then message, /INF, $
+ 'NAXIS keywords in FITS header have been updated'
+ goto, BITPIX
+ endif
+
+ end
diff --git a/Code/script_idl_mv/astrolib/checksum32.pro b/Code/script_idl_mv/astrolib/checksum32.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2e23c540a26fc3080ebe540547ae4a4df0063cb8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/checksum32.pro
@@ -0,0 +1,125 @@
+pro checksum32, array, checksum, FROM_IEEE = from_IEEE, NOSAVE = nosave
+;+
+; NAME:
+; CHECKSUM32
+;
+; PURPOSE:
+; To compute the 32bit checksum of an array (ones-complement arithmetic)
+;
+; EXPLANATION:
+; The 32bit checksum is adopted in the FITS Checksum convention
+; http://fits.gsfc.nasa.gov/registry/checksum.html
+;
+; CALLING SEQUENCE:
+; CHECKSUM32, array, checksum, [/FROM_IEEE, /NoSAVE]
+;
+; INPUTS:
+; array - any numeric idl array. If the number of bytes in the array is
+; not a multiple of four then it is padded with zeros internally
+; (the array is returned unchanged). Convert a string array
+; (e.g. a FITS header) to bytes prior to calling CHECKSUM32.
+;
+; OUTPUTS:
+; checksum - unsigned long scalar, giving sum of array elements using
+; ones-complement arithmetic
+; OPTIONAL INPUT KEYWORD:
+;
+; /FROM_IEEE - If this keyword is set, then the input is assumed to be in
+; big endian format (e.g. an untranslated FITS array). This keyword
+; only has an effect on little endian machines (e.g. Linux boxes).
+;
+; /NoSAVE - if set, then the input array is not saved upon exiting. Use
+; the /NoSave keyword to save time if the input array is not needed
+; in further computations.
+; METHOD:
+; Uses TOTAL() to sum the array into an unsigned integer variable. The
+; overflow bits beyond 2^32 are then shifted back to the least significant
+; bits. The summing is done in chunks. of 2^31 numbers to avoid loss
+; of precision. Adapted from FORTRAN code in
+; heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/general/checksum/node30.html
+;
+; Could probably be done in a cleverer way (similar to the C
+; implementation) but then the array-oriented TOTAL() function could not
+; be used.
+; RESTRICTIONS:
+; (1) Not valid for object or pointer data types
+; EXAMPLE:
+; Find the 32 bit checksum of the array x = findgen(35)
+;
+; IDL> checksum32, x, s ===> s = 2920022024
+; FUNCTION CALLED:
+; HOST_TO_IEEE, IS_IEEE_BIG(), N_BYTES()
+; MODIFICATION HISTORY:
+; Written W. Landsman June 2001
+; Work correctly on little endian machines, added /FROM_IEEE and /NoSave
+; W. Landsman November 2002
+; Pad with zeros when array size not a multiple of 4 W.Landsman Aug 2003
+; Always copy to new array, somewhat slower but more robust algorithm
+; especially for Linux boxes W. Landsman Sep. 2004
+; Sep. 2004 update not implemented correctly (sigh) W. Landsman Dec 2004
+; No need to byteswap 4 byte datatypes on little endian W. L. May 2009
+; Use /INTEGER keyword to TOTAL() function W.L. June 2009
+;
+;-
+ if N_params() LT 2 then begin
+ print,'Syntax - CHECKSUM32, array, checksum, /FROM_IEEE, /NoSAVE'
+ return
+ endif
+ idltype = size(array,/type)
+
+; Convert data to byte. If array size is not a multiple of 4, then we pad with
+; zeros
+
+ N = N_bytes(array)
+ Nremain = N mod 4
+ if Nremain GT 0 then begin
+ if keyword_set(nosave) then $
+ uarray = [ byte(temporary(array),0,N), bytarr(4-Nremain)] $
+ else uarray = [ byte(array,0,N), bytarr(4-Nremain)]
+ N = N + 4 - Nremain
+ endif else begin
+ if keyword_set(nosave) then $
+ uarray = byte( temporary(array) ,0,N) else $
+ uarray = byte( array ,0,N)
+ endelse
+
+; Get maximum number of base 2 digits available in an unsigned long array,
+; without losing any precision. Since we will sum unsigned longwords, the
+; original array must be byteswapped as longwords.
+
+ maxnum = long64(2)^31
+ Niter = (N-1)/maxnum
+ checksum = long64(0)
+ word32 = long64(2)^32
+ bswap = ~is_ieee_big()
+ if bswap then begin
+ if ~keyword_set( from_ieee) then begin
+ if (idltype NE 3) && (idltype NE 4) then begin
+ if idltype NE 1 then host_to_ieee, uarray,idltype=idltype
+ byteorder,uarray,/NTOHL
+ endif
+ endif else byteorder,uarray,/NTOHL
+ endif
+
+ for i=0, Niter do begin
+
+ if i EQ Niter then begin
+ nbyte = (N mod maxnum)
+ if nbyte EQ 0 then nbyte = maxnum
+ endif else nbyte = maxnum
+
+ checksum += total(ulong( uarray,maxnum*i,nbyte/4), /integer)
+; Fold any overflow bits beyond 32 back into the word.
+
+ hibits = long(checksum/word32)
+ while hibits GT 0 do begin
+ checksum = checksum - (hibits*word32) + hibits
+ hibits = long(checksum/word32)
+ endwhile
+
+ checksum = ulong(checksum)
+
+ endfor
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/cic.pro b/Code/script_idl_mv/astrolib/cic.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b1ff45bf3ad6dd0c11bb45c3d963c95d21bb7e08
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cic.pro
@@ -0,0 +1,417 @@
+FUNCTION cic,value,posx,nx,posy,ny,posz,nz, $
+ AVERAGE=average,WRAPAROUND=wraparound,ISOLATED=isolated, $
+ NO_MESSAGE=no_message
+;+
+; NAME:
+; CIC
+;
+; PURPOSE:
+; Interpolate an irregularly sampled field using Cloud in Cell method
+;
+; EXPLANATION:
+; This function interpolates an irregularly sampled field to a
+; regular grid using Cloud In Cell (nearest grid point gets
+; weight 1-dngp, point on other side gets weight dngp, where
+; dngp is the distance to the nearest grid point in units of the
+; cell size).
+;
+; CATEGORY:
+; Mathematical functions, Interpolation
+;
+; CALLING SEQUENCE:
+; Result = CIC, VALUE, POSX, NX[, POSY, NY, POSZ, NZ,
+; AVERAGE = average, WRAPAROUND = wraparound,
+; ISOLATED = isolated, NO_MESSAGE = no_message]
+;
+; INPUTS:
+; VALUE: Array of sample weights (field values). For e.g. a
+; temperature field this would be the temperature and the
+; keyword AVERAGE should be set. For e.g. a density field
+; this could be either the particle mass (AVERAGE should
+; not be set) or the density (AVERAGE should be set).
+; POSX: Array of X coordinates of field samples, unit indices: [0,NX>.
+; NX: Desired number of grid points in X-direction.
+;
+; OPTIONAL INPUTS:
+; POSY: Array of Y coordinates of field samples, unit indices: [0,NY>.
+; NY: Desired number of grid points in Y-direction.
+; POSZ: Array of Z coordinates of field samples, unit indices: [0,NZ>.
+; NZ: Desired number of grid points in Z-direction.
+;
+; KEYWORD PARAMETERS:
+; AVERAGE: Set this keyword if the nodes contain field samples
+; (e.g. a temperature field). The value at each grid
+; point will then be the weighted average of all the
+; samples allocated to it. If this keyword is not
+; set, the value at each grid point will be the
+; weighted sum of all the nodes allocated to it
+; (e.g. for a density field from a distribution of
+; particles). (D=0).
+; WRAPAROUND: Set this keyword if you want the first grid point
+; to contain samples of both sides of the volume
+; (see below).
+; ISOLATED: Set this keyword if the data is isolated, i.e. not
+; periodic. In that case total `mass' is not conserved.
+; This keyword cannot be used in combination with the
+; keyword WRAPAROUND.
+; NO_MESSAGE: Suppress informational messages.
+;
+; Example of default allocation of nearest grid points: n0=4, *=gridpoint.
+;
+; 0 1 2 3 Index of gridpoints
+; * * * * Grid points
+; |---|---|---|---| Range allocated to gridpoints ([0.0,1.0> --> 0, etc.)
+; 0 1 2 3 4 posx
+;
+; Example of ngp allocation for WRAPAROUND: n0=4, *=gridpoint.
+;
+; 0 1 2 3 Index of gridpoints
+; * * * * Grid points
+; |---|---|---|---|-- Range allocated to gridpoints ([0.5,1.5> --> 1, etc.)
+; 0 1 2 3 4=0 posx
+;
+;
+; OUTPUTS:
+; Prints that a CIC interpolation is being performed of x
+; samples to y grid points, unless NO_MESSAGE is set.
+;
+; RESTRICTIONS:
+; Field data is assumed to be periodic with the sampled volume
+; the basic cell, unless ISOLATED is set.
+; All input arrays must have the same dimensions.
+; Position coordinates should be in `index units' of the
+; desired grid: POSX=[0,NX>, etc.
+; Keywords ISOLATED and WRAPAROUND cannot both be set.
+;
+; PROCEDURE:
+; Nearest grid point is determined for each sample.
+; CIC weights are computed for each sample.
+; Samples are interpolated to the grid.
+; Grid point values are computed (sum or average of samples).
+; NOTES:
+; Use tsc.pro for a higher-order interpolation scheme, ngp.pro for a lower
+; order interpolation scheme. A standard reference for these
+; interpolation methods is: R.W. Hockney and J.W. Eastwood, Computer
+; Simulations Using Particles (New York: McGraw-Hill, 1981).
+; EXAMPLE:
+; nx=20
+; ny=10
+; posx=randomu(s,1000)
+; posy=randomu(s,1000)
+; value=posx^2+posy^2
+; field=cic(value,posx*nx,nx,posy*ny,ny,/average)
+; surface,field,/lego
+;
+; MODIFICATION HISTORY:
+; Written by Joop Schaye, Feb 1999.
+; Avoid integer overflow for large dimensions P.Riley/W.Landsman Dec. 1999
+;-
+
+nrsamples=n_elements(value)
+nparams=n_params()
+dim=(nparams-1)/2
+
+IF dim LE 2 THEN BEGIN
+ nz=1
+ IF dim EQ 1 THEN ny=1
+ENDIF
+nxny=long(nx)*long(ny)
+
+
+;---------------------
+; Some error handling.
+;---------------------
+
+on_error,2 ; Return to caller if an error occurs.
+
+IF NOT (nparams EQ 3 OR nparams EQ 5 OR nparams EQ 7) THEN BEGIN
+ message,'Incorrect number of arguments!',/continue
+ message,'Syntax: CIC, VALUE, POSX, NX[, POSY, NY, POSZ, NZ,' + $
+ ' AVERAGE = average, PERIODIC = periodic]'
+ENDIF
+
+IF (nrsamples NE n_elements(posx)) OR $
+ (dim GE 2 AND nrsamples NE n_elements(posy)) OR $
+ (dim EQ 3 AND nrsamples NE n_elements(posz)) THEN $
+ message,'Input arrays must have the same dimensions!'
+
+IF keyword_set(isolated) AND keyword_set(wraparound) THEN $
+ message,'Keywords ISOLATED and WRAPAROUND cannot both be set!'
+
+IF NOT keyword_set(no_message) THEN $
+ print,'Interpolating ' + strtrim(string(nrsamples,format='(i10)'),1) $
+ + ' samples to ' + strtrim(string(nxny*nz,format='(i10)'),1) + $
+ ' grid points using CIC...'
+
+
+;-----------------------
+; Calculate CIC weights.
+;-----------------------
+
+; Compute weights per axis, in order to reduce memory (everything
+; needs to be in memory if we compute all nearest grid points first).
+
+;*************
+; X-direction.
+;*************
+
+; Coordinates of nearest grid point (ngp).
+IF keyword_set(wraparound) THEN ngx=fix(posx+0.5) $
+ELSE ngx=fix(posx)+0.5
+
+; Distance from sample to ngp.
+dngx=ngx-posx
+
+; Index of ngp.
+IF keyword_set(wraparound) THEN kx1=temporary(ngx) $
+ELSE kx1=temporary(ngx)-0.5
+; Weight of ngp.
+wx1=1.0-abs(dngx)
+
+; Other side.
+left=where(dngx LT 0.0,nrleft) ; samples with ngp to the left.
+; The following is only correct if x(ngp)>posx (ngp to the right).
+kx2=kx1-1
+; Correct points where x(ngp)posy (ngp to the right).
+ ky2=ky1-1
+ ; Correct points where y(ngp)posz (ngp to the right).
+ kz2=kz1-1
+ ; Correct points where z(ngp) --> cube length different from EDFW paper).
+
+index=kx1+ky1*nx+kz1*nxny
+cicweight=wx1*wy1*wz1
+IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+index=kx2+ky1*nx+kz1*nxny
+cicweight=wx2*wy1*wz1
+IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+
+IF dim GE 2 THEN BEGIN
+ index=kx1+ky2*nx+kz1*nxny
+ cicweight=wx1*wy2*wz1
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ index=kx2+ky2*nx+kz1*nxny
+ cicweight=wx2*wy2*wz1
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+
+ IF dim EQ 3 THEN BEGIN
+ index=kx1+ky1*nx+kz2*nxny
+ cicweight=wx1*wy1*wz2
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ index=kx2+ky1*nx+kz2*nxny
+ cicweight=wx2*wy1*wz2
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ index=kx1+ky2*nx+kz2*nxny
+ cicweight=wx1*wy2*wz2
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ index=kx2+ky2*nx+kz2*nxny
+ cicweight=wx2*wy2*wz2
+ IF keyword_set(average) THEN BEGIN
+ FOR j=0l,nrsamples-1l DO BEGIN
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ totcicweight[index[j]]=totcicweight[index[j]]+cicweight[j]
+ ENDFOR
+ ENDIF ELSE FOR j=0l,nrsamples-1l DO $
+ field[index[j]]=field[index[j]]+cicweight[j]*value[j]
+ ENDIF
+
+ENDIF
+
+; Free memory (no need to free any more local arrays, will not lower
+; maximum memory usage).
+index=0
+
+
+;--------------------------
+; Compute weighted average.
+;--------------------------
+
+IF keyword_set(average) THEN BEGIN
+ good=where(totcicweight NE 0,nrgood)
+ field[good]=temporary(field[good])/temporary(totcicweight[good])
+ENDIF
+
+return,field
+
+END ; End of function cic.
diff --git a/Code/script_idl_mv/astrolib/cirrange.pro b/Code/script_idl_mv/astrolib/cirrange.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e2044059969e50d36fe534a8b362b87d30db108b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cirrange.pro
@@ -0,0 +1,49 @@
+PRO cirrange, ang, RADIANS=rad
+;+
+; NAME:
+; CIRRANGE
+; PURPOSE:
+; To force an angle into the range 0 <= ang < 360.
+; CALLING SEQUENCE:
+; CIRRANGE, ang, [/RADIANS]
+;
+; INPUTS/OUTPUT:
+; ang - The angle to modify, in degrees. This parameter is
+; changed by this procedure. Can be a scalar or vector.
+; The type of ANG is always converted to double precision
+; on output.
+;
+; OPTIONAL INPUT KEYWORDS:
+; /RADIANS - If present and non-zero, the angle is specified in
+; radians rather than degrees. It is forced into the range
+; 0 <= ang < 2 PI.
+; PROCEDURE:
+; The angle is transformed between -360 and 360 using the MOD operator.
+; Negative values (if any) are then transformed between 0 and 360
+; MODIFICATION HISTORY:
+; Written by Michael R. Greason, Hughes STX, 10 February 1994.
+; Get rid of WHILE loop, W. Landsman, Hughes STX, May 1996
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ On_error,2
+ if N_params() LT 1 then begin
+ print, 'Syntax: CIRRANGE, ang, [ /RADIANS ]'
+ return
+ endif
+
+; Determine the additive constant.
+
+ if keyword_set(RAD) then cnst = !dpi * 2.d $
+ else cnst = 360.d
+
+; Deal with the lower limit.
+
+ ang = ang mod cnst
+
+; Deal with negative values, if any
+
+ neg = where(ang LT 0., Nneg)
+ if Nneg GT 0 then ang[neg] = ang[neg] + cnst
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/cleanplot.pro b/Code/script_idl_mv/astrolib/cleanplot.pro
new file mode 100644
index 0000000000000000000000000000000000000000..abcd1b11b7b929ea3f39ff32d4e331396d6e039a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cleanplot.pro
@@ -0,0 +1,150 @@
+Pro CleanPlot, silent=silent, ShowOnly = showonly ;Reset System Variables
+;+
+; NAME:
+; CLEANPLOT
+; PURPOSE:
+; Reset all plotting system variables (!P,!X,!Y,!Z) to their default values
+; EXPLANATION:
+; Reset all system variables (!P,!X,!Y,!Z) which are set by the user
+; and which affect plotting to their default values.
+;
+; CALLING SEQUENCE:
+; Cleanplot, [ /Silent, /ShowOnly]
+;
+; INPUTS:
+; None
+;
+; OPTIONAL KEYWORD INPUT:
+; /SHOWONLY - If set, then CLEANPLOT will display the plotting system
+; variables with nondefault values, but it will not reset them.
+;
+; /SILENT - If set, then CLEANPLOT will not display a message giving the
+; the system variables tags being reset. One cannot set
+; both /SILENT and /SHOWONLY
+; OUTPUTS:
+; None
+;
+; SIDE EFFECTS:
+; The system variables that concern plotting are reset to their default
+; values. A message is output for each variable changed.
+; The !P.CLIP and CRANGE, S, WINDOW, and REGION fields of the
+; !X, !Y, and !Z system variables are not checked since these are
+; set by the graphics device and not by the user.
+;
+; PROCEDURE:
+; This does NOT reset the plotting device.
+; This does not change any system variables that don't control plotting.
+;
+; RESTRICTIONS:
+; If user default values for !P, !X, !Y and !Z are different from
+; the defaults adopted below, user should change P_old etc accordingly
+;
+; MODIFICATION HISTORY:
+; Written IDL Version 2.3.0 W. Landsman & K. Venkatakrishna May '92
+; Handle new system variables in V3.0.0 W. Landsman Dec 92
+; Assume user has at least V3.0.0 W. Landsman August 95
+; V5.0 has 60 instead of 30 TICKV values W. Landsman Sep. 97
+; Change !D.N_COLORS to !D.TABLE_SIZE for 24 bit displays
+; W. Landsman April 1998
+; Added silent keyword to supress output & modified X_old to
+; handle the new !X and !Y tags in IDL 5.4 S. Penton July 2000
+; Test for visual depth if > V5.1 W. Landsman July 2000
+; Macs can report a visual depth of 32 W. Landsman March 2001
+; Call device,get_visual_depth only for device which allow it
+; W. Landsman June 2001
+; Default !P.color is 16777215 for 16 bit systems
+; W. Landsman/M. Hadfield November 2001
+; Added ShowOnly keyword W. Landsman April 2002
+; Use V6.0 notation W. Landsman April 2011
+;
+;-
+ compile_opt idl2
+
+ On_error,2
+ silent = keyword_set(silent)
+ if keyword_set(showonly) then begin
+ print,'Current Plotting System Variables with non-default Values'
+ clearing = ''
+ oldvalue = ' '
+ reset = 0
+ endif else begin
+ clearing = 'Clearing '
+ oldvalue = ', old value '
+ reset = 1
+ end
+; For !X, !Y, and !Z we will assume that the default values except for MARGIN are
+; either 0 or '', while for !P we explicitly write all default values in P_old
+
+ P_old = { BACKGROUND: 0L,CHARSIZE:0.0, CHARTHICK:0.0, $
+ CLIP:[0L,0,639,511,0,0], $ ;Not used
+ COLOR : !D.TABLE_SIZE-1, FONT: -1L, LINESTYLE: 0L, MULTI:lonarr(5),$
+ NOCLIP: 0L, NOERASE: 0L, NSUM: 0L, POSITION: fltarr(4),$
+ PSYM: 0L, REGION: fltarr(4), SUBTITLE:'', SYMSIZE:0.0, T:fltarr(4,4),$
+ T3D:0L, THICK: 0.0, TITLE:'', TICKLEN:0.02, CHANNEL:0L }
+
+ X_old=!X
+for i=0,n_tags(!X)-1 do $
+ if size(!X.(i),/type) eq 7 then X_old.(i)= '' else X_old.(i) = 0
+
+ X_old.MARGIN = [10.0,3.0]
+
+ Y_old = X_old
+ Y_old.MARGIN = [4.0, 2.0]
+
+ Z_old = X_old
+ Z_old.MARGIN = [0.0, 0.0]
+
+ P_var = tag_names(!P)
+
+ if !D.NAME EQ 'PS' then begin
+ P_old.background = 255
+ P_old.color = 0
+ endif else if ( (!D.NAME EQ 'X') || (!D.NAME EQ 'MAC') || $
+ (!D.NAME EQ 'WIN') ) then begin
+ device,get_visual_depth = depth
+ if depth GT 8 then P_old.color = 16777215 else $
+ P_old.color = 256L^(depth/8) - 1
+ endif
+
+; Reset !P to its default value except for !P.CLIP
+
+ for i=0, N_elements(P_var)-1 do begin
+ if i NE 3 then begin
+ n = N_elements(!P.(i))
+ if ~array_equal(!P.(i), P_old.(i)) then Begin
+ if ~silent then $
+ Print,clearing + '!P.'+P_var[i]+ oldvalue +'=',!P.(i)
+ if reset then !P.(i) = P_old.(i)
+ EndIf
+ endif
+ endfor
+; Reset !X !Y and !Z to their default values
+ X_var = tag_names(!X)
+ Y_var = tag_names(!Y)
+ Z_var = tag_names(!Z)
+
+ for i = 0, n_tags(!X)-1 do begin
+ if total( i EQ [7,8,11,12] ) EQ 0 then begin ;Skip S,CRANGE,WINDOW,REGION
+ n = N_elements(!X.(i))
+ if ~array_equal(!X.(i) , X_old.(i)) then Begin
+ if ~silent then $
+ Print,clearing + '!X.'+X_var[i]+ oldvalue + '=', !X.(i)
+ if reset then !X.(i) = X_old.(i)
+ EndIf
+
+ if ~array_equal(!Y.(i), Y_old.(i)) then Begin
+ if ~silent then $
+ Print,clearing + '!Y.'+Y_var[i]+ oldvalue + '=', !Y.(i)
+ if reset then !Y.(i) = Y_old.(i)
+ EndIf
+
+ if ~array_equal(!Z.(i), Z_old.(i)) then Begin
+ if ~silent then $
+ Print,clearing +'!Z.'+Z_var[i]+ oldvalue + '=',!Z.(i)
+ if reset then !Z.(i) = Z_old.(i)
+ EndIf
+ endif
+endfor
+
+Return ;Completed
+End
diff --git a/Code/script_idl_mv/astrolib/cntrd.pro b/Code/script_idl_mv/astrolib/cntrd.pro
new file mode 100644
index 0000000000000000000000000000000000000000..04ceb814673d3010cb26871c0ff61c278fd0ab75
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cntrd.pro
@@ -0,0 +1,245 @@
+pro cntrd, img, x, y, xcen, ycen, fwhm, SILENT= silent, DEBUG=debug, $
+ EXTENDBOX = extendbox, KeepCenter = KeepCenter
+;+
+; NAME:
+; CNTRD
+; PURPOSE:
+; Compute the centroid of a star using a derivative search
+; EXPLANATION:
+; CNTRD uses an early DAOPHOT "FIND" centroid algorithm by locating the
+; position where the X and Y derivatives go to zero. This is usually a
+; more "robust" determination than a "center of mass" or fitting a 2d
+; Gaussian if the wings in one direction are affected by the presence
+; of a neighboring star.
+;
+; CALLING SEQUENCE:
+; CNTRD, img, x, y, xcen, ycen, [ fwhm , /KEEPCENTER, /SILENT, /DEBUG
+; EXTENDBOX = ]
+;
+; INPUTS:
+; IMG - Two dimensional image array
+; X,Y - Scalar or vector integers giving approximate integer stellar
+; center
+;
+; OPTIONAL INPUT:
+; FWHM - floating scalar; Centroid is computed using a box of half
+; width equal to 1.5 sigma = 0.637* FWHM. CNTRD will prompt
+; for FWHM if not supplied
+;
+; OUTPUTS:
+; XCEN - the computed X centroid position, same number of points as X
+; YCEN - computed Y centroid position, same number of points as Y,
+; floating point
+;
+; Values for XCEN and YCEN will not be computed if the computed
+; centroid falls outside of the box, or if the computed derivatives
+; are non-decreasing. If the centroid cannot be computed, then a
+; message is displayed and XCEN and YCEN are set to -1.
+;
+; OPTIONAL OUTPUT KEYWORDS:
+; /SILENT - Normally CNTRD prints an error message if it is unable
+; to compute the centroid. Set /SILENT to suppress this.
+; /DEBUG - If this keyword is set, then CNTRD will display the subarray
+; it is using to compute the centroid.
+; EXTENDBOX = {non-negative positive integer}. CNTRD searches a box with
+; a half width equal to 1.5 sigma = 0.637* FWHM to find the
+; maximum pixel. To search a larger area, set EXTENDBOX to
+; the number of pixels to enlarge the half-width of the box.
+; Default is 0; prior to June 2004, the default was EXTENDBOX= 3
+; /KeepCenter = By default, CNTRD finds the maximum pixel in a box
+; centered on the input X,Y coordinates, and then extracts a new
+; box about this maximum pixel. Set the /KeepCenter keyword
+; to skip then step of finding the maximum pixel, and instead use
+; a box centered on the input X,Y coordinates.
+; PROCEDURE:
+; Maximum pixel within distance from input pixel X, Y determined
+; from FHWM is found and used as the center of a square, within
+; which the centroid is computed as the value (XCEN,YCEN) at which
+; the derivatives of the partial sums of the input image over (y,x)
+; with respect to (x,y) = 0. In order to minimize contamination from
+; neighboring stars stars, a weighting factor W is defined as unity in
+; center, 0.5 at end, and linear in between
+;
+; RESTRICTIONS:
+; (1) Does not recognize (bad) pixels. Use the procedure GCNTRD.PRO
+; in this situation.
+; (2) DAOPHOT now uses a newer algorithm (implemented in GCNTRD.PRO) in
+; which centroids are determined by fitting 1-d Gaussians to the
+; marginal distributions in the X and Y directions.
+; (3) The default behavior of CNTRD changed in June 2004 (from EXTENDBOX=3
+; to EXTENDBOX = 0).
+; (4) Stone (1989, AJ, 97, 1227) concludes that the derivative search
+; algorithm in CNTRD is not as effective (though faster) as a
+; Gaussian fit (used in GCNTRD.PRO).
+; MODIFICATION HISTORY:
+; Written 2/25/86, by J. K. Hill, S.A.S.C., following
+; algorithm used by P. Stetson in DAOPHOT.
+; Allowed input vectors G. Hennessy April, 1992
+; Fixed to prevent wrong answer if floating pt. X & Y supplied
+; W. Landsman March, 1993
+; Convert byte, integer subimages to float W. Landsman May 1995
+; Converted to IDL V5.0 W. Landsman September 1997
+; Better checking of edge of frame David Hogg October 2000
+; Avoid integer wraparound for unsigned arrays W.Landsman January 2001
+; Handle case where more than 1 pixel has maximum value W.L. July 2002
+; Added /KEEPCENTER, EXTENDBOX (with default = 0) keywords WL June 2004
+; Some errrors were returning X,Y = NaN rather than -1,-1 WL Aug 2010
+;-
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ if N_params() LT 5 then begin
+ print,'Syntax: CNTRD, img, x, y, xcen, ycen, [ fwhm, '
+ print,' EXTENDBOX= , /KEEPCENTER, /SILENT, /DEBUG ]'
+ PRINT,'img - Input image array'
+ PRINT,'x,y - Input scalars giving approximate X,Y position'
+ PRINT,'xcen,ycen - Output scalars giving centroided X,Y position'
+ return
+ endif else if N_elements(fwhm) NE 1 then $
+ read,'Enter approximate FWHM of image in pixels: ',fwhm
+
+ sz_image = size(img)
+ if sz_image[0] NE 2 then message, $
+ 'ERROR - Image array (first parameter) must be 2 dimensional'
+
+ xsize = sz_image[1]
+ ysize = sz_image[2]
+ dtype = sz_image[3] ;Datatype
+
+; Compute size of box needed to compute centroid
+
+ if ~keyword_set(extendbox) then extendbox = 0
+ nhalf = fix(0.637*fwhm) > 2 ;
+ nbox = 2*nhalf+1 ;Width of box to be used to compute centroid
+ nhalfbig = nhalf + extendbox
+ nbig = nbox + extendbox*2 ;Extend box 3 pixels on each side to search for max pixel value
+ npts = N_elements(x)
+ xcen = float(x) & ycen = float(y)
+ ix = round( x ) ;Central X pixel ;Added 3/93
+ iy = round( y ) ;Central Y pixel
+
+ for i = 0,npts-1 do begin ;Loop over X,Y vector
+
+ pos = strtrim(x[i],2) + ' ' + strtrim(y[i],2)
+
+ if ~keyword_set(keepcenter) then begin
+ if ( (ix[i] LT nhalfbig) || ((ix[i] + nhalfbig) GT xsize-1) || $
+ (iy[i] LT nhalfbig) || ((iy[i] + nhalfbig) GT ysize-1) ) then begin
+ if not keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos + ' too near edge of image'
+ xcen[i] = -1 & ycen[i] = -1
+ goto, DONE
+ endif
+
+ bigbox = img[ix[i]-nhalfbig : ix[i]+nhalfbig, iy[i]-nhalfbig : iy[i]+nhalfbig]
+
+; Locate maximum pixel in 'NBIG' sized subimage
+
+ mx = max( bigbox) ;Maximum pixel value in BIGBOX
+ mx_pos = where(bigbox EQ mx, Nmax) ;How many pixels have maximum value?
+ idx = mx_pos mod nbig ;X coordinate of Max pixel
+ idy = mx_pos / nbig ;Y coordinate of Max pixel
+ if NMax GT 1 then begin ;More than 1 pixel at maximum?
+ idx = round(total(idx)/Nmax)
+ idy = round(total(idy)/Nmax)
+ endif else begin
+ idx = idx[0]
+ idy = idy[0]
+ endelse
+
+ xmax = ix[i] - (nhalf+extendbox) + idx ;X coordinate in original image array
+ ymax = iy[i] - (nhalf+extendbox) + idy ;Y coordinate in original image array
+ endif else begin
+ xmax = ix[i]
+ ymax = iy[i]
+ endelse
+
+; ---------------------------------------------------------------------
+; check *new* center location for range
+; added by Hogg
+
+ if ( (xmax LT nhalf) || ((xmax + nhalf) GT xsize-1) || $
+ (ymax LT nhalf) || ((ymax + nhalf) GT ysize-1) ) then begin
+ if not keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos + ' moved too near edge of image'
+ xcen[i] = -1 & ycen[i] = -1
+ goto, DONE
+ endif
+; ---------------------------------------------------------------------
+
+; Extract smaller 'STRBOX' sized subimage centered on maximum pixel
+
+ strbox = img[xmax-nhalf : xmax+nhalf, ymax-nhalf : ymax+nhalf]
+ if (dtype NE 4) and (dtype NE 5) then strbox = float(strbox)
+
+ if keyword_set(DEBUG) then begin
+ message,'Subarray used to compute centroid:',/inf
+ print,strbox
+ endif
+
+ ir = (nhalf-1) > 1
+ dd = indgen(nbox-1) + 0.5 - nhalf
+; Weighting factor W unity in center, 0.5 at end, and linear in between
+ w = 1. - 0.5*(abs(dd)-0.5)/(nhalf-0.5)
+ sumc = total(w)
+
+; Find X centroid
+
+ deriv = shift(strbox,-1,0) - strbox ;Shift in X & subtract to get derivative
+ deriv = deriv[0:nbox-2,nhalf-ir:nhalf+ir] ;Don't want edges of the array
+ deriv = total( deriv, 2 ) ;Sum X derivatives over Y direction
+ sumd = total( w*deriv )
+ sumxd = total( w*dd*deriv )
+ sumxsq = total( w*dd^2 )
+
+ if sumxd GE 0 then begin ;Reject if X derivative not decreasing
+
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Unable to compute X centroid around position '+ pos
+ xcen[i]=-1 & ycen[i]=-1
+ goto,DONE
+ endif
+
+ dx = sumxsq*sumd/(sumc*sumxd)
+ if ( abs(dx) GT nhalf ) then begin ;Reject if centroid outside box
+ if not keyword_set(SILENT) then message,/INF, $
+ 'Computed X centroid for position '+ pos + ' out of range'
+ xcen[i]=-1 & ycen[i]=-1
+ goto, DONE
+ endif
+
+ xcen[i] = xmax - dx ;X centroid in original array
+
+; Find Y Centroid
+
+ deriv = shift(strbox,0,-1) - strbox
+ deriv = deriv[nhalf-ir:nhalf+ir,0:nbox-2]
+ deriv = total( deriv,1 )
+ sumd = total( w*deriv )
+ sumxd = total( w*deriv*dd )
+ sumxsq = total( w*dd^2 )
+ if (sumxd GE 0) then begin ;Reject if Y derivative not decreasing
+ if not keyword_set(SILENT) then message,/INF, $
+ 'Unable to compute Y centroid around position '+ pos
+ xcen[i] = -1 & ycen[i] = -1
+ goto, DONE
+ endif
+
+ dy = sumxsq*sumd/(sumc*sumxd)
+ if (abs(dy) GT nhalf) then begin ;Reject if computed Y centroid outside box
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Computed X centroid for position '+ pos + ' out of range'
+ xcen[i]=-1 & ycen[i]=-1
+ goto, DONE
+ endif
+
+ ycen[i] = ymax-dy
+
+ DONE:
+
+ endfor
+
+ return
+ end
+
+
diff --git a/Code/script_idl_mv/astrolib/co_aberration.pro b/Code/script_idl_mv/astrolib/co_aberration.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e1ea5e39070e9f23985e3b482312c6ad7ef16638
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/co_aberration.pro
@@ -0,0 +1,92 @@
+PRO co_aberration, jd, ra, dec, d_ra, d_dec, eps=eps
+;+
+; NAME:
+; CO_ABERRATION
+; PURPOSE:
+; Calculate changes to Ra and Dec due to the effect of annual aberration
+; EXPLANATION:
+; as described in Meeus, Chap 23.
+; CALLING SEQUENCE:
+; co_aberration, jd, ra, dec, d_ra, d_dec, [EPS = ]
+; INPUTS
+; jd : Julian Date [scalar or vector]
+; ra, dec : Arrays (or scalars) of the ra and dec's in degrees
+; Note: if jd is a vector, then ra and dec must either be scalars, or
+; vectors of the same length.
+;
+; OUTPUTS
+; d_ra, d_dec: the corrections to ra and dec due to aberration in
+; arcseconds. (These values can be added to the true RA
+; and dec to get the apparent position). Note that d_ra
+; is *not* multiplied by cos(dec), so that
+; apparent_ra = ra + d_ra/3600.
+; OPTIONAL INPUT KEYWORD:
+; eps : set this to the true obliquity of the ecliptic (in radians), or
+; it will be set for you if you don't know it (in that case, set it to
+; an empty variable).
+; EXAMPLE:
+; Compute the change in RA and Dec of Theta Persei (RA = 2h46m,11.331s, Dec =
+; 49d20',54.54") due to aberration on 2028 Nov 13.19 TD
+;
+; IDL> jdcnv,2028,11,13,.19*24,jd ;Get Julian date
+; IDL> co_aberration,jd,ten(2,46,11.331)*15,ten(49,20,54.54),d_ra,d_dec
+;
+; ==> d_ra = 30.045" (=2.003s) d_dec = 6.697"
+; NOTES:
+; These formula are from Meeus, Chapters 23. Accuracy is much better than 1
+; arcsecond.
+;
+; The maximum deviation due to annual aberration is 20.49" and occurs when the
+; Earth velocity is perpendicular to the direction of the star.
+;
+; REVISION HISTORY:
+; Written, June 2002, Chris O'Dell, U. of Wisconsin
+; Fix error with vector input W. Landsman June 2009
+; June 2009 update fixed case where JD was scalar but RA,Dec were vectors, but
+; broke the case when both JD and RA,Dec were vectors Aug 2012 W. Landsman
+; Further fix when JD is 1 element vector W. Landsman
+;-
+ compile_opt idl2
+ d2r = !dpi/180.
+ if N_elements(jd) EQ 1 then jd = jd[0]
+ T = (jd -2451545.0)/36525.0 ; julian centuries from J2000 of jd.
+ if n_elements(eps) eq 0 then begin ; must calculate obliquity of ecliptic
+ njd = n_elements(jd)
+ d_psi = dblarr(njd)
+ d_epsilon = d_psi
+ for i=0L,njd-1 do begin
+ nutate, jd[i], dp, de ; d_psi and d_epsilon in degrees
+ d_psi[i] = dp
+ d_epsilon[i] = de
+ endfor
+ eps0 = ten(23,26,21.448)*3600.d - 46.8150*T - 0.00059*T^2 + $
+ 0.001813*T^3
+ eps = (eps0 + d_epsilon)/3600.*d2r ; true obliquity of the ecliptic
+; in radians
+endif
+
+ sunpos, jd, sunra, sundec, sunlon
+
+; Earth's orbital eccentricity
+ e = 0.016708634d - 0.000042037d*T - 0.0000001267d*T^2
+; longitude of perihelion, in degrees
+pi = 102.93735 + 1.71946*T + 0.00046*T^2
+k = 20.49552 ;constant of aberration, in arcseconds
+
+;Useful Trig Functions
+cd = cos(dec*d2r) & sd = sin(dec*d2r)
+if N_elements(eps) EQ 1 then eps = eps[0] ;Special scalar case
+ce = cos(eps) & te = tan(eps)
+cp = cos(pi*d2r) & sp = sin(pi*d2r)
+cs = cos(sunlon*d2r) & ss = sin(sunlon*d2r)
+ca = cos(ra*d2r) & sa = sin(ra*d2r)
+
+term1 = (ca*cs*ce+sa*ss)/cd
+term2 = (ca*cp*ce+sa*sp)/cd
+term3 = (cs*ce*(te*cd-sa*sd)+ca*sd*ss)
+term4 = (cp*ce*(te*cd-sa*sd)+ca*sd*sp)
+
+d_ra = -k * term1 + e*k * term2
+d_dec = -k * term3 + e*k * term4
+
+END
diff --git a/Code/script_idl_mv/astrolib/co_nutate.pro b/Code/script_idl_mv/astrolib/co_nutate.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4371a7a65351604a832dece6d38defd943f75a84
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/co_nutate.pro
@@ -0,0 +1,115 @@
+PRO co_nutate, jd, ra, dec, d_ra, d_dec, eps=eps, d_psi=d_psi, d_eps=d_eps
+;+
+; NAME:
+; CO_NUTATE
+; PURPOSE:
+; Calculate changes in RA and Dec due to nutation of the Earth's rotation
+; EXPLANATION:
+; Calculates necessary changes to ra and dec due to
+; the nutation of the Earth's rotation axis, as described in Meeus, Chap 23.
+; Uses formulae from Astronomical Almanac, 1984, and does the calculations
+; in equatorial rectangular coordinates to avoid singularities at the
+; celestial poles.
+;
+; CALLING SEQUENCE:
+; CO_NUTATE, jd, ra, dec, d_ra, d_dec, [EPS=, D_PSI =, D_EPS = ]
+; INPUTS
+; JD: Julian Date [scalar or vector]
+; RA, DEC : Arrays (or scalars) of the ra and dec's of interest
+;
+; Note: if jd is a vector, ra and dec MUST be vectors of the same length.
+;
+; OUTPUTS:
+; d_ra, d_dec: the corrections to ra and dec due to nutation (must then
+; be added to ra and dec to get corrected values).
+; OPTIONAL OUTPUT KEYWORDS:
+; EPS: set this to a named variable that will contain the obliquity of the
+; ecliptic.
+; D_PSI: set this to a named variable that will contain the nutation in the
+; longitude of the ecliptic
+; D_EPS: set this to a named variable that will contain the nutation in the
+; obliquity of the ecliptic
+; EXAMPLE:
+; (1) Example 23a in Meeus: On 2028 Nov 13.19 TD the mean position of Theta
+; Persei is 2h 46m 11.331s 49d 20' 54.54". Determine the shift in
+; position due to the Earth's nutation.
+;
+; IDL> jd = JULDAY(11,13,2028,.19*24) ;Get Julian date
+; IDL> CO_NUTATE, jd,ten(2,46,11.331)*15.,ten(49,20,54.54),d_ra,d_dec
+;
+; ====> d_ra = 15.843" d_dec = 6.217"
+; PROCEDURES USED:
+; NUTATE
+; REVISION HISTORY:
+; Written Chris O'Dell, 2002
+; Vector call to NUTATE W. Landsman June 2002
+; Fix when JD is 1 element vector, and RA,Dec are vectors WL May 2013
+;-
+
+ if N_Params() LT 4 then begin
+ print,'Syntax - CO_NUTATE, jd, ra, dec, d_ra, d_dec, '
+ print,' Output keywords: [EPS=, D_PSI =, D_EPS = ]'
+ return
+ endif
+ d2r = !dpi/180.
+ d2as = !dpi/(180.d*3600.d)
+ T = (jd -2451545.0)/36525.0 ; Julian centuries from J2000 of jd.
+
+; must calculate obliquity of ecliptic
+ nutate,jd,d_psi, d_eps
+
+ eps0 = 23.4392911*3600.d - 46.8150*T - 0.00059*T^2 + 0.001813*T^3
+ eps = (eps0 + d_eps)/3600.*d2r ; true obliquity of the ecliptic in radians
+ if N_elements(eps) EQ 1 then eps = eps[0]
+ if N_elements(d_psi) Eq 1 then d_psi = d_psi[0]
+
+;useful numbers
+ ce = cos(eps)
+ se = sin(eps)
+
+; convert ra-dec to equatorial rectangular coordinates
+ x = cos(ra*d2r) * cos(dec*d2r)
+ y = sin(ra*d2r) * cos(dec*d2r)
+ z = sin(dec*d2r)
+
+; apply corrections to each rectangular coordinate
+ x2 = x - (y*ce + z*se)*d_psi * d2as
+ y2 = y + (x*ce*d_psi - z*d_eps) * d2as
+ z2 = z + (x*se*d_psi + y*d_eps) * d2as
+
+; convert back to equatorial spherical coordinates
+ r = sqrt(x2^2 + y2^2 + z2^2)
+ xyproj = sqrt(x2^2 + y2^2)
+
+ ra2 = x2 * 0.d
+ dec2= x2 * 0.d
+
+ w1 = where( (xyproj eq 0) AND (z ne 0) )
+ w2 = where(xyproj ne 0)
+
+; Calculate Ra and Dec in RADIANS (later convert to DEGREES)
+ if w1[0] ne -1 then begin
+ ; places where xyproj=0 (point at NCP or SCP)
+ dec2[w1] = asin(z2[w1]/r[w1])
+ ra2[w1] = 0.
+ endif
+ if w2[0] ne -1 then begin
+ ; places other than NCP or SCP
+ ra2[w2] = atan(y2[w2],x2[w2])
+ dec2[w2] = asin(z2[w2]/r[w2])
+ endif
+
+ ; convert to DEGREES
+
+ ra2 = ra2 /d2r
+ dec2 = dec2 /d2r
+
+ w = where(ra2 LT 0., Nw)
+ if Nw GT 0 then ra2[w] = ra2[w] + 360.
+
+
+; Return changes in ra and dec in arcseconds
+ d_ra = (ra2 - ra) * 3600.
+ d_dec = (dec2 - dec) * 3600.
+
+END
diff --git a/Code/script_idl_mv/astrolib/co_refract.pro b/Code/script_idl_mv/astrolib/co_refract.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec95de65e1f579b02ebc1f53ad5a9f0a3fdd456b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/co_refract.pro
@@ -0,0 +1,186 @@
+;+
+; NAME:
+; CO_REFRACT()
+;
+; PURPOSE:
+; Calculate correction to altitude due to atmospheric refraction.
+;
+; DESCRIPTION:
+; CO_REFRACT can calculate both apparent altitude from observed altitude and
+; vice-versa.
+;
+; CALLING SEQUENCE:
+; new_alt = CO_REFRACT(old_alt, [ ALTITUDE= , PRESSURE= , $
+; TEMPERATURE= , /TO_OBSERVED , EPSILON= ])
+;
+; INPUT:
+; old_alt - Observed (apparent) altitude, in DEGREES. (apparent if keyword
+; /TO_OBSERVED set). May be scalar or vector.
+;
+; OUTPUT:
+; Function returns apparent (observed) altitude, in DEGREES. (observed if
+; keyword /TO_OBSERVED set). Will be of same type as input
+; altitude(s).
+;
+; OPTIONAL KEYWORD INPUTS:
+; ALTITUDE : The height of the observing location, in meters. This is
+; only used to determine an approximate temperature and pressure,
+; if these are not specified separately. [default=0, i.e. sea level]
+; PRESSURE : The pressure at the observing location, in millibars.
+; TEMPERATURE: The temperature at the observing location, in Kelvin.
+; EPSILON: When keyword /TO_OBSERVED has been set, this is the accuracy
+; to obtain via the iteration, in arcseconds [default = 0.25
+; arcseconds].
+; /TO_OBSERVED: Set this keyword to go from Apparent->Observed altitude,
+; using the iterative technique.
+;
+; Note, if altitude is set, but temperature or pressure are not, the
+; program will make an intelligent guess for the temperature and pressure.
+;
+; DESCRIPTION:
+;
+; Because the index of refraction of air is not precisely 1.0, the atmosphere
+; bends all incoming light, making a star or other celestial object appear at
+; a slightly different altitude (or elevation) than it really is. It is
+; important to understand the following definitions:
+;
+; Observed Altitude: The altitude that a star is SEEN to BE, with a telescope.
+; This is where it appears in the sky. This is always
+; GREATER than the apparent altitude.
+;
+; Apparent Altitude: The altitude that a star would be at, if *there were no
+; atmosphere* (sometimes called "true" altitude). This is
+; usually calculated from an object's celestial coordinates.
+; Apparent altitude is always LOWER than the observed
+; altitude.
+;
+; Thus, for example, the Sun's apparent altitude when you see it right on the
+; horizon is actually -34 arcminutes.
+;
+; This program uses couple simple formulae to estimate the effect for most
+; optical and radio wavelengths. Typically, you know your observed altitude
+; (from an observation), and want the apparent altitude. To go the other way,
+; this program uses an iterative approach.
+;
+; EXAMPLE:
+; The lower limb of the Sun is observed to have altitude of 0d 30'.
+; Calculate the the true (=apparent) altitude of the Sun's lower limb using
+; mean conditions of air pressure and temperature
+;
+; IDL> print, co_refract(0.5) ===> 0.025degrees (1.55')
+; WAVELENGTH DEPENDENCE:
+; This correction is 0 at zenith, about 1 arcminute at 45 degrees, and 34
+; arcminutes at the horizon FOR OPTICAL WAVELENGTHS. The correction is
+; NON-NEGLIGIBLE at all wavelengths, but is not very easily calculable.
+; These formulae assume a wavelength of 550 nm, and will be accurate to
+; about 4 arcseconds for all visible wavelengths, for elevations of 10
+; degrees and higher. Amazingly, they are also ACCURATE FOR RADIO
+; FREQUENCIES LESS THAN ~ 100 GHz.
+;
+; It is important to understand that these formulae really can't do better
+; than about 30 arcseconds of accuracy very close to the horizon, as
+; variable atmospheric effects become very important.
+;
+; REFERENCES:
+; 1. Meeus, Astronomical Algorithms, Chapter 15.
+; 2. Explanatory Supplement to the Astronomical Almanac, 1992.
+; 3. Methods of Experimental Physics, Vol 12 Part B, Astrophysics,
+; Radio Telescopes, Chapter 2.5, "Refraction Effects in the Neutral
+; Atmosphere", by R.K. Crane.
+;
+;
+; DEPENDENCIES:
+; CO_REFRACT_FORWARD (contained in this file and automatically compiled).
+;
+; AUTHOR:
+; Chris O'Dell
+; Assistant Professor of Atmospheric Science
+; Colorado State University
+; Email: odell@atmos.colostate.edu
+;
+; REVISION HISTORY:
+; version 1 (May 31, 2002)
+; Update iteration formula, W. Landsman June 2002
+; Corrected slight bug associated with scalar vs. vector temperature and
+; pressure inputs. 6/10/2002
+; Fixed problem with vector input when /TO_OBSERVED set W. Landsman Dec 2005
+; Allow arrays with more than 32767 elements W.Landsman/C.Dickinson Feb 2010
+;-
+function co_refract_forward, a, P=P, T=T
+
+; INPUTS
+; a = The observed (apparent) altitude, in DEGREES.
+; May be scalar or vector.
+;
+; INPUT KEYWORDS
+; P: Pressure [in millibars]. Default is 1010 millibars. [scalar or vector]
+; T: Ground Temp [in Celsius]. Default is 0 Celsius. [scalar or vector]
+
+compile_opt idl2
+d2r = !dpi/180.
+if n_elements(P) eq 0 then P = 1010.
+if n_elements(T) eq 0 then T = 283.
+
+; you have observed the altitude a, and would like to know what the "apparent"
+; altitude is (the one behind the atmosphere).
+w = where(a LT 15.)
+R = 0.0166667/tan((a + 7.31/(a+4.4))*d2r)
+
+;R = 1.02/tan((a + 10.3/(a+5.11))*d2r)/60.
+; this formula goes the other direction!
+
+if w[0] ne -1 then R[w] = 3.569*(0.1594 + .0196*a[w] + $
+ .00002*a[w]^2)/(1.+.505*a[w]+.0845*a[w]^2)
+tpcor = P/1010. * 283/T
+R = tpcor * R
+
+return, R
+
+END
+
+function co_refract, a, altitude=altitude, pressure=pressure, $
+ temperature=temperature, To_observed=To_observed, epsilon=epsilon
+
+; This is the main window. Calls co_refract_forward either iteratively or a
+; single time depending on the direction we are going for refraction.
+
+compile_opt idl2
+o = keyword_set(To_observed)
+alpha = 0.0065 ; temp lapse rate [deg C per meter]
+
+if n_elements(altitude) eq 0 then altitude = 0.
+if n_elements(temperature) eq 0 then begin
+ if altitude GT 11000 then temperature = 211.5 $
+ else temperature = 283.0 - alpha*altitude
+endif
+; estimate Pressure based on altitude, using U.S. Standard Atmosphere formula.
+if n_elements(pressure) eq 0 then $
+ pressure = 1010.*(1-6.5/288000*altitude)^5.255
+if n_elements(epsilon) eq 0 then $
+ epsilon = 0.25 ; accuracy of iteration for observed=1 case, in arcseconds
+
+if not o then begin
+ aout = a - co_refract_forward(a,P=pressure,T=temperature)
+endif else begin
+ aout = a*0.
+ na = n_elements(a)
+; if there are multiple elevations but only one temp and pressure entered,
+; expand those to be arrays of the same size.
+ P = pressure + a*0. & T = temperature + a*0.
+ for i=0L,na-1 do begin
+ ;calculate initial refraction guess
+ dr = co_refract_forward(a[i],P=P[i],T=T[i])
+ cur = a[i] + dr ; guess of observed location
+
+ repeat begin
+ last = cur
+ dr = co_refract_forward(cur,P=P[i],T=T[i])
+ cur= a[i] + dr
+ endrep until abs(last-cur)*3600. LT epsilon
+ aout[i] = cur
+ endfor
+endelse
+
+if N_elements(aout) GT 1 then return, reform(aout) else return, aout
+
+END
diff --git a/Code/script_idl_mv/astrolib/compare_struct.pro b/Code/script_idl_mv/astrolib/compare_struct.pro
new file mode 100644
index 0000000000000000000000000000000000000000..aa497e3601d9dd5791e9ef70b30da88da34659fd
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/compare_struct.pro
@@ -0,0 +1,239 @@
+;+
+; NAME:
+; COMPARE_STRUCT
+; PURPOSE:
+; Compare all matching tag names and return differences
+;
+; EXPLANATION:
+; Compare all matching Tags names (except for "except_Tags")
+; between two structure arrays (may have different struct.definitions),
+; and return a structured List of fields found different.
+;
+; The Exelis contrib library has a faster but less powerful procedure
+; struct_equal.pro, see
+; http://www.exelisvis.com/Default.aspx?tabid=1540&id=1175
+;
+; CALLING SEQUENCE:
+; diff_List = compare_struct( struct_A, struct_B [ EXCEPT=, /BRIEF,
+; /FULL, /NaN, /RECUR_A, /RECUR_B )
+; INPUTS:
+; struct_A, struct_B : the two structure arrays to compare.
+; Struct_Name : for internal recursion use only.
+; OPTIONAL INPUT KEYWORDS:
+; EXCEPT = string array of Tag names to ignore (NOT to compare).
+; /BRIEF = number of differences found for each matching field
+; of two structures is printed.
+; /FULL = option to print even if zero differences found.
+; /NaN = if set, then tag values are considered equal if they
+; are both set to NaN
+; /RECUR_A = option to search for Tag names
+; in sub-structures of struct_A,
+; and then call compare_struct recursively
+; for those nested sub-structures.
+; /RECUR_B = search for sub-structures of struct_B,
+; and then call compare_struct recursively
+; for those nested sub-structures.
+; Note:
+; compare_struct is automatically called recursively
+; for those nested sub-structures in both struct_A and struct_B
+; (otherwise cannot take difference)
+; OUTPUT:
+; Returns a structure array describing differences found.
+; which can be examined using print,diff_List or help,/st,diff_List.
+; The tags are
+; TAG_NUM_A - the tag number in structure A
+; TAG_NUM_B - the tag number in structure B
+; FIELD - the tag name
+; NDIFF - number of differences (always 1 for a scalar tag).
+; PROCEDURE:
+; Match Tag names and then use where function on tags.
+; EXAMPLE:
+; Find the tags in the !X system variable which are changed after a
+; simple plot.
+; IDL> x = !X ;Save original values
+; IDL> plot, indgen(25) ;Make a simple plot
+; IDL> help,/str,compare_struct(x,!X) ;See how structure has changed
+;
+; and one will see that the tags !X.crange and !X.S are changed
+; by the plot.
+; MODIFICATION HISTORY:
+; written 1990 Frank Varosi STX @ NASA/GSFC (using copy_struct)
+; modif Aug.90 by F.V. to check and compare same # of elements only.
+; Added /NaN keyword W. Landsman March 2004
+; Don't test string for NaN values W. Landsman March 2008
+;-
+
+function compare_struct, struct_A, struct_B, EXCEPT=except_Tags, Struct_Name, $
+ FULL=full, BRIEF=brief, NaN = NaN, $
+ RECUR_A = recur_A, RECUR_B = recur_B
+
+ compile_opt idl2
+ common compare_struct, defined
+ if N_params() LT 2 then begin
+ print,'Syntax - diff_List = compare_struct(struct_A, struct_B '
+ print,' [EXCEPT=, /BRIEF, /FULL, /NaN, /RECUR_A, /RECUR_B ]'
+ if N_elements(diff_List) GT 0 then return, diff_List else return, -1
+ endif
+
+ if N_elements( defined ) NE 1 then begin
+
+ diff_List = { DIFF_LIST, Tag_Num_A:0, Tag_Num_B:0, $
+ Field:"", Ndiff:0L }
+ defined = N_tags( diff_List )
+ endif else diff_List = replicate( {DIFF_LIST}, 1 )
+
+ Ntag_A = N_tags( struct_A )
+ if (Ntag_A LE 0) then begin
+ message," 1st argument must be a structure variable",/CONTIN
+ return,diff_List
+ endif
+ Ntag_B = N_tags( struct_B )
+ if (Ntag_B LE 0) then begin
+ message," 2nd argument must be a structure variable",/CONTIN
+ return,diff_List
+ endif
+
+ N_A = N_elements( struct_A )
+ N_B = N_elements( struct_B )
+
+ if (N_A LT N_B) then begin
+
+ message,"comparing "+strtrim(N_A,2)+" of first structure",/CON
+ message,"to first "+strtrim(N_A,2)+" of "+strtrim(N_B,2)+ $
+ " in second structure",/CONTIN
+
+ diff_List = compare_struct( struct_A, struct_B[0:N_A-1], $
+ EXCEPT=except_Tags, $
+ RECUR_A = recur_A, $
+ RECUR_B = recur_B, $
+ FULL=full, BRIEF=brief )
+ return,diff_List
+
+ endif else if (N_A GT N_B) then begin
+
+ message,"comparing first "+strtrim(N_B,2)+" of "+ $
+ strtrim(N_A,2)+" in first structure",/CON
+ message,"to "+strtrim(N_B,2)+" in second structure",/CONTIN
+
+ diff_List = compare_struct( struct_A[0:N_B-1], struct_B, $
+ EXCEPT=except_Tags, $
+ RECUR_A = recur_A, $
+ RECUR_B = recur_B, $
+ FULL=full, BRIEF=brief )
+ return,diff_List
+ endif
+
+ Tags_A = tag_names( struct_A )
+ Tags_B = tag_names( struct_B )
+ wB = indgen( N_elements( Tags_B ) )
+ Nextag = N_elements( except_Tags )
+
+ if (Nextag GT 0) then begin
+
+ except_Tags = [strupcase( except_Tags )]
+
+ for t=0,Nextag-1 do begin
+
+ w = where( Tags_B NE except_Tags[t], Ntag_B )
+ Tags_B = Tags_B[w]
+ wB = wB[w]
+ endfor
+ endif
+
+ if N_elements( struct_name ) NE 1 then sname = "." $
+ else sname = struct_name + "."
+
+ for t = 0, Ntag_B-1 do begin
+
+ wA = where( Tags_A EQ Tags_B[t] , nf )
+
+ if (nf GT 0) then begin
+
+ tA = wA[0]
+ tB = wB[t]
+
+ NtA = N_tags( struct_A.(tA) )
+ NtB = N_tags( struct_B.(tB) )
+
+ if (NtA GT 0 ) AND (NtB GT 0) then begin
+
+ if keyword_set( full ) OR keyword_set( brief ) then $
+ print, sname + Tags_A[tA], " :"
+
+ diffs = compare_struct( struct_A.(tA), struct_B.(tB), $
+ sname + Tags_A[tA], $
+ EXCEPT=except_Tags, $
+ FULL=full, BRIEF=brief )
+ diff_List = [ diff_List, diffs ]
+
+ endif else if (NtA LE 0) AND (NtB LE 0) then begin
+
+ if keyword_set(NaN) then begin
+ x1 = struct_b.(tB)
+ x2 = struct_a.(tA)
+ if (size(x1,/tname) NE 'STRING') and $
+ (size(x2,/tname) NE 'STRING') then begin
+ g = where( finite(x1) or finite(x2), Ndiff )
+ if Ndiff GT 0 then $
+ w = where( x1[g] NE x2[g], Ndiff )
+ endif
+ endif else $
+ w = where( struct_B.(tB) NE struct_A.(tA) , Ndiff )
+
+ if (Ndiff GT 0) then begin
+ diff = replicate( {DIFF_LIST}, 1 )
+ diff.Tag_Num_A = tA
+ diff.Tag_Num_B = tB
+ diff.Field = sname + Tags_A[tA]
+ diff.Ndiff = Ndiff
+ diff_List = [ diff_List, diff ]
+ endif
+
+ if keyword_set( full ) OR $
+ (keyword_set( brief ) AND (Ndiff GT 0)) then $
+ print, Tags_A[tA], Ndiff, FORM="(15X,A15,I9)"
+
+ endif else print, Tags_A[ta], " not compared"
+
+ endif
+ endfor
+
+ if keyword_set( recur_A ) then begin
+
+ for tA = 0, Ntag_A-1 do begin
+
+ if N_tags( struct_A.(tA) ) GT 0 then begin
+
+ diffs = compare_struct( struct_A.(tA), struct_B, $
+ sname + Tags_A[tA], $
+ EXCEPT=except_Tags, $
+ RECUR_A = recur_A, $
+ RECUR_B = recur_B, $
+ FULL=full, BRIEF=brief )
+ diff_List = [ diff_List, diffs ]
+ endif
+ endfor
+ endif
+
+ if keyword_set( recur_B ) then begin
+
+ for tB = 0, Ntag_B-1 do begin
+
+ if N_tags( struct_B.(tB) ) GT 0 then begin
+
+ diffs = compare_struct( struct_A, struct_B.(tB), $
+ sname + Tags_B[tB], $
+ EXCEPT=except_Tags, $
+ RECUR_A = recur_A, $
+ RECUR_B = recur_B, $
+ FULL=full, BRIEF=brief )
+ diff_List = [ diff_List, diffs ]
+ endif
+ endfor
+ endif
+
+ w = where( [diff_List.Ndiff] GT 0, np )
+ if (np LE 0) then w = [0]
+
+return, diff_List[w]
+end
diff --git a/Code/script_idl_mv/astrolib/concat_dir.pro b/Code/script_idl_mv/astrolib/concat_dir.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a89656a9edce565ad24616fb2f55e775c7cad1b8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/concat_dir.pro
@@ -0,0 +1,110 @@
+;+
+; NAME:
+; CONCAT_DIR()
+;
+; PURPOSE:
+; To concatenate directory and file names for current OS.
+; EXPLANATION:
+; The given file name is appended to the given directory name with the
+; format appropriate to the current operating system.
+;
+; CALLING SEQUENCE:
+; result = concat_dir( directory, file)
+;
+; INPUTS:
+; directory - the directory path (string)
+; file - the basic file name and extension (string)
+; can be an array of filenames.
+;
+; OUTPUTS:
+; The function returns the concatenated string. If the file input
+; is a string array then the output will be a string array also.
+;
+; EXAMPLES:
+; IDL> pixfile = concat_dir('$DIR_GIS_MODEL','pixels.dat')
+;
+; IDL> file = ['f1.dat','f2.dat','f3.dat']
+; IDL> dir = '$DIR_NIS_CAL'
+; IDL>
+
+;
+; RESTRICTIONS:
+;
+; The version of CONCAT_DIR available at
+; http://sohowww.nascom.nasa.gov/solarsoft/gen/idl/system/concat_dir.pro
+; includes (mostly) additional VMS-specific keywords.
+;
+; CATEGORY
+; Utilities, Strings
+;
+; REVISION HISTORY:
+; Prev Hist. : Yohkoh routine by M. Morrison
+; Written : CDS version by C D Pike, RAL, 19/3/93
+; Version : Version 1 19/3/93
+; Documentation modified Nov-94 W. Landsman
+; Add V4.0 support for Windows W. Landsman Aug 95
+; Converted to IDL V5.0 W. Landsman September 1997
+; Changed loops to long integer W. Landsman December 1998
+; Added Mac support, translate Windows environment variables,
+; & treat case where dirname ends in '/' W. Landsman Feb. 2000
+; Assume since V5.5, remove VMS support W. Landsman Sep. 2006
+;-
+;
+function concat_dir, dirname, filnam
+;
+; Check number of parameters
+;
+ if N_params() lt 2 then begin
+ print,'Syntax - out_string = concat_dir( directory, filename)'
+ print,' '
+ return,''
+ endif
+;
+; remove leading/trailing blanks
+;
+ dir0 = strtrim(dirname, 2)
+ n_dir = N_Elements(dir0)
+;
+; Act according to operating system
+; Under Windows, if the directory starts with a dollar sign, then check to see
+; the if it's really an environment variable. If it is, then substitute the
+; the environment variable for the directory name.
+;
+ IF !VERSION.OS_FAMILY EQ 'Windows' THEN BEGIN
+ FOR i = 0l, n_dir-1 DO BEGIN
+ FIRST = STRMID(DIR0[I], 0, 1)
+ IF FIRST EQ '$' THEN BEGIN
+ SLASH = STRPOS(DIR0[I]+'/','/') < STRPOS(DIR0[I]+'\','\')
+ TEST = GETENV(STRMID(DIR0[I],1,SLASH-1))
+ IF TEST NE '' THEN BEGIN
+ IF STRLEN(DIR0[I]) GT SLASH THEN TEST = TEST + $
+ STRMID(DIR0[I],SLASH,STRLEN(DIR0[I])-SLASH)
+ DIR0[I] = TEST
+ ENDIF
+ ENDIF
+;
+ last = STRMID(dir0[i], STRLEN(dir0[i])-1, 1)
+ IF (last NE '\') AND (last NE '/') AND (last NE ':') THEN BEGIN
+ dir0[i] = dir0[i] + '\' ;append an ending '\'
+ ENDIF
+ ENDFOR
+
+; Macintosh/UNIX section
+
+ endif else begin
+ psep = path_sep()
+ for i = 0l, n_dir-1 do begin
+ last = strmid(dir0[i], strlen(dir0[i])-1, 1)
+ if(last ne psep) then dir0[i] = dir0[i] + psep ;append path separator
+ endfor
+endelse
+
+;
+; no '/' needed when using default directory
+;
+ g = where(dirname EQ '', Ndef)
+ if Ndef GT 0 then dir0[g] = ''
+
+ return, dir0 + filnam
+
+ end
diff --git a/Code/script_idl_mv/astrolib/cons_dec.pro b/Code/script_idl_mv/astrolib/cons_dec.pro
new file mode 100644
index 0000000000000000000000000000000000000000..414a9e18f5de78b8679bc42e5a5090a225f5ab96
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cons_dec.pro
@@ -0,0 +1,116 @@
+FUNCTION CONS_DEC,DEC,X,ASTR,ALPHA ;Find line of constant Dec
+;+
+; NAME:
+; CONS_DEC
+; PURPOSE:
+; Obtain the X and Y coordinates of a line of constant declination
+; EXPLANATION:
+; Returns a set of Y pixels values, given an image with astrometry, and
+; either
+; (1) A set of X pixel values, and a scalar declination value, or
+; (2) A set of declination values, and a scalar X value
+;
+; Form (1) can be used to find the (X,Y) values of a line of constant
+; declination. Form (2) can be used to find the Y positions of a set
+; declinations, along a line of constant X.
+;
+; CALLING SEQUENCE:
+; Y = CONS_DEC( DEC, X, ASTR, [ ALPHA ])
+;
+; INPUTS:
+; DEC - Declination value(s) in DEGREES (-!PI/2 < DEC < !PI/2).
+; If X is a vector, then DEC must be a scalar.
+; X - Specified X pixel value(s) for line of constant declination
+; If DEC is a vector, then X must be a scalar.
+; ASTR - Astrometry structure, as extracted from a FITS header by the
+; procedure EXTAST
+; OUTPUT:
+; Y - Computed set of Y pixel values. The number of Y values is the
+; same as either DEC or X, whichever is greater.
+;
+; OPTIONAL OUTPUT:
+; ALPHA - the right ascensions (DEGREES) associated with the (X,Y) points
+;
+; RESTRICTIONS:
+; Implemented only for the TANgent, SIN and CAR projections
+;
+; NOTES:
+; The algorithm (and notation) is based on AIPS Memo 27 by Eric Greisen,
+; with modifications for a coordinate description (CD) matrix as
+; described in Paper II of Greisen & Calabretta (2002, A&A, 395, 1077).
+; These documents are available from
+; http://www.cv.nrao.edu/fits/documents/wcs/wcs.html
+;
+; REVISION HISTORY:
+; Written, Wayne Landsman STX Co. April 1988
+; Use new astrometry structure, W. Landsman HSTX Jan. 1994
+; Use CD matrix, add SIN projection W. Landsman HSTX April, 1996
+; Converted to IDL V5.0 W. Landsman September 1997
+; Fix case where DEC is scalar, X is vector W. Landsman RITSS Feb. 2000
+; Fix possible sign error introduced Jan. 2000 W. Landsman May 2000
+; Work for the CARee' projection W. Landsman May 2003
+;-
+ On_error,2
+
+ if N_params() lt 3 then begin
+ print,'Syntax - Y = CONS_DEC( DEC, X, ASTR, [ALPHA] )'
+ return, 0
+ endif
+
+ RADEG = 180.0D/!DPI
+
+ n = N_elements(x)
+ Ndec = N_elements(dec)
+ crpix = astr.crpix -1.
+ crval = astr.crval/RADEG
+ cd = astr.cd/RADEG
+ cdelt = astr.cdelt
+
+ A = -cd[0,0]*cdelt[0]
+ B = -cd[0,1]*cdelt[0]
+ C = cd[1,0]*cdelt[1]
+ D = cd[1,1]*cdelt[1]
+
+ xx = x - crpix[0] ;New coordinate origin
+ sdel0 = sin(crval[1]) & cdel0 = cos(crval[1])
+
+ ctype = strupcase( strmid(astr.ctype[0], 5,3))
+ case ctype of
+
+'TAN': begin
+ aa = d
+ bb = (b*c-d*a)*xx*cdel0 + sdel0*b
+ sign = 2*( aa GT 0 ) - 1
+ alpha = crval[0] + atan(bb/aa) + $
+ sign * asin( tan(dec/RADEG)* ( (B*C-D*A)*xx*sdel0 - B*cdel0)/ $
+ sqrt(aa^2+bb^2))
+ end
+
+'SIN': begin
+
+ aa = d
+ bb = b*sdel0
+ sign = 2*( aa GT 0 ) - 1
+
+ denom = cos(dec/RADEG)*sqrt(aa^2+bb^2)
+ alpha = crval[0] + atan(bb/aa) + $
+ sign * asin( ( (b*c-a*d)*xx - sin(dec/RADEG)*cdel0*b ) / denom )
+ end
+
+'CAR': begin
+ alpha = crval[0] + (b*c -a*d)*xx
+ if (N_elements(alpha) EQ 1) and (Ndec GT 1) then $
+ alpha = replicate(alpha[0],Ndec)
+end
+
+ELSE: message,'ERROR - Program only works for TAN, SIN and CAR projections'
+ endcase
+
+ alpha = alpha * RADEG
+
+ if (N_elements(dec) EQ 1) and (n GT 1) then $
+ ad2xy, alpha, replicate(dec, n) , astr, x1, y else $
+ ad2xy, alpha, dec, astr, x1, y
+
+ return,y
+ end
diff --git a/Code/script_idl_mv/astrolib/cons_ra.pro b/Code/script_idl_mv/astrolib/cons_ra.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c90fcb097d9808c8a6fdd7538b251b17f1438547
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cons_ra.pro
@@ -0,0 +1,119 @@
+FUNCTION CONS_RA,RA,Y,ASTR, DELTA ;Find line of constant RA
+;+
+; NAME:
+; CONS_RA
+; PURPOSE:
+; Obtain the X and Y coordinates of a line of constant right ascension
+; EXPLANATION:
+; Return a set of X pixel values given an image with astrometry,
+; and either
+; (1) a set of Y pixel values, and a scalar right ascension (or
+; longitude), or
+; (2) a set of right ascension values, and a scalar Y value.
+;
+; In usage (1), CONS_RA can be used to determine the (X,Y) values
+; of a line of constant right ascension. In usage (2), CONS_RA can
+; used to determine the X positions of specified RA values, along a
+; line of constant Y.
+;
+; CALLING SEQUENCE:
+; X = CONS_RA( RA, Y, ASTR, [ DEC] )
+;
+; INPUTS:
+; RA - Right Ascension value in DEGREES (0 < RA < 360.). If Y is a
+; vector, then RA must be a scalar
+; Y - Specified Y pixel value(s) for line of constant right ascension
+; If RA is a vector, then Y must be a scalar
+; ASTR - Astrometry structure as extracted from a FITS header by the
+; procedure EXTAST
+; OUTPUTS
+; X - Computed set of X pixel values. The number of elements of X
+; is the maximum of the number of elements of RA and Y.
+; OPTIONAL OUTPUT:
+; DEC - Computed set of declinations (in DEGREES) for X,Y, coordinates
+; NOTES:
+; The algorithm (and notation) is based on AIPS Memo 27 by Eric Greisen,
+; with modifications for a coordinate description (CD) matrix as
+; described in Paper II of Calabretta & Greisen (2002, A&A, 395, 1077).
+; These documents are available from
+; http://www.cv.nrao.edu/fits/documents/wcs/wcs.html
+;
+; RESTRICTIONS:
+; Implemented only for the TANgent, SIN and CARtesian projections
+;
+; REVISION HISTORY:
+; Written, Wayne Landsman STX Co. April, 1988
+; Algorithm adapted from AIPS memo No. 27 by Eric Greisen
+; New astrometry structure
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added SIN projection W. Landsman January 2000
+; Fix possible sign error introduced Jan. 2000 W. Landsman May 2000
+; Work for the CARee' projection W. Landsman May 2003
+; For TAN projection ensure angles between -90 and 90 W. Landsman Jan 2008
+;-
+ On_error,2
+ compile_opt idl2
+
+ if ( N_params() LT 3 ) then begin
+ print,'Syntax - X = CONS_RA( RA, Y, ASTR, [ Dec ])'
+ return, 0
+ endif
+
+ radeg = 180.0/!DPI
+ n = N_elements(y)
+ nra = N_elements(ra)
+ crpix = astr.crpix - 1.
+ crval = astr.crval/RADEG
+ cdelt = astr.cdelt
+ cdelta = [ [ cdelt[0], 0.],[0., cdelt[1] ] ]
+ cd = astr.cd/RADEG
+ cdel0 = cos( crval[1] ) & sdel0 = sin( crval[1] )
+ delra = ra/RADEG - crval[0]
+ cdelra = cos( delra ) & sdelra = sin( delra )
+
+ ctype = strupcase( strmid(astr.ctype[0], 5,3))
+ case ctype of
+
+ 'TAN': begin
+
+ cdi = invert( cdelta # cd ) ;Greisen uses invert of CD matrix
+ yy = y - ( crpix[1]) ;New coordinate origin, Unit pixel offset in CRPIX
+ delta = atan((sdel0*cdelra*cdi[1,1] - sin(delra)*cdi[1,0] + yy*cdelra*cdel0) $
+ / (cdel0*cdi[1,1] - yy*sdel0))
+
+ end
+ 'SIN': begin
+
+ A = -cd[0,0]*cdelt[0]
+ B = -cd[0,1]*cdelt[0]
+ C = cd[1,0]*cdelt[1]
+ D = cd[1,1]*cdelt[1]
+ yy = (y - crpix[1])*(b*c - a*d) ;New coordinate origin
+ aa = cdel0*d
+ bb = sdel0*cdelra*d + sdelra*b
+ denom = sqrt(aa^2 + bb^2)
+ delta = atan(bb/aa) + asin(yy/denom)
+
+ end
+
+ 'CAR': begin
+ A = -cd[0,0]*cdelt[0]
+ B = -cd[0,1]*cdelt[0]
+ C = cd[1,0]*cdelt[1]
+ D = cd[1,1]*cdelt[1]
+ delta = (y - crpix[1])*(b*c - a*d) +crval[1] ;New coordinate origin
+ if (N_elements(delta) EQ 1) and (Nra GT 1) then $
+ delta = replicate(delta[0],Nra)
+
+ end
+
+ ELSE: message,'ERROR - Program only works for TAN and SIN projections'
+ endcase
+
+ delta = delta*RADEG
+ if (Nra EQ 1) and (n GT 1) then $
+ ad2xy, replicate(ra,n), delta, astr, x else $
+ ad2xy, ra, delta, astr, x
+
+ return, x
+ end
diff --git a/Code/script_idl_mv/astrolib/convolve.pro b/Code/script_idl_mv/astrolib/convolve.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f56e016a738b30892db4d4ee9b177903675baacc
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/convolve.pro
@@ -0,0 +1,178 @@
+function convolve, image, psf, FT_PSF=psf_FT, FT_IMAGE=imFT, NO_FT=noft, $
+ CORRELATE=correlate, AUTO_CORRELATION=auto, $
+ NO_PAD = no_pad
+;+
+; NAME:
+; CONVOLVE
+; PURPOSE:
+; Convolution of an image with a Point Spread Function (PSF)
+; EXPLANATION:
+; The default is to compute the convolution using a product of
+; Fourier transforms (for speed).
+;
+; The image is padded with zeros so that a large PSF does not
+; overlap one edge of the image with the opposite edge of the image.
+;
+; This routine is now partially obsolete due to the introduction of the
+; intrinsic CONVOL_FFT() function in IDL 8.1
+;
+; CALLING SEQUENCE:
+;
+; imconv = convolve( image1, psf, FT_PSF = psf_FT )
+; or:
+; correl = convolve( image1, image2, /CORREL )
+; or:
+; correl = convolve( image, /AUTO )
+;
+; INPUTS:
+; image = 2-D array (matrix) to be convolved with psf
+; psf = the Point Spread Function, (size < or = to size of image).
+;
+; The PSF *must* be symmetric about the point
+; FLOOR((n_elements-1)/2), where n_elements is the number of
+; elements in each dimension. For Gaussian PSFs, the maximum
+; of the PSF must occur in this pixel (otherwise the convolution
+; will shift everything in the image).
+;
+; OPTIONAL INPUT KEYWORDS:
+;
+; FT_PSF = passes out/in the Fourier transform of the PSF,
+; (so that it can be re-used the next time function is called).
+; FT_IMAGE = passes out/in the Fourier transform of image.
+;
+; /CORRELATE uses the conjugate of the Fourier transform of PSF,
+; to compute the cross-correlation of image and PSF,
+; (equivalent to IDL function convol() with NO rotation of PSF)
+;
+; /AUTO_CORR computes the auto-correlation function of image using FFT.
+;
+; /NO_FT overrides the use of FFT, using IDL function convol() instead.
+; (then PSF is rotated by 180 degrees to give same result)
+;
+; /NO_PAD - if set, then do not pad the image to avoid edge effects.
+; This will improve memory and speed of the computation at the
+; expense of edge effects. This was the default method prior
+; to October 2009
+; METHOD:
+; When using FFT, PSF is centered & expanded to size of image.
+; HISTORY:
+; written, Frank Varosi, NASA/GSFC 1992.
+; Appropriate precision type for result depending on input image
+; Markus Hundertmark February 2006
+; Fix the bug causing the recomputation of FFT(psf) and/or FFT(image)
+; Sergey Koposov December 2006
+; Fix the centering bug
+; Kyle Penner October 2009
+; Add /No_PAD keyword for better speed and memory usage when edge effects
+; are not important. W. Landsman March 2010
+; Add warning when kernel type does not match integer array
+; W. Landsman Feb 2012
+; Don't force double precision output W. Landsman July 2014
+;-
+ compile_opt idl2
+ sp = size( psf_FT,/str ) & sif = size( imFT, /str )
+ sim = size( image )
+
+
+ if (sim[0] NE 2) || keyword_set( noft ) then begin
+ if keyword_set( auto ) then begin
+ message,"auto-correlation only for images with FFT",/INF
+ return, image
+ endif
+ dtype = size(image,/type)
+ if dtype LE 3 then if size(psf,/type) NE dtype then $
+ message,/CON, $
+ 'WARNING - ' + size(psf,/TNAME) + $
+ ' kernel converted to type ' + size(image,/tname)
+ if keyword_set( correlate ) then $
+ return, convol( image, psf ) $
+ else return, convol( image, rotate( psf, 2 ) )
+ endif
+
+ if keyword_Set(No_Pad) then begin
+
+ sc = sim/2 & npix = N_elements( image )
+ if (sif.N_dimensions NE 2) || ((sif.type NE 6) && (sif.type NE 9)) || $
+ (sif.dimensions[0] NE sim[1]) || (sif.dimensions[1] NE sim[2]) then imFT = FFT( image,-1 )
+
+ if keyword_set( auto ) then $
+ return, shift( npix*real_part(FFT( imFT*conj( imFT ),1 )), sc[1],sc[2] )
+
+ if (sp.N_dimensions NE 2) || ((sp.type NE 6) && (sp.type NE 9)) || $
+ (sp.dimensions[0] NE sim[1]) || (sp.dimensions[1] NE sim[2]) then begin
+ sp = size( psf )
+ if (sp[0] NE 2) then begin
+ message,"must supply PSF matrix (2nd arg.)",/INFO
+ return, image
+ endif
+ Loc = ( sc - sp/2 ) > 0 ;center PSF in new array,
+ s = (sp/2 - sc) > 0 ;handle all cases: smaller or bigger
+ L = (s + sim-1) < (sp-1)
+ psf_FT = conj(image)*0 ;initialise with correct size+type according
+ ;to logic of conj and set values to 0 (type of psf_FT is conserved)
+ psf_FT[ Loc[1], Loc[2] ] = psf[ s[1]:L[1], s[2]:L[2] ]
+ psf_FT = FFT( psf_FT, -1, /OVERWRITE )
+ endif
+
+ if keyword_set( correlate ) then $
+ conv = npix * real_part(FFT( imFT * conj( psf_FT ), 1 )) $
+ else conv = npix * real_part(FFT( imFT * psf_FT, 1 ))
+
+ sc = sc + (sim MOD 2) ;shift correction for odd size images.
+
+ return, shift( conv, sc[1], sc[2] )
+ endif else begin
+
+
+ sc = floor((sim-1)/2) & npix = n_elements(image)*4.
+ ; the spooky factor of 4 in npix is because we're going to pad the image
+ ; with zeros
+
+ if (sif.N_dimensions NE 2) || ((sif.type NE 6) && (sif.type NE 9)) || $
+ (sif.dimensions[0] NE sim[1]) || (sif.dimensions[1] NE sim[2]) then begin
+
+ ; here is where we make an array with twice the dimensions of image and
+ ; pad with zeros -- thanks to Daniel Eisenstein for this fix
+
+ image_big = make_array(type = sim[sim[0]+1], sim[1]*2, sim[2]*2)
+ image_big[0:sim[1]-1,0:sim[2]-1] = image
+ imFT = FFT( image_big,-1 )
+ npix = n_elements(image_big)
+
+ endif
+
+ if keyword_set( auto ) then begin
+ intermed = shift( npix*real_part(FFT( imFT*conj( imFT ),1 )), sc[1],sc[2] )
+ return, intermed[0:sim[1]-1,0:sim[2]-1]
+ endif
+
+
+ if (sp.N_dimensions NE 2) || ((sp.type NE 6) && (sp.type NE 9)) OR $
+ (sp.dimensions[0] NE sim[1]) || (sp.dimensions[1] NE sim[2]) then begin
+ sp = size( psf )
+ if (sp[0] NE 2) then begin
+ message,"must supply PSF matrix (2nd arg.)",/INFO
+ return, image
+ endif
+ ; this obfuscated line determines the offset between the center of the
+ ; image and the center of the PSF
+ Loc = ( sc - floor((sp-1)/2) ) > 0
+
+ psf_image = make_array(type = sim[sim[0]+1],sim[1]*2,sim[2]*2)
+ psf_image[Loc[1]:Loc[1]+sp[1]-1, Loc[2]:Loc[2]+sp[2]-1] = psf
+ psf_FT = FFT(psf_image, -1)
+ endif
+
+ if keyword_set( correlate ) then begin
+ conv = npix * real_part(FFT( imFT * conj( psf_FT ), 1 ))
+ conv = shift(conv, sc[1], sc[2])
+ endif else begin
+ conv = npix * real_part(FFT( imFT * psf_FT, 1 ))
+ conv = shift(conv, -sc[1], -sc[2])
+
+ endelse
+
+
+ return, conv[0:sim[1]-1,0:sim[2]-1]
+ endelse
+end
diff --git a/Code/script_idl_mv/astrolib/copy_struct.pro b/Code/script_idl_mv/astrolib/copy_struct.pro
new file mode 100644
index 0000000000000000000000000000000000000000..147fc0da185a4665e9964b1a413c86963d884ad0
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/copy_struct.pro
@@ -0,0 +1,250 @@
+;+
+; NAME:
+; COPY_STRUCT
+; PURPOSE:
+; Copy all fields with matching tag names from one structure to another
+; EXPLANATION:
+; COPY_STRUCT is similar to the intrinsic STRUCT_ASSIGN procedure but
+; has optional keywords to exclude or specify specific tags.
+;
+; Fields with matching tag names are copied from one structure array to
+; another structure array of different type.
+; This allows copying of tag values when equating the structures of
+; different types is not allowed, or when not all tags are to be copied.
+; Can also recursively copy from/to structures nested within structures.
+; Note that the number of elements in the output structure array
+; is automatically adjusted to equal the length of input structure array.
+; If this not desired then use pro copy_struct_inx which allows
+; specifying via subscripts which elements are copied where in the arrays.
+;
+; CALLING SEQUENCE:
+;
+; copy_struct, struct_From, struct_To, NT_copied
+; copy_struct, struct_From, struct_To, EXCEPT=["image","misc"]
+; copy_struct, struct_From, struct_To, /RECUR_TANDEM
+;
+; INPUTS:
+; struct_From = structure array to copy from.
+; struct_To = structure array to copy values to.
+;
+; KEYWORDS:
+;
+; EXCEPT_TAGS = string array of tag names to ignore (to NOT copy).
+; Used at all levels of recursion.
+;
+; SELECT_TAGS = tag names to copy (takes priority over EXCEPT).
+; This keyword is not passed to recursive calls in order
+; to avoid the confusion of not copying tags in sub-structures.
+;
+; /RECUR_FROM = search for sub-structures in struct_From, and then
+; call copy_struct recursively for those nested structures.
+;
+; /RECUR_TO = search for sub-structures of struct_To, and then
+; call copy_struct recursively for those nested structures.
+;
+; /RECUR_TANDEM = call copy_struct recursively for the sub-structures
+; with matching Tag names in struct_From and struct_To
+; (for use when Tag names match but sub-structure types differ).
+;
+; OUTPUTS:
+; struct_To = structure array to which new tag values are copied.
+; NT_copied = incremented by total # of tags copied (optional)
+;
+; INTERNAL:
+; Recur_Level = # of times copy_struct calls itself.
+; This argument is for internal recursive execution only.
+; The user call is 1, subsequent recursive calls increment it,
+; and the counter is decremented before returning.
+; The counter is used just to find out if argument checking
+; should be performed, and to set NT_copied = 0 first call.
+; EXTERNAL CALLS:
+; pro match (when keyword SELECT_TAGS is specified)
+; PROCEDURE:
+; Match Tag names and then use corresponding Tag numbers.
+; HISTORY:
+; written 1989 Frank Varosi STX @ NASA/GSFC
+; mod Jul.90 by F.V. added option to copy sub-structures RECURSIVELY.
+; mod Aug.90 by F.V. adjust # elements in TO (output) to equal
+; # elements in FROM (input) & count # of fields copied.
+; mod Jan.91 by F.V. added Recur_Level as internal argument so that
+; argument checking done just once, to avoid confusion.
+; Checked against Except_Tags in RECUR_FROM option.
+; mod Oct.91 by F.V. added option SELECT_TAGS= selected field names.
+; mod Aug.95 by W. Landsman to fix match of a single selected tag.
+; mod Mar.97 by F.V. do not pass the SELECT_TAGS keyword in recursion.
+; Converted to IDL V5.0 W. Landsman September 1997
+; mod May 01 by D. Schlegel use long integers
+;-
+
+pro copy_struct, struct_From, struct_To, NT_copied, Recur_Level, $
+ EXCEPT_TAGS = except_Tags, $
+ SELECT_TAGS = select_Tags, $
+ RECUR_From = recur_From, $
+ RECUR_TO = recur_To, $
+ RECUR_TANDEM = recur_tandem
+
+ if N_elements( Recur_Level ) NE 1 then Recur_Level = 0L
+
+ Ntag_from = N_tags( struct_From )
+ Ntag_to = N_tags( struct_To )
+
+ if (Recur_Level EQ 0) then begin ;check only at first user call.
+
+ NT_copied = 0L
+
+ if (Ntag_from LE 0) OR (Ntag_to LE 0) then begin
+ message,"two arguments must be structures",/INFO
+ print," "
+ print,"syntax: copy_struct, struct_From, struct_To"
+ print," "
+ print,"keywords: EXCEPT_TAGS= , SELECT_TAGS=, "
+ print," /RECUR_From, /RECUR_TO, /RECUR_TANDEM"
+ return
+ endif
+
+ N_from = N_elements( struct_From )
+ N_to = N_elements( struct_To )
+
+ if (N_from GT N_to) then begin
+
+ message," # elements (" + strtrim( N_to, 2 ) + $
+ ") in output TO structure",/INFO
+ message," increased to (" + strtrim( N_from, 2 ) + $
+ ") as in FROM structure",/INFO
+ struct_To = [ struct_To, $
+ replicate( struct_To[0], N_from-N_to ) ]
+
+ endif else if (N_from LT N_to) then begin
+
+ message," # elements (" + strtrim( N_to, 2 ) + $
+ ") in output TO structure",/INFO
+ message," decreased to (" + strtrim( N_from, 2 ) + $
+ ") as in FROM structure",/INFO
+ struct_To = struct_To[0:N_from-1]
+ endif
+ endif
+
+ Recur_Level = Recur_Level + 1 ;go for it...
+
+ Tags_from = Tag_names( struct_From )
+ Tags_to = Tag_names( struct_To )
+ wto = lindgen( Ntag_to )
+
+;Determine which Tags are selected or excluded from copying:
+
+ Nseltag = N_elements( select_Tags )
+ Nextag = N_elements( except_Tags )
+
+ if (Nseltag GT 0) then begin
+
+ match, Tags_to, [strupcase( select_Tags )], mt, ms,COUNT=Ntag_to
+
+ if (Ntag_to LE 0) then begin
+ message," selected tags not found",/INFO
+ return
+ endif
+
+ Tags_to = Tags_to[mt]
+ wto = wto[mt]
+
+ endif else if (Nextag GT 0) then begin
+
+ except_Tags = [strupcase( except_Tags )]
+
+ for t=0L,Nextag-1 do begin
+ w = where( Tags_to NE except_Tags[t], Ntag_to )
+ Tags_to = Tags_to[w]
+ wto = wto[w]
+ endfor
+ endif
+
+;Now find the matching Tags and copy them...
+
+ for t = 0L, Ntag_to-1 do begin
+
+ wf = where( Tags_from EQ Tags_to[t] , nf )
+
+ if (nf GT 0) then begin
+
+ from = wf[0]
+ to = wto[t]
+
+ if keyword_set( recur_tandem ) AND $
+ ( N_tags( struct_To.(to) ) GT 0 ) AND $
+ ( N_tags( struct_From.(from) ) GT 0 ) then begin
+
+ struct_tmp = struct_To.(to)
+
+ copy_struct, struct_From.(from), struct_tmp, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_TANDEM, $
+ RECUR_FROM = recur_From, $
+ RECUR_TO = recur_To
+
+ struct_To.(to) = struct_tmp
+
+ endif else begin
+
+ struct_To.(to) = struct_From.(from)
+ NT_copied = NT_copied + 1
+ endelse
+ endif
+ endfor
+
+;Handle request for recursion on FROM structure:
+
+ if keyword_set( recur_From ) then begin
+
+ wfrom = lindgen( Ntag_from )
+
+ if (Nextag GT 0) then begin
+
+ for t=0L,Nextag-1 do begin
+ w = where( Tags_from NE except_Tags[t], Ntag_from )
+ Tags_from = Tags_from[w]
+ wfrom = wfrom[w]
+ endfor
+ endif
+
+ for t = 0L, Ntag_from-1 do begin
+
+ from = wfrom[t]
+
+ if N_tags( struct_From.(from) ) GT 0 then begin
+
+ copy_struct, struct_From.(from), struct_To, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_FROM, $
+ RECUR_TO = recur_To, $
+ RECUR_TANDEM = recur_tandem
+ endif
+ endfor
+ endif
+
+;Handle request for recursion on TO structure:
+
+ if keyword_set( recur_To ) then begin
+
+ for t = 0L, Ntag_to-1 do begin
+
+ to = wto[t]
+
+ if N_tags( struct_To.(to) ) GT 0 then begin
+
+ struct_tmp = struct_To.(to)
+
+ copy_struct, struct_From, struct_tmp, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_TO, $
+ RECUR_FROM = recur_From, $
+ RECUR_TANDEM = recur_tandem
+ struct_To.(to) = struct_tmp
+ endif
+ endfor
+ endif
+
+ Recur_Level = Recur_Level - 1
+end
diff --git a/Code/script_idl_mv/astrolib/copy_struct_inx.pro b/Code/script_idl_mv/astrolib/copy_struct_inx.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c162bb41f8ba41cdac069faf7c54588099063d14
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/copy_struct_inx.pro
@@ -0,0 +1,287 @@
+;+
+; NAME:
+; COPY_STRUCT_INX
+; PURPOSE:
+; Copy matching tags & specified indices from one structure to another
+; EXPLANATION:
+; Copy all fields with matching tag names (except for "except_Tags")
+; from one structure array to another structure array of different type.
+; This allows copying of tag values when equating the structures of
+; different types is not allowed, or when not all tags are to be copied.
+; Can also recursively copy from/to structures nested within structures.
+; This procedure is same as copy_struct with option to
+; specify indices (subscripts) of which array elements to copy from/to.
+; CALLING SEQUENCE:
+;
+; copy_struct_inx, struct_From, struct_To, NT_copied, INDEX_FROM=subf
+;
+; copy_struct_inx, struct_From, struct_To, INDEX_FROM=subf, INDEX_TO=subto
+;
+; INPUTS:
+; struct_From = structure array to copy from.
+; struct_To = structure array to copy values to.
+;
+; KEYWORDS:
+;
+; INDEX_FROM = indices (subscripts) of which elements of array to copy.
+; (default is all elements of input structure array)
+;
+; INDEX_TO = indices (subscripts) of which elements to copy to.
+; (default is all elements of output structure array)
+;
+; EXCEPT_TAGS = string array of Tag names to ignore (to NOT copy).
+; Used at all levels of recursion.
+;
+; SELECT_TAGS = Tag names to copy (takes priority over EXCEPT).
+; This keyword is not passed to recursive calls in order
+; to avoid the confusion of not copying tags in sub-structures.
+;
+; /RECUR_FROM = search for sub-structures in struct_From, and then
+; call copy_struct recursively for those nested structures.
+;
+; /RECUR_TO = search for sub-structures of struct_To, and then
+; call copy_struct recursively for those nested structures.
+;
+; /RECUR_TANDEM = call copy_struct recursively for the sub-structures
+; with matching Tag names in struct_From and struct_To
+; (for use when Tag names match but sub-structure types differ).
+;
+; OUTPUTS:
+; struct_To = structure array to which new tag values are copied.
+; NT_copied = incremented by total # of tags copied (optional)
+;
+; INTERNAL:
+; Recur_Level = # of times copy_struct_inx calls itself.
+; This argument is for internal recursive execution only.
+; The user call is 1, subsequent recursive calls increment it,
+; and the counter is decremented before returning.
+; The counter is used just to find out if argument checking
+; should be performed, and to set NT_copied = 0 first call.
+; EXTERNAL CALLS:
+; pro match (when keyword SELECT_TAGS is specified)
+; PROCEDURE:
+; Match Tag names and then use corresponding Tag numbers,
+; apply the sub-indices during = and recursion.
+; HISTORY:
+; adapted from copy_struct: 1991 Frank Varosi STX @ NASA/GSFC
+; mod Aug.95 by F.V. to fix match of a single selected tag.
+; mod Mar.97 by F.V. do not pass the SELECT_TAGS keyword in recursion,
+; and check validity of INDEX_FROM and INDEX_TO in more detail.
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use long integers W. Landsman May 2001
+;-
+
+pro copy_struct_inx, struct_From, struct_To, NT_copied, Recur_Level, $
+ EXCEPT_TAGS = except_Tags, $
+ SELECT_TAGS = select_Tags, $
+ INDEX_From = index_From, $
+ INDEX_To = index_To, $
+ RECUR_From = recur_From, $
+ RECUR_To = recur_To, $
+ RECUR_TANDEM = recur_tandem
+
+ if N_elements( Recur_Level ) NE 1 then Recur_Level = 0L
+
+ Ntag_from = N_tags( struct_From )
+ Ntag_to = N_tags( struct_To )
+
+ if (Recur_Level EQ 0) then begin ;check only at first user call.
+
+ NT_copied = 0L
+
+ if (Ntag_from LE 0) OR (Ntag_to LE 0) then begin
+ message,"two arguments must be structures",/INFO
+ print," "
+ print,"syntax: copy_struct_inx, struct_From, struct_To"
+ print," "
+ print,"keywords: INDEX_From= , INDEX_To="
+ print," EXCEPT_TAGS= , SELECT_TAGS=, "
+ print," /RECUR_From, /RECUR_To, /RECUR_TANDEM"
+ return
+ endif
+
+ N_from = N_elements( struct_From )
+ N_to = N_elements( struct_To )
+
+ if N_elements( index_From ) LE 0 then index_From = $
+ lindgen( N_from )
+ Ni_from = N_elements( index_From )
+ if N_elements( index_To ) LE 0 then index_To = lindgen( Ni_from )
+ Ni_to = N_elements( index_To )
+
+ if (Ni_from LT Ni_to) then begin
+
+ message," # elements (" + strtrim( Ni_to, 2 ) + $
+ ") in output TO indices",/INFO
+ message," decreased to (" + strtrim( Ni_from, 2 ) + $
+ ") as in FROM indices",/INFO
+ index_To = index_To[0:Ni_from-1]
+
+ endif else if (Ni_from GT Ni_to) then begin
+
+ message," # elements (" + strtrim( Ni_from, 2 ) + $
+ ") of input FROM indices",/INFO
+ message," decreased to (" + strtrim( Ni_to, 2 ) + $
+ ") as in TO indices",/INFO
+ index_From = index_From[0:Ni_to-1]
+ endif
+
+ Mi_to = max( [index_To] )
+ Mi_from = max( [index_From] )
+
+ if (Mi_to GE N_to) then begin
+
+ message," # elements (" + strtrim( N_to, 2 ) + $
+ ") in output TO structure",/INFO
+ message," increased to (" + strtrim( Mi_to, 2 ) + $
+ ") as max value of INDEX_To",/INFO
+ struct_To = [ struct_To, $
+ replicate( struct_To[0], Mi_to-N_to ) ]
+ endif
+
+ if (Mi_from GE N_from) then begin
+
+ w = where( index_From LT N_from, nw )
+
+ if (nw GT 0) then begin
+ index_From = index_From[w]
+ message,"max value (" + strtrim( Mi_from, 2 ) +$
+ ") in FROM indices",/INFO
+ print,"decreased to " + strtrim( N_from,2 ) + $
+ ") as in FROM structure",/INFO
+ endif else begin
+ message,"all FROM indices are out of bounds",/IN
+ return
+ endelse
+ endif
+ endif
+
+ Recur_Level = Recur_Level + 1 ;go for it...
+
+ Tags_from = Tag_names( struct_From )
+ Tags_to = Tag_names( struct_To )
+ wto = lindgen( Ntag_to )
+
+;Determine which Tags are selected or excluded from copying:
+
+ Nseltag = N_elements( select_Tags )
+ Nextag = N_elements( except_Tags )
+
+ if (Nseltag GT 0) then begin
+
+ match, Tags_to, [strupcase( select_Tags )], mt, ms,COUNT=Ntag_to
+
+ if (Ntag_to LE 0) then begin
+ message," selected tags not found",/INFO
+ return
+ endif
+
+ Tags_to = Tags_to[mt]
+ wto = wto[mt]
+
+ endif else if (Nextag GT 0) then begin
+
+ except_Tags = [strupcase( except_Tags )]
+
+ for t=0L,Nextag-1 do begin
+ w = where( Tags_to NE except_Tags[t], Ntag_to )
+ Tags_to = Tags_to[w]
+ wto = wto[w]
+ endfor
+ endif
+
+;Now find the matching Tags and copy them...
+
+ for t = 0L, Ntag_to-1 do begin
+
+ wf = where( Tags_from EQ Tags_to[t] , nf )
+
+ if (nf GT 0) then begin
+
+ from = wf[0]
+ to = wto[t]
+
+ if keyword_set( recur_tandem ) AND $
+ ( N_tags( struct_To.(to) ) GT 0 ) AND $
+ ( N_tags( struct_From.(from) ) GT 0 ) then begin
+
+ struct_tmp = struct_To[index_To].(to)
+
+ copy_struct, struct_From[index_From].(from), $
+ struct_tmp, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_TANDEM, $
+ RECUR_FROM = recur_From, $
+ RECUR_To = recur_To
+
+ struct_To[index_To].(to) = struct_tmp
+
+ endif else begin
+
+ struct_To[index_To].(to) = $
+ struct_From[index_From].(from)
+ NT_copied = NT_copied + 1
+ endelse
+ endif
+ endfor
+
+;Handle request for recursion on FROM structure:
+
+ if keyword_set( recur_From ) then begin
+
+ wfrom = lindgen( Ntag_from )
+
+ if (Nextag GT 0) then begin
+
+ for t=0L,Nextag-1 do begin
+ w = where( Tags_from NE except_Tags[t], Ntag_from )
+ Tags_from = Tags_from[w]
+ wfrom = wfrom[w]
+ endfor
+ endif
+
+ for t = 0L, Ntag_from-1 do begin
+
+ from = wfrom[t]
+
+ if N_tags( struct_From.(from) ) GT 0 then begin
+
+ copy_struct_inx, struct_From.(from), struct_To, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_FROM, $
+ INDEX_From = index_From, $
+ INDEX_To = index_To, $
+ RECUR_To = recur_To, $
+ RECUR_TANDEM = recur_tandem
+ endif
+ endfor
+ endif
+
+;Handle request for recursion on TO structure:
+
+ if keyword_set( recur_To ) then begin
+
+ for t = 0L, Ntag_to-1 do begin
+
+ to = wto[t]
+
+ if N_tags( struct_To.(to) ) GT 0 then begin
+
+ struct_tmp = struct_To[index_To].(to)
+
+ copy_struct_inx, struct_From, struct_tmp, $
+ NT_copied, Recur_Level, $
+ EXCEPT=except_Tags, $
+ /RECUR_To, $
+ INDEX_From = index_From, $
+ RECUR_FROM = recur_From, $
+ RECUR_TANDEM = recur_tandem
+ struct_To[index_To].(to) = struct_tmp
+ endif
+ endfor
+ endif
+
+ Recur_Level = Recur_Level - 1
+end
diff --git a/Code/script_idl_mv/astrolib/correl_images.pro b/Code/script_idl_mv/astrolib/correl_images.pro
new file mode 100644
index 0000000000000000000000000000000000000000..de9aaa2009d4c112ca94e9224f29405c2e7e1691
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/correl_images.pro
@@ -0,0 +1,210 @@
+function correl_images, image_A, image_B, XSHIFT = x_shift, $
+ YSHIFT = y_shift, $
+ XOFFSET_B = x_offset, $
+ YOFFSET_B = y_offset, $
+ REDUCTION = reducf, $
+ MAGNIFICATION = Magf, $
+ NUMPIX=numpix, MONITOR=monitor
+;+
+; NAME:
+; CORREL_IMAGES
+; PURPOSE:
+; Compute the 2-D cross-correlation function of two images
+; EXPLANATION:
+; Computes the 2-D cross-correlation function of two images for
+; a range of (x,y) shifting by pixels of one image relative to the other.
+;
+; CALLING SEQUENCE:
+; Result = CORREL_IMAGES( image_A, image_B,
+; [XSHIFT=, YSHIFT=, XOFFSET_B=, YOFFSET_B=, REDUCTION=,
+; MAGNIFICATION=, /NUMPIX, /MONITOR )
+;
+; INPUTS:
+; image_A, image_B = the two images of interest.
+;
+; OPTIONAL INPUT KEYWORDS:
+; XSHIFT = the + & - shift to be applied in X direction, default=7.
+; YSHIFT = the Y direction + & - shifting, default=7.
+;
+; XOFFSET_B = initial X pixel offset of image_B relative to image_A.
+; YOFFSET_B = Y pixel offset, defaults are (0,0).
+;
+; REDUCTION = optional reduction factor causes computation of
+; Low resolution correlation of bin averaged images,
+; thus faster. Can be used to get approximate optimal
+; (x,y) offset of images, and then called for successive
+; lower reductions in conjunction with CorrMat_Analyze
+; until REDUCTION=1, getting offset up to single pixel.
+;
+; MAGNIFICATION = option causes computation of high resolution correlation
+; of magnified images, thus much slower.
+; Shifting distance is automatically = 2 + Magnification,
+; and optimal pixel offset should be known and specified.
+; Optimal offset can then be found to fractional pixels
+; using CorrMat_Analyze( correl_images( ) ).
+;
+; /NUMPIX - if set, causes the number of pixels for each correlation
+; to be saved in a second image, concatenated to the
+; correlation image, so Result is fltarr( Nx, Ny, 2 ).
+; /MONITOR causes the progress of computation to be briefly printed.
+;
+; OUTPUTS:
+; Result is the cross-correlation function, given as a matrix.
+;
+; PROCEDURE:
+; Loop over all possible (x,y) shifts, compute overlap and correlation
+; for each shift. Correlation set to zero when there is no overlap.
+;
+; MODIFICATION HISTORY:
+; Written, July,1991, Frank Varosi, STX @ NASA/GSFC
+; Use ROUND instead of NINT, June 1995, Wayne Landsman HSTX
+; Avoid divide by zero errors, W. Landsman HSTX April 1996
+; Remove use of !DEBUG W. Landsman June 1997
+; Subtract mean of entire image before computing correlation, not just
+; mean of overlap region H. Ebeling/W. Landsman June 1998
+; Always REBIN() using floating pt arithmetic W. Landsman Nov 2007
+;
+;-
+ compile_opt idl2
+ if N_params() LT 2 then begin
+ print,'Syntax - Result = CORREL_IMAGES( image_A, image_B,'
+ print,'[ XSHIFT=, YSHIFT=, XOFFSET_B=, YOFFSET_B=, REDUCTION=, '
+ print,' MAGNIFICATION=, /NUMPIX, /MONITOR )'
+ return,-1
+ endif
+
+ simA = size( image_A )
+ simB = size( image_B )
+ do_int = (simA[3] LE 3) or (simA[3] GE 12) or $
+ (simB[3] LE 3) or (simB[3] GE 12)
+
+ if (simA[0] LT 2) OR (simB[0] LT 2) then begin
+ message,"first two arguments must be images",/INFO,/CONTIN
+ return,[-1]
+ endif
+
+ if N_elements( x_offset ) NE 1 then x_offset=0
+ if N_elements( y_offset ) NE 1 then y_offset=0
+
+ if N_elements( x_shift ) NE 1 then x_shift = 7
+ if N_elements( y_shift ) NE 1 then y_shift = 7
+ x_shift = abs( x_shift )
+ y_shift = abs( y_shift )
+
+ if keyword_set( reducf ) then begin
+
+ reducf = fix( reducf ) > 1
+ if keyword_set( monitor ) then $
+ print,"Reduction = ",strtrim( reducf, 2 )
+ simA = simA/reducf
+ LA = simA * reducf -1 ;may have to drop edges of images.
+ simB = simB/reducf
+ LB = simB * reducf -1
+
+ if do_int then begin
+
+ imtmp_A = Rebin( float( image_A[ 0:LA[1], 0:LA[2] ]), $
+ simA[1], simA[2] )
+ imtmp_B = Rebin( float( image_B[ 0:LB[1], 0:LB[2] ]), $
+ simB[1], simB[2] )
+ endif else begin
+ imtmp_A =Rebin( image_A[ 0:LA[1], 0:LA[2] ], simA[1], simA[2] )
+ imtmp_B =Rebin( image_B[ 0:LB[1], 0:LB[2] ], simB[1], simB[2] )
+ endelse
+
+ xoff = round ( x_offset/reducf )
+ yoff = round ( y_offset/reducf )
+ xs = x_shift/reducf
+ ys = y_shift/reducf
+
+ return, correl_images( imtmp_A, imtmp_B, XS=xs,YS=ys,$
+ XOFF=xoff, YOFF=yoff, $
+ MONITOR=monitor, NUMPIX=numpix )
+
+ endif else if keyword_set( Magf ) then begin
+
+ Magf = fix( Magf ) > 1
+ if keyword_set( monitor ) then $
+ print,"Magnification = ",strtrim( Magf, 2 )
+ simA = simA*Magf
+ simB = simB*Magf
+
+ imtmp_A = rebin( image_A, simA[1], simA[2], /SAMPLE )
+ imtmp_B = rebin( image_B, simB[1], simB[2], /SAMPLE )
+
+ xoff = round( x_offset*Magf )
+ yoff = round( y_offset*Magf )
+
+ return, correl_images( imtmp_A, imtmp_B, XS=Magf+2, YS=Magf+2,$
+ XOFF=xoff, YOFF=yoff, $
+ MONITOR=monitor, NUMPIX=numpix )
+ endif
+
+ Nx = 2 * x_shift + 1
+ Ny = 2 * y_shift + 1
+ if keyword_set( numpix ) then Nim=2 else Nim=1
+
+ correl_mat = fltarr( Nx, Ny, Nim )
+
+ xs = round( x_offset ) - x_shift
+ ys = round( y_offset ) - y_shift
+
+ sAx = simA[1]-1
+ sAy = simA[2]-1
+ sBx = simB[1]-1
+ sBy = simB[2]-1
+ meanA = total( image_A )/(simA[1]*simA[2])
+ meanB = total( image_B )/(simB[1]*simB[2])
+
+ for y = 0, Ny-1 do begin ;compute correlation for each y,x shift.
+
+ yoff = ys + y
+ yAmin = yoff > 0
+ yAmax = sAy < (sBy + yoff)
+ yBmin = (-yoff) > 0
+ yBmax = sBy < (sAy - yoff) ;Y overlap
+
+ if (yAmax GT yAmin) then begin
+
+ for x = 0, Nx-1 do begin
+
+ xoff = xs + x
+ xAmin = xoff > 0
+ xAmax = sAx < (sBx + xoff)
+ xBmin = (-xoff) > 0
+ xBmax = sBx < (sAx - xoff) ;X overlap
+
+ if (xAmax GT xAmin) then begin
+
+ im_ov_A = image_A[ xAmin:xAmax, yAmin:yAmax ]
+ im_ov_B = image_B[ xBmin:xBmax, yBmin:yBmax ]
+ Npix = N_elements( im_ov_A )
+
+ if N_elements( im_ov_B ) NE Npix then begin
+ message,"overlap error: # pixels NE",/INFO,/CONT
+ print, Npix, N_elements( im_ov_B )
+ endif
+
+ im_ov_A = im_ov_A - meanA
+ im_ov_B = im_ov_B - meanB
+ totAA = total( im_ov_A * im_ov_A )
+ totBB = total( im_ov_B * im_ov_B )
+
+ if (totAA EQ 0) or (totBB EQ 0) then $
+ correl_mat[x,y] = 0.0 else $
+ correl_mat[x,y] = total( im_ov_A * im_ov_B ) / $
+ sqrt( totAA * totBB )
+
+ if keyword_set( numpix ) then correl_mat[x,y,1] = Npix
+ endif
+
+ endfor
+ endif
+
+ if keyword_set( monitor ) then print, Ny-y, FORM="($,i3)"
+ endfor
+
+ if keyword_set( monitor ) then print," "
+
+return, correl_mat
+end
diff --git a/Code/script_idl_mv/astrolib/correl_optimize.pro b/Code/script_idl_mv/astrolib/correl_optimize.pro
new file mode 100644
index 0000000000000000000000000000000000000000..71c93951cf5bbbd60908288aac6b470f667d2e09
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/correl_optimize.pro
@@ -0,0 +1,125 @@
+pro correl_optimize, image_A, image_B, xoffset_optimum, yoffset_optimum, $
+ XOFF_INIT = xoff_init, $
+ YOFF_INIT = yoff_init, $
+ PRINT=print, MONITOR=monitor, $
+ NUMPIX=numpix, MAGNIFICATION=Magf, $
+ PLATEAU_TRESH = plateau
+;+
+; NAME:
+; CORREL_OPTIMIZE
+;
+; PURPOSE:
+; Find the optimal (x,y) pixel offset of image_B relative to image_A
+; EXPLANATION"
+; Optimal offset is computed by means of maximizing the correlation
+; function of the two images.
+;
+; CALLING SEQUENCE:
+; CORREL_OPTIMIZE, image_A, image_B, xoffset_optimum, yoffset_optimum
+; [ XOFF_INIT=, YOFF_INIT=, MAGNIFICATION=, /PRINT, /NUMPIX,
+; /MONITOR, PLATEAU_THRESH= ]
+;
+; INPUTS:
+; image_A, image_B = the two images of interest.
+;
+; OPTIONAL INPUT KEYWORDS:
+; XOFF_INIT = initial X pixel offset of image_B relative to image_A,
+; YOFF_INIT = Y pixel offset, (default offsets are 0 and 0).
+; MAGNIFICATION = option to determine offsets up to fractional pixels,
+; (example: MAG=2 means 1/2 pixel accuracy, default=1).
+; /NUMPIX: sqrt( sqrt( # pixels )) used as correlation weighting factor.
+; /MONITOR causes the progress of computation to be briefly printed.
+; /PRINT causes the results of analysis to be printed.
+; PLATEAU_THRESH = threshold used for detecting plateaus in
+; the cross-correlation matrix near maximum, (default=0.01),
+; used only if MAGNIFICATION > 1. Decrease this value for
+; high signal-to-noise data
+;
+; OUTPUTS:
+; xoffset_optimum = optimal X pixel offset of image_B relative to image_A.
+; yoffset_optimum = optimal Y pixel offset.
+;
+; CALLS:
+; function correl_images( image_A, image_B )
+; pro corrmat_analyze
+;
+; PROCEDURE:
+; The combination of function correl_images( image_A, image_B ) and
+; corrmat_analyze of the result is used to obtain the (x,y) offset
+; yielding maximal correlation. The combination is first executed at
+; large REDUCTION factors to speed up computation, then zooming in
+; recursively on the optimal (x,y) offset by factors of 2.
+; Finally, the MAGNIFICATION option (if specified)
+; is executed to determine the (x,y) offset up to fractional pixels.
+;
+; MODIFICATION HISTORY:
+; Written, July,1991, Frank Varosi, STX @ NASA/GSFC
+; Added PLATEAU_THRESH keyword June 1997, Wayne Landsman STX
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ if N_params() LT 2 then begin
+ print,'Syntax - CORREL_OPTIMIZE, imA, imB, Xoffset, Yoffset'
+ print,'Keywords - /Monitor, /Print, XoffInit =, YoffInit =' + $
+ ', Magnification =, /Numpix'
+ return
+ endif
+
+ simA = size( image_A )
+ simB = size( image_B )
+
+ if (simA[0] LT 2) OR (simB[0] LT 2) then begin
+ message,"first two arguments must be images",/INFO,/CONTIN
+ return
+ endif
+
+ if N_elements( xoff_init ) NE 1 then xoff_init=0
+ if N_elements( yoff_init ) NE 1 then yoff_init=0
+ if N_elements( plateau ) NE 1 then plateau = 0.01
+ xoff = xoff_init
+ yoff = yoff_init
+
+ reducf = min( [simA[1:2],simB[1:2]] ) / 8 ;Bin average to about
+ ; 8 by 8 pixel image.
+ if N_elements( Magf ) NE 1 then Magf=1
+
+ xsiz = max( [simA[1],simB[1]] )
+ ysiz = max( [simA[2],simB[2]] )
+ xshift = xsiz
+ yshift = ysiz ;shift over the whole images first correlation.
+
+ while (reducf GT 1) do begin
+
+ corrmat = correl_images( image_A, image_B, XOFF=xoff,YOFF=yoff,$
+ NUM=numpix, XS=xshift,YS=yshift,$
+ REDUCTION=reducf, MONIT=monitor )
+
+ corrmat_analyze, corrmat, xoff, yoff, XOFF=xoff, YOFF=yoff, $
+ PRINT=print, REDUCTION=reducf
+ xshift = 2*reducf
+ yshift = 2*reducf ;shift over coarse pixels to refine
+ reducf = reducf/2 ; in further correlations.
+ endwhile
+
+ xshift = xshift/2 ;now refine offsets to actual pixels.
+ yshift = yshift/2
+ corrmat = correl_images( image_A, image_B, XOFF=xoff, YOFF=yoff,$
+ MON=monitor, NUM=numpix, XS=xshift, YS=yshift )
+
+ corrmat_analyze, corrmat, xoffset_optimum, yoffset_optimum, $
+ XOFF=xoff, YOFF=yoff, PRINT=print
+
+ if (Magf GE 2) then begin
+
+ xoff = xoffset_optimum ;refine offsets to
+ yoff = yoffset_optimum ; fractional pixels.
+
+ corrmat = correl_images( image_A, image_B, XOFF=xoff,YOFF=yoff,$
+ MAGNIFIC=Magf, MONITOR=monitor )
+
+ corrmat_analyze, corrmat, xoffset_optimum, yoffset_optimum, $
+ XOFF=xoff,YOFF=yoff,$
+ PRINT=print, MAG=Magf, $
+ PLATEAU_THRESH = plateau
+ endif
+return
+end
diff --git a/Code/script_idl_mv/astrolib/corrmat_analyze.pro b/Code/script_idl_mv/astrolib/corrmat_analyze.pro
new file mode 100644
index 0000000000000000000000000000000000000000..26af51caa7fc9b7fab8420c9dffea8001ecb1a69
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/corrmat_analyze.pro
@@ -0,0 +1,174 @@
+pro corrmat_analyze, correl_mat, xoffset_optimum, yoffset_optimum, $
+ max_corr, edge, plateau, $
+ XOFF_INIT = xoff_init, $
+ YOFF_INIT = yoff_init, $
+ REDUCTION = reducf, MAGNIFICATION = Magf, $
+ PRINT = print, PLATEAU_THRESH = plateau_thresh
+;+
+; NAME:
+; CORRMAT_ANALYZE
+; PURPOSE:
+; Find the optimal (x,y) offset to maximize correlation of 2 images
+; EXPLANATION:
+; Analyzes the 2-D cross-correlation function of two images
+; and finds the optimal(x,y) pixel offsets.
+; Intended for use with function CORREL_IMAGES.
+;
+; CALLING SEQUENCE:
+; corrmat_analyze, correl_mat, xoffset_optimum, yoffset_optimum,
+; max_corr, edge, plateau, [XOFF_INIT=, YOFF_INIT=, REDUCTION=,
+; MAGNIFICATION=, PLATEAU_THRESH=, /PRINT]
+;
+; INPUTS:
+; correl_mat = the cross-correlation matrix of 2 images.
+; (as computed by function CORREL_IMAGES( imA, imB ) ).
+;
+; NOTE:
+; If correl_mat(*,*,1) is the number of pixels for each correlation,
+; (the case when /NUMPIX was specified in call to CORREL_IMAGES)
+; then sqrt( sqrt( # pixels )) is used as correlation weighting factor.
+;
+; OPTIONAL INPUT KEYWORDS:
+; XOFF_INIT = initial X pixel offset of image_B relative to image_A.
+; YOFF_INIT = Y pixel offset, (both as specified to correl_images).
+; REDUCTION = reduction factor used in call to CORREL_IMAGES.
+; MAGNIFICATION = magnification factor used in call to CORREL_IMAGES,
+; this allows determination of offsets up to fractions of a pixel.
+; PLATEAU_THRESH = threshold used for detecting plateaus in
+; the cross-correlation matrix near maximum, (default=0.01),
+; used only if MAGNIFICATION > 1
+; /PRINT causes the result of analysis to be printed.
+;
+; OUTPUTS:
+; xoffset_optimum = optimal X pixel offset of image_B relative to image_A.
+; yoffset_optimum = optimal Y pixel offset.
+; max_corr = the maximal correlation corresponding to optimal offset.
+; edge = 1 if maximum is at edge of correlation domain, otherwise=0.
+; plateau = 1 if maximum is in a plateau of correlation function, else=0.
+;
+; PROCEDURE:
+; Find point of maximum cross-correlation and calc. corresponding offsets.
+; If MAGNIFICATION > 1:
+; the correl_mat is checked for plateau near maximum, and if found,
+; the center of plateau is taken as point of maximum cross-correlation.
+;
+; MODIFICATION HISTORY:
+; Written, July-1991, Frank Varosi, STX @ NASA/GSFC
+; Use ROUND instead of NINT, June 1995 Wayne Landsman HSTX
+; Remove use of non-standard !DEBUG system variable W.L. HSTX
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ scm = size( correl_mat )
+
+ if (scm[0] LT 2) then begin
+ message,"first argument must be at least 2-D matrix",/INFO,/CON
+ return
+ endif
+
+ Nx = scm[1]
+ Ny = scm[2]
+ x_shift = Nx/2
+ y_shift = Ny/2
+ if N_elements( xoff_init ) NE 1 then xoff_init=0
+ if N_elements( yoff_init ) NE 1 then yoff_init=0
+
+ if (scm[0] GE 3) then begin ;weight by # of overlap pixels:
+
+ Npix_mat = correl_mat[*,*,1]
+ Maxpix = max( Npix_mat )
+ corr_mat = correl_mat[*,*,0] * sqrt( sqrt( Npix_mat/Maxpix ) )
+
+ endif else corr_mat = correl_mat
+
+ max_corr = max( corr_mat, maxLoc )
+ xi = (maxLoc MOD Nx)
+ yi = (maxLoc/Nx)
+
+ if N_elements( Magf ) NE 1 then Magf=1
+ if N_elements( reducf ) NE 1 then reducf=1
+ if N_elements( plateau_thresh ) NE 1 then plateau_thresh=0.01
+ plateau=0
+ edge=0
+
+ if ( reducf GT 1 ) then begin
+
+ xoffset_optimum = ( xi - x_shift + xoff_init/reducf ) * reducf
+ yoffset_optimum = ( yi - y_shift + yoff_init/reducf ) * reducf
+ xoffset_optimum = round( xoffset_optimum )
+ yoffset_optimum = round( yoffset_optimum )
+ format = "(2i5)"
+
+ endif else if ( Magf GT 1 ) then begin
+
+ w = where( (max_corr - corr_mat) LE plateau_thresh, Npl )
+
+ if (Npl GT 1) then begin
+
+ wx = [ w MOD Nx ]
+ wy = [ w/Nx ]
+ wxmin = min( wx )
+ wymin = min( wy )
+ wxmax = max( wx )
+ wymax = max( wy )
+ npix = (wxmax - wxmin)+(wymax - wymin)
+
+ if (Npl GE npix) AND $
+ (xi GE wxmin) AND (xi LE wxmax) AND $
+ (yi GE wymin) AND (yi LE wymax) then begin
+ plateau=1
+ xi = wxmin + (wxmax - wxmin)/2.
+ yi = wymin + (wymax - wymin)/2.
+ max_corr = corr_mat[xi,yi]
+ endif
+ endif
+
+ xoffset_optimum = xoff_init + float( xi - x_shift )/Magf
+ yoffset_optimum = yoff_init + float( yi - y_shift )/Magf
+ format = "(2f9.3)"
+
+ endif else begin
+ xoffset_optimum = xi - x_shift + round( xoff_init )
+ yoffset_optimum = yi - y_shift + round( yoff_init )
+ format = "(2i5)"
+ endelse
+
+ if (xi EQ 0) OR (xi EQ Nx-1) OR $
+ (yi EQ 0) OR (yi EQ Ny-1) then edge=1
+
+ if keyword_set( print ) then begin
+
+ mincm = min( corr_mat, minLoc )
+
+ if (scm[0] GE 3) then begin
+ xm = (minLoc MOD Nx)
+ ym = (minLoc/Nx)
+ Npixmin = Long( Npix_mat[xm,ym] ) * reducf * reducf
+ Npixmax = Long( Npix_mat[xi,yi] ) * reducf * reducf
+ info_min = " ( " + strtrim( Npixmin, 2 ) + " pixels )"
+ info_max = " ( " + strtrim( Npixmax, 2 ) + " pixels )"
+ endif else begin
+ info_min = ""
+ info_max = ""
+ endelse
+
+ print," min Correlation = ", strtrim( mincm, 2 ), info_min
+ print," MAX Correlation = ", strtrim( max_corr, 2 ), info_max,$
+ " at (x,y) offset:", $
+ string( [ xoffset_optimum, yoffset_optimum ], FORM=format )
+
+ if (plateau) then begin
+ print," plateau of MAX Correlation:"
+ print," (Correl - MAX + " + $
+ string( plateau_thresh, FORM="(F5.3)" ) + ") > 0"
+ print,(corr_mat - max(corr_mat) + plateau_thresh) > 0
+ endif
+
+ if (edge) then begin
+ print," Maximum is at EDGE of shift range, " + $
+ "result is inconclusive"
+ print," try larger shift or new starting offset"
+ endif
+ endif
+
+return
+end
diff --git a/Code/script_idl_mv/astrolib/cosmo_param.pro b/Code/script_idl_mv/astrolib/cosmo_param.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4472c9de9dcaf235c632056c3c74658caac90a47
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cosmo_param.pro
@@ -0,0 +1,106 @@
+pro cosmo_param,Omega_m, Omega_Lambda, Omega_k, q0
+;+
+; NAME:
+; COSMO_PARAM
+; PURPOSE:
+; Derive full set of cosmological density parameters from a partial set
+; EXPLANATION:
+; This procedure is called by LUMDIST and GALAGE to allow the user a choice
+; in defining any two of four cosmological density parameters.
+;
+; Given any two of the four input parameters -- (1) the normalized matter
+; density Omega_m (2) the normalized cosmological constant, Omega_lambda
+; (3) the normalized curvature term, Omega_k and (4) the deceleration
+; parameter q0 -- this program will derive the remaining two. Here
+; "normalized" means divided by the closure density so that
+; Omega_m + Omega_lambda + Omega_k = 1. For a more
+; precise definition see Carroll, Press, & Turner (1992, ArAA, 30, 499).
+;
+; If less than two parameters are defined, this procedure sets default
+; values of Omega_k=0 (flat space), Omega_lambda = 0.7, Omega_m = 0.3
+; and q0 = -0.55
+; CALLING SEQUENCE:
+; COSMO_PARAM, Omega_m, Omega_lambda, Omega_k, q0
+;
+; INPUT-OUTPUTS:
+; Omega_M - normalized matter energy density, non-negative numeric scalar
+; Omega_Lambda - Normalized cosmological constant, numeric scalar
+; Omega_k - normalized curvature parameter, numeric scalar. This is zero
+; for a flat universe
+; q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2
+; = 0.5*Omega_m - Omega_lambda
+; NOTES:
+; If more than two parameters are defined upon input (overspecification),
+; then the first two defined parameters in the ordered list Omega_m,
+; Omega_lambda, Omega_k, q0 are used to define the cosmology.
+; EXAMPLE:
+; Suppose one has Omega_m = 0.3, and Omega_k = 0.5 then to determine
+; Omega_lambda and q0
+;
+; IDL> cosmo_param, 0.3, omega_lambda, 0.5, q0
+;
+; which will return omega_lambda = 0.2 and q0 = -2.45
+; REVISION HISTORY:
+; W. Landsman Raytheon ITSS April 2000
+; Better Error checking W. Landsman/D. Syphers October 2010
+;-
+
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 3 then begin
+ print,'Syntax - COSMO_PARAM, Omega_m, Omega_lambda, Omega_k, q0'
+ return
+ endif
+
+ Nk = n_elements(Omega_k) < 1
+ NLambda = N_elements(Omega_lambda) < 1
+ Nomega = N_elements(Omega_m) < 1
+ Nq0 = N_elements(q0) < 1
+
+; Use must specify 0 or 2 parameters
+
+ if total(Nk + Nlambda + Nomega + Nq0,/int) EQ 1 then $
+ message,'ERROR - At least 2 cosmological parameters must be specified'
+
+; Check which two parameters are defined, and then determine the other two
+
+ if (Nomega and Nlambda) then begin
+ if Nk EQ 0 then Omega_k = 1 - omega_m - Omega_lambda
+ if Nq0 EQ 0 then q0 = omega_m/2. - Omega_lambda
+ endif else $
+
+ if (Nomega and Nk) then begin
+ if Nlambda EQ 0 then Omega_lambda = 1. -omega_m - Omega_k
+ if Nq0 EQ 0 then q0 = -1 + Omega_k + 3*Omega_m/2
+ endif else $
+
+ if (Nlambda and Nk) then begin
+ if Nomega EQ 0 then omega_m = 1.-Omega_lambda - Omega_k
+ if Nq0 EQ 0 then q0 = (1 - Omega_k - 3.*Omega_lambda)/2.
+ endif else $
+
+ if (Nomega and Nq0) then begin
+ if Nk EQ 0 then Omega_k = 1 + q0 - 3*omega_m/2.
+ if Nlambda EQ 0 then Omega_lambda = 1. - omega_m - Omega_k
+ endif else $
+
+ if (Nlambda and Nq0) then begin
+ if Nk EQ 0 then Omega_k = 1 - 2*q0 - 3*Omega_lambda
+ if Nomega EQ 0 then omega_m = 1.-Omega_lambda - Omega_k
+ endif else $
+
+ if (Nk and Nq0) then begin
+ if Nomega EQ 0 then omega_m = (1 + q0 - Omega_k)*2/3.
+ if Nlambda EQ 0 then Omega_lambda = 1. - omega_m - Omega_k
+ endif
+
+;Set default values
+
+ if N_elements(Omega_k) EQ 0 then Omega_k = 0 ;Default is flat space
+ if N_elements(Omega_lambda) EQ 0 then Omega_lambda = 0.7
+ if N_elements(omega_m) EQ 0 then omega_m = 1 - Omega_lambda
+ if N_elements(q0) EQ 0 then q0 = (1 - Omega_k - 3*Omega_lambda)/2.
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/cr_reject.pro b/Code/script_idl_mv/astrolib/cr_reject.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec0e3159dd97133812383deba8760ff21d1e1f4c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cr_reject.pro
@@ -0,0 +1,886 @@
+PRO cr_reject, input_cube, rd_noise_dn, dark_dn, gain, mult_noise, $
+ combined_image, combined_noise, combined_npix, $
+ MASK_CUBE=mask_cube, NOISE_CUBE=noise_cube, $
+ NSIG=nsig, MEDIAN_LOOP=median_loop, MEAN_LOOP=mean_loop, $
+ MINIMUM_LOOP=minimum_loop, INIT_MED=init_med, $
+ INIT_MIN=init_min, INIT_MEAN=init_mean, EXPTIME=exptime,$
+ BIAS=bias, VERBOSE=verbose, $
+ TRACKING_SET=tracking_set, DILATION=dilation, DFACTOR=dfactor, $
+ NOSKYADJUST=noskyadjust,NOCLEARMASK=noclearmask, $
+ XMEDSKY=xmedsky, RESTORE_SKY=restore_sky, $
+ SKYVALS=skyvals, NULL_VALUE=null_value, $
+ INPUT_MASK=input_mask, WEIGHTING=weighting, SKYBOX=skybox
+;+
+; NAME:
+; CR_REJECT
+;
+; PURPOSE:
+; General, iterative cosmic ray rejection using two or more input images.
+;
+; EXPLANATION:
+; Uses a noise model input by the user, rather than
+; determining noise empirically from the images themselves.
+;
+; The image returned has the combined exposure time of all the input
+; images, unless the bias flag is set, in which case the mean is
+; returned. This image is computed by summation (or taking mean)
+; regardless of loop and initialization options (see below).
+;
+; CALLING SEQUENCE:
+; cr_reject, input_cube, rd_noise_dn, dark_dn, gain, mult_noise, $
+; combined_image, combined_npix, combined_noise
+;
+; MODIFIED ARGUMENT:
+; input_cube - Cube in which each plane is an input image.
+; If the noise model is used (rd_noise_dn, dark_dn,
+; gain), then input_cube must be in units of DN.
+; If an input noise cube is supplied (rd_noise_dn
+; <0), then the units of input_cube and noise_cube
+; merely need to be consistent.
+;
+; This array is used as a buffer and its contents
+; are not guaranteed on output (although for now,
+; weighting=0 with /restore_sky should give you back
+; your input unaltered).
+;
+; INPUT ARGUMENTS:
+; rd_noise_dn - Read noise per pixel. Units are DN.
+; If negative, then the user supplies an error cube
+; via the keyword noise_cube. In the latter case,
+; mult_noise still applies, since it is basically a fudge.
+; dark_dn - Dark rate in DN per pixel per s. This can be a scalar,
+; or it can be a dark image divided by the exposure
+; time.
+; gain - Electrons per DN.
+; mult_noise - Coefficient for multiplicative noise term -- helps
+; account for differing PSFs or subpixel image shifts.
+;
+; INPUT KEYWORDS:
+; exptime - If the images have different exposure times, pass
+; them in a vector. You can leave this off for
+; frames with the same exposure time, but dark counts
+; won't be treated correctly.
+; verbose - If set, lots of output.
+; nsig - Rejection limit in units of pixel-to-pixel noise
+; (sigma) on each input image. Can be specified as
+; an array, in which case the dimension gives the
+; maximum number of iterations to run. (Default =
+; [8, 6, 4]
+; dilation - With dfactor, provides functionality similar to the
+; expansion of the CR with pfactor and radius in STSDAS
+; crrej. Dilate gives the size of the border to be
+; tested around each initially detected CR pixel.
+; E.g., dilate=1 searches a 9 X 9 area centered on the
+; original pixel. If dfactor is set, the default is 1.
+; dfactor - See dilation. This parameter is equivalent to pfactor
+; in STSDAS crrej. The current threshold for rejection
+; is multiplied by this factor when doing the search
+; with the dilated mask. If dilation is set, the default
+; for this parameter is 0.5.
+; bias - Set if combining biases (divides through by number
+; of images at end, since exposure time is 0).
+; tracking_set - Subscripts of pixels to be followed through the
+; computation.
+; noskyadjust - Sky not to be subtracted before rejection tests. Default
+; is to do the subtraction.
+; xmedsky - Flag. If set, the sky is computed as a 1-d array
+; which is a column-by-column median. This is intended
+; for STIS slitless spectra. If sky adjustment is
+; disabled, this keyword has no effect.
+; input_mask - Mask cube input by the user. Should be byte data
+; because it's boolean. 1 means use the pixel,
+; and 0 means reject the pixel - these rejections
+; are in addition to those done by the CR rejection
+; algorithm as such.
+;
+; The following keywords control how the current guess at a CR-free
+; "check image" is recomputed on each iteration:
+;
+; median_loop - If set, the check image for each iteration is
+; the pixel-by-pixel median. THE MEAN IS
+; RETURNED in combined_image even if you set
+; this option. (Default is mean_loop.)
+; minimum_loop - If set, the check image for each iteration is
+; the pixel-by-pixel minimum. THE MEAN IS
+; RETURNED in combined_image even if you set
+; this option. (Default is mean_loop.)
+; mean_loop - If set, the check image for each iteration is
+; the pixel-by-pixel mean. (Same as the default.)
+; noclearmask - By default, the mask of CR flags is reset before
+; every iteration, and a pixel that has been
+; rejected has a chance to get back in the game
+; if the average migrates toward its value. If this
+; keyword is set, then any rejected pixel stays
+; rejected in subsequent iterations. Note that what
+; stsdas.hst_calib.wfpc.crrej does is the same
+; as the default. For this procedure, the default
+; was NOT to clear the flags, until 20 Oct. 1997.
+; restore_sky - Flag. If set, the routine adds the sky back into
+; input_cube before returning. Works only if
+; weighting=0.
+; null_value - Value to be used for output pixels to which no
+; input pixels contribute. Default=0
+; weighting - Selects weighting scheme in final image
+; combination:
+; 0 (default) - Poissonian weighting - co-add
+; detected DN from non-CR pixels. (Pixel-by-
+; pixel scaling up to total exposure time,
+; for pixels in stack where some rejected.)
+; Equivalent to exptime weighting of rates.
+; 1 or more - Sky and read noise weighting of rates.
+; Computed as weighted average of DN rates,
+; with total exp time multiplied back in
+; afterward.
+;
+; In all cases, the image is returned as a sum in
+; DN with the total exposure time of the image
+; stack, and with total sky added back in.
+;
+; The following keywords allow the initial guess at a CR-free "check
+; image" to be of a different kind from the iterative guesses:
+;
+; init_med - If set, the initial check image is
+; the pixel-by-pixel median. (Not permitted if
+; input_cube has fewer than 3 planes; default is minimum.)
+; init_mean - If set, the initial check image is
+; the pixel-by-pixel mean. (Default is minimum.)
+; init_min - If set, the initial check image is
+; the pixel-by-pixel minimum. (Same as the default.)
+;
+; OUTPUT ARGUMENTS::
+; combined_image - Mean image with CRs removed.
+; combined_npix - Byte (or integer) image of same dimensions as
+; combined_image, with each element containing
+; the number of non-CR stacked pixels that
+; went into the result.
+; combined_noise - Noise in combined image according to noise model
+; or supplied noise cube.
+;
+; OUTPUT KEYWORDS:
+; mask_cube - CR masks for each input image. 1 means
+; good pixel; 0 means CR pixel.
+; skyvals - Sky value array. For an image cube with N planes,
+; this array is fltarr(N) if the sky is a scalar per
+; image plane, and fltarr(XDIM, N), is the XMEDSKY
+; is set.
+;
+; INPUT/OUTPUT KEYWORD:
+; noise_cube - Estimated noise in each pixel of input_cube as
+; returned (if rd_noise_dn ge 0), or input noise
+; per pixel of image_cube (if rd_noise_dn lt 0).
+; skybox - X0, X1, Y0, Y1 bounds of image section used
+; to compute sky. If supplied by user, this
+; region is used. If not supplied, the
+; image bounds are returned. This parameter might
+; be used (for instance) if the imaging area
+; doesn't include the whole chip.
+;
+; COMMON BLOCKS: none
+;
+; SIDE EFFECTS: none
+;
+; METHOD:
+;
+; COMPARISON WITH STSDAS
+;
+; Cr_reject emulates the crrej routine in stsdas.hst_calib.wfpc.
+; The two routines have been verified to give identical results
+; (except for some pixels along the edge of the image) under the
+; following conditions:
+;
+; no sky adjustment
+; no dilation of CRs
+; initialization of trial image with minimum
+; taking mean for each trial image after first (no choice
+; in crrej)
+;
+; Dilation introduces a difference between crrej and this routine
+; around the very edge of the image, because the IDL mask
+; manipulation routines don't handle the edge the same way as crrej
+; does. Away from the edge, crrej and cr_reject are the same with
+; respect to dilation.
+;
+; The main difference between crrej and cr_reject is in the sky
+; computation. Cr_reject does a DAOPHOT I sky computation on a
+; subset of pixels grabbed from the image, whereas crrej searches
+; for a histogram mode.
+;
+; REMARKS ON USAGE
+;
+; The default is that the initial guess at a CR-free image is the
+; pixel-by-pixel minimum of all the input images. The pixels
+; cut from each component image are the ones more than nsig(0) sigma
+; from this minimum image. The next iteration is based on the
+; mean of the cleaned-up component images, and the cut is taken
+; at nsig(1) sigma. The next iteration is also based on the mean with
+; the cut taken at nsig(2) sigma.
+;
+; The user can specify an arbitrary sequence of sigma cuts, e.g.,
+; nsig=[6,2] or nsig=[10,9,8,7]. The user can also specify that
+; the initial guess is the median (/init_med) rather than the
+; minimum, or even the mean. The iterated cleaned_up images after
+; the first guess can be computed as the mean or the median
+; (/mean_loop or /median_loop). The minimum_loop option is also
+; specified, but this is a trivial case, and you wouldn't want
+; to use it except perhaps for testing.
+;
+; The routine takes into account exposure time if you want it to,
+; i.e., if the pieces of the CR-split aren't exactly the same.
+; For bias frames (exposure time 0), set /bias to return the mean
+; rather than the total of the cleaned-up component images.
+;
+; The crrej pfactor and radius to propagate the detected CRs
+; outward from their initial locations have been implemented
+; in slightly different form using the IDL DILATE function.
+;
+; It is possible to end up with output pixels to which no valid
+; input pixels contribute. These end up with the value
+; NULL_VALUE, and the corresponding pixels of combined_npix are
+; also returned as 0. This result can occur when the pixel is
+; very noisy across the whole image stack, i.e., if all the
+; values are, at any step of the process, far from the stack
+; average at that position even after rejecting the real
+; outliers. Because pixels are flagged symmetrically N sigma
+; above and below the current combined image (see code), all
+; the pixels at a given position can end up getting flagged.
+; (At least, that's how I think it happens.)
+;
+; MODIFICATION HISTORY:
+; 5 Mar. 1997 - Written. R. S. Hill
+; 14 Mar. 1997 - Changed to masking approach to keep better
+; statistics and return CR-affected pixels to user.
+; Option to track subset of pixels added.
+; Dilation of initially detected CRs added.
+; Other small changes. RSH
+; 17 Mar. 1997 - Arglist and treatment of exposure times fiddled
+; to mesh better with stis_cr. RSH
+; 25 Mar. 1997 - Fixed bug if dilation finds nothing. RSH
+; 4 Apr. 1997 - Changed name to cr_reject. RSH
+; 15 Apr. 1997 - Restyled with emacs, nothing else done. RSH
+; 18 Jun. 1997 - Input noise cube allowed. RSH
+; 19 Jun. 1997 - Multiplicative noise deleted from final error. RSH
+; 20 Jun. 1997 - Fixed error in using input noise cube. RSH
+; 12 July 1997 - Sky adjustment option. RSH
+; 27 Aug. 1997 - Dilation kernel made round, not square, and
+; floating-point radius allowed. RSH
+; 16 Sep. 1997 - Clearmask added. Intermediate as well as final
+; mean is exptime weighted. RSH
+; 17 Sep. 1997 - Redundant zeroes around dilation kernel trimmed. RSH
+; 1 Oct. 1997 - Bugfix in preceding. RSH
+; 21 Oct. 1997 - Clearmask changed to noclearmask. Bug in robust
+; array division fixed (misplaced parens). Sky as
+; a function of X (option). RSH
+; 30 Jan. 1998 - Restore_sky keyword added. RSH
+; 5 Feb. 1998 - Quick help corrected and updated. RSH
+; 6 Feb. 1998 - Fixed bug in execution sequence for tracking_set
+; option. RSH
+; 18 Mar. 1998 - Eliminated confusing maxiter spec. Added
+; null_value keyword. RSH
+; 15 May 1998 - Input_mask keyword. RSH
+; 27 May 1998 - Initialization of minimum image corrected. NRC, RSH
+; 9 June 1998 - Input mask cube processing corrected. RSH
+; 21 Sep. 1998 - Weighting keyword added. RSH
+; 7 Oct. 1998 - Fixed bug in input_mask processing (introduced
+; in preceding update). Input_mask passed to
+; skyadj_cube. RSH
+; 5 Mar. 1999 - Force init_min for 2 planes. RSH
+; 1 Oct. 1999 - Make sure weighting=1 not given with noise cube. RSH
+; 1 Dec. 1999 - Corrections to doc; restore_sky needs weighting=0. RSH
+; 17 Mar. 2000 - SKYBOX added. RSH
+;-
+on_error,0
+IF n_params(0) LT 6 THEN BEGIN
+ print,'CALLING SEQUENCE: cr_reject, input_cube, rd_noise_dn, $'
+ print,' dark_dn, gain, mult_noise, combined_image, combined_noise, $'
+ print,' combined_npix'
+ print,'KEYWORD PARAMETERS: nsig, exptime, bias, verbose,'
+ print,' tracking_set, median_loop, mean_loop, minimum_loop, '
+ print,' init_med, init_mean, init_min,'
+ print,' mask_cube, noise_cube, dilation, dfactor, noclearmask, '
+ print,' noskyadjust, xmedsky, restore_sky, skyvals, null_value'
+ print,' input_mask, weighting, skybox'
+ return
+ENDIF
+
+verbose = keyword_set(verbose)
+xmed = keyword_set(xmedsky)
+
+track = n_elements(tracking_set) GT 0
+
+sz = size(input_cube)
+IF sz[0] NE 3 THEN BEGIN
+ print,'CR_REJECT: Input cube must have 3 dimensions.'
+ return
+ENDIF
+
+IF n_elements(input_mask) GT 0 THEN BEGIN
+ szinpm = size(input_mask)
+ wsz = where(szinpm[0:3] NE sz[0:3], cwsz)
+ IF cwsz GT 0 THEN BEGIN
+ print,'CR_REJECT: INPUT_MASK must be same size as IMAGE_CUBE.'
+ return
+ ENDIF ELSE BEGIN
+ IF verbose THEN print,'CR_REJECT: Using INPUT_MASK.'
+ ENDELSE
+ use_input_mask = 1b
+ENDIF ELSE BEGIN
+ use_input_mask = 0b
+ENDELSE
+
+xdim = sz[1]
+ydim = sz[2]
+nimg = sz[3]
+npix = xdim*ydim
+
+usemedian = keyword_set(median_loop)
+usemean = keyword_set(mean_loop)
+usemin = keyword_set(minimum_loop)
+IF (usemean + usemedian + usemin) GT 1 THEN BEGIN
+ print,'CR_REJECT: Specify only one of MEDIAN_LOOP, MEAN_LOOP' $
+ + ', or MINIMUM_LOOP'
+ return
+ENDIF
+IF (usemean + usemedian + usemin) EQ 0 THEN BEGIN
+ usemean = 1
+ENDIF
+
+inimed = keyword_set(init_med)
+inimean = keyword_set(init_mean)
+inimin = keyword_set(init_min)
+IF (inimean + inimed + inimin) GT 1 THEN BEGIN
+ print,'CR_REJECT: Specify only one of INIT_MED, INIT_MEAN,' $
+ + ' or INIT_MIN.'
+ return
+ENDIF
+IF (inimean + inimed + inimin) EQ 0 THEN BEGIN
+ inimin = 1
+ENDIF
+IF nimg LT 3 AND inimed THEN BEGIN
+ inimed = 0
+ inimin = 1
+ IF verbose THEN BEGIN
+ print,'CR_REJECT: INIT_MED only permitted for 3 or more ' $
+ + 'images.'
+ print,' Forcing INIT_MIN.'
+ ENDIF
+ENDIF
+
+;
+; Accumulation mode for bad pixels.
+;
+IF keyword_set(noclearmask) THEN BEGIN
+ clearmask = 0b
+ IF verbose THEN print,'CR_REJECT: CR flags accumulate strictly.'
+ENDIF ELSE BEGIN
+ clearmask = 1b
+ IF verbose THEN print,'CR_REJECT: CR flags cleared between iterations.'
+ENDELSE
+;
+; Default iterations.
+;
+IF (n_elements(nsig) LT 1) THEN BEGIN
+ nsig = [8, 6, 4]
+ENDIF
+sig_limit = nsig
+maxiter = n_elements(nsig)
+IF n_elements(null_value) LT 1 THEN null_value=0
+IF verbose THEN BEGIN
+ print,'CR_REJECT: Iteration spec: '
+ print,' nsig = ',nsig
+ print,' maxiter = ',maxiter
+ print,' null_value = ',null_value
+ENDIF
+;
+IF n_elements(exptime) NE 0 THEN BEGIN
+ IF n_elements(exptime) NE nimg THEN BEGIN
+ print,'CR_REJECT: EXPTIME must have one element per input image.'
+ return
+ ENDIF
+ zexp = 0b
+ FOR i=0,nimg-1 DO zexp = zexp OR (exptime[i] LE 0.0)
+ IF zexp THEN BEGIN
+ save_expt = exptime
+ exptime = make_array(nimg, value=1.0)
+ IF verbose THEN print, $
+ 'CR_REJECT: All exposure times <= 0.'
+ ENDIF
+ENDIF ELSE BEGIN
+ zexp = 1b
+ save_expt = make_array(nimg, value=0.0)
+ exptime = make_array(nimg, value=1.0)
+ENDELSE
+etot = total(exptime)
+
+IF n_elements(weighting) GT 0 THEN BEGIN
+ wgt = weighting
+ wgt = round(wgt)
+ IF wgt ne 0 and wgt ne 1 THEN BEGIN
+ print, 'CR_REJECT: Weighting must be 0 or 1'
+ print,' Executing return'
+ return
+ ENDIF
+ENDIF ELSE BEGIN
+ wgt = 0
+ENDELSE
+
+IF verbose THEN BEGIN
+ print,'CR_REJECT: gain = ',gain
+ IF n_elements(dark_dn) EQ 1 THEN BEGIN
+ print,' dark rate = ',dark_dn
+ ENDIF ELSE BEGIN
+ print,' dark image supplied '
+ ENDELSE
+ print,' read noise = ',rd_noise_dn
+ print,' multiplicative noise coefficient = ',mult_noise
+ print,' number of images = ',nimg
+ print,' exposure times: '
+ print,exptime
+ print,' total exposure time = ',etot
+ CASE wgt OF
+ 0: print,' flux to be co-added'
+ 1: print,' weighting of rate by sky and read noise'
+ ENDCASE
+ENDIF
+
+;
+; Process dilation specs
+;
+IF keyword_set(dilation) OR keyword_set(dfactor) THEN BEGIN
+ do_dilation = 1b
+ IF n_elements(dilation) LT 1 THEN dilation = 1
+ IF n_elements(dfactor) LT 1 THEN dfactor = 0.5
+ IF (dilation LE 0) OR (dfactor LE 0) THEN BEGIN
+ print,'CR_REJECT: Dilation specs not valid: '
+ print,' dilation = ',dilation
+ print,' dfactor = ',dfactor
+ return
+ ENDIF
+ kdim = 1 + 2*floor(dilation+1.e-4)
+ kernel = make_array(kdim, kdim, value=1b)
+ half_kern = fix(kdim/2)
+ wkz = where(shift(dist(kdim),half_kern,half_kern) $
+ GT (dilation+0.0001), ckz)
+ IF ckz GT 0 THEN kernel[wkz] = 0b
+ IF verbose THEN BEGIN
+ print,'CR_REJECT: Dilation will be done. Specs:'
+ print,' dilation = ',dilation
+ print,' dfactor = ',dfactor
+ print,' kernel = '
+ print,kernel
+ ENDIF
+ENDIF ELSE BEGIN
+ do_dilation = 0b
+ IF verbose THEN print,'CR_REJECT: Mask dilation will not be done.'
+ENDELSE
+
+
+IF verbose THEN print,'CR_REJECT: Initializing noise and mask cube.'
+IF rd_noise_dn GE 0 THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Noise cube computed.'
+ supplied = 0b
+ noise_cube = 0.0*input_cube
+ FOR i=0, nimg-1 DO BEGIN
+ noise_cube[0,0,i] = sqrt((rd_noise_dn^2 $
+ + ((input_cube[*,*,i] $
+ + dark_dn*exptime[i])>0)/gain) > 0.0)
+ ENDFOR
+ENDIF ELSE BEGIN
+ IF verbose THEN print,'CR_REJECT: Noise cube supplied.'
+ supplied = 1b
+ IF wgt EQ 1 THEN BEGIN
+ print, 'CR_REJECT: WEIGHTING=1 incompatible with supplying ', $
+ 'noise cube.'
+ print, ' Executing return.'
+ return
+ ENDIF
+ENDELSE
+;
+; Mask flags CR with zeroes
+;
+mask_cube = make_array(xdim, ydim, nimg, value=1B)
+IF nimg LE 255 THEN ivalue=byte(nimg) ELSE ivalue=fix(nimg)
+combined_npix = make_array(xdim, ydim, value=ivalue)
+
+IF keyword_set(noskyadjust) THEN BEGIN
+ skyvals = fltarr(nimg)
+ totsky = 0
+ENDIF ELSE BEGIN
+ IF verbose THEN print,'CR_REJECT: Sky adjustment being made.'
+ skyadj_cube, input_cube, skyvals, totsky, $
+ verbose=verbose, xmedsky=xmed, input_mask=input_mask, $
+ region=skybox
+ENDELSE
+
+IF verbose THEN print,'CR_REJECT: Scaling by exposure time.'
+
+FOR i=0,nimg-1 DO BEGIN
+ input_cube[0,0,i] = input_cube[*,*,i]/exptime[i]
+ noise_cube[0,0,i] = noise_cube[*,*,i]/exptime[i]
+ENDFOR
+
+;
+; Initialization of main loop.
+;
+ncut_tot = lonarr(nimg)
+cr_subs = lonarr(npix)
+IF inimin OR usemin THEN flagval = max(input_cube)+1
+IF inimed THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Initializing with median.'
+ IF use_input_mask THEN BEGIN
+ medarr,input_cube,combined_image,input_mask
+ ENDIF ELSE BEGIN
+ medarr,input_cube,combined_image
+ ENDELSE
+ENDIF ELSE IF inimean THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Initializing with mean.'
+ IF use_input_mask THEN BEGIN
+ tm = total(input_mask,3) > 1e-6
+ combined_image = total(input_cube*input_mask,3)/tm
+ wz = where(temporary(tm) le 0.001, cwz)
+ IF cwz GT 0 THEN $
+ combined_image[temporary(wz)] = 0
+ ENDIF ELSE BEGIN
+ combined_image = total(input_cube,3)/nimg
+ ENDELSE
+ENDIF ELSE IF inimin THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Initializing with minimum.'
+ IF use_input_mask THEN BEGIN
+ combined_image = make_array(xdim,ydim,value=flagval)
+ FOR i=0, nimg-1 DO BEGIN
+ indx = where(input_mask[*,*,i] gt 0, cindx)
+ IF cindx GT 0 THEN $
+ combined_image[indx] = $
+ (combined_image < input_cube[*,*,i])[indx]
+ ENDFOR
+ wf = where(combined_image EQ flagval, cf)
+ IF cf GT 0 THEN combined_image[wf] = null_value
+ ENDIF ELSE BEGIN
+ combined_image = input_cube[*,*,0]
+ FOR i=1, nimg-1 DO BEGIN
+ combined_image = (combined_image < input_cube[*,*,i])
+ ENDFOR
+ ENDELSE
+ENDIF ELSE BEGIN
+ print,'CR_REJECT: Logic error in program initializing check image.'
+ return
+ENDELSE
+;
+; ---------------- MAIN CR REJECTION LOOP. ------------------
+;
+iter=0
+main_loop:
+iter=iter+1
+
+IF clearmask THEN mask_cube[*]=1b
+
+IF track THEN BEGIN
+ print,'CR_REJECT: Tracking. Iter = ',strtrim(iter,2)
+ print,' Combined_image: '
+ print,combined_image[tracking_set]
+ FOR i = 0, nimg-1 DO BEGIN
+ print,' Image ', strtrim(i,2), ':'
+ print,(input_cube[*,*,i])[tracking_set]
+ print,' Noise ', strtrim(i,2), ':'
+ print,(noise_cube[*,*,i])[tracking_set]
+ print,' Mask ', strtrim(i,2), ':'
+ print,(mask_cube[*,*,i])[tracking_set]
+ ENDFOR
+ENDIF
+IF verbose THEN BEGIN
+ print,'CR_REJECT: Beginning iteration number ',strtrim(iter,2)
+ print,' Sigma limit = ',sig_limit[iter-1]
+ENDIF
+
+FOR i=0, nimg-1 DO BEGIN
+
+ skyarray = fltarr(xdim, ydim)
+ IF xmed THEN BEGIN
+ FOR jl = 0,ydim-1 DO skyarray[0,jl] = skyvals[*,i]
+ ENDIF ELSE BEGIN
+ skyarray[*] = skyvals[i]
+ ENDELSE
+ model_image = $
+ (temporary(skyarray) + (combined_image + dark_dn)*exptime[i])>0
+
+ IF supplied THEN BEGIN
+ current_var = noise_cube[*,*,i]^2 $
+ + ((mult_noise*temporary(model_image))/exptime[i])^2
+ ENDIF ELSE BEGIN
+ current_var = (rd_noise_dn^2 + model_image/gain $
+ + (mult_noise*temporary(model_image))^2) $
+ / (exptime[i]^2)
+ ENDELSE
+
+ IF track THEN BEGIN
+ print,'CR_REJECT: Tracking. Iter = ',strtrim(iter,2), $
+ ' Image = ',strtrim(i,2)
+ print,' Current_var: '
+ print,current_var[tracking_set]
+ ENDIF
+
+ testnoise = sig_limit[iter-1] * sqrt(temporary(current_var))
+
+ IF track THEN BEGIN
+ print,' Testnoise: '
+ print,testnoise[tracking_set]
+ ENDIF
+;
+; Absolute value used so that if you remove too much, at least you
+; won't introduce a new bias.
+;
+ cr_subs[0] = $
+ where(abs(input_cube[*,*,i] - combined_image) $
+ GT testnoise, count)
+ IF count GT 0 THEN BEGIN
+ mask_cube[i*npix + cr_subs[0:count-1]] $
+ = replicate(0b,count)
+ ENDIF
+ IF verbose THEN print,'CR_REJECT: ',strtrim(count,2), $
+ ' pixels flagged in image ',strtrim(i,2)
+
+;
+; Dilation of mask
+;
+ count2 = 0
+ IF do_dilation THEN BEGIN
+ tempw = where(dilate(1b-mask_cube[*,*,i], kernel),dct)
+ IF dct GT 0 THEN BEGIN
+ ic1 = input_cube[npix*i + tempw]
+ tn1 = testnoise[tempw]
+ cmi = combined_image[tempw]
+ tewsub = where(abs(temporary(ic1) $
+ - temporary(cmi)) $
+ GT (dfactor*temporary(tn1)), count2)
+ cr_subs[0] = (temporary(tempw))[temporary(tewsub)>0]
+ IF count2 GT 0 THEN BEGIN
+ mask_cube[i*npix + cr_subs[0:count2-1]] $
+ = replicate(0b,count2)
+ ENDIF
+ ENDIF
+ IF verbose THEN print,'CR_REJECT: Mask dilation performed. ', $
+ strtrim(count2,2), ' pixels flagged in image ',strtrim(i,2)
+ ENDIF
+ENDFOR
+
+FOR i=0, nimg-1 DO BEGIN
+ cr_subs[0] = where(1b-mask_cube[*,*,i],count)
+; IF verbose THEN print,'CR_REJECT: ',strtrim(count,2), $
+; ' accumulated flags in image ',strtrim(i,2)
+; IF count GT 0 THEN BEGIN
+; input_cube(i*npix + cr_subs(0:count-1)) $
+; = combined_image(cr_subs(0:count-1))
+; noise_cube(i*npix + cr_subs(0:count-1)) $
+; = sqrt(current_var(cr_subs(0:count-1)))
+; ENDIF
+ENDFOR
+
+IF use_input_mask THEN BEGIN
+ combined_npix[0,0] = total((mask_cube AND input_mask),3)
+ENDIF ELSE BEGIN
+ combined_npix[0,0] = total(mask_cube,3)
+ENDELSE
+;
+; Loop termination condition.
+;
+IF (iter GE maxiter) THEN GOTO,end_main_loop
+
+IF usemedian THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Taking median.'
+ IF use_input_mask THEN BEGIN
+ medarr,input_cube,combined_image,mask_cube AND input_mask
+ ENDIF ELSE BEGIN
+ medarr,input_cube,combined_image,mask_cube
+ ENDELSE
+ENDIF ELSE IF usemean THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Taking mean.'
+ IF use_input_mask THEN BEGIN
+ maskprod = input_mask[*,*,0] AND mask_cube[*,*,0]
+ combined_image = input_cube[*,*,0]*maskprod*exptime[0]
+ combined_expt = temporary(maskprod)*exptime[0]
+ IF nimg GT 1 THEN BEGIN
+ FOR i=1,nimg-1 DO BEGIN
+ maskprod = input_mask[*,*,i] AND mask_cube[*,*,i]
+ combined_image = combined_image $
+ + input_cube[*,*,i]*maskprod*exptime[i]
+ combined_expt = combined_expt $
+ + temporary(maskprod)*exptime[i]
+ ENDFOR
+ ENDIF
+ wexpt0 = where(combined_expt LE 0,cexpt0)
+ combined_image = combined_image / (combined_expt>1e-6)
+ IF cexpt0 GT 0 THEN combined_image[wexpt0] = 0
+ ENDIF ELSE BEGIN
+ combined_image = input_cube[*,*,0]*mask_cube[*,*,0]*exptime[0]
+ combined_expt = mask_cube[*,*,0]*exptime[0]
+ IF nimg GT 1 THEN BEGIN
+ FOR i=1,nimg-1 DO BEGIN
+ combined_image = combined_image $
+ + input_cube[*,*,i]*mask_cube[*,*,i]*exptime[i]
+ combined_expt = combined_expt $
+ + mask_cube[*,*,i]*exptime[i]
+ ENDFOR
+ ENDIF
+ wexpt0 = where(combined_expt LE 0,cexpt0)
+ combined_image = combined_image / (combined_expt>1e-6)
+ IF cexpt0 GT 0 THEN combined_image[wexpt0] = 0
+ ENDELSE
+ENDIF ELSE IF usemin THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Taking minimum.'
+ IF use_input_mask THEN BEGIN
+ combined_image[*] = flagval
+ FOR i=0, nimg-1 DO BEGIN
+ indx = where((input_mask[*,*,i] $
+ AND mask_cube[*,*,i]) gt 0, cindx)
+ IF cindx GT 0 THEN $
+ combined_image[indx] = $
+ (combined_image < input_cube[*,*,i])[indx]
+ ENDFOR
+ wf = where(combined_image EQ flagval, cf)
+ IF cf GT 0 THEN combined_image[wf] = null_value
+ ENDIF ELSE BEGIN
+ combined_image = input_cube[*,*,0]
+ FOR i=1, nimg-1 DO BEGIN
+ combined_image = (combined_image < input_cube[*,*,i])
+ ENDFOR
+ ENDELSE
+
+ IF use_input_mask THEN BEGIn
+ combined_image = input_cube[*,*,0]*input_mask[*,*,0]
+ FOR i=1, nimg-1 DO BEGIN
+ combined_image = (combined_image < input_cube[*,*,i] $
+ *input_mask[*,*,i])
+ ENDFOR
+ ENDIF ELSE BEGIN
+ combined_image = input_cube[*,*,0]
+ FOR i=1, nimg-1 DO BEGIN
+ combined_image = (combined_image < input_cube[*,*,i])
+ ENDFOR
+ ENDELSE
+ENDIF ELSE BEGIN
+ print,'CR_REJECT: Logic error in program recomputing check image.'
+ return
+ENDELSE
+
+GOTO,main_loop
+END_main_loop:
+;
+; End of CR rejection loop.
+;
+IF verbose THEN BEGIN
+ FOR i=0,nimg-1 DO BEGIN
+ wdummy = where(1b-mask_cube[*,*,i],count)
+ ncut_tot[i] = count
+ ENDFOR
+ print,'CR_REJECT: Total pixels changed: '
+ print,ncut_tot
+ENDIF
+
+IF track THEN BEGIN
+ print,'CR_REJECT: Tracking. After loop exit.'
+ print,' Combined_image: '
+ print,combined_image[tracking_set]
+; print,' Current_var: '
+; print,current_var[tracking_set]
+ FOR i = 0, nimg-1 DO BEGIN
+ print,' Image ', strtrim(i,2), ':'
+ print,(input_cube[*,*,i])[tracking_set]
+ print,' Noise ', strtrim(i,2), ':'
+ print,(noise_cube[*,*,i])[tracking_set]
+ print,' Mask ', strtrim(i,2), ':'
+ print,(mask_cube[*,*,i])[tracking_set]
+ ENDFOR
+ENDIF
+
+;
+; Compute weights according to scheme chosen
+;
+xrepl = make_array(dim=xdim,value=1)
+yrepl = make_array(dim=ydim,value=1)
+
+IF wgt EQ 0 THEN BEGIN
+ wgts = xrepl # exptime
+ENDIF ELSE BEGIN
+ IF xmed THEN skytmp = skyvals>1e-6 ELSE skytmp = xrepl # (skyvals>1e-6)
+ exp2tmp = xrepl # (exptime^2)
+ sky_rate_var = temporary(skytmp)/gain/exp2tmp
+ ron_rate_var = rd_noise_dn^2/temporary(exp2tmp)
+ wgts = 1.0/(temporary(sky_rate_var) + temporary(ron_rate_var))
+ENDELSE
+
+;
+; Do the final co-addition
+;
+wgt_coeff = fltarr(xdim, ydim)
+FOR i=0,nimg-1 DO BEGIN
+ plane_wgts = wgts[*,i] # yrepl
+ input_cube[0,0,i] = input_cube[*,*,i]*plane_wgts
+ noise_cube[0,0,i] = noise_cube[*,*,i]*plane_wgts
+ IF use_input_mask THEN BEGIN
+ mcim = (mask_cube[*,*,i] AND input_mask[*,*,i])
+ ENDIF ELSE BEGIN
+ mcim = mask_cube[*,*,i]
+ ENDELSE
+ wgt_coeff[0,0] = wgt_coeff + temporary(mcim) * temporary(plane_wgts)
+ENDFOR
+wh0 = where(combined_npix EQ 0,c0)
+wgt_coeff = etot/(wgt_coeff > 1.0e-8)
+IF c0 GT 0 THEN wgt_coeff[wh0] = 0.0
+
+IF verbose THEN BEGIN
+ IF c0 GT 0 THEN $
+ print,'CR_REJECT: ',strtrim(c0,2),' pixels rejected on all inputs.'
+ENDIF
+
+IF use_input_mask THEN BEGIN
+ IF xmed THEN BEGIN
+ combined_image = wgt_coeff * total(input_cube $
+ * (mask_cube AND input_mask),3) $
+ + totsky#yrepl
+ ENDIF ELSE BEGIN
+ combined_image = wgt_coeff * total(input_cube $
+ * (mask_cube AND input_mask),3) $
+ + totsky
+ ENDELSE
+ combined_noise = wgt_coeff * sqrt(total((noise_cube $
+ * (mask_cube AND input_mask))^2,3))
+ENDIF ELSE BEGIN
+ IF xmed THEN BEGIN
+ combined_image = wgt_coeff * total(input_cube*mask_cube,3) $
+ + totsky#yrepl
+ ENDIF ELSE BEGIN
+ combined_image = wgt_coeff * total(input_cube*mask_cube,3) $
+ + totsky
+ ENDELSE
+ combined_noise = wgt_coeff * sqrt(total((noise_cube*mask_cube)^2,3))
+ENDELSE
+
+IF keyword_set(bias) THEN BEGIN
+ print,'CR_REJECT: Bias flag set -- returning mean instead of total.'
+ combined_image = combined_image/nimg
+ combined_noise = combined_noise/nimg
+ENDIF
+
+IF c0 GT 0 THEN combined_image[wh0] = null_value
+
+IF keyword_set(restore_sky) THEN BEGIN
+ IF wgt EQ 0 THEN BEGIN
+ IF verbose THEN print,'CR_REJECT: Adding sky back into data cube'
+ IF xmed THEN BEGIN
+ FOR i=0,nimg-1 DO BEGIN
+ FOR j=0, ydim-1 DO input_cube[0,j,i] = input_cube[*,j,i] $
+ + skyvals[*,i]
+ ENDFOR
+ ENDIF ELSE BEGIN
+ FOR i=0,nimg-1 DO $
+ input_cube[0,0,i] = input_cube[*,*,i] + skyvals[i]
+ ENDELSE
+ ENDIF ELSE BEGIN
+ print, 'CR_REJECT: /RESTORE_SKY ignored because weighting spec ' $
+ + 'not zero.'
+ ENDELSE
+ENDIF
+
+IF zexp THEN exptime = save_expt
+
+return
+END
diff --git a/Code/script_idl_mv/astrolib/create_struct.pro b/Code/script_idl_mv/astrolib/create_struct.pro
new file mode 100644
index 0000000000000000000000000000000000000000..602dacb6a2758695a3848a5fc9e4f5ce9b582fe7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/create_struct.pro
@@ -0,0 +1,309 @@
+pro create_struct, struct, strname, tagnames, tag_descript, DIMEN = dimen, $
+ CHATTER = chatter, NODELETE = nodelete
+;+
+; NAME:
+; CREATE_STRUCT
+; PURPOSE:
+; Create an IDL structure from a list of tag names and dimensions
+; EXPLANATION:
+; Dynamically create an IDL structure variable from list of tag names
+; and data types of arbitrary dimensions. Useful when the type of
+; structure needed is not known until run time.
+;
+; Unlike the intrinsic function CREATE_STRUCT(), this procedure does not
+; require the user to know the number of tags before run time. (Note
+; there is no name conflict since the intrinsic CREATE_STRUCT() is a
+; function, and this file contains a procedure.)
+; CALLING SEQUENCE:
+; CREATE_STRUCT, STRUCT, strname, tagnames, tag_descript,
+; [ DIMEN = , /CHATTER, /NODELETE ]
+;
+; INPUTS:
+; STRNAME - name to be associated with structure (string)
+; Must be unique for each structure created. Set
+; STRNAME = '' to create an anonymous structure
+;
+; TAGNAMES - tag names for structure elements (string or string array)
+; Any strings that are not valid IDL tag names (e.g. 'a\2')
+; will be converted by IDL_VALIDNAME to a valid tagname by
+; replacing with underscores as necessary (e.g. 'a_2')
+;
+; TAG_DESCRIPT - String descriptor for the structure, containing the
+; tag type and dimensions. For example, 'A(2),F(3),I', would
+; be the descriptor for a structure with 3 tags, strarr(2),
+; fltarr(3) and Integer scalar, respectively.
+; Allowed types are 'A' for strings, 'B' or 'L' for unsigned byte
+; integers, 'I' for integers, 'J' for longword integers,
+; 'K' for 64bit integers, 'F' or 'E' for floating point,
+; 'D' for double precision 'C' for complex, and 'M' for double
+; complex. Uninterpretable characters in a format field are
+; ignored.
+;
+; For vectors, the tag description can also be specified by
+; a repeat count. For example, '16E,2J' would specify a
+; structure with two tags, fltarr(16), and lonarr(2)
+;
+; OPTIONAL KEYWORD INPUTS:
+; DIMEN - number of dimensions of structure array (default is 1)
+;
+; CHATTER - If set, then CREATE_STRUCT() will display
+; the dimensions of the structure to be created, and prompt
+; the user whether to continue. Default is no prompt.
+;
+; /NODELETE - If set, then the temporary file created
+; CREATE_STRUCT will not be deleted upon exiting. See below
+;
+; OUTPUTS:
+; STRUCT - IDL structure, created according to specifications
+;
+; EXAMPLES:
+;
+; IDL> create_struct, new, 'name',['tag1','tag2','tag3'], 'D(2),F,A(1)'
+;
+; will create a structure variable new, with structure name NAME
+;
+; To see the structure of new:
+;
+; IDL> help,new,/struc
+; ** Structure NAME, 3 tags, 20 length:
+; TAG1 DOUBLE Array[2]
+; TAG2 FLOAT 0.0
+; TAG3 STRING Array[1]
+;
+; PROCEDURE:
+; Generates a temporary procedure file using input information with
+; the desired structure data types and dimensions hard-coded.
+; This file is then executed with CALL_PROCEDURE.
+;
+; NOTES:
+; If CREATE_STRUCT cannot write a temporary .pro file in the current
+; directory, then it will write the temporary file in the getenv('HOME')
+; directory.
+;
+; Note that 'L' now specifies a LOGICAL (byte) data type and not a
+; a LONG data type for consistency with FITS binary tables
+;
+; RESTRICTIONS:
+; The name of the structure must be unique, for each structure created.
+; Otherwise, the new variable will have the same structure as the
+; previous definition (because the temporary procedure will not be
+; recompiled). ** No error message will be generated ***
+;
+; SUBROUTINES CALLED:
+; REPCHR()
+;
+; MODIFICATION HISTORY:
+; Version 1.0 RAS January 1992
+; Modified 26 Feb 1992 for Rosat IDL Library (GAR)
+; Modified Jun 1992 to accept arrays for tag elements -- KLV, Hughes STX
+; Accept anonymous structures W. Landsman HSTX Sep. 92
+; Accept 'E' and 'J' format specifications W. Landsman Jan 93
+; 'L' format now stands for logical and not long array
+; Accept repeat format for vectors W. Landsman Feb 93
+; Accept complex and double complex (for V4.0) W. Landsman Jul 95
+; Work for long structure definitions W. Landsman Aug 97
+; Write temporary file in HOME directory if necessary W. Landsman Jul 98
+; Use OPENR,/DELETE for OS-independent file removal W. Landsman Jan 99
+; Use STRSPLIT() instead of GETTOK() W. Landsman July 2002
+; Assume since V5.3 W. Landsman Feb 2004
+; Added RESOLVE_ROUTINE to ensure recompilation W. Landsman Sep. 2004
+; Delete temporary with FILE_DELETE W. Landsman Sep 2006
+; Assume since V5.5, delete VMS reference W.Landsman Sep 2006
+; Added 'K' format for 64 bit integers, IDL_VALIDNAME check on tags
+; W. Landsman Feb 2007
+; Use vector form of IDL_VALIDNAME() if V6.4 or later W.L. Dec 2007
+; Suppress compilation mesage of temporary file A. Conley/W.L. May 2009
+; Remove FDECOMP, some cleaner coding W.L. July 2009
+; Do not limit string length to 1000 chars P. Broos, Feb 2011
+; Assume since IDL V6.4 W. Landsman Aug 2013
+;-
+;-------------------------------------------------------------------------------
+
+ compile_opt idl2
+ if N_params() LT 4 then begin
+ print,'Syntax - CREATE_STRUCT, STRUCT, strname, tagnames, tag_descript,'
+ print,' [ DIMEN = , /CHATTER, /NODELETE ]'
+ return
+ endif
+
+ if ~keyword_set( chatter) then chatter = 0 ;default is 0
+ if (N_elements(dimen) eq 0) then dimen = 1 ;default is 1
+
+ if (dimen lt 1) then begin
+ print,' Number of dimensions must be >= 1. Returning.'
+ return
+ endif
+
+; For anonymous structure, strname = ''
+ anonymous = 0b
+ if (strlen( strtrim(strname,2)) EQ 0 ) then anonymous = 1b
+
+ good_fmts = [ 'A', 'B', 'I', 'L', 'F', 'E', 'D', 'J','C','M', 'K' ]
+ fmts = ["' '",'0B','0','0B','0.0','0.0','0.0D0','0L','complex(0)', $
+ 'dcomplex(0)', '0LL']
+ arrs = [ 'strarr', 'bytarr', 'intarr', 'bytarr', 'fltarr', 'fltarr', $
+ 'dblarr', 'lonarr','complexarr','dcomplexarr','lon64arr']
+ ngoodf = N_elements( good_fmts )
+
+; If tagname is a scalar string separated by commas, convert to a string array
+
+ if size(tagnames,/N_dimensions) EQ 0 then begin
+ tagname = strsplit(tagnames,',',/EXTRACT)
+ endif else tagname = tagnames
+
+ Ntags = N_elements(tagname)
+
+; Make sure supplied tag names are valid.
+
+ tagname = idl_validname( tagname, /convert_all )
+
+; If user supplied a scalar string descriptor then we want to break it up
+; into individual items. This is somewhat complicated because the string
+; delimiter is not always a comma, e.g. if 'F,F(2,2),I(2)', so we need
+; to check positions of parenthesis also.
+
+ sz = size(tag_descript)
+ if sz[0] EQ 0 then begin
+ tagvar = strarr( Ntags)
+ temptag = tag_descript
+ for i = 0, Ntags - 1 do begin
+ comma = strpos( temptag, ',' )
+ lparen = strpos( temptag, '(' )
+ rparen = strpos( temptag, ')' )
+ if ( comma GT lparen ) and (comma LT Rparen) then pos = Rparen+1 $
+ else pos = comma
+ if pos EQ -1 then begin
+ if i NE Ntags-1 then message, $
+ 'WARNING - could only parse ' + strtrim(i+1,2) + ' string descriptors'
+ tagvar[i] = temptag
+ goto, DONE
+ endif else begin
+ tagvar[i] = strmid( temptag, 0, pos )
+ temptag = strmid( temptag, pos+1)
+ endelse
+ endfor
+ DONE:
+
+ endif else tagvar = tag_descript
+
+; create string array for IDL statements, to be written into
+; 'temp_'+strname+'.pro'
+
+ pro_string = strarr (ntags + 2)
+
+ if (dimen EQ 1) then begin
+
+ pro_string[0] = "struct = { " + strname + " $"
+ pro_string[ntags+1] = " } "
+
+ endif else begin
+
+ dimen = long(dimen) ;Changed to LONG from FIX Mar 95
+ pro_string[0] = "struct " + " = replicate ( { " + strname + " $"
+ pro_string[ntags+1] = " } , " + string(dimen) + ")"
+
+ endelse
+
+ tagvar = strupcase(tagvar)
+
+ for i = 0, ntags-1 do begin
+
+ goodpos = -1
+ for j = 0,ngoodf-1 do begin
+ fmt_pos = strpos( tagvar[i], good_fmts[j] )
+ if ( fmt_pos GE 0 ) then begin
+ goodpos = j
+ break
+ endif
+ endfor
+
+ if goodpos EQ -1 then begin
+ print,' Format not recognized: ' + tagvar[i]
+ print,' Allowed formats are :',good_fmts
+ stop,' Redefine tag format (' + string(i) + ' ) or quit now'
+ endif
+
+
+ if fmt_pos GT 0 then begin
+
+ repeat_count = strmid( tagvar[i], 0, fmt_pos )
+ if strnumber( repeat_count, value ) then begin
+ fmt = arrs[ goodpos ] + '(' + strtrim(fix(value), 2) + ')'
+ endif else begin
+ print,' Format not recognized: ' + tagvar[i]
+ stop,' Redefine tag format (' + string(i) + ' ) or quit now'
+ endelse
+
+ endif else begin
+
+; Break up the tag descriptor into a format and a dimension
+ tagfmts = strmid( tagvar[i], 0, 1)
+ tagdim = strtrim( strmid( tagvar[i], 1, 80),2)
+ if strmid(tagdim,0,1) NE '(' then tagdim = ''
+ fmt = (tagdim EQ '') ? fmts[goodpos] : arrs[goodpos] + tagdim
+ endelse
+
+ if anonymous and ( i EQ 0 ) then comma = '' else comma = " , "
+
+ pro_string[i+1] = comma + tagname[i] + ": " + fmt + " $"
+
+ endfor
+
+; Check that this structure definition is OK (if chatter set to 1)
+
+ if keyword_set ( Chatter ) then begin
+ ans = ''
+ print,' Structure ',strname,' will be defined according to the following:'
+ temp = repchr( pro_string, '$', '')
+ print, temp
+ read,' OK to continue? (Y or N) ',ans
+ if strmid(strupcase(ans),0,1) eq 'N' then begin
+ print,' Returning at user request.'
+ return
+ endif
+ endif
+
+; --- Determine if a file already exists with same name as temporary file
+
+ tempfile = 'temp_' + strlowcase( strname )
+ while file_test( tempfile + '.pro' ) do tempfile = tempfile + 'x'
+
+; ---- open temp file and create procedure
+; ---- If problems writing into the current directory, try the HOME directory
+
+ cd,current= prodir
+ cdhome = 0
+ openw, unit, tempfile +'.pro', /get_lun, ERROR = err
+ if (err LT 0) then begin
+ prodir = getenv('HOME')
+ tempfile = prodir + path_sep() + tempfile
+ while file_test( tempfile + '.pro' ) do tempfile = tempfile + 'x'
+ openw, unit, tempfile +'.pro', /get_lun, ERROR = err
+ if err LT 0 then message,'Unable to create a temporary .pro file'
+ cdhome = 1
+ endif
+ name = file_basename(tempfile)
+ printf, unit, 'pro ' + name + ', struct'
+ printf,unit,'compile_opt hidden'
+ for j = 0,N_elements(pro_string)-1 do $
+ printf, unit, strtrim( pro_string[j] )
+ printf, unit, 'return'
+ printf, unit, 'end'
+ free_lun, unit
+
+; If using the HOME directory, it needs to be included in the IDL !PATH
+
+ if cdhome then cd,getenv('HOME'),curr=curr
+ resolve_routine, name
+ Call_procedure, name, struct
+ if cdhome then cd,curr
+
+ if keyword_set( NODELETE ) then begin
+ message,'Created temporary file ' + tempfile + '.pro',/INF
+ return
+ endif else file_delete, tempfile + '.pro'
+
+ return
+ end ;pro create_struct
+
+
diff --git a/Code/script_idl_mv/astrolib/cspline.pro b/Code/script_idl_mv/astrolib/cspline.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7dede40e206aa4ca965e58288db1971576f28591
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/cspline.pro
@@ -0,0 +1,79 @@
+function cspline,xx, yy, tt, Deriv = deriv
+;+
+; NAME:
+; CSPLINE
+;
+; PURPOSE:
+; Function to evaluate a natural cubic spline at specified data points
+; EXPLANATION:
+; Combines the Numerical Recipes functions SPL_INIT and SPL_INTERP
+;
+; CALLING SEQUENCE:
+; result = cspline( x, y, t, [ DERIV = ])
+;
+; INPUTS:
+; x - vector of spline node positions, must be monotonic increasing or
+; decreasing
+; y - vector of node values
+; t - x-positions at which to evaluate the spline, scalar or vector
+;
+; INPUT-OUTPUT KEYWORD:
+; DERIV - values of the second derivatives of the interpolating function
+; at the node points. This is an intermediate step in the
+; computation of the natural spline that requires only the X and
+; Y vectors. If repeated interpolation is to be applied to
+; the same (X,Y) pair, then some computation time can be saved
+; by supplying the DERIV keyword on each call. On the first call
+; DERIV will be computed and returned on output.
+;
+; OUTPUT:
+; the values for positions t are returned as the function value
+; If any of the input variables are double precision, then the output will
+; also be double precision; otherwise the output is floating point.
+;
+; EXAMPLE:
+; The following uses the example vectors from the SPL_INTERP documentation
+;
+; IDL> x = (findgen(21)/20.0)*2.0*!PI ;X vector
+; IDL> y = sin(x) ;Y vector
+; IDL> t = (findgen(11)/11.0)*!PI ;Values at which to interpolate
+; IDL> cgplot,x,y,psym=1 ;Plot original grid
+; IDL> cgplot, /over, t,cspline(x,y,t),psym=2 ;Overplot interpolated values
+;
+; METHOD:
+; The "Numerical Recipes" implementation of the natural cubic spline is
+; used, by calling the intrinsic IDL functions SPL_INIT and SPL_INTERP.
+;
+; HISTORY:
+; version 1 D. Lindler May, 1989
+; version 2 W. Landsman April, 1997
+; Rewrite using the intrinsic SPL_INIT & SPL_INTERP functions
+; Converted to IDL V5.0 W. Landsman September 1997
+; Work for monotonic decreasing X vector W. Landsman February 1999
+;-
+;--------------------------------------------------------------------------
+
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 3 then begin
+ print,'Syntax: result = cspline( x, y, t, [ DERIV = ] )'
+ return,-1
+ endif
+
+ n = N_elements(xx)
+ if xx[n-1] LT xx[0] then begin ;Descending order?
+ xrev = reverse(xx)
+ yrev = reverse(yy)
+ if N_elements(Deriv) NE n then begin
+ if min( xx - xx[1:*]) LT 0 then $
+ message,'ERROR - Input vector not monotonic'
+ deriv = spl_init( xrev, yrev)
+ endif
+ return, spl_interp( xrev, yrev, deriv, tt)
+ endif
+
+ if N_elements(Deriv) NE n then deriv = spl_init( xx, yy)
+ return, spl_interp( xx, yy, deriv, tt)
+
+ end
diff --git a/Code/script_idl_mv/astrolib/ct2lst.pro b/Code/script_idl_mv/astrolib/ct2lst.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2244ce8b929d01a529406061b17c0d73be55343e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ct2lst.pro
@@ -0,0 +1,109 @@
+PRO CT2LST, lst, lng, tz, tme, day, mon, year
+;+
+; NAME:
+; CT2LST
+; PURPOSE:
+; To convert from Local Civil Time to Local Mean Sidereal Time.
+;
+; CALLING SEQUENCE:
+; CT2LST, Lst, Lng, Tz, Time, [Day, Mon, Year]
+; or
+; CT2LST, Lst, Lng, dummy, JD
+;
+; INPUTS:
+; Lng - The longitude in degrees (east of Greenwich) of the place for
+; which the local sidereal time is desired, scalar. The Greenwich
+; mean sidereal time (GMST) can be found by setting Lng = 0.
+; Tz - The time zone of the site in hours, positive East of the Greenwich
+; meridian (ahead of GMT). Use this parameter to easily account
+; for Daylight Savings time (e.g. -4=EDT, -5 = EST/CDT), scalar
+; This parameter is not needed (and ignored) if Julian date is
+; supplied. ***Note that the sign of TZ was changed in July 2008
+; to match the standard definition.***
+; Time or JD - If more than four parameters are specified, then this is
+; the time of day of the specified date in decimal hours. If
+; exactly four parameters are specified, then this is the
+; Julian date of time in question, scalar or vector
+;
+; OPTIONAL INPUTS:
+; Day - The day of the month (1-31),integer scalar or vector
+; Mon - The month, in numerical format (1-12), integer scalar or vector
+; Year - The 4 digit year (e.g. 2008), integer scalar or vector
+;
+; OUTPUTS:
+; Lst The Local Sidereal Time for the date/time specified in hours.
+;
+; RESTRICTIONS:
+; If specified, the date should be in numerical form. The year should
+; appear as yyyy.
+;
+; PROCEDURE:
+; The Julian date of the day and time is question is used to determine
+; the number of days to have passed since 0 Jan 2000. This is used
+; in conjunction with the GST of that date to extrapolate to the current
+; GST; this is then used to get the LST. See Astronomical Algorithms
+; by Jean Meeus, p. 84 (Eq. 11-4) for the constants used.
+;
+; EXAMPLE:
+; Find the Greenwich mean sidereal time (GMST) on 2008 Jul 30 at 15:53 pm
+; in Baltimore, Maryland (longitude=-76.72 degrees). The timezone is
+; EDT or tz=-4
+;
+; IDL> CT2LST, lst, -76.72, -4,ten(15,53), 30, 07, 2008
+;
+; ==> lst = 11.356505 hours (= 11h 21m 23.418s)
+;
+; The Web site http://tycho.usno.navy.mil/sidereal.html contains more
+; info on sidereal time, as well as an interactive calculator.
+; PROCEDURES USED:
+; jdcnv - Convert from year, month, day, hour to julian date
+;
+; MODIFICATION HISTORY:
+; Adapted from the FORTRAN program GETSD by Michael R. Greason, STX,
+; 27 October 1988.
+; Use IAU 1984 constants Wayne Landsman, HSTX, April 1995, results
+; differ by about 0.1 seconds
+; Longitudes measured *east* of Greenwich W. Landsman December 1998
+; Time zone now measure positive East of Greenwich W. Landsman July 2008
+; Remove debugging print statement W. Landsman April 2009
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 3 THEN BEGIN
+ print,'Syntax - CT2LST, Lst, Lng, Tz, Time, Day, Mon, Year'
+ print,' or'
+ print,' CT2LST, Lst, Lng, Tz, JD'
+ return
+ endif
+; If all parameters were given, then compute
+; the Julian date; otherwise assume it is stored
+; in Time.
+;
+
+ IF N_params() gt 4 THEN BEGIN
+ time = tme - tz
+ jdcnv, year, mon, day, time, jd
+
+ ENDIF ELSE jd = double(tme)
+;
+; Useful constants, see Meeus, p.84
+;
+ c = [280.46061837d0, 360.98564736629d0, 0.000387933d0, 38710000.0 ]
+ jd2000 = 2451545.0D0
+ t0 = jd - jd2000
+ t = t0/36525
+;
+; Compute GST in seconds.
+;
+ theta = c[0] + (c[1] * t0) + t^2*(c[2] - t/ c[3] )
+;
+; Compute LST in hours.
+;
+ lst = ( theta + double(lng))/15.0d
+ neg = where(lst lt 0.0D0, n)
+ if n gt 0 then lst[neg] = 24.D0 + (lst[neg] mod 24)
+ lst = lst mod 24.D0
+;
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/curs.pro b/Code/script_idl_mv/astrolib/curs.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c6282e556311479431b95948912f42eccd4e7389
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/curs.pro
@@ -0,0 +1,135 @@
+pro curs, sel
+;+
+; NAME:
+; CURS
+; PURPOSE:
+; Selects an X windows cursor shape
+; CALLING SEQUENCE:
+; curs ;Interactively select a cursor shape.
+; curs, sel ;Make the given CURSOR_STANDARD value the cursor
+; shape.
+; OPTIONAL INPUT:
+; sel - Either an integer giving the CURSOR_STANDARD value (usually an
+; even value between 0 and 152) indicating the cursor shape, or
+; a string from the following menu
+; a -- Up arrow
+; b -- Left-angled arrow
+; c -- Right-angled arrow
+; d -- Crosshair
+; e -- Finger pointing left
+; f -- Finger pointing right
+; g -- Narrow crosshair
+; h -- Cycle through all possible standard cursor shapes
+;
+; The full list of available cursor values is given in
+; /usr/include/X11/cursorfont.h
+; OUTPUTS:
+; None.
+; RESTRICTIONS:
+; Uses the CURSOR_STANDARD keyword of the DEVICE procedure. Although
+; this keyword is available in Windows IDL, the values
+; used by this procedure are specific to the X windows device.
+;
+; PROCEDURE:
+; If the user supplies a valid cursor shape value, it is set. Otherwise,
+; an interactive command loop is entered; it will continue until a valid
+; value is given.
+; MODIFICATION HISTORY:
+; Converted to VAX 3100 workstations / IDL V2. M. Greason, STX, May 1990.
+; Avoid bad cursor parameter values W. Landsman February, 1991
+; Don't change value of input param W. Landsman August 1995
+; Use SIZE(/TNAME) instead of DATATYPE() W. Landsman October 2001
+;-
+On_error,2
+if !D.NAME NE 'X' then message, $
+ 'ERROR - Requires an X-windows display, current device is ' + !D.NAME
+; Check parameter.
+;
+isel = indgen(76)*2
+nsel = n_elements(isel)
+;
+IF N_elements( sel ) EQ 0 THEN sel = 0
+;
+; Get the selection interactively, if not already
+; specified.
+;
+; Initialize.
+;
+mnu = [" a -- Up arrow", " b -- Left-angled arrow", $
+ " c -- Right-angled arrow", " d -- Crosshair", $
+ " e -- Finger pointing left", " f -- Finger pointing right", $
+ " g -- Narrow crosshair", $
+ " h -- Cycle through all possible standard cursor shapes", $
+ " i -- Enter cursor shape number directly", " j -- Quit"]
+nmnu = n_elements(mnu)
+fmt = "($,'Code ',I3,' ',I3,' of ',I3,' ')"
+IF size(sel,/TNAME) EQ 'STRING' then begin
+ cmd = strupcase(sel)
+ csel = -99
+ENDIF ELSE csel = sel
+;
+; While loop until a selection is made.
+;
+WHILE (csel LE 0) OR (csel GT isel[nsel-1]) DO BEGIN
+;
+; Get command.
+;
+if csel NE -99 then begin
+ print, "Cursor selection:"
+ print, " "
+ FOR i = 0, (nmnu-1) DO print, mnu[i]
+ print, " "
+ cmd = ''
+ read, "Enter the letter of the desired command: ",cmd
+endif
+;
+; Perform the command.
+;
+MENU: CASE strupcase(cmd) OF
+ 'A' : csel = 22 ; Up arrow
+ 'B' : csel = 132 ; Left arrow
+ 'C' : csel = 2 ; Right arrow
+ 'D' : csel = 34 ; X-hair.
+ 'E' : csel = 56 ; Left hand.
+ 'F' : csel = 58 ; Right hand.
+ 'G' : csel = 33 ; Narrow crosshair.
+ 'H' : BEGIN ; Cycle thru all cursors.
+ print, " "
+ print, " "
+ print, "Cycling through the possible cursors."
+ print, " "
+ print, "Strike the space bar to select, any other"
+ print, "key to reject."
+ print, " "
+ print, " "
+ scr_curmov, 0, 1
+ cont = 1
+ FOR i = 0, (nsel-1) DO BEGIN
+ IF cont THEN BEGIN
+ csel = isel[i]
+ print, format=fmt, csel, i+1, nsel
+ scr_curmov, 2, 31
+ device, cursor_standard=csel
+ IF get_kbrd(1) EQ ' ' THEN cont = 0
+ ENDIF
+ ENDFOR
+ END
+ 'I' : BEGIN ; Get # from user.
+ print, " "
+ print, " "
+ print, format="(A14,$)", "Enter cursor #"
+ read, csel
+ IF (csel LE 0) OR (csel GT isel[nsel-1]) THEN $
+ print, "Invalid entry."
+ END
+ 'J' : csel = 34 ; Quit. Set to X-hair.
+ ELSE : csel = 0 ; Invalid command.
+ ENDCASE
+ENDWHILE
+;
+; Set the cursor shape
+;
+device, cursor_standard=csel
+;
+RETURN
+END
diff --git a/Code/script_idl_mv/astrolib/curval.pro b/Code/script_idl_mv/astrolib/curval.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7dd13ba7abce9da084ef58083b5747b40c7571f2
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/curval.pro
@@ -0,0 +1,304 @@
+pro curval, hd, im, OFFSET = offset, ZOOM = zoom, Filename=Filename, ALT = alt
+;+
+; NAME:
+; CURVAL
+; PURPOSE:
+; Cursor controlled display of image intensities and astronomical coords
+; EXPLANATION
+; CURVAL displays different information depending whether the user
+; supplied an image array, and/or a FITS header array
+;
+; Note that in the usual truecolor mode, the byte intensity returned by
+; CURVAL does not correspond to the byte scaled image value but rather
+; returns the maximum value in each color gun.
+; CALLING SEQUENCE(S):
+; curval ;Display x,y and byte intensity (inten)
+;
+; curval, im ;Display x,y,inten, and also pixel value (from image array)
+;
+; curval, hdr, [ im, OFFSET= , ZOOM=, FILENAME=, ALT=]
+;
+; OPTIONAL INPUTS:
+; Hdr = FITS Header array
+; Im = Array containing values that are displayed. Any type.
+;
+; OPTIONAL KEYWORD INPUTS:
+; ALT - single character 'A' through 'Z' or ' ' specifying an alternate
+; astrometry system present in the FITS header. The default is
+; to use the primary astrometry or ALT = ' '. If /ALT is set,
+; then this is equivalent to ALT = 'A'. See Section 3.3 of
+; Greisen & Calabretta (2002, A&A, 395, 1061) for information about
+; alternate astrometry keywords.
+; OFFSET - 2 element vector giving the location of the image pixel (0,0)
+; on the window display. OFFSET can be positive (e.g if the
+; image is centered in a larger window) or negative (e.g. if the
+; only the central region of an image much larger than the window
+; is being displayed.
+; Default value is [0,0], or no offset.
+; ZOOM - Scalar specifying the magnification of the window with respect
+; to the image variable. Use, for example, if image has been
+; REBINed before display.
+; FILENAME = name of file to where CURVAL data can be saved.
+; Data will only be saved if left or center mouse button
+; are pressed.
+;
+; OUTPUTS:
+; None.
+;
+; SIDE EFFECTS:
+; X and Y values, etc., of the pixel under the cursor are constantly
+; displayed.
+; Pressing left or center mouse button prints a line of output, and
+; starts a new line.
+; Pressing right mouse button exits the procedure.
+; If the keyword FILENAME is defined, the date and time, and a heading
+; will be printed in the file before the data.
+;
+; PROCEDURES CALLED:
+; ADSTRING(), EXTAST, GSSSXYAD, RADEC, SXPAR(), UNZOOM_XY, XY2AD
+; REVISION HISTORY:
+; Written, K. Rhode, STX May 1990
+; Added keyword FILENAME D. Alexander June 1991
+; Don't write to Journal file W. Landsman March 1993
+; Use astrometry structure W. Landsman Feb 1994
+; Modified for Mac IDL I. Freedman April 1994
+; Allow for zoomed or offset image W. Landsman Mar 1996
+; Proper rounding of zoomed pixel values W. Landsman/R. Hurt Dec. 1997
+; Remove unneeded calls to obsolete !ERR W. Landsman December 2000
+; Replace remaining !ERR calls with !MOUSE.BUTTON W. Landsman Jan 2001
+; Allow for non-celestial (e.g. Galactic) coordinates W. Landsman Apr 2003
+; Work if RA/Dec reversed in CTYPE keyword W. Landsman Feb. 2004
+; Always call UNZOOM_XY for MOUSSE compatibility W. Landsman Sep. 2004
+; Added ALT keyword W. Landsman October 2004
+; Always test if offset/zoom supplied W. Landsman Feb 2008
+;-
+ On_error,2 ;if an error occurs, return to caller
+ compile_opt idl2
+
+
+ f_header = 0b ;True if a FITS header supplied
+ f_image = 0b ;True if an image array supplied
+ f_astrom = 0b ;True if FITS header contains astrometry
+ f_bscale = 0b ;True if FITS header contains BSCALE factors
+ f_imhd = 0b ;True if image array is in HD (1 parameter)
+ npar = N_params()
+ fileflag=0 ;True once left or middle mouse button pressed
+
+ if !D.WINDOW EQ -1 then begin
+ message,'ERROR - No image window active',/INF
+ return
+ endif
+
+
+if (!D.FLAGS and 256) EQ 256 then wshow,!D.WINDOW ;Bring active window to foreground
+
+; Print formats and header for different astrometry,image, BSCALE combinations
+
+ cr = string(13b)
+ line0 = ' X Y Byte Inten'
+ line1 = ' X Y Byte Inten Value'
+ line5 = ' X Y ByteInten Value Flux'
+
+ f0 = "($,a,i4,2x,i4,6x,i4)"
+ f1 = "($,a,i4,2x,i4,6x,i4,5x,a)"
+ f2 = "($,a,i4,2x,i4,6x,i4,7x,a,1x,a)"
+ f3 = "($,a,i4,2x,i4,2x,i4,7x,a,2x,a,1x,a,3x,e9.2)"
+ f4 = "($,a,i4,2x,i4,2x,i4,7x,a,1x,a,a)"
+ f5 = "($,a,i4,2x,i4,2x,i4,3x,a,5x,e9.2)"
+
+ g0 = "(a,i4,2x,i4,6x,i4)"
+ g1 = "(a,i4,2x,i4,6x,i4,5x,a)"
+ g2 = "(a,i4,2x,i4,6x,i4,7x,a,1x,a)"
+ g3 = "(a,i4,2x,i4,2x,i4,7x,a,2x,a,1x,a,3x,e9.2)"
+ g4 = "(a,i4,2x,i4,2x,i4,7x,a,2x,a,1x,a)"
+ g5 = "(a,i4,2x,i4,2x,i4,3x,a,5x,e9.2)"
+
+if (npar gt 0) then begin
+ type = size(hd)
+ if (npar eq 1) and (type[0] eq 2) then begin
+ f_image = 1b & f_imhd = 1b
+ imtype = type
+ endif else if (type[2] ne 7) or (type[0] ne 1) then begin
+ print,'Syntax options: CURVAL ;Display byte values'
+ print,' CURVAL, IM ;where IM is a 2-D image,'
+ print,' CURVAL, Hdr ;where Hdr is a FITS header,'
+ print,' or CURVAL, Hdr,IM'
+ return
+ endif else if (type[2] eq 7) and (type[0] eq 1) then f_header = 1b
+ if (npar eq 2) then begin
+ f_image = 1b & f_header = 1b
+ imtype = size(im)
+ if (imtype[0] lt 2) or $
+ (imtype[imtype[0]+2] ne imtype[1]*imtype[2]) then $
+ message,'Image array (second parameter) is not two dimensional.'
+ endif
+endif
+
+; Get information from the header
+
+ if f_header then begin
+
+ EXTAST, hd, astr, noparams, alt=alt ;Extract astrometry structure
+ if (noparams ge 0) then f_astrom = 1b
+
+ if f_image then begin
+ bscale = sxpar(hd,'BSCALE')
+ if (bscale ne 0) then begin
+ bzero = sxpar(hd,'BZERO')
+ bunit = sxpar(hd,'BUNIT', Count = N_Bunit)
+ if N_Bunit GE 1 then $
+ if f_astrom then line3 = line3 + '('+bunit+ ')' else $
+ line5 = line5 + '('+bunit+')'
+ f_bscale = 1b
+ endif
+ endif
+ endif
+
+; Determine if an offset or zoom supplied
+ unzoom = f_image or f_header or keyword_set(offset) or keyword_set(zoom)
+
+ if f_astrom GT 0 then begin
+ coord = strmid(astr.ctype,0,4)
+ coord = repchr(coord,'-',' ')
+ if (coord[0] EQ 'DEC ') or (coord[0] EQ 'ELAT') or $
+ (coord[0] EQ 'GLAT') then coord = rotate(coord,2)
+
+ line2 = ' X Y Byte Inten ' + coord[0] + ' ' +coord[1]
+ line3 = ' X Y ByteInten Value ' + coord[0] + ' ' + $
+ coord[1] + ' Flux'
+ line4 = ' X Y ByteInten Value ' + coord[0] + ' ' + $
+ coord[1]
+
+ sexig = strupcase(strmid(coord[0],0,4)) EQ 'RA '
+ endif
+
+ print,'Press left or center mouse button for new output line,'
+ print,'... right mouse button to exit.'
+
+; different print statements, depending on the parameters
+
+ case 1 of
+
+(f_image eq 0b) and (f_astrom eq 0b): begin
+ curtype = 0 & print, line0 & end ;No image or header info
+
+(f_image) and (f_astrom eq 0b) and (f_bscale eq 0b): begin
+ curtype = 1 & print,line1 & end ;Only image array supplied
+
+(f_image eq 0b) and (f_astrom) and (f_bscale eq 0b): begin
+ curtype = 2 & print,line2 & end ;Astrometry but no image array
+
+(f_image) and (f_astrom) and (f_bscale): begin
+ curtype =3 & print,line3 & end ;Image array + astrometry + BSCALE
+
+(f_image) and (f_astrom) and (f_bscale eq 0b): begin
+ curtype = 4 & print,line4 & end ;Image array +astrometry
+
+(f_image) and (f_astrom eq 0b) and (f_bscale): begin
+ curtype = 5 & print,line5 & end ;Image array + BSCALE
+
+endcase
+ if f_image then begin
+ dtype = imtype[imtype[0]+1]
+ if (dtype LT 4) or (dtype GE 12) then dfmt = '(I8)' else dfmt = '(G8.3)'
+ endif
+
+ LOOP: sv_err = !MOUSE.BUTTON
+ !MOUSE.BUTTON = 0
+ cursor,x,y,2,/DEVICE,/CHANGE
+ cr_err = !MOUSE.BUTTON
+
+ if cr_err EQ 4 then begin
+ print,' '
+ if fileflag then free_lun,lun
+ return
+
+ endif
+
+
+ x = x>0 & y = y>0
+ inten = fix(tvrd(x,y,1,1)) ; read the byte intensity
+
+ if unzoom then unzoom_xy,x,y,offset=offset,zoom=zoom
+
+ if f_astrom then begin
+
+ case strmid(astr.ctype[0],5,3) of
+ 'GSS': gsssxyad, astr, x, y, a, d
+ else: xy2ad, x, y, astr, a, d ; convert to ra and dec
+ endcase
+
+ if sexig then begin
+ str = adstring(a,d,2)
+ a = strmid(str,1,13)
+ d = strmid(str,14,13)
+ endif else begin
+ a = string(a,'(f10.2)') + ' '
+ d = string(d,'(f10.2)') + ' '
+ endelse
+ endif
+
+ x = round(x) & y = round(y)
+
+ if f_image then begin
+ if (x LT 0) or (x GE imtype[1]) or $
+ (y LT 0) or (y GE imtype[2]) then value = 0 else $
+ if f_imhd then value = hd[x,y] else value = im[x,y]
+ svalue = string(value,f=dfmt)
+ endif
+
+ if f_bscale then flux = bscale*value + bzero
+ case curtype of
+ 0: print,form=f0,cr,x,y,inten
+ 1: print,form=f1,cr,x,y,inten,svalue
+ 2: print,form=f2,cr,x,y,inten,a,d
+ 3: print,form=f3,cr,x,y,inten,svalue,a,d,flux
+ 4: print,form=f4,cr,x,y,inten,svalue,a,d
+ 5: print,form=f5,cr,x,y,inten,svalue,flux
+ endcase
+
+; Were left or center buttons been pressed?
+
+ if (cr_err GE 1) and (cr_err LE 3) and (cr_err NE sv_err) then begin
+ print,form="($,a)",string(10b) ; print a form feed
+ if keyword_set(filename) and (not fileflag) then begin ; open file & print table header to file
+ get_lun,lun
+ openw,lun,filename
+ printf,lun,'CURVAL: ',systime() ;print time and date to file
+ case 1 of ;different print statements for file, depending on parameters
+
+ (f_image eq 0b) and (f_astrom eq 0b) : begin
+ printf, lun, line0 & end ;No image or header info
+
+ (f_image) and (f_astrom eq 0b) and (f_bscale eq 0b) : begin
+ printf, lun, line1 & end ;Only image array supplied
+
+ (f_image eq 0b) and (f_astrom) and (f_bscale eq 0b) : begin
+ printf, lun, line2 & end ;Astrometry but no image array
+
+ (f_image) and (f_astrom) and (f_bscale) : begin
+ printf, lun, line3 & end ;Image array + astrometry + BSCALE
+
+ (f_image) and (f_astrom) and (f_bscale eq 0b) : begin
+ printf, lun, line4 & end ;Image array + astrometry
+
+ (f_image) and (f_astrom eq 0b) and (f_bscale) : begin
+ printf, lun, line5 & end ;Image array + BSCALE
+ endcase
+ fileflag=1
+ endif
+ if keyword_set(filename) then begin
+ case curtype of
+ 0: printf, lun, form=g0,'', x, y, inten
+ 1: printf, lun, form=g1,'', x, y, inten, svalue
+ 2: printf, lun, form=g2,'', x, y, inten, a, d
+ 3: printf, lun, form=g3,'', x, y, inten, svalue, a, d, flux
+ 4: printf, lun, form=g4,'', x, y, inten, svalue, a, d
+ 5: printf, lun, form=g5,'', x, y, inten, svalue, flux
+ endcase
+ endif
+ endif
+
+ goto,LOOP
+
+ end
diff --git a/Code/script_idl_mv/astrolib/dao_value.pro b/Code/script_idl_mv/astrolib/dao_value.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2aaa4aa4d528ebc794c070326eae11c3e65c9078
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dao_value.pro
@@ -0,0 +1,87 @@
+FUNCTION DAO_VALUE, XX, YY, GAUSS, PSF, DVDX, DVDY
+;+
+; NAME:
+; DAO_VALUE
+; PURPOSE:
+; Returns the value of a DAOPHOT point-spread function at a set of points.
+; EXPLANATION:
+; The value of the point-spread function is the sum of a
+; two-dimensional integral under a bivariate Gaussian function, and
+; a value obtained by interpolation in a look-up table. DAO_VALUE will
+; optionally compute the derivatives wrt X and Y
+;
+; CALLING SEQUENCE:
+; Result = DAO_VALUE( xx, yy, gauss, psf, [ dvdx, dvdy ] )
+;
+; INPUTS:
+; XX,YY - the real coordinates of the desired point relative
+; to the centroid of the point-spread function.
+; GAUSS - 5 element vector describing the bivariate Gaussian
+; GAUSS(0)- the peak height of the best-fitting Gaussian profile.
+; GAUSS(1,2) - x and y offsets from the centroid of the point-spread
+; function to the center of the best-fitting Gaussian.
+; GAUSS(3,4) - the x and y sigmas of the best-fitting Gaussian.
+; PSF - a NPSF by NPSF array containing the look-up table.
+;
+; OUTPUTS:
+; RESULT - the computed value of the point-spread function at
+; a position XX, YY relative to its centroid (which
+; coincides with the center of the central pixel of the
+; look-up table).
+;
+; OPTIONAL OUTPUTS:
+; DVDX,DVDY - the first derivatives of the composite point-spread
+; function with respect to x and y.
+;
+; NOTES
+; although the arguments XX,YY of the function DAO_VALUE
+; are relative to the centroid of the PSF, the function RINTER which
+; DAO_VALUE calls requires coordinates relative to the corner of the
+; array (see code).
+;
+; PROCEDURES CALLED:
+; DAOERF, RINTER()
+; REVISON HISTORY:
+; Adapted to IDL by B. Pfarr, STX, 11/17/87 from 1986 STSDAS version
+; of DAOPHOT
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ s = size(psf)
+ npsf = s[1]
+ half = float(npsf-1)/2
+
+ x = 2.*xx + half ;Initialize
+ y = 2.*yy + half
+
+; X and Y are the coordinates relative to the corner of the look-up table,
+; which has a half-pixel grid size.
+
+ if ( (min(x) LT 1.) or ( max(x) GT npsf-2.) or $
+ (min(y) LT 1.) or ( max(y) GT npsf-2.) ) then begin
+ message,'X,Y positions too close to edge of frame',/INF
+ return,xx*0
+ endif
+
+; Evaluate the approximating Gaussian.
+; Then add a value interpolated from the look-up table to the approximating
+; Gaussian. Since the lookup table has a grid size of one-half pixel in each
+; coordinate, the spatial derivatives must be multiplied by two to yield
+; the derivatives in units of ADU/pixel in the big frame.
+
+ if N_params() GT 4 then begin ;Compute derivatives?
+
+ DAOERF, xx, yy, gauss, e, pder
+ value = e + RINTER( psf, x, y, dfdx, dfdy)
+ dvdx = 2.*dfdx - pder[*,1]
+ dvdy = 2.*dfdy - pder[*,2]
+
+ endif else begin
+
+ DAOERF, xx, yy, gauss, e
+ value = e + RINTER(psf,x,y)
+
+ endelse
+
+ return, value
+
+ end
diff --git a/Code/script_idl_mv/astrolib/daoerf.pro b/Code/script_idl_mv/astrolib/daoerf.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1451e6948d58734717e4eaa84b46fe7153179e5
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/daoerf.pro
@@ -0,0 +1,58 @@
+pro daoerf,x,y,a,f,pder ;DAOphot ERRor function
+;+
+; NAME:
+; DAOERF
+; PURPOSE:
+; Calulates the intensity, and derivatives, of a 2-d Gaussian PSF
+; EXPLANATION:
+; Corrects for the finite size of a pixel by integrating the Gaussian
+; over the size of the pixel. Used in the IDL-DAOPHOT sequence.
+;
+; CALLING SEQUENCE:
+; DAOERF, XIN, YIN, A, F, [ PDER ]
+;
+; INPUTS:
+; XIN - input scalar, vector or array, giving X coordinate values
+; YIN - input scalar, vector or array, giving Y coordinate values, must
+; have same number of elements as XIN.
+; A - 5 element parameter array describing the Gaussian
+; A(0) - peak intensity
+; A(1) - X position of peak intensity (centroid)
+; A(2) - Y position of peak intensity (centroid)
+; A(3) - X sigma of the gaussian (=FWHM/2.345)
+; A(4) - Y sigma of gaussian
+;
+; OUTPUTS:
+; F - array containing value of the function at each (XIN,YIN)
+; The number of output elements in F and PDER is identical with
+; the number of elements in X and Y
+;
+; OPTIONAL OUTPUTS:
+; PDER - 2 dimensional array of size (NPTS,5) giving the analytic
+; derivative at each value of F with respect to each parameter A.
+;
+; REVISION HISTORY:
+; Written: W. Landsman October, 1987
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ norm = 2.506628275 ;norm = sqrt(2*!pi)
+ npts = N_elements(x)
+
+ u2 = (x[*] - a[1] + 0.5)/a[3] & u1 = (x[*] - a[1] - 0.5)/a[3]
+ v2 = (y[*] - a[2] + 0.5)/a[4] & v1 = (y[*] - a[2] - 0.5)/a[4]
+ fx = norm*a[3]*(gaussint(u2) - gaussint(u1))
+ fy = norm*a[4]*(gaussint(v2) - gaussint(v1))
+ f = a[0]*fx*fy
+ if N_params() le 4 then return ;Need partial derivatives ?
+
+ pder = fltarr(npts,5)
+ pder[0,0] = fx*fy
+ uplus = exp(-0.5*u2^2) & uminus = exp(-0.5*u1^2)
+ pder[0,1] = a[0]*fy*(-uplus + uminus)
+ vplus = exp(-0.5*v2^2) & vminus = exp(-0.5*v1^2)
+ pder[0,2] = a[0]*fx*(-vplus + vminus)
+ pder[0,3] = a[0]*fy*(fx/a[3] + u1*uminus - u2*uplus)
+ pder[0,4] = a[0]*fx*(fy/a[4] + v1*vminus - v2*vplus)
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/date.pro b/Code/script_idl_mv/astrolib/date.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2abd07f68f248324e96c5a53e7cd88883941ef49
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/date.pro
@@ -0,0 +1,75 @@
+FUNCTION DATE,YEAR,DAY
+;+
+; NAME:
+; DATE
+; PURPOSE:
+; Convert day-of-year to a DD-MMM-YYYY string
+;
+; CALLING SEQUENCE:
+; D_String = DATE(Year, day )
+;
+; INPUTS:
+; Year - Integer scalar specifying the year. If the year contains only
+; two digits, then it is assumed to indicate the number of
+; years after 1900.
+;
+; Day - Integer scalar giving number of days after Jan 0 of the
+; specified year. Can be larger than 366
+;
+; OUTPUTS:
+; D_String - String giving date in format '13-MAR-1986'
+;
+; RESTRICTIONS:
+; Will not work for years before 100 AD
+; EXAMPLE:
+; IDL> print, date(1997,279)
+; '6-Oct-1997'
+;
+; MODIFICATION HISTORY:
+; D.M. fecit 24 October,1983
+; Work for years outside of the 19th century W. Landsman September 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ IF day LE 0 THEN BEGIN
+ D_String = '%DATE-F-DAY.LE.ZERO'
+ ENDIF ELSE BEGIN
+ Last_Day = [31,59,90,120,151,181,212,243,273,304,334,365]
+ LD = [0,INTARR(11)+1]
+ Day_of_Year = Day
+ Months = 'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'
+
+; Every year that is exactly divisible by 4 is a leap year, except for years
+; that exactly divisible by 100; these centurial years are leap years only if
+; they are exactly divisible by 400.
+
+ IF Year LT 100 THEN Yr = Year + 1900 ELSE Yr = Year
+ Leap = (((Yr MOD 4) EQ 0) AND ((Yr MOD 100) NE 0)) $
+ OR ((Yr MOD 400) EQ 0)
+ N_Days = 365 + Leap
+
+ WHILE Day_of_Year GT N_Days DO BEGIN
+ Day_of_Year = Day_of_Year - N_Days
+ Yr = Yr + 1
+ Leap = (((Yr MOD 4) EQ 0) AND ((Yr MOD 100) NE 0)) $
+ OR ((Yr MOD 400) EQ 0)
+ N_Days = 365 + Leap
+ END
+
+ End_Date = '-' + STRTRIM(YR,2)
+
+ IF Leap THEN Last_Day = Last_Day + LD
+ Last_Month = Day_of_Year LE Last_Day
+ Where_LD = WHERE(Last_Month, N_Month)
+
+ IF N_Month EQ 12 THEN BEGIN
+ D_String = STRTRIM(Day_of_Year,2) + '-JAN' + End_Date
+ ENDIF ELSE BEGIN
+ LAST_Month = Where_LD[0]
+ Month = STRMID(Months,3*Last_Month,3)
+ Day_of_Month = Day_of_Year - Last_Day[Last_Month-1]
+ D_String = STRTRIM(Day_of_Month,2) + '-' + Month + End_Date
+ END
+ END
+
+ RETURN,D_String
+ END
diff --git a/Code/script_idl_mv/astrolib/date_conv.pro b/Code/script_idl_mv/astrolib/date_conv.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e34a46d70031c7c59fb167f697bd5d2fb546bbc1
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/date_conv.pro
@@ -0,0 +1,449 @@
+function date_conv,date,type, BAD_DATE = bad_date
+;+
+; NAME:
+; DATE_CONV
+; PURPOSE:
+; Procedure to perform conversion of dates to one of three possible formats.
+;
+; EXPLANATION:
+; The following date formats are allowed
+;
+; format 1: real*8 scalar encoded as:
+; year*1000 + day + hour/24. + min/24./60 + sec/24./60/60
+; where day is the day of year (1 to 366)
+; format 2: Vector encoded as:
+; date[0] = year (eg. 2005)
+; date[1] = day of year (1 to 366)
+; date[2] = hour
+; date[3] = minute
+; date[4] = second
+; To indicate a date only, set a negative hour.
+; format 3: string (ascii text) encoded as
+; DD-MON-YEAR HH:MM:SS.SS
+; (eg. 14-JUL-2005 15:25:44.23)
+; OR
+; YYYY-MM-DD HH:MM:SS.SS (ISO standard)
+; (eg. 1987-07-14 15:25:44.23 or 1987-07-14T15:25:44.23)
+;
+; OR
+; DD/MM/YY (pre-2000 option for FITS DATE keywords)
+; Time of day segment is optional in all of these.
+;
+; format 4: three element vector giving spacecraft time words
+; from a Hubble Space Telescope (HST) telemetry packet. Based on
+; total number of secs since midnight, JAN. 1, 1979
+;
+; format 5: Julian day. As this is also a scalar, like format 1,
+; the distinction between the two on input is made based on their
+; value. Numbers > 2300000 are interpreted as Julian days.
+;
+; CALLING SEQUENCE
+; results = DATE_CONV( DATE, TYPE )
+;
+; INPUTS:
+; DATE - input date in one of the possible formats. Must be scalar.
+; TYPE - type of output format desired. If not supplied then
+; format 3 (real*8 scalar) is used.
+; valid values:
+; 'REAL' - format 1
+; 'VECTOR' - format 2
+; 'STRING' - format 3
+; 'FITS' - YYYY-MM-DDTHH:MM:SS.SS'
+; 'JULIAN' - Julian date
+; 'MODIFIED' - Modified Julian date (JD-2400000.5)
+; TYPE can be abbreviated to the single character strings 'R',
+; 'V', 'S', 'F', 'J', and 'M'.
+; Nobody wants to convert TO spacecraft time (I hope!)
+; OUTPUTS:
+; The converted date is returned as the function value.
+; Output is -1 if date is unrecognisable.
+;
+; If the time of day is omitted from the input, it will also
+; be omitted from any output string (format STRING or FITS).
+; Note that date-only strings are allowed by the FITS standard.
+; For other output formats any missing time of day is set to
+; 00:00:00.0
+;
+; KEYWORD OUTPUTS
+;
+; BAD_DATE set to 1B if date is unrecognisable
+;
+; EXAMPLES:
+; IDL> print,date_conv('2006-03-13 19:58:00.00'),f='(f15.5)'
+; 2006072.83194
+; IDL> print,date_conv( 2006072.8319444d,'F')
+; 2006-03-13T19:58:00.00
+; IDL> print,date_conv( 2006072.8319444d,'V')
+; 2006.00 72.0000 19.0000 57.0000 59.9962
+; IDL> print,date_conv( 2006072.8319444d,'J'), f='(f15.5)'
+; 2453808.33194
+;
+;
+; HISTORY:
+; version 1 D. Lindler July, 1987
+; adapted for IDL version 2 J. Isensee May, 1990
+; Made year 2000 compliant; allow ISO format input jls/acc Oct 1998
+; DJL/ACC Jan 1998, Modified to work with dates such as 6-JAN-1996 where
+; day of month has only one digit.
+; DJL, Nov. 2000, Added input/output format YYYY-MM-DDTHH:MM:SS.SS
+; Replace spaces with '0' in output FITS format W.Landsman April 2006
+; Added Julian date capabilities on input and output. M.Perrin, July 2007
+; Removed spurious /WARN keyword to MESSAGE W.L. Feb 2012
+; ...and another /WARN; added BAD_DATE, drop spurious time-of-day
+; output from strings. J. P. Leahy July 2013
+; changed all /CONTINUE warning messages to /INFO: can be suppressed
+; by setting !QUIET = 1. J. P. Leahy July 2013
+;-
+;-------------------------------------------------------------
+;
+compile_opt idl2
+; data declaration
+;
+days = [0,31,28,31,30,31,30,31,31,30,31,30,31]
+months = [' ','JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT',$
+ 'NOV','DEC']
+;
+; set default type if not supplied
+;
+if N_params() lt 2 then type = 'REAL'
+;
+; Determine type of input supplied
+;
+s = size(date) & ndim = s[0] & datatype = s[ndim+1]
+if ndim gt 0 then begin ;vector?
+ if ndim gt 1 then goto,notvalid
+ if (s[1] ne 5) && (s[1] ne 3) then goto,notvalid
+ if (s[1] eq 5) then form = 2 else form = 4
+ end else begin ;scalar input
+ if datatype eq 0 then goto,notvalid
+ if datatype eq 7 then form = 3 $ ;string
+ else form = 1 ;numeric scalar
+end
+;
+; -----------------------------------
+;
+;*** convert input to year,day,hour,minute,second
+;
+; -----------------------------------
+case form of
+
+ 1: begin ;real scalar
+ ; The 'real' input format may be interpreted EITHER
+ ; a) if < 2300000
+ ; as the traditional 'real*8 encoded' format used by date_conv
+ ; b) if > 2300000
+ ; as a Julian Day Number
+ idate = long(date)
+ year = long(idate/1000)
+
+ if year lt 2300 then begin
+
+ ; if year is only 2 digits, assume 1900
+ if year lt 100 then begin
+ message,/INF, $
+ 'Warning: Year specified is only 2 digits, assuming 19xx'
+ year=1900+year
+ idate=1900000+idate
+ date=1900000.+date
+ end
+ day = idate - year*1000
+ fdate = date-idate
+ fdate = fdate*24.
+ hour = fix(fdate)
+ fdate = (fdate-hour)*60.0
+ minute = fix(fdate)
+ sec = float((fdate-minute)*60.0)
+
+ endif else begin
+ daycnv, date, year, mn, mndy, hr
+ ; convert from month/day to day of year
+ ; how many days PRECEED the start of each month?
+ YDAYS = [0,31,59,90,120,151,181,212,243,273,304,334,366]
+ LEAP = (((YeaR MOD 4) EQ 0) AND ((YeaR MOD 100) NE 0)) OR $
+ ((YeaR MOD 400) EQ 0)
+ IF LEAP THEN YDAYS[2:*] = YDAYS[2:*] + 1
+ day = ydays[mn-1]+mndy
+
+ hour = fix(hr)
+ fmin = (hr-hour)*60
+ minute = fix(fmin)
+ sec = float((fmin-minute)*60)
+ endelse
+ end
+
+ 2: begin ;vector
+ year = fix(date[0])
+;
+; if year is only 2 digits, assume 1900
+;
+ if year lt 100 then begin
+ message,/INF, $
+ 'Warning: Year specified is only 2 digits, assuming 19xx'
+ year=1900+year
+ end
+;
+ day = fix(date[1])
+ hour = fix(date[2])
+ minute = fix(date[3])
+ sec = float(date[4])
+ end
+
+ 3: begin ;string
+ temp = date
+;
+; check for old type of date, DD-MMM-YYYY
+;
+ test = STRPOS(temp,'-')
+ if test ge 0 && test le 2 then begin
+ day_of_month = fix(gettok(temp,'-'))
+ month_name = gettok(temp,'-')
+ year = fix(gettok(temp,' '))
+;
+; determine month number from month name
+;
+ month_name = strupcase(month_name)
+ for mon = 1,12 do begin
+ if month_name eq months[mon] then goto,found
+ end
+ message,/INFORMATIONAL, 'Invalid month name specified'
+ goto, notvalid
+;
+; check for new type of date, ISO: YYYY-MM-DD
+;
+ end else if strpos(temp,'-') eq 4 then begin
+ year = fix(gettok(temp,'-'))
+ month_name = gettok(temp,'-')
+ mon= FIX(month_name)
+ day_of_month=gettok(temp,' ')
+ if strlen(temp) eq 0 then begin
+ dtmp=gettok(day_of_month,'T')
+ temp=day_of_month
+ day_of_month=dtmp
+ end
+ day_of_month=fix(day_of_month)
+;
+; check for DD/MM/YY
+;
+ end else if STRPOS(temp,'/') eq 2 then begin
+ day_of_month = FIX(gettok(temp,'/'))
+ mon = FIX(gettok(temp,'/'))
+ year = 1900 + FIX(STRMID(temp,0,2))
+ end else goto, notvalid
+
+ found:
+ hour = gettok(temp,':')
+ hour = hour NE '' ? FIX(hour) : -1
+ minute = fix(gettok(temp,':'))
+ sec = float(strtrim(strmid(temp,0,5)))
+
+ IF (mon LT 1 || mon GT 12) THEN BEGIN
+ MESSAGE, /INFORMATIONAL, 'Invalid month specified'
+ goto, notvalid
+ ENDIF
+;
+; if year is only 2 digits, assume 1900
+;
+ if year lt 100 then begin
+ message,/INFORMATIONAL, $
+ 'Warning: Year specified is only 2 digits, assuming 19xx'
+ year=1900+year
+ end
+;
+;
+; convert to day of year from month/day_of_month
+;
+; correction for leap years
+;
+; if (fix(year) mod 4) eq 0 then days(2) = 29 ;add one to february
+ lpyr = ((year mod 4) eq 0) and ((year mod 100) ne 0) $
+ or ((year mod 400) eq 0)
+ if lpyr eq 1 then days[2] = 29 ; if leap year, add day to Feb.
+;
+;
+; compute day of year
+;
+ day = fix(total(days[0:mon-1])+day_of_month)
+ end
+
+ 4 : begin ;spacecraft time
+ SC = DOUBLE(date)
+ SC = SC + (SC LT 0.0)*65536. ;Get rid of neg. numbers
+;
+; Determine total number of secs since midnight, JAN. 1, 1979
+;
+ SECS = SC[2]/64 + SC[1]*1024 + SC[0]*1024*65536.
+ SECS = SECS/8192.0D0 ;Convert from spacecraft units
+;
+; Determine number of years
+;
+ MINS = SECS/60.
+ HOURS = MINS/60.
+ TOTDAYS = HOURS/24.
+ YEARS = TOTDAYS/365.
+ YEARS = FIX(YEARS)
+;
+; Compute number of leap years past
+;
+ LEAPYEARS = (YEARS+2)/4
+;
+; Compute day of year
+;
+ DAY = FIX(TOTDAYS-YEARS*365.-LEAPYEARS)
+;
+; Correct for case of being right at end of leapyear
+;
+ IF DAY LT 0 THEN BEGIN
+ DAY = DAY+366
+ LEAPYEARS = LEAPYEARS-1
+ YEARS = YEARS-1
+ END
+;
+; COMPUTE HOUR OF DAY
+;
+ TOTDAYS = YEARS*365.+DAY+LEAPYEARS
+ HOUR = FIX(HOURS - 24*TOTDAYS)
+ TOTHOURS = TOTDAYS*24+HOUR
+;
+; COMPUTE MINUTE
+;
+ MINUTE = FIX(MINS-TOTHOURS*60)
+ TOTMIN = TOTHOURS*60+MINUTE
+;
+; COMPUTE SEC
+;
+ SEC = SECS-TOTMIN*60
+;
+; COMPUTE ACTUAL YEAR
+;
+ YEAR = YEARS+79
+;
+; if year is only 2 digits, assume 1900
+;
+ if year lt 100 then begin
+ message, /INF, $
+ 'Warning: Year specified is only 2 digits, assuming 19xx'
+ year=1900+year
+ end
+;
+;
+; START DAY AT ONE AND NOT ZERO
+;
+ DAY++
+ END
+ENDCASE
+;
+; correction for leap years
+;
+ if form ne 3 then begin ;Was it already done?
+ lpyr = ((year mod 4) eq 0) && ((year mod 100) ne 0) $
+ || ((year mod 400) eq 0)
+ if lpyr eq 1 then days[2] = 29 ; if leap year, add day to Feb.
+ end
+;
+; check for valid day
+;
+ if (day lt 1) || (day gt total(days)) then begin
+ message, /INFORMATIONAL, $
+ 'ERROR -- There are only ' + strtrim(fix(total(days)),2) + $
+ ' days in year '+strtrim(year,2)
+ goto, notvalid
+ endif
+;
+; find month which day occurs
+;
+ day_of_month = day
+ month_num = 1
+ while day_of_month gt days[month_num] do begin
+ day_of_month = day_of_month - days[month_num]
+ month_num = month_num+1
+ end
+; ---------------------------------------
+;
+; ***** Now convert to output format
+;
+; ---------------------------------------
+;
+; is type a string
+;
+s = size(type)
+if (s[0] ne 0) or (s[1] ne 7) then $
+ message,'ERROR - Output type specification must be a string'
+;
+outcode = STRMID(STRUPCASE(type),0,1)
+IF (outcode EQ 'S' || outcode EQ 'F') && hour GE 0 THEN BEGIN
+ xsec = strmid(string(sec+100,'(f6.2)'),1,5)
+ if xsec EQ '60.00' then begin
+ minute = minute+1
+ xsec = '00.00'
+ endif
+ xminute = string(minute,'(i2.2)')
+ if xminute EQ '60' then begin
+ hour = hour+1
+ xminute = '00'
+ endif
+ tod = string(hour,'(i2.2)') + ':' +xminute + ':'+ xsec
+ENDIF
+
+case outcode of
+
+ 'V' : begin ;vector output
+ out = fltarr(5)
+ out[0] = year
+ out[1] = day
+ out[2] = hour > 0
+ out[3] = minute
+ out[4] = sec
+ end
+
+ 'R' : begin ;floating point scalar
+; if year gt 1900 then year = year-1900
+ out = sec/24.0d0/60./60. + minute/24.0d0/60. $
+ + (hour > 0)/24.0d0 + day + year*1000d0
+ end
+
+ 'S' : begin ;string output
+
+ month_name = months[month_num]
+;
+; encode into ascii_date
+;
+ out = string(day_of_month,'(i2)') +'-'+ month_name +'-' + $
+ string(year,'(i4)')
+
+ ; Omit time of day from output string if not specified on input
+ IF hour GE 0 THEN out += ' '+tod
+ end
+ 'F' : begin
+ out = string(year,'(i4)')+'-'+string(month_num,'(I2.2)') $
+ + '-' + string(day_of_month,'(i2.2)')
+ IF hour GE 0 THEN out += 'T' + tod
+ end
+
+ 'J' : begin ; Julian Date
+ ydn2md, year, day, mn, dy
+ juldate, [year, mn, dy, hour, minute, sec], rjd
+ out = rjd+2400000 ; convert from reduced to regular JD
+ end
+ 'M' : begin ; Modified Julian Date = JD - 2400000.5
+ ydn2md, year, day, mn, dy
+ juldate, [year, mn, dy, hour, minute, sec], rjd
+ out = rjd-0.5 ; convert from reduced to modified JD
+ end
+
+ else: begin ;invalid type specified
+ print,'DATE_CONV-- Invalid output type specified'
+ print,' It must be ''REAL'', ''STRING'', ''VECTOR'', ''JULIAN'', ''MODIFIED'', or ''FITS''.'
+ return,-1
+ end
+endcase
+
+bad_date = 0B
+return,out
+;
+; invalid input date error section
+;
+NOTVALID:
+bad_date = 1B
+message, 'Invalid input date specified', /INFORMATIONAL
+return, -1
+end
diff --git a/Code/script_idl_mv/astrolib/daycnv.pro b/Code/script_idl_mv/astrolib/daycnv.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d0f79583ace4f5a20c7c11728e23fa14f711c004
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/daycnv.pro
@@ -0,0 +1,73 @@
+PRO DAYCNV, XJD, YR, MN, DAY, HR
+;+
+; NAME:
+; DAYCNV
+; PURPOSE:
+; Converts Julian dates to Gregorian calendar dates
+;
+; EXPLANATION:
+; Duplicates the functionality of the intrinsic JUL2GREG procedure
+; which was introduced in V8.2.1
+; CALLING SEQUENCE:
+; DAYCNV, XJD, YR, MN, DAY, HR
+;
+; INPUTS:
+; XJD = Julian date, positive double precision scalar or vector
+;
+; OUTPUTS:
+; YR = Year (Integer)
+; MN = Month (Integer)
+; DAY = Day (Integer)
+; HR = Hours and fractional hours (Real). If XJD is a vector,
+; then YR,MN,DAY and HR will be vectors of the same length.
+;
+; EXAMPLE:
+; IDL> DAYCNV, 2440000.D, yr, mn, day, hr
+;
+; yields yr = 1968, mn =5, day = 23, hr =12.
+;
+; WARNING:
+; Be sure that the Julian date is specified as double precision to
+; maintain accuracy at the fractional hour level.
+;
+; METHOD:
+; Uses the algorithm of Fliegel and Van Flandern (1968) as reported in
+; the "Explanatory Supplement to the Astronomical Almanac" (1992), p. 604
+; Works for all Gregorian calendar dates with XJD > 0, i.e., dates after
+; -4713 November 23.
+; REVISION HISTORY:
+; Converted to IDL from Yeoman's Comet Ephemeris Generator,
+; B. Pfarr, STX, 6/16/88
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() lt 2 then begin
+ print,"Syntax - DAYCNV, xjd, yr, mn, day, hr'
+ print,' Julian date, xjd, should be specified in double precision'
+ return
+ endif
+
+; Adjustment needed because Julian day starts at noon, calendar day at midnight
+
+ jd = long(xjd) ;Truncate to integral day
+ frac = double(xjd) - jd + 0.5 ;Fractional part of calendar day
+ after_noon = where(frac ge 1.0, Next)
+ if Next GT 0 then begin ;Is it really the next calendar day?
+ frac[after_noon] = frac[after_noon] - 1.0
+ jd[after_noon] = jd[after_noon] + 1
+ endif
+ hr = frac*24.0
+ l = jd + 68569
+ n = 4*l / 146097l
+ l = l - (146097*n + 3l) / 4
+ yr = 4000*(l+1) / 1461001
+ l = l - 1461*yr / 4 + 31 ;1461 = 365.25 * 4
+ mn = 80*l / 2447
+ day = l - 2447*mn / 80
+ l = mn/11
+ mn = mn + 2 - 12*l
+ yr = 100*(n-49) + yr + l
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/db_ent2ext.pro b/Code/script_idl_mv/astrolib/db_ent2ext.pro
new file mode 100644
index 0000000000000000000000000000000000000000..987424df45a24fb687a0d1294e0d39dac0c26559
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_ent2ext.pro
@@ -0,0 +1,121 @@
+ PRO DB_ENT2EXT, ENTRY
+;+
+; NAME:
+; DB_ENT2EXT
+; PURPOSE:
+; Convert a database entry to external (IEEE) data format
+; EXPLANATION:
+; Converts a database entry to external (IEEE) data format prior to
+; writing it. Called from DBWRT.
+;
+; CALLING SEQUENCE:
+; DB_ENT2EXT, ENTRY
+;
+; INPUTS:
+; ENTRY = Byte array containing a single record to be written to the
+; database file.
+;
+; OUTPUTS:
+; ENTRY = The converted array is returned in place of the input array.
+;
+; COMMON BLOCKS:
+; DB_COM
+;
+; HISTORY:
+; Version 1, William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Version 2, William Thompson, GSFC/CDS (ARC), 15 September 1995
+; Fixed bug where only the first element in a
+; multidimensional array was converted.
+; Version 2.1 W. Landsman August 2010 Fix for multidimensional strings
+; Version 2.2 W. Landsman Sep 2011 Work with new DB format
+;-
+;
+ ON_ERROR,2
+ COMPILE_OPT IDL2
+;
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2)
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .dbx file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 119 True if database is in external (IEEE) data format
+;
+; QITEMS[*,i] contains description of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; 24-25 Starting byte position in original DBF record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Print field length
+; 100 Flag set to one if pointer item
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+;
+;
+; QLINK[i] contains the entry number in the second data base
+; corresponding to entry i in the first data base.
+;
+ COMMON DB_COM,QDB,QITEMS,QLINK
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE, 'Syntax: DB_ENT2EXT, ENTRY'
+;
+; Get some information on the data base.
+;
+ LEN = DB_INFO( 'LENGTH', 0 ) ;Record length
+ N_ITEMS = DB_INFO( 'ITEMS', 0 ) ;Number of items
+;
+; Determine if ENTRY is correct.
+;
+ S = SIZE(ENTRY)
+ IF S[0] NE 1 THEN MESSAGE, 'ENTRY must be a 1-dimensional array'
+ IF S[1] NE LEN THEN MESSAGE, $
+ 'ENTRY not the proper length of ' + STRTRIM(LEN,2) + ' bytes'
+ IF S[2] NE 1 THEN MESSAGE, 'ENTRY must be a byte array'
+;
+; Extract information about the individual items.
+;
+ newdb = qdb[118, 0]
+
+ IDLTYPE = FIX(QITEMS[20:21,*],0,N_ITEMS)
+ NVALUES = NEWDB ? LONG(QITEMS[179:182,*],0,N_ITEMS) : $
+ FIX(QITEMS[22:23,*],0,N_ITEMS)
+ SBYTE = NEWDB ? LONG(QITEMS[183:186,*],0,N_ITEMS) : $
+ FIX(QITEMS[24:25,*],0,N_ITEMS)
+ NBYTES = FIX(QITEMS[26:27,*],0,N_ITEMS)*NVALUES
+ BSWAP = (IDLTYPE NE 7) AND (IDLTYPE NE 1)
+;
+; For each entry, convert the data into external format.
+;
+ FOR I = 0, N_ITEMS-1 DO BEGIN
+ IF BSWAP[I] THEN BEGIN
+
+ ITEM = DBXVAL(ENTRY,IDLTYPE[I],NVALUES[I],SBYTE[I],NBYTES[I])
+ SWAP_ENDIAN_INPLACE, ITEM, /SWAP_IF_LITTLE
+ DBXPUT, ITEM, ENTRY, IDLTYPE[I], SBYTE[I], NBYTES[I]
+ ENDIF
+ ENDFOR
+;
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/db_ent2host.pro b/Code/script_idl_mv/astrolib/db_ent2host.pro
new file mode 100644
index 0000000000000000000000000000000000000000..522495028b2a18239b62381550bd3becce0bb566
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_ent2host.pro
@@ -0,0 +1,134 @@
+ PRO DB_ENT2HOST, ENTRY, DBNO
+;+
+; NAME:
+; DB_ENT2HOST
+; PURPOSE:
+; Converts a database entry from external data format to host format.
+; EXPLANATION:
+; All items are extracted from the entry, and then converted to host
+; format, and placed back into the entry. Called from DBRD and DBEXT_DBF.
+;
+; CALLING SEQUENCE:
+; DB_ENT2HOST, ENTRY, DBNO
+;
+; INPUTS:
+; ENTRY = Byte array containing a single record read from the
+; database file.
+; DBNO = Number of the opened database file.
+;
+; OUTPUTS:
+; ENTRY = The converted array is returned in place of the input array.
+;
+; COMMON BLOCKS:
+; DB_COM
+;
+; HISTORY:
+; Version 1, William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Version 2, William Thompson, GSFC/CDS (ARC), 15 September 1995
+; Fixed bug where only the first element in a
+; multidimensional array was converted.
+; Version 3, Richard Schwartz, GSFC/SDAC, 23 August 1996
+; Allow 2 dimensional byte arrays for entries to facilitate
+; multiple entry processing. Pass IDLTYPE onto IEEE_TO_HOST
+; Version 4, 2 May 2003, W. Thompson
+; Use BSWAP keyword to DBXVAL instead of calling IEEE_TO_HOST.
+; Version 4.1 W. Landsman August 2010 Fix for multidimensional strings
+; Version 4.2 W. Landsman Sep 2011 Work with new DB format
+;-
+;
+ ON_ERROR,2
+ COMPILE_OPT IDL2
+;
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2)
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .dbx file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 119 True if database is in external (IEEE) data format
+;
+; QITEMS[*,i] contains description of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; 24-25 Starting byte position in original DBF record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Print field length
+; 100 Flag set to one if pointer item
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+;
+;
+; QLINK[i] contains the entry number in the second data base
+; corresponding to entry i in the first data base.
+;
+ COMMON DB_COM,QDB,QITEMS,QLINK
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN MESSAGE, 'Syntax: DB_ENT2HOST, ENTRY, DBNO'
+;
+; Get some information on the data base.
+;
+ LEN = DB_INFO( 'LENGTH', DBNO ) ;Record length
+ N_ITEMS = DB_INFO( 'ITEMS', DBNO ) ;Number of items
+;
+; Determine if ENTRY is correct.
+;
+ S = SIZE(ENTRY)
+ IF S[0] GT 2 THEN MESSAGE, 'ENTRY must be a 1 or 2-dimensional array'
+ IF S[1] NE LEN THEN MESSAGE, $
+ 'ENTRY not the proper length of ' + STRTRIM(LEN,2) + ' bytes'
+ IF S[2] NE 1 THEN MESSAGE, 'ENTRY must be a byte array'
+;
+; Find out which items belong to the database given by DBNO.
+;
+ N = (SIZE(QITEMS))[2] ;Number of items in combined database.
+ DB_NUM = FIX(QITEMS[173:174,*],0,N)
+ W = WHERE(DB_NUM EQ DBNO, COUNT)
+ IF COUNT NE N_ITEMS THEN MESSAGE, $
+ 'Database inconsistency--problem with number of items'
+;
+; Extract information about the individual items.
+;
+ newdb = qdb[118, 0]
+ IDLTYPE = FIX(QITEMS[20:21,*],0,N) & IDLTYPE = IDLTYPE[W]
+ NVALUES = NEWDB ? LONG(QITEMS[179:182,*],0,N) : $
+ FIX(QITEMS[22:23,*],0,N) & NVALUES = NVALUES[W]
+ SBYTE = NEWDB ? LONG(QITEMS[183:186,*],0,N) : $
+ FIX(QITEMS[24:25,*],0,N) & SBYTE = SBYTE[W]
+ NBYTES = FIX(QITEMS[26:27,*],0,N) & NBYTES = NBYTES[W]
+ BSWAP = (IDLTYPE NE 7) AND (IDLTYPE NE 1)
+;
+; For each entry, convert the data into external format.
+;
+ FOR I = 0, N_ITEMS-1 DO BEGIN
+ NB = NBYTES[I]*NVALUES[I]
+ ITEM = DBXVAL(ENTRY,IDLTYPE[I],NVALUES[I],SBYTE[I],NB,$
+ BSWAP = BSWAP[I])
+
+ DBXPUT, ITEM, ENTRY, IDLTYPE[I], SBYTE[I], NB
+ ENDFOR
+
+;
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/db_info.pro b/Code/script_idl_mv/astrolib/db_info.pro
new file mode 100644
index 0000000000000000000000000000000000000000..77d0dd88991a5b26c3b4c65e065391486ccd7785
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_info.pro
@@ -0,0 +1,218 @@
+function db_info,request,dbname
+;+
+; NAME:
+; DB_INFO
+; PURPOSE:
+; Function to obtain information on opened data base file(s)
+;
+; CALLING SEQUENCES:
+; 1) result = db_info(request)
+; 2) result = db_info(request,dbname)
+; INPUTS (calling sequence 1):
+;
+; request - string specifying requested value(s)
+; value of request value returned in result
+; 'open' Flag set to 1 if data base(s) are opened
+; 'number' Number of data base files opened
+; 'items' Total number of items (all db's opened)
+; 'update' update flag (1 if opened for update)
+; 'unit_dbf' Unit number of the .dbf files
+; 'unit_dbx' Unit number of the .dbx files
+; 'entries' Number of entries in the db's
+; 'length' Record lengths for the db's
+; 'external' True if the db's are in external format
+;
+; INPUTS (calling sequence 2):
+;
+; request - string specifying requested value(s)
+; value of request value returned in result
+; 'name' Name of the data base
+; 'number' Sequential number of the db
+; 'items' Number of items for this db
+; 'item1' Position of item1 for this db
+; in item list for all db's
+; 'item2' Position of last item for this db.
+; 'pointer' Number of the item which points
+; to this db. 0 for first or primary
+; db. -1 if link file pointers.
+; 'length' Record length for this db.
+; 'title' Title of the data base
+; 'unit_dbf' Unit number of the .dbf file
+; 'unit_dbx' Unit number of the .dbx file
+; 'entries' Number of entries in the db
+; 'seqnum' Last sequence number used
+; 'alloc' Allocated space (# entries)
+; 'update' 1 if data base opened for update
+; 'external' True if data base in external format
+; 'newdb' True if new (post Oct 2010) format
+; that allows entries > 32767 bytes
+;
+; dbname - data base name or number
+; OUTPUTS:
+; Requested value(s) are returned as the function value.
+;
+; HISTORY:
+; version 1 D. Lindler Oct. 1987
+; changed type from 1 to 7 for IDLV2, J. Isensee, Nov., 1990
+; William Thompson, GSFC/CDS (ARC), 30 May 1994
+; Added EXTERNAL request type.
+; Support new DB format, add NEWDB request type W. Landsman Oct 2010
+;-
+;------------------------------------------------------------------------
+on_error,2 ;Return to caller
+;
+; data base common block
+;
+common db_com,QDB,QITEMS,QLINK
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2), old format
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .dbx file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 105-108 record length of DBF file (integer*4), new format
+; 119 True if database is in external (IEEE) format
+;
+; QITEMS[*,i] contains deacription of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; 24-25 Starting byte position in original DBF record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Print field length
+; 100 Flag set to one if pointer item
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD, old format
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+; 177-178 Item number within the specific data base
+; 179-182 Number of values for item (1 for scalar) (integer*4)
+; 183-186 Starting byte position in original DBF record (integer*4)
+; 187-190 Starting byte in record returned by DBRD
+;
+;
+; QLINK[i] contains the entry number in the second data base
+; corresponding to entry i in the first data base.
+;-------------------------------------------------------------------------
+;
+req=strtrim(strupcase(request)) ;requested value
+s=size(qdb)
+if req eq 'OPEN' then begin
+ if s[0] eq 0 then return,0 else return,1
+end
+if s[0] eq 0 then message,'No data base file(s) opened'
+n=s[2] ;number of data bases
+;
+; calling sequence 1 result=db_info(request)
+;
+newdb = qdb[118,0]
+if N_params() lt 2 then begin
+ case req of
+ 'NUMBER' : return,n ;number of files opened
+ 'ITEMS' : begin ;total number of items
+ s=size(qitems)
+ return,s[2]
+ end
+ 'LENGTH' : begin
+ len = newdb ? long( qdb[105:108,*],0,n) : $
+ fix(qdb[82:83,*],0,n)
+ return,len
+ end
+ ;total record length
+ 'UPDATE' : return,qdb[104,0] ;update flag
+ 'UNIT_DBF' : return,qdb[96,*] ;.dbf unit number
+ 'UNIT_DBX' : return,qdb[97,*] ;.dbx unit number
+ 'ENTRIES' : return,long(qdb[84:87,*],0,n) ;number of entries
+ 'EXTERNAL' : return,qdb[119,*] eq 1 ;external format?
+ 'NEWDB' : return, newdb ;New db format?
+ else : message,'Invalid request for information'
+ endcase
+endif
+;
+; second calling sequence: result=db_info(request,dbname) ----------
+;
+s=size(dbname)
+ndim=s[0]
+type=s[ndim+1]
+if (ndim gt 0) || (type eq 0) then goto,abort
+;
+; convert name to number
+;
+if type eq 7 then begin
+ db_name=strtrim(strupcase(dbname))
+ for i=0,n-1 do $
+ if db_name eq strtrim(string(qdb[0:18,i])) then goto,found
+ goto,abort ;not found
+found: dbnum=i
+ end else begin ;number supplied
+ dbnum=fix(dbname)
+ if (dbnum lt 0) || (dbnum ge n) then goto,abort
+end
+newdb = qdb[118,dbnum]
+
+case req of
+ 'NAME' : return,strtrim(string(qdb[0:18,dbnum])) ;db name
+ 'NUMBER' : return,dbnum ;data base number
+ 'ITEMS' : begin ;number of items
+ x=fix(qdb[80:81,dbnum],0,1)
+ return,x[0]
+ end
+ 'ITEM1' : begin ;starting item number
+ x=fix(qdb[88:89,dbnum],0,1)
+ return,x[0]
+ end
+ 'ITEM2' : begin ;last item number
+ x=fix(qdb[90:91,dbnum],0,1)
+ return,x[0]
+ end
+ 'POINTER' : begin ;item number pointer
+ x=fix(qdb[98:99,dbnum],0,1)
+ return,x[0]
+ end
+ 'LENGTH' : begin
+ x = newdb ? long(qdb[105:108,dbnum],0,1) : $ ;record length
+ fix(qdb[82:83,dbnum],0,1)
+ return,long(x[0])
+ end
+ 'TITLE' : return,strtrim(string(qdb[19:79,dbnum])) ;data base title
+ 'UNIT_DBF' : return,qdb[96,dbnum] ;.dbf unit number
+ 'UNIT_DBX' : return,qdb[97,dbnum] ;.dbx unit number
+ 'ENTRIES' : begin ;number of entries
+ x=long(qdb[84:87,dbnum],0,1)
+ return,x[0]
+ end
+ 'SEQNUM' : begin ;last sequence number
+ x=long(qdb[92:95,dbnum],0,1)
+ return,x[0]
+ end
+ 'ALLOC' : begin ;allocated size
+ x=long(qdb[100:103,dbnum],0,1)
+ return,x[0]
+ end
+ 'UPDATE' : return,qdb[104,dbnum] ;update flag
+ 'EXTERNAL' : begin ;External format?
+ x=qdb[119,*] eq 1
+ return,x[0]
+ end
+ 'NEWDB' : return, newdb ;New db format?
+ else: message,'Invalid information request'
+endcase
+abort: message,'Invalid data base name or number supplied'
+end
diff --git a/Code/script_idl_mv/astrolib/db_item.pro b/Code/script_idl_mv/astrolib/db_item.pro
new file mode 100644
index 0000000000000000000000000000000000000000..626dc071568f4b3687f94edd5bae10999433dc21
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_item.pro
@@ -0,0 +1,347 @@
+pro db_item,items,itnum,ivalnum,idltype,sbyte,numvals,nbytes,errmsg=errmsg
+;+
+; NAME:
+; DB_ITEM
+; PURPOSE:
+; Returns the item numbers and other info. for an item name.
+; EXPLANATION:
+; Procedure to return the item numbers and other information
+; of a specified item name
+;
+; CALLING SEQUENCE:
+; db_item, items, itnum, ivalnum, idltype, sbyte, numvals, nbytes
+;
+; INPUTS:
+; items - item name or number
+; form 1 scalar string giving item(s) as list of names
+; separated by commas
+; form 2 string array giving list of item names
+; form 3 string of form '$filename' giving name
+; of text file containing items (one item per
+; line)
+; form 4 integer scalar giving single item number or
+; integer vector list of item numbers
+; form 5 Null string specifying interactive selection
+; Upon return items will contain selected items
+; in form 1
+; form 6 '*' select all items
+;
+; OUTPUTS:
+; itnum - item number
+; ivalnum - value(s) number from multiple valued item
+; idltype - data type(s) (1=string,2=byte,4=i*4,...)
+; sbyte - starting byte(s) in entry
+; numvals - number of data values for item(s)
+; It is the full length of a vector item unless
+; a subscript was supplied
+; nbytes - number of bytes for each value
+; All outputs are vectors even if a single item is requested
+;
+; OPTIONAL INPUT KEYWORDS:
+; ERRMSG = If defined and passed, then any error messages will
+; be returned to the user in this parameter rather than depending
+; on the MESSAGE routine in IDL. If no errors are encountered,
+; then a null string is returned. In order to use this feature,
+; ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; DB_ITEM, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; PROCEDURE CALLS:
+; DB_INFO, GETTOK, SELECT_W
+;
+; REVISION HISTORY:
+; Written: D. Lindler, GSFC/HRS, October 1987
+; Version 2, William Thompson, GSFC, 17-Mar-1997
+; Added keyword ERRMSG
+; Use STRSPLIT instead of GETTOK to parse form 1, W. Landsman July 2002
+; Assume since V5.4 use FILE_EXPAND_PATH() instead of SPEC_DIR()
+; W. Landsman April 2006
+; Support new DB format allowing entry lengths > 32767 bytes WL Oct 2010
+; Ignore blank lines in .items file WL February 2011
+;-
+;
+;------------------------------------------------------------------------
+ compile_opt idl2
+ On_error,2
+ if N_params() LT 2 then begin
+ print,'Syntax - DB_ITEM,items,itnum,ivalnum,idltype,sbyte,numvals,nbytes'
+ return
+ endif
+; data base common block
+;
+common db_com,QDB,QITEMS,QLINK
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2) old DB format
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .dbx file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 105-108 record length of DBF file (integer*4)
+; 118 Equals 1 if database can store records larger than 32767 bytes
+; 119 Equals 1 if external data representation (IEEE) is used
+;
+; QITEMS[*,i] contains a description of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; 24-25 Starting byte position in original DBF record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Print field length
+; 100 Flag set to one if pointer item
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD, old DB format
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+; 177-178 Item number within the specific data base
+; 179-182 Number of values for item (1 for scalar) (integer*4)
+; 183-186 Starting byte position in original DBF record (integer*4)
+; 187-190 Starting byte in record returned by DBRD
+;
+;
+; QLINK[i] contains the entry number in the second data base
+; corresponding to entry i in the first data base.
+;-------------------------------------------------------------------------
+if n_elements(items) eq 0 then items = ''
+;
+; check if data base open
+;
+if n_elements(qdb) lt 120 then begin
+ message = 'data base file not open'
+ goto, handle_error
+endif
+
+;
+; determine type of item list -------------------------------------------
+;
+vector=1 ;vector output flag
+newdb = qdb[118,0] EQ 1
+s=size(items,/str)
+ndim = s.n_dimensions
+if s.type_name eq 'STRING' then begin ;string(s)
+ if ndim eq 0 then begin ;string scalar?
+ if strtrim(items) eq '' then form=5 else $ ;null string - form 5
+ if strmid(items,0,1) eq '$' then form=3 $ ;filename - form 3
+ else form=1 ;scalar list - form 1
+ if strtrim(items) eq '*' then form=6 ;all items '*' - form 6
+ end else form=2 ;string vector - form 2
+ end else begin ;non-string
+ form=4 ;integer - form 4
+end
+s=size(qitems)
+if s[0] ne 2 then begin
+ message = 'No data base opened'
+ goto, handle_error
+endif
+qnumit=s[2]
+
+;-----------------------------------------------------------------------------
+; CONVERT INPUT ITEMS TO INTEGER LIST OR STRING LIST
+;
+;
+; Form 4 ------------------ Integer
+;
+If form eq 4 then begin
+ if ndim eq 0 then begin
+ itnum=intarr(1)+items
+ ivalnum=intarr(1)
+ ivalflag=intarr(1)
+ goto,scalar ;speedy method
+ end else begin
+ itnum=items
+ nitems=n_elements(itnum)
+ ivalflag=bytarr(nitems)
+ ivalnum=intarr(nitems)
+ if (min(itnum) lt 0) or (max(itnum) ge qnumit) then begin
+ message = 'Invalid item number specified'
+ goto, handle_error
+ endif
+ goto,vector
+ end
+end
+
+;
+; Form 3 ----------------- File name
+;
+if form eq 3 then begin
+ item_names=strarr(200) ;input buffer
+ if strlen(items) gt 1 then filename=strmid(items,1,strlen(items)-1) $
+ else filename=strtrim(db_info('name',0))+'.items'
+ if ~file_test(filename) then begin
+ message = 'Unable to locate file ' + FILE_EXPAND_PATH(filename) + $
+ ' with item list'
+ goto, handle_error
+ endif
+ nlines = file_lines(filename)
+ item_names = strarr(nlines)
+ openr,unit,filename,/get_lun ;open file
+ readf,unit,item_names
+ free_lun,unit
+ item_names = strtrim(item_names,2)
+; Remove any blank lines
+ good = where(strlen(item_names) GT 0, Nitems)
+ if Nitems LT Nlines then item_names = item_names[good]
+end
+;
+; form 1 ----------------- scalar string list 'item1,item2,item3...'
+;
+ if form eq 1 then begin
+ item_names = strsplit(items,',',/EXTRACT)
+ nitems = N_elements(item_names)
+ endif
+;
+; form 2 -------------------------- string array
+;
+if form eq 2 then begin
+ item_names=items
+ nitems = N_elements(items)
+endif
+;
+; form 5 -------------------------- null string (interactive input)
+;
+if form eq 5 then begin
+ names=strtrim(qitems[0:19,*],2)
+ desc=string(qitems[29:78,*])
+ select_w,names,itnum,desc,'Select List of Items',count=count
+ if count le 0 then begin
+ message = 'No items selected'
+ goto, handle_error
+ endif
+;
+ nitems=n_elements(itnum)
+ items = strtrim(names[itnum[0]],2)
+ if nitems gt 1 then for i=1,nitems-1 do $
+ items = items +','+strtrim(names[itnum[i]],2)
+ ivalflag=bytarr(nitems)
+ ivalnum=intarr(nitems)
+ goto,vector
+end
+;
+; Form 4 ------------------ '*' select all items
+;
+If form eq 6 then begin
+ nitems=db_info('items') ;number of items
+ itnum=indgen(nitems)
+ ivalflag=bytarr(nitems)
+ ivalnum=intarr(nitems)
+ goto,vector
+end
+;
+;-------------------------------------------------------------------------
+; CONVERT STRING LIST TO INTEGER LIST AND PULL OFF SUBSCRIPT IF SUPPLIED
+;
+;
+ names=strtrim(qitems[0:19,*],2) ;all possible item names
+ ivalnum=intarr(nitems) ;selection of multi-value items
+ ivalflag=bytarr(nitems) ;Flag for subscripted items
+ itnum=intarr(nitems) ;integer item numbers
+;
+; loop on item names supplied
+;
+ for i=0,nitems-1 do begin ;loop on items
+ st=strtrim(item_names[i],2) ;get item
+ name=gettok(st,'(') ;get name
+;
+; subscript supplied
+;
+ if st ne '' then begin ;number supplied?
+ ivalnum[i]=fix(gettok(st,')')) ;get number
+ ivalflag[i]=1
+ end;
+;
+; data base name supplied
+;
+ if strpos(name,'.') ge 0 then begin ;data base name supplied
+ dbname=gettok(name,'.') ; form is 'dbname.itemname'
+ i1=db_info('item1',dbname) ;first item for the db
+ i2=db_info('item2',dbname) ;last item for the db
+ end else begin ;search all items
+ i1=0 & i2=qnumit-1
+ end
+;
+; search for item name
+;
+ name=strupcase(name) ;convert to upper case
+ j = where(names[i1:i2] eq name,nmatch)
+ if nmatch eq 0 then begin
+ message = 'Item '+ name +' is invalid'
+ goto, handle_error
+ endif
+itnum[i] =j[0] +i1 ;save item number
+endfor;i loop on items
+if nitems eq 1 then goto,scalar ;speedy method
+
+;
+;---------------------------------------------------------------------------
+; We now have
+; 1) integer list of item numbers of length nitems
+; 2) we have list of ivalnum (subscripts) with
+; flag(s) ivalflag if subscript supplied
+; EXTRACT OTHER PARAMETERS
+;
+
+vector: ;---- vector processing
+ idltype = fix(qitems[20:21,*],0,qnumit)
+ numvals = newdb ? long(qitems[179:182,*],0,qnumit) : $
+ fix(qitems[22:23,*],0,qnumit)
+ sbyte = newdb ? long(qitems[187:190,*],0,qnumit) : $
+ fix(qitems[171:172,*],0,qnumit)
+ nbytes = fix(qitems[26:27,*],0,qnumit)
+ idltype = idltype[itnum]
+ numvals = numvals[itnum]
+ sbyte = sbyte[itnum]
+ nbytes = nbytes[itnum]
+;
+; add offset for subscripted variables
+;
+sbyte=sbyte+ivalnum*nbytes
+;
+; if ivalflag is set we have subscripted item and don't want all
+; values in vector
+;
+pos=where(ivalflag, Npos)
+if Npos GT 0 then numvals[pos]=1
+return
+;
+; -----------------------
+scalar: ;------- scalar processing
+it=itnum[0]
+if (it lt 0) or (it ge qnumit) then begin
+ message = 'Invalid item number '+strtrim(it,2)+' specified'
+ goto, handle_error
+endif
+;
+idltype = fix(qitems[20:21,it],0,1)
+numvals = newdb ? long(qitems[179:182,it],0,1) : $
+ fix(qitems[22:23,it],0,1)
+sbyte = newdb ? long(qitems[187:190,it],0,1) : $
+ fix(qitems[171:172,it],0,1)
+nbytes = fix(qitems[26:27,it],0,1)
+sbyte = sbyte+nbytes*ivalnum
+if ivalflag[0] then numvals[0]=1
+return
+;
+; Error handling point.
+;
+HANDLE_ERROR:
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = 'DB_ITEM: ' + MESSAGE $
+ ELSE MESSAGE, MESSAGE
+end
diff --git a/Code/script_idl_mv/astrolib/db_item_info.pro b/Code/script_idl_mv/astrolib/db_item_info.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1dfa2b7edf007ca9863cb353c3c83efce474cf6c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_item_info.pro
@@ -0,0 +1,122 @@
+function db_item_info,request,itnums
+;+
+; NAME:
+; DB_ITEM_INFO
+; PURPOSE:
+; routine to return information on selected item(s) in the opened
+; data bases.
+;
+; CALLING SEQUENCE:
+; result = db_item_info( request, itnums)
+; INPUTS:
+; request - string giving the requested information.
+; 'name' - item names
+; 'idltype' - IDL data type (integers)
+; see documentation of intrinsic SIZE funtion
+; 'nvalues' - vector item length (1 for scalar)
+; 'sbyte' - starting byte in .dbf record (use bytepos
+; to get starting byte in record returned by
+; dbrd)
+; 'nbytes' - bytes per data value
+; 'index' - index types
+; 'description' - description of the item
+; 'pflag' - pointer item flags
+; 'pointer' - data bases the items point to
+; 'format' - print formats
+; 'flen' - print field length
+; 'headers' - print headers
+; 'bytepos' - starting byte in dbrd record for the items
+; 'dbnumber' - number of the opened data base
+; 'pnumber' - number of db it points to (if the db is
+; opened)
+; 'itemnumber' - item number in the file
+;
+; itnums -(optional) Item numbers. If not supplied info on all items
+; are returned.
+; OUTPUT:
+; Requested information is returned as a vector. Its type depends
+; on the item requested.
+; HISTORY:
+; version 1 D. Lindler Nov. 1987
+; Converted to IDL V5.0 W. Landsman September 1997
+; Support new DB format which allows > 32767 bytes W.L. Oct 2010
+;-
+;------------------------------------------------------------------------
+; data base common block
+;
+common db_com,QDB,QITEMS,QLINK
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2)
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .IND file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 119 Equals 1 if external data representation (IEEE) is used
+;
+; QITEMS[*,i] contains a description of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; 24-25 Starting byte position in original DBF record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Print format field length
+; 100 Flag set to one if pointer item
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+; 177-178 item number within file
+; 179-182 Number of values for item (1 for scalar) (integer*4)
+; 183-186 Starting byte position in original DBF record (integer*4)
+; 187-190 Starting byte in record returned by DBRD
+;
+; QLINK[i] contains the entry number in the second data base
+; corresponding to entry i in the first data base.
+;-------------------------------------------------------------------------
+s=size(qitems) & n=s[2]
+newdb = qdb[118,0] EQ 1
+case strupcase(strtrim(request)) of
+
+ 'NAME' : x=string(qitems[0:19,*])
+ 'IDLTYPE' : x=fix(qitems[20:21,*],0,n)
+ 'NVALUES' : x = newdb? long(qitems[179:182,*],0,n) : $
+ fix(qitems[22:23,*],0,n)
+ 'SBYTE' : x = newdb ? long(qitems[183:186,*],0,n) : $
+ fix(qitems[24:25,*],0,n)
+ 'NBYTES' : x=fix(qitems[26:27,*],0,n)
+ 'INDEX' : x=qitems[28,*]
+ 'DESCRIPTION' : x=string(qitems[29:99,*])
+ 'PFLAG' : x=qitems[100,*]
+ 'POINTER' : x=string(qitems[101:119,*])
+ 'FORMAT' : x=string(qitems[120:125,*])
+ 'FLEN' : x=fix(qitems[98:99,*],0,n)
+ 'HEADERS' : x=string(qitems[126:170,*])
+ 'BYTEPOS' : x = newdb ? long(qitems[187:190,*],0,n) : $
+ fix(qitems[171:172,*],0,n)
+ 'DBNUMBER' : x=fix(qitems[173:174,*],0,n)
+ 'PNUMBER' : x=fix(qitems[175:176,*],0,n)
+ 'ITEMNUMBER' : x=fix(qitems[177:178,*],0,n)
+ else: begin
+ print,'DB_ITEM_INFO-- invalid information request'
+ retall
+ end
+endcase
+if N_params() eq 1 then return,x else return,x[itnums]
+end
diff --git a/Code/script_idl_mv/astrolib/db_or.pro b/Code/script_idl_mv/astrolib/db_or.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cb6cd105c21b06b7260f2ad5938d5affba242c2d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_or.pro
@@ -0,0 +1,52 @@
+function db_or,list1,list2
+;+
+; NAME:
+; DB_OR
+; PURPOSE:
+; Combine two vectors of entry numbers, removing duplicate values.
+; EXPLANATION:
+; DB_OR can also be used to remove duplicate values from any longword
+; vector
+;
+; CALLING SEQUENCE:
+; LIST = DB_OR( LIST1 ) ;Remove duplicate values from LIST1
+; or
+; LIST = DB_OR( LIST1, LIST2 ) ;Concatenate LIST1 and LIST2, remove dups
+;
+; INPUTS:
+; LIST1, LIST2 - Vectors containing entry numbers, must be non-negative
+; integers or longwords.
+; OUTPUT:
+; LIST - Vector containing entry numbers in either LIST1 or LIST2
+;
+; METHOD
+; DB_OR returns where the histogram of the entry vectors is non-zero
+;
+; PROCEDURE CALLS
+; ZPARCHECK - checks parameters
+; REVISION HISTORY:
+; Written, W. Landsman February, 1989
+; Check for degenerate values W.L. February, 1993
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ if N_params() EQ 0 then begin
+ print,'Syntax - list = db_or( list1, [ list2] )
+ return, -1
+ endif
+
+ zparcheck, 'DB_OR', list1, 1, [1,2,3], [1,2], 'First Entry Vector'
+
+ if N_params() eq 1 then begin
+ minlist1 = min( list1, max = maxlist1 )
+ if ( minlist1 EQ maxlist1 ) then return, minlist1 else $
+ return, where( histogram( list1 ) GT 0 ) + minlist1
+ endif
+
+ zparcheck, 'DB_OR', list1, 1, [1,2,3], [1,2], 'Second Entry Vector'
+
+ list = [list1, list2]
+ minlist = min( list, max = maxlist )
+ if ( minlist EQ maxlist ) then return, minlist else $
+ return,where( histogram( list ) GT 0 ) + minlist
+
+ end
diff --git a/Code/script_idl_mv/astrolib/db_titles.pro b/Code/script_idl_mv/astrolib/db_titles.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3cb8389ab1dcde63b84e8fc70b65f5fc93308b8d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/db_titles.pro
@@ -0,0 +1,54 @@
+pro db_titles,fnames,titles
+;+
+; NAME:
+; DB_TITLES
+;
+; PURPOSE:
+; Print database name and title. Called by DBHELP
+;
+; CALLING SEQUENCE:
+; db_titles, fnames, titles
+;
+; INPUT:
+; fnames - string array of data base names
+;
+; SIDE EFFECT:
+; Database name is printed along with the description in the .dbh file
+;
+; HISTORY:
+; version 2 W. Landsman May, 1989
+; modified to work under Unix, D. Neill, ACC, Feb 1991.
+; William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Added support for external (IEEE) representation.
+; William Thompson, GSFC, 3 November 1994
+; Modified to allow ZDBASE to be a path string.
+; Converted to IDL V5.0 W. Landsman September 1997
+; Assume since V5.5, W. Landsman September 2006
+;-
+;
+;-----------------------------------------------------------------------------
+ compile_opt idl2
+ n = N_elements(fnames)
+ get_lun,unit
+ b = bytarr(59)
+ npar = N_params()
+ if npar eq 2 then titles = strarr(n)
+ for i = 0,n-1 do begin
+ dbh_file = find_with_def(strtrim(fnames[i])+'.dbh', 'ZDBASE')
+ openr,unit,dbh_file,error=err
+ if err lt 0 then $ ;Does database exist?
+ printf,!TEXTUNIT,'Unable to locate database ',fnames[i] $
+ else begin
+ readu,unit,b
+ if npar eq 1 then begin
+ printf,!TEXTUNIT,format='(A,T20,A)',fnames[i],strtrim(b[19:58],2)
+ endif else titles[i] = string(b[19:58])
+ endelse
+
+ close,unit
+
+ endfor
+
+ free_lun,unit
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/dbbuild.pro b/Code/script_idl_mv/astrolib/dbbuild.pro
new file mode 100644
index 0000000000000000000000000000000000000000..58b78d11965365175840d7c2557d465aafd04cbe
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbbuild.pro
@@ -0,0 +1,168 @@
+pro dbbuild,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18, $
+ v19,v20,v21,v22,v23,v24,v25,v26,v27,v28,v29,v30,v31,v32,v33,v34,v35,v36, $
+ v37,v38,v39,v40,v41,v42,v43,v44,v45,v46,v47,v48,v49,v50, $
+ NOINDEX = noindex, STATUS=STATUS, SILENT=SILENT
+;+
+; NAME:
+; DBBUILD
+; PURPOSE:
+; Build a database by appending new values for every item.
+; EXPLANATION:
+; The database must be opened for update (with DBOPEN) before calling
+; DBBUILD.
+;
+; CALLING SEQUENCE:
+; DBBUILD, [ v1, v2, v3, v4......v50, /NOINDEX, /SILENT, STATUS = ]
+;
+; INPUTS:
+; v1,v2....v50 - vectors containing values for all items in the database.
+; V1 contains values for the first item, V2 for the second, etc.
+; The number of vectors supplied must equal the number of items
+; (excluding entry number) in the database. The number of elements
+; in each vector should be the same. A multiple valued item
+; should be dimensioned NVALUE by NENTRY, where NVALUE is the number
+; of values, and NENTRY is the number of entries.
+;
+; OPTIONAL INPUT KEYWORDS:
+; /NOINDEX - If this keyword is supplied and non-zero then DBBUILD will
+; *not* create an indexed file. Useful to save time if
+; DBBUILD is to be called several times and the indexed file need
+; only be created on the last call
+;
+; /SILENT - If the keyword SILENT is set and non-zero, then DBBUILD
+; will not print a message when the index files are generated
+;
+; OPTIONAL OUTPUT KEYWORD:
+; STATUS - Returns a status code denoting whether the operation was
+; successful (1) or unsuccessful (0). Useful when DBBUILD is
+; called from within other applications.
+;
+; EXAMPLE:
+; Suppose a database named STARS contains the four items NAME,RA,DEC, and
+; FLUX. Assume that one already has the four vectors containing the
+; values, and that the database definition (.DBD) file already exists.
+;
+; IDL> !PRIV=2 ;Writing to database requires !PRIV=2
+; IDL> dbcreate,'stars',1,1 ;Create database (.dbf) & index (.dbx) file
+; IDL> dbopen,'stars',1 ;Open database for update
+; IDL> dbbuild,name,ra,dec,flux ;Write 4 vectors into the database
+;
+; NOTES:
+; Do not call DBCREATE before DBBUILD if you want to append entries to
+; an existing database
+;
+; DBBUILD checks that each value vector matches the idl type given in the
+; database definition (..dbd) file, and that character strings are the
+; proper length.
+; PROCEDURE CALLS:
+; DBCLOSE, DBINDEX, DBXPUT, DBWRT, IS_IEEE_BIG()
+; REVISION HISTORY:
+; Written W. Landsman March, 1989
+; Added /NOINDEX keyword W. Landsman November, 1992
+; User no longer need supply all items W. Landsman December, 1992
+; Added STATUS keyword, William Thompson, GSFC, 1 April 1994
+; Added /SILENT keyword, William Thompson, GSFC, October 1995
+; Allow up to 30 items, fix problem if first item was multiple value
+; W. Landsman GSFC, July 1996
+; Faster build of external databases on big endian machines
+; W. Landsman GSFC, November 1997
+; Use SIZE(/TNAME) for error mesage display W.Landsman July 2001
+; Fix message display error introduced July 2001 W. Landsman Oct. 2001
+; Make sure error message appears even if !QUIET is set W.L November 2006
+; Major rewrite to use SCOPE_VARFETCH, accept 50 input items
+; W. Landsman November 2006
+; Fix warning if parameters have different # of elements W.L. May 2010
+; Fix warning if scalar parameter supplied W.L. June 2010
+; Fix for when first parameter is multi-dimensioned W.L. July 2010
+; Check data type of first parameter W.L. Jan 2012
+;-
+ COMPILE_OPT IDL2
+ On_error,2 ;Return to caller
+ npar = N_params()
+ if npar LT 1 then begin
+ print,'Syntax - DBBUILD, v1, [ v2, v3, v4, v5, ... v50,'
+ print,' /NOINDEX, /SILENT, STATUS = ]'
+ return
+ endif
+
+ dtype = ['UNDEFINED','BYTE','INT','LONG','FLOAT','DOUBLE', $
+ 'COMPLEX','STRING','STRUCT','DCOMPLEX','POINTER','OBJREF', $
+ 'UINT', 'ULONG', 'LONG64','ULONG64']
+
+
+; Initialize STATUS as unsuccessful (0). If the routine is successful, this
+; will be updated below.
+
+ status = 0
+
+ nitem = db_info( 'ITEMS' )
+ if nitem LE npar then message, 'ERROR - ' + strtrim(npar,2) + $ $
+ ' variables supplied but only ' + strtrim(nitem-1,2) + ' items in database'
+
+ items = indgen(nitem)
+ db_item, items, itnum, ivalnum, idltype, sbyte, numvals, nbyte
+ nitems = ( npar < nitem)
+ vv = 'v' + strtrim( indgen(nitems+1), 2)
+
+;Create a pointer array to point at each of the supplied variables
+ tmp = ptrarr(nitems,/allocate_heap)
+ for i=0,nitems-1 do *tmp[i] = SCOPE_VARFETCH(vv[i+1], LEVEL=0)
+
+ ndata = N_elements(v1)/ numvals[1] ;# of elements in last dimension
+
+ for i = 1,npar do begin ;Get the dimensions and type of each input vector
+
+ sz = size( *tmp[i-1], /STRUCT)
+ ndatai = sz.N_elements/numvals[i]
+ if ndatai NE ndata then message, $
+ 'WARNING - Parameter ' + strtrim(i,2) + ' has dimension ' + $
+ strjoin(strtrim( sz.dimensions[0:sz.n_dimensions-1 > 0],2),' ') ,/con
+ if sz.type_name NE dtype[idltype[i]] then begin
+ message, 'Item ' + strtrim( db_item_info('NAME',i),2) + $
+ ' - parameter '+strtrim(i,2) + ' - has an incorrect data type',/CON
+ message, 'Required data type is ' + dtype[idltype[i]], /INF
+ message, 'Supplied data type is ' + sz.type_name, /INF
+ ptr_free,tmp
+ return
+ endif
+
+ endfor
+ external = db_info('external',0)
+ noconvert = external ? is_ieee_big() : 1b
+
+ entry = make_array( DIMEN = db_info('LENGTH'),/BYTE ) ;Empty entry array
+ nvalues = long( db_item_info( 'NVALUES' ) ) ;# of values per item
+ nbyte = nbyte*nvalues ;Number of bytes per item
+
+ for i = 0l, Ndata - 1 do begin
+ i1 = i*nvalues
+ i2 = i1 + nvalues -1
+
+ dbxput,0l,entry,idltype[0],sbyte[0],nbyte[0]
+ for j = 1,nitems do $
+ dbxput, (*tmp[j-1])[ i1[j]:i2[j] ], $
+ entry,idltype[j], sbyte[j], nbyte[j]
+
+ dbwrt,entry,noconvert=noconvert ;Write the entry into the database
+
+ endfor
+ ptr_free,tmp
+
+ if ~keyword_set( NOINDEX ) then begin
+
+ indexed = db_item_info( 'INDEX' ) ;Need to create an indexed file?
+ if ~array_equal(indexed,0) then begin
+ if ~keyword_set(silent) then $
+ message,'Now creating indexed files',/INF
+ dbindex,items
+ endif
+
+ endif
+
+ dbclose
+
+; Mark successful completion, and return.
+
+ status = 1
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbcircle.pro b/Code/script_idl_mv/astrolib/dbcircle.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8c5a44b031c77f653f5bb49235e065bfd72fd72d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbcircle.pro
@@ -0,0 +1,208 @@
+function dbcircle, ra_cen, dec_cen, radius, dis, sublist,SILENT=silent, $
+ TO_J2000 = to_J2000, TO_B1950 = to_B1950, GALACTIC= galactic, $
+ COUNT = nfound
+;+
+; NAME:
+; DBCIRCLE
+; PURPOSE:
+; Find sources in a database within specified radius of specified center
+; EXPLANATION:
+; Database must include items named 'RA' (in hours) and 'DEC' (in degrees)
+; and must have previously been opened with DBOPEN
+;
+; CALLING SEQUENCE:
+; list = DBCIRCLE( ra_cen, dec_cen, [radius, dis, sublist, /SILENT,
+; /GALACTIC, TO_B1950, /TO_J2000, COUNT= ] )
+;
+; INPUTS:
+; RA_CEN - Right ascension of the search center in decimal HOURS, scalar
+; DEC_CEN - Declination of the search center in decimal DEGREES, scalar
+; RA_CEN and DEC_CEN should be in the same equinox as the
+; currently opened catalog.
+;
+; OPTIONAL INPUT:
+; RADIUS - Radius of the search field in arc minutes, scalar.
+; DBCIRCLE prompts for RADIUS if not supplied.
+; SUBLIST - Vector giving entry numbers in currently opened database
+; to be searched. Default is to search all entries
+;
+; OUTPUTS:
+; LIST - Vector giving entry numbers in the currently opened catalog
+; which have positions within the specified search circle
+; LIST is set to -1 if no sources fall within the search circle
+;
+; OPTIONAL OUTPUT
+; DIS - The distance in arcminutes of each entry specified by LIST
+; to the search center (given by RA_CEN and DEC_CEN)
+;
+; OPTIONAL KEYWORD INPUT:
+; /GALACTIC - if set, then the first two parameters are interpreted as
+; Galactic coordinates in degrees, and is converted internally
+; to J2000 celestial to search the database.
+; /SILENT - If this keyword is set, then DBCIRCLE will not print the
+; number of entries found at the terminal
+; /TO_J2000 - If this keyword is set, then the entered coordinates are
+; assumed to be in equinox B1950, and will be converted to
+; J2000 before searching the database
+; /TO_B1950 - If this keyword is set, then the entered coordinates are
+; assumed to be in equinox J2000, and will be converted to
+; B1950 before searching the database
+; NOTE: The user must determine on his own whether the database
+; is in B1950 or J2000 coordinates.
+; OPTIONAL KEYWORD OUTPUT:
+; COUNT - - Integer scalar giving the number of valid matches
+; METHOD:
+; A DBFIND search is first performed on a square area of given radius.
+; The list is the restricted to a circular area by using GCIRC to
+; compute the distance of each object to the field center.
+;
+; RESTRICTIONS;
+; The database must have items 'RA' (in hours) and 'DEC' (in degrees).
+; Alternatively, the database could have items RA_OBJ and DEC_OBJ
+; (both in degrees)
+; EXAMPLE:
+; Find all Hipparcos stars within 40' of the nucleus of M33
+; (at J2000 1h 33m 50.9s 30d 39' 36.7'')
+;
+; IDL> dbopen,'hipparcos'
+; IDL> list = dbcircle( ten(1,33,50.9), ten(3,39,36.7), 40)
+;
+; PROCEDURE CALLS:
+; BPRECESS, DBFIND(), DBEXT, DB_INFO(), GCIRC, GLACTC, JPRECESS
+; REVISION HISTORY:
+; Written W. Landsman STX January 1990
+; Fixed search when crossing 0h July 1990
+; Spiffed up code a bit October, 1991
+; Leave DIS vector unchanged if no entries found W. Landsman July 1999
+; Use maximum declination, rather than declination at field center to
+; correct RA for latitude effect W. Landsman September 1999
+; Added COUNT, GALACTIC keywords W. Landsman December 2008
+; Fix problem when RA range exceeds 24h W. Landsman April 2009
+; Work as advertised for RA_OBJ field W. Landsman June 2010
+; Fix occasional problem when crossing 0h E. Donoso/W.Landsman Jan 2013
+; Check if database has been opened W. Landsman Aug 2013
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 2 then begin
+ print,'Syntax - list = ' + $
+ 'DBCIRCLE( ra[hours], dec[degrees], radius[arcmin], [ dis, sublist '
+ print,' Count=, /GALACTIC, /SILENT, /TO_J2000, /TO_B1950 ] )'
+ if N_elements(sublist) GT 0 then return, sublist else return,[-1L]
+ endif
+
+ if (N_elements(ra_cen) NE 1) || (N_elements(dec_cen) NE 1) then begin
+ print, 'DBCIRCLE: ERROR - Expecting scalar RA and Dec parameters'
+ if N_elements(sublist) GT 0 then return, sublist else return,[-1L]
+ endif
+
+ if N_params() LT 3 then read,'Enter search radius in arc minutes: ',radius
+
+ nentries = db_info( 'ENTRIES',0 )
+ if nentries EQ 0 then begin
+ if ~keyword_set(SILENT) then message, $
+ 'ERROR - No entries in database ' + db_info("NAME",0),/INF
+ if N_elements(sublist) GT 0 then return, sublist else return,[-1]
+ endif
+
+ if keyword_set(TO_J2000) then begin
+ jprecess,ra_cen*15.,dec_cen,racen,deccen
+ racen = racen[0]/15. & deccen = deccen[0]
+ endif else if keyword_set(TO_B1950) then begin
+ bprecess,ra_cen*15.,dec_cen,racen,deccen
+ racen = racen[0]/15. & deccen = deccen[0]
+ endif else if keyword_set(galactic) then begin
+ glactc,racen,deccen,2000,ra_cen*15,dec_cen,2 ;Convert from Galactic
+ endif else begin
+ racen = ra_cen[0] & deccen = dec_cen[0]
+ endelse
+
+ size = radius/60. ;Size of search field in degrees
+ decmin = double(deccen-size) > (-90.)
+ decmax = double(deccen+size) < 90.
+ bigdec = max(abs([decmin, decmax]))
+ items = strtrim(db_item_info('name'))
+ g = where(items EQ 'RA', Ncount)
+ if Ncount EQ 0 then begin
+ g = where(items EQ 'RA_OBJ', Ncount)
+ if Ncount EQ 0 then message, $
+ 'ERROR - Database must have item named RA or RA_OBJ' else begin
+ sra = 'RA_OBJ' & sdec = 'DEC_OBJ'
+ endelse
+ endif else begin
+ sra = 'RA' & sdec = 'DEC'
+ endelse
+
+ if abs(bigdec) EQ 90 then rasize = 24 else $ ;Updated Sep 1999
+ rasize = abs(size/(15.*cos(bigdec/!RADEG))) < 24. ;Correct for latitude effect
+
+ if 2*rasize gt 24. then begin ;Only need search on Dec?
+ st = string(decmin) + ' dbcompare,3624,3625,/diff
+;
+; PROCEDURES USED:
+; DB_INFO(), DB_ITEM, DB_ITEM_INFO(), DBRD, DBXVAL()
+; TEXTOPEN, TEXTCLOSE
+; HISTORY:
+; Written, W. Landsman July 1996
+; Fix documentation, add Syntax display W. Landsman November 1998
+; Replace DATATYPE() with size(/TNAME) W. Landsman November 2001
+; Assume since V5.5, remove VMS call W. Landsman September 2006
+; Fix problem with multiple values when /DIFF set W. Landsman April 2007
+;-
+;
+ On_error,2 ;Return to caller
+ compile_opt idl2
+ if N_params() LT 2 then begin
+ print,'Syntax - DBCOMPARE, list1, list2, [items, TEXTOUT= ,/DIFF]'
+ return
+ endif
+
+; Make list a vector
+
+ dbname = db_info( 'NAME', 0 )
+
+ nentry = db_info( 'ENTRIES', 0)
+ if list1[0] GT nentry then message, dbname + $
+ ' LIST1 entry number must be between 1 and ' + strtrim( nentry, 2 )
+
+ if list2[0] GT nentry then message, dbname + $
+ ' LIST2 entry number must be between 1 and ' + strtrim( nentry, 2 )
+
+
+; Determine items to print
+
+ if N_elements(items) EQ 0 then items = '*'
+ db_item,items, it, ivalnum, dtype, sbyte, numvals, nbytes
+ nvalues = db_item_info( 'NVALUES', it ) ;number of values in item
+ nitems = N_elements( it ) ;number of items requested
+ qnames = db_item_info( 'NAME', it )
+ qtitle = db_info( 'TITLE', 0 ) ;data base title
+
+; Open output text file
+
+ if not keyword_set(TEXTOUT) then textout = !textout ;use default output dev.
+
+ textopen, dbname, TEXTOUT = textout
+ if size(TEXTOUT,/TNAME) EQ 'STRING' then text_out = 5 else $
+ text_out = textout maxentry
+
+ 'ITEMS' : begin
+;
+; process statement in form
+;
+;
+ item_name=" "
+ item_name=strupcase(gettok(st,' '))
+ st = strtrim(st, 1)
+ item_type = " "
+ item_type=gettok(st,' ')
+ st = strtrim(st, 1)
+ desc[nitems]=st
+ if item_name eq '' then $
+ message,'Invalid item name',/IOERROR
+ names[nitems]=gettok(item_name,'(')
+ if item_name ne '' then $ ;is it a vector
+ numvals[nitems]=fix(gettok(item_name,')'))
+ if item_type eq '' then $
+ message,'Item data type not supplied for item ' + $
+ strupcase(item_name),/IOERROR
+ data_type=strmid(strupcase(gettok(item_type,'*')),0,1)
+ num_bytes=item_type
+ if num_bytes eq '' then num_bytes='4'
+ if (data_type eq 'R') || (data_type eq 'I') || $
+ (data_type eq 'U') then $
+ data_type=data_type+num_bytes
+ case data_type of
+ 'B' : begin & idltype= 1 & nb=1 & ff='I6' & end
+ 'L' : begin & idltype= 1 & nb=1 & ff='I6' & end
+ 'I2': begin & idltype= 2 & nb=2 & ff='I7' & end
+ 'I4': begin & idltype= 3 & nb=4 & ff='I11' & end
+ 'I8': begin & idltype= 14 & nb=8 & ff='I22' & end
+ 'R4': begin & idltype= 4 & nb=4 & ff='G12.6' & end
+ 'R8': begin & idltype= 5 & nb=8 & ff='G20.12' & end
+ 'U2': begin & idltype= 12 & nb=2 & ff='I7' & end
+ 'U4': begin & idltype= 13 & nb=4 & ff='I11' & end
+ 'U8': begin & idltype= 15 & nb=8 & ff='I22' & end
+ 'C' : begin
+ idltype = 7
+ nb=fix(num_bytes)
+ ff='A'+num_bytes
+ end
+ else: message,'Invalid data type "'+ item_type+ $
+ '" specified',/IOERROR
+ endcase
+ format[nitems]=ff ;default print format
+ headers[1,nitems]=names[nitems] ;default print header
+ type[nitems]=idltype ;idl data type for item
+ nbytes[nitems]=nb ;number of bytes for item
+ sbyte[nitems]=nextbyte ;position in record for item
+ nextbyte=nextbyte+nb*numvals[nitems] ;next byte position
+ nitems++
+ end
+
+ 'FORMATS': begin
+;
+; process strings in form:
+; ,,
+;
+ item_name=" "
+ item_name=strupcase(gettok(st,' '))
+ item_no=0
+ while item_no lt nitems do begin
+ if strtrim(names[item_no]) eq item_name then begin
+ st = strtrim(st, 1)
+ format[item_no]=gettok(st,' ')
+ if strtrim(st,2) ne '' then begin
+ st = strtrim(st, 1)
+ headers[0,item_no]=gettok(st,',')
+ headers[1,item_no]=gettok(st,',')
+ headers[2,item_no]=strtrim(st)
+ endif
+ endif
+ item_no++
+ endwhile
+ end
+
+ 'POINTERS': begin
+;
+; process record in form:
+;
+;
+ item_name=strupcase(gettok(st,' '))
+ item_no=0
+ while item_no lt nitems do begin
+ if strtrim(names[item_no]) eq item_name then $
+ pointers[item_no]=strupcase(strtrim(st, 1))
+ item_no++
+ endwhile
+ endcase
+
+ 'INDEX': begin
+;
+; process record of type:
+;
+;
+ item_name=strupcase(gettok(st,' '))
+ st = strtrim(st, 1)
+ indextype=gettok(st,' ')
+ item_no=0
+ while item_no lt nitems do begin
+ if strtrim(names[item_no]) eq item_name then begin
+ case strupcase(indextype) of
+ 'INDEX' : index[item_no]=1
+ 'SORTED': index[item_no]=2
+ 'SORT' : index[item_no]=3
+ 'SORT/INDEX' : index[item_no]=4
+ else : message,'Invalid index type',/IOERROR
+ endcase
+ endif
+ item_no++
+ endwhile
+ end
+ else : begin
+ print,'DBCREATE-- invalid block specification of ',block
+ print,' Valid values are #TITLE, #ITEMS, #FORMATS, #INDEX,'
+ print,' #MAXENTRIES or #POINTERS'
+ end
+ endcase
+next:
+endwhile; loop on records
+
+;
+; create data base descriptor record --------------------------------------
+;
+; byte array of 120 values
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 105-108 record length of DBF file (integer*4)
+; 84-117 values filled in by DBOPEN
+; 119 equals 1 if keyword EXTERNAL is true.
+;
+totbytes=((nextbyte+3)/4*4) ;make record length a multiple of 4
+drec = bytarr(120)
+drec[0:79]=32b ;blanks
+drec[0] = byte(strupcase(filename))
+drec[19] = byte(title)
+drec[80] = byte(fix(nitems),0,2)
+drec[105] = byte(long(totbytes),0,4)
+drec[118] = 1b
+drec[119] = byte(extern)
+;
+; create item description records
+;
+; irec[*,i] contains description of item number i with following
+; byte assignments:
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integet*2)
+; 24-25 Starting byte position i record (integer*2)
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 Field length of the print format
+; 100 Pointer flag
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 179-182 Number of values for item (1 for scalar) (integer*4)
+; 183-186 Starting byte position in original DBF record (integer*4)
+; 187-199 Added by DBOPEN
+irec=bytarr(200,nitems)
+
+headers = strmid(headers,0,15) ;Added 15-Sep-92
+
+for i=0,nitems-1 do begin
+ rec=bytarr(200)
+ rec[0:19]=32b & rec[101:170]=32b ;Default string values are blanks
+ rec[29:87] = 32b
+ rec[0] = byte(names[i])
+ rec[20] = byte(type[i],0,2)
+ rec[179] = byte(numvals[i],0,4)
+ rec[183] = byte(sbyte[i],0,4)
+ rec[26] = byte(nbytes[i],0,2)
+ rec[28] = index[i]
+ rec[29] = byte(desc[i])
+ if strtrim(pointers[i]) ne '' then rec[100]=1 else rec[100]=0
+ rec[101]= byte(strupcase(pointers[i]))
+ rec[120]= byte(format[i])
+ ff=strtrim(format[i])
+ test = strnumber(gettok(strmid(ff,1,strlen(ff)-1),'.'),val)
+ if test then flen =fix(val) else $ ;Modified Nov-10
+ message,'Invalid print format supplied: ' + format[i],/IOERROR
+ rec[98] = byte(flen,0,2)
+ rec[126]= byte(headers[0,i]) > 32b ;Modified Nov-91
+ rec[141]= byte(headers[1,i]) > 32b
+ rec[156]= byte(headers[2,i]) > 32b
+ irec[0,i]=rec
+
+end
+;
+; Make sure user is on ZDBASE and write description file
+;
+
+ close,unit
+ openw,unit,zdir + fname+'.dbh'
+On_ioerror, NULL
+if extern then begin
+ tmp = fix(drec,80,1) & byteorder,tmp,/htons & drec[80] = byte(tmp,0,2)
+ tmp = long(drec,105,1) & byteorder,tmp,/htonl & drec[105] = byte(tmp,0,4)
+;
+ tmp = fix(irec[20:27,*],0,4,nitems)
+ byteorder,tmp,/htons
+ irec[20,0] = byte(tmp,0,8,nitems)
+;
+ tmp = fix(irec[98:99,*],0,1,nitems)
+ byteorder,tmp,/htons
+ irec[98,0] = byte(tmp,0,2,nitems)
+;
+ tmp = fix(irec[171:178,*],0,4,nitems)
+ byteorder,tmp,/htons
+ irec[171,0] = byte(tmp,0,8,nitems)
+
+ tmp = long(irec[179:186,*],0,2,nitems)
+ byteorder,tmp,/htonl
+ irec[179,0] = byte(tmp,0,8,nitems)
+
+endif
+writeu, unit, drec
+writeu, unit, irec
+;
+; if new data base create .dbf and .dbx files -----------------------------
+;
+
+if newdb then begin
+ close,unit
+ openw, unit, zdir + fname+'.dbf'
+ header = bytarr(totbytes)
+ p = assoc(unit,header)
+ p[0] = header
+end
+
+;
+; determine if any indexed items
+;
+nindex = total(index GT 0)
+;
+; create empty index file if needed
+;
+if (nindex GT 0) && (newindex) then begin
+ indexed = where(index GT 0)
+;
+; create header array
+; header=intarr(7,nindex)
+; header(i,*) contains values
+; i=0 item number
+; i=1 index type
+; i=2 idl data type for the item
+; i=3 starting block for header
+; i=4 starting block for data
+; i=5 starting block for indices (type 3)
+; i=6 starting block for unsorted data (type 4)
+;
+ nb = (maxentries+511)/512 ;number of 512 value groups
+ nextblock = 1
+ header = lonarr(7,nindex)
+ for ii = 0, nindex-1 do begin
+ item = indexed[ii]
+ header[0,ii] = item
+ header[1,ii] = index[item]
+ header[2,ii] = type[item]
+ data_blocks = nbytes[item]*nb
+ if index[item] NE 1 $
+ then header_blocks = (nbytes[item]*nb+511)/512 $
+ else header_blocks = 0
+ if (index[item] eq 3) or (index[item] EQ 4) then $
+ index_blocks=(4*nb) else index_blocks=0
+ if index[item] EQ 4 then unsort_blocks = data_blocks else $
+ unsort_blocks=0
+ header[3,ii] = nextblock
+ header[4,ii] = nextblock+header_blocks
+ header[5,ii] = header[4,ii]+data_blocks
+ header[6,ii] = header[5,ii]+index_blocks
+ nextblock = header[6,ii]+unsort_blocks
+ end
+ totblocks = nextblock
+ close, unit
+ openw, unit, zdir + fname+'.dbx'
+;
+ p = assoc(unit,lonarr(2))
+ tmp = [long(nindex),maxentries]
+ if extern then byteorder, tmp,/htonl
+ p[0] = tmp
+;
+ p = assoc(unit,lonarr(7,nindex),8)
+ tmp = header
+ if extern then byteorder, tmp,/htonl
+ p[0] = tmp
+endif
+free_lun, unit
+return
+;
+BAD_IO: free_lun,unit
+print, !ERROR_STATE.MSG_PREFIX + !ERROR_STATE.MSG
+print, !ERROR_STATE.MSG_PREFIX + !ERROR_STATE.SYS_mSG
+
+return
+;
+end
diff --git a/Code/script_idl_mv/astrolib/dbdelete.pro b/Code/script_idl_mv/astrolib/dbdelete.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f145b0b18243208278a00b48470c48bc4eef8516
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbdelete.pro
@@ -0,0 +1,142 @@
+pro dbdelete, list, name, DEBUG = debug
+;+
+; NAME:
+; DBDELETE
+; PURPOSE:
+; Deletes specified entries from data base
+;
+; CALLING SEQUENCE:
+; DBDELETE, list, [ name, /DEBUG ]
+;
+; INPUTS:
+; list - list of entries to be deleted, scalar or vector
+; name - optional name of data base, scalar string. If not specified
+; then the data base file must be previously opened for update
+; by DBOPEN.
+;
+; OPERATIONAL NOTES:
+; !PRIV must be at least 3 to execute.
+;
+; SIDE EFFECTS:
+; The data base file (ZDBASE:name.dbf) is modified by removing the
+; specified entries and reordering the remaining entry numbers
+; accordingly (ie. if you delete entry 100, it will be replaced
+; by entry 101 and the database will contain 1 less entry.
+;
+; EXAMPLE:
+; Delete entries in a database STARS where RA=DEC = 0.0
+;
+; IDL> !PRIV= 3 ;Set privileges
+; IDL> dbopen,'STARS',1 ;Open for update
+; IDL> list = dbfind('ra=0.0,dec=0.0') ;Obtain LIST vector
+; IDL> dbdelete, list ;Delete specified entries from db
+;
+; NOTES:
+; The procedure is rather slow because the entire database is re-
+; created with the specified entries deleted.
+; OPTIONAL KEYWORD INPUT:
+; DEBUG - if this keyword is set and non-zero, then additional
+; diagnostics will be printed as each entry is deleted.
+; COMMON BLOCKS:
+; DBCOM
+; PROCEDURE CALLS:
+; DBINDEX, DB_INFO(), DBOPEN, DBPUT, ZPARCHECK
+; HISTORY
+; Version 2 D. Lindler July, 1989
+; Updated documentation W. Landsman December 1992
+; William Thompson, GSFC, 28 February 1995
+; Fixed bug when external representation used.
+; Fixed for case where second parameter supplied W. Landsman April 1996
+; Use keyword DEBUG rather than !DEBUG W. Landsman May 1997
+; Don't call DBINDEX if no indexed items W. Landsman May 2006
+; Use TRUNCATE_LUN if V5.6 or later W. Landsman Sep 2006
+; Fix problem when deleting last entry W. Landsman Mar 2007
+; Assume since V5.6 so TRUNCATE_LUN is available W. Landsman
+;
+;-
+;-------------------------------------------------------------------------------
+ On_error,2
+ compile_opt idl2
+
+ if N_params() EQ 0 then begin
+ print,'Syntax - DBDELETE, entry, [ dbname ]'
+ return
+ endif
+
+; data base common block
+
+ common db_com,QDB,QITEMS,QDBREC
+
+; Check parameters
+
+ zparcheck, 'DBDELETE', list, 1, [1,2,3], [0,1], 'entry list'
+ if N_params() GT 1 then $
+ zparcheck, 'dbdelete', name, 2, 7, 0, 'data base name'
+
+ if !PRIV lt 3 then $
+ message,'!priv must be at least 3 to execute'
+
+; Open data base if name supplied
+
+ if N_params() GT 1 then dbopen,name,1 else begin ;Open specified database
+
+ if not db_info( 'OPEN') then $
+ message,'No database open for update'
+ if not db_info('update') then $
+ message,'Database '+ db_info('NAME',0) + ' not open for update'
+
+ endelse
+
+; Determine whether or not the database uses external data representation.
+
+ external = qdb[119] eq 1
+
+
+; Create vector if list is a scalar
+
+ outrec = 0L ; Create counter of output record
+ len = db_info('length')
+
+; loop on entries in data base
+
+ qnentry = db_info('ENTRIES',0)
+
+ for i = 1L, qnentry do begin
+
+ ; Is it to be kept?
+
+ found = where( list EQ i, Nfound)
+
+ if keyword_set(debug) then print,i,nfound ; allow diags.
+
+ if ( Nfound LE 0 ) then begin
+ outrec = outrec + 1 ; increment counter
+ if ( outrec NE i ) then begin
+ entry = qdbrec[i]
+ tmp = outrec
+ if external then byteorder,tmp,/htonl
+ dbput, 0, tmp, entry ; modify entry number
+ qdbrec[outrec] = entry
+ endif
+ endif
+ endfor
+
+; Update adjusted total number of entries.
+
+ qdb[84] = byte( outrec,0,4 )
+
+; Truncate the .dbf file at the current position.
+
+ unit = db_info('unit_dbf')
+ point_lun, unit, long64(outrec+1)*len
+ truncate_lun, unit
+
+; Update index file
+
+ indextype = db_item_info( 'INDEX')
+ if total(indextype) NE 0 then dbindex
+
+ if N_params() GT 1 then dbclose
+
+ return ; dbdelete
+ end ; dbdelete
diff --git a/Code/script_idl_mv/astrolib/dbedit.pro b/Code/script_idl_mv/astrolib/dbedit.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1f439fd2354f0c9ba0710de349bf6ad03c32cccd
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbedit.pro
@@ -0,0 +1,395 @@
+;+
+; NAME:
+; DBEDIT
+;
+; PURPOSE:
+; Interactively edit specified fields in an IDL database.
+; EXPLANATION:
+; The value of each field is displayed, and the user has the option
+; of changing or keeping the value. Widgets will be used if they
+; are available.
+;
+; CALLING SEQUENCE:
+; dbedit, list, [ items ]
+;
+; INPUTS:
+; list - scalar or vector of database entry numbers. Set list = 0 to
+; interactively add a new entry to a database. Set list = -1 to edit
+; all entries.
+;
+; OPTIONAL INPUTS:
+; items - list of items to be edited. If omitted, all fields can be
+; edited.
+;
+; KEYWORDS:
+; BYTENUM = If set, treat byte variables as numbers instead of
+; characters.
+;
+; COMMON BLOCKS:
+; DB_COM -- contains information about the opened database.
+; DBW_C -- contains information intrinsic to this program.
+;
+; SIDE EFFECTS:
+; Will update the database files.
+;
+; RESTRICTIIONS:
+; Database must be opened for update prior to running
+; this program. User must be running DBEDIT from an
+; account that has write privileges to the databases.
+;
+; If one is editing an indexed item, then after all edits are complete,
+; DBINDEX will be called to reindex the entire item. This may
+; be time consuming.
+;
+; Cannot be used to edit items with multiple values
+;
+; EXAMPLE:
+; Suppose one had new parallaxes for all stars fainter than 5th magnitude
+; in the Yale Bright Star Catalog and wanted to update the PRLAX and
+; PRLAX_CODE fields with these new numbers
+;
+; IDL> !priv=2
+; IDL> dbopen, 'yale_bs', 1 ;Open catalog for update
+; IDL> list = dbfind( 'v>5') ;Find fainter than 5th magnitude
+; IDL> dbedit, list, 'prlax, prlax_code' ;Manual entry of new values
+;
+; PROCEDURE:
+; (1) Use the cursor and point to the value you want to edit.
+; (2) Type the new field value over the old field value.
+; (3) When you are done changing all of the field values for each entry
+; save the entry to the databases by pressing 'SAVE ENTRY TO DATABASES'.
+; Here all of the values will be checked to see if they are the correct
+; data type. If a field value is not of the correct data type, it will
+; not be saved.
+;
+; Use the buttons "PREV ENTRY" and "NEXT ENTRY" to move between entry
+; numbers. You must save each entry before going on to another entry in
+; order for your changes to be saved.
+;
+; Pressing "RESET THIS ENTRY" will remove any unsaved changes to the
+; current entry.
+;
+;REVISION HISTORY:
+; Adapted from Landsman's DBEDIT
+; added widgets, Melissa Marsh, HSTX, August 1993
+; do not need to press return after entering each entry,
+; fixed layout problem on SUN,
+; Melissa Marsh, HSTX, January 1994
+; Only updates the fields which are changed. Joel Offenberg, HSTX, Mar 94
+; Corrected test for changed fields Wayne Landsman HSTX, Mar 94
+; Removed a couple of redundant statements W. Landsman HSTX Jan 96
+; Converted to IDL V5.0 W. Landsman September 1997
+; Replace DATAYPE() with size(/TNAME) W. Landsman November 2001
+; Work for entry numbers > 32767 W. Landsman December 2001
+; Added /BYTENUM William Thompson 13-Mar-2006
+; Use DIALOG_MESSAGE for error messages W. Landsman April 2006
+; Assume since V5.5, remove VMS support W. Landsman Sep 2006
+;-
+
+;----------------------------------------------------------------
+
+
+;event handler for main part of program
+
+pro widgetedit_event,event
+
+common db_com,qdb,QITEMS,QDBREC
+
+common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
+ it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
+ endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
+ holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag,bytenum
+
+CASE event.id OF
+
+ endbut: widget_control,event.top,/destroy ;destory main widget--end session
+
+ prevbut:begin ;go to previous entry
+ if wereat ne 0 then wereat= wereat-1
+ liston = thislist[wereat]
+ widedit
+ end
+
+ nextbut:begin ;go to next entry
+ if wereat lt nlist-1 then wereat = wereat+1 else $
+ widget_control,event.top,/destroy ;end session
+ liston = thislist[wereat]
+ widedit
+ end
+
+ resetbut:begin ;reset this entry
+ liston = liston
+ widedit
+ end
+
+ savebut: begin ;save entry to databases
+ ;update database
+ for i = 0, nitems -1 do begin
+ widget_control,widtext[i],get_value=val
+ ;test value
+ valid = 0
+ oldval = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
+
+ on_ioerror,BADVAL
+ IF (strtrim(oldval[0],2) ne (strtrim(val[0],2))) THEN BEGIN
+ oldval[0] = strtrim(val,2)
+ valid = 1
+ dbxput,oldval,entry,dtype[i],sbyte[i],nbytes[i]
+ print,strcompress('Entry ' + string(liston) +': ' + $
+ names[i] + ' = ' + string(val))
+ newflag[ wereat, i ] = 1b
+ BADVAL: if (not valid) then begin
+ result = dialog_message(title='Bad Value',/ERROR, $
+ 'Item '+ strcompress(names[i],/rem) + $
+ ' must be of type ' + size(oldval[0],/TNAME) )
+ str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
+ if (dtype[i] eq 1) and keyword_set(bytenum) then str=fix(str)
+ str = ' '+string(str[0])
+ widget_control,widtext[i],set_value=str
+ endif
+ endIF
+ on_ioerror,NULL
+ endfor
+
+ if (liston EQ 0) then begin
+ dbwrt,entry,0,1 ;new entry
+ endif else begin
+ dbwrt,entry
+ endelse
+ widedit
+ ;create widget telling the user that the changes have been made.
+ end
+
+ else: ;donothing
+
+ endcase
+end
+
+;--------------------------------------------------------------------
+pro widedit
+;program that makes "middle" of main widget (field values)
+
+
+common db_com,qdb,QITEMS,QDBREC
+
+
+common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
+ it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
+ endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
+ holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag,bytenum
+
+
+;get entry number
+ dbrd, liston, entry
+
+;get field values for this entry
+ widget_control, widtext0, set_value=string(liston)
+ for i = 0,nitems-1 do begin
+ str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
+ if (dtype[i] eq 1) and keyword_set(bytenum) then str=fix(str)
+ str = ' '+string(str[0])
+ widget_control,widtext[i],set_value=str
+ endfor
+
+;check to see if this entry is the minimum or maximum entry
+ if (liston EQ minlist) then widget_control,prevbut,sensitive=0 else $
+ widget_control,prevbut,sensitive=1
+ if (liston EQ maxlist) then widget_control,nextbut,sensitive=0 else $
+ widget_control,nextbut,sensitive=1
+
+ end
+;-------------------------------------------------------------------------
+;main program
+
+pro dbedit,list,items,bytenum=k_bytenum
+
+ compile_opt idl2
+common db_com,qdb,QITEMS,QDBREC
+
+;Nitems - Number elements in input list
+;Thislist - Sorted list of entry numbers
+;Minlist - Minimum input entry number
+;Maxlist - Maximum input entry number
+;Liston - The current entry number being edited (scalar)
+;wereat - The index of ThisList vector being edited, i.e. Thislist(wereat)=LIston
+;dtype - data type(s) (1=string,2=byte,4=i*4,...)
+;sbyte - starting byte(s) in entry
+;numvals - number of data values for item(s)
+; NOTE: dtype, sbyte, numvals are dimensioned for *all* entries
+
+common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
+ it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
+ endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
+ holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag,bytenum
+
+ On_error,2
+ if N_params() LT 1 then begin
+ print,'Syntax - dbedit, list, [ items ]'
+ return
+ endif
+
+;Set the value of bytenum
+bytenum = keyword_set(k_bytenum)
+
+;make sure widgets are available
+ if (!D.FLAGS AND 65536) EQ 0 then begin
+ dbedit_basic, list, items
+ return
+ endif
+
+;check to make sure database is open
+ ;first check to see if there is an open database
+ s = size(qdb)
+ if (s[0] EQ 0) then begin
+
+ result = dialog_message(/ERROR, title='NOT OPEN FOR UPDATE', $
+ 'No database has been opened')
+ goto, PROEND
+ endif
+;check to make sure the database is opened for update
+ dbname = db_info('NAME',0)
+ if not db_info('UPDATE') then begin
+
+ result = dialog_message(/ERROR, title='NOT OPEN FOR UPDATE', $
+ 'Database ' + dbname + ' must be opened for update.')
+ goto,PROEND
+
+ endif
+
+
+ ;check parameters
+ zparcheck, 'DBEDIT', list, 1, [1,2,3], [0,1], 'Database entry numbers'
+
+ ;get items. If items not specified use all items except ENTRY
+ if ( N_params() LT 2 ) then begin
+ nitems = db_info('ITEMS',0) -1
+ items = indgen(nitems) + 1
+ endif
+
+ nlist = N_elements(list)
+
+ if nlist gt 1 then begin ;sort entry numbers
+
+ sar = sort(list)
+ thislist = list[sar]
+
+ endif else begin
+
+ thislist = lonarr(1)
+ thislist[0] = list
+
+ endelse
+
+ ;edit all entries? get number of entries
+ if ( list[0] EQ -1 ) then begin
+ nlist = db_info('ENTRIES',0)
+ if nlist le 0 then begin
+ print,'Empty database cannot be edited. Use list=0 to add new entry'
+ goto, PROEND
+ endif
+ thislist = lindgen(nlist) + 1
+ endif
+
+ minlist = min(thislist, max = maxlist)
+
+
+ nentry = db_info('ENTRIES',0)
+ if (maxlist gt nentry) then begin
+ result = dialog_message(title='INVALID ENTRY NUMBER',/ERROR, $
+ dbname + ' entry numbers must be less than ' + strtrim(nentry+1,2) )
+ goto, PROEND
+ endif
+
+ nitems = db_info('ITEMS',0) -1
+ allitems = indgen(nitems) + 1
+
+ ;get information about items
+ db_item,allitems,itnum,ivalnum,dtype,sbyte,numvals,nbytes
+ nvalues = db_item_info('nvalues')
+
+ db_item,items,it
+
+ nit = n_elements(it) ;Number of items to be edited
+ names = db_item_info('name',itnum) ;Get names of each item
+ newflag = bytarr(nlist,nitems) ;Keeps track of fields actually updated
+
+ wereat = 0
+ liston = thislist[wereat]
+ dbrd,liston,entry
+
+ ;create widget and display
+ main = widget_base(/COLUMN,title='Widgetized Database Editor')
+ w1 = widget_label(main,value='****** ' + dbname + ' ******')
+ bigmid = widget_base(main,/column,x_scroll_size=325,y_scroll_size=650)
+
+
+ butbase = widget_base(main,/column,/frame)
+ savebut = widget_button(butbase,value='SAVE THIS ENTRY')
+ buts = widget_base(butbase,/row)
+ prevbut = widget_button(buts,value='<- PREV ENTRY')
+ but2 = widget_base(buts,/column)
+ resetbut = widget_button(but2,value='RESET THIS ENTRY')
+ endbut = widget_button(but2,value='END SESSION')
+ nextbut = widget_button(buts,value='NEXT ENTRY ->')
+
+ widlabel = lonarr(nitems+1)
+ widtext = lonarr(nitems+1)
+ holder = lonarr(nitems+1)
+
+ mid = widget_base(bigmid,/column)
+
+ holder0 = widget_base(mid,/row)
+ widlabel0 =widget_label(holder0,value=' ENTRY NUMBER ',/frame)
+ num = string(liston)
+ widtext0 = widget_label(holder0,value=num)
+
+ middle = widget_base(mid,/column)
+
+ for i = 0,nitems-1 do begin
+ ed = 'N'
+ str1 = names[i]
+
+ for j = 0, N_elements(it)-1 do begin
+ if it[j] EQ itnum[i] then ed = 'Y'
+ endfor
+
+ str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
+ if (dtype[i] eq 1) and keyword_set(bytenum) then str=fix(str)
+ str = ' ' + string(str[0])
+ if ed eq 'Y' then begin
+ holder[i] = widget_base(middle,/row)
+ widlabel[i] = widget_label(holder[i],value = str1,/frame)
+ widtext[i] = widget_text(holder[i],/frame,value=str,/edit)
+ endif else begin
+ holder[i] = widget_base(middle,/row)
+ widlabel[i] = widget_label(holder[i],value = str1,/frame)
+ widtext[i] = widget_label(holder[i],value=str)
+ endelse
+ endfor
+
+ if (liston EQ minlist) then widget_control,prevbut,sensitive=0 else $
+ widget_control,prevbut,sensitive=1
+ if (liston EQ maxlist) then widget_control,nextbut,sensitive=0 else $
+ widget_control,nextbut,sensitive=1
+
+ widget_control,main,/realize
+ xmanager,'widgetedit',main
+
+ newitem = total(newflag, 1)
+ indexnum = where(newitem, nindex)
+
+ if ( nindex GT 0 ) then begin ;Any mods made?
+ indexnum = itnum[indexnum]
+ indextype = db_item_info('INDEX',indexnum);Index type of modified fields
+ good = where(indextype GE 1, Ngood) ;Which fields are indexed?
+ if Ngood GT 0 then begin
+ message, 'Now updating index file', /INF
+ dbindex, indexnum[good]
+ endif
+ dbopen,strlowcase(dbname),1
+ endif
+
+PROEND:
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbedit_basic.pro b/Code/script_idl_mv/astrolib/dbedit_basic.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d934c87f8736fcdd5307ac12addb2112ba82e93f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbedit_basic.pro
@@ -0,0 +1,157 @@
+pro dbedit_basic,list,items
+;+
+; NAME:
+; DBEDIT_BASIC
+; PURPOSE:
+; Subroutine of DBEDIT_BASIC to edit a database on a dumb terminal.
+; EXPLANATION:
+; Interactively edit specified fields in a database. The
+; value of each field is displayed, and the user has the option
+; of changing or keeping the value.
+;
+; CALLING SEQUENCE:
+; dbedit_basic, list, [ items ]
+;
+; INPUTS:
+; list - scalar or vector of database entry numbers. Set LIST=0
+; to interactively add a new entry to a database.
+;
+; OPTIONAL INPUTS
+; items - list of items to be edited. If not supplied, then the
+; value of every field will be displayed.
+;
+; NOTES:
+; (1) Database must be opened for update (dbopen,,1) before
+; calling DBEDIT_BASIC. User must have write privileges on the database
+; files.
+; (2) User gets a second chance to look at edited values, before
+; they are actually written to the database
+;
+; PROMPTS:
+; The item values for each entry to be edited are first displayed
+; User is the asked "EDIT VALUES IN THIS ENTRY (Y(es), N(o), or Q(uit))?
+; If user answers 'Y' or hits RETURN, then each item is displayed
+; with its current value, which the user can update. If user answered
+; 'N' then DBEDIT_BASIC skips to the next entry. If user answers 'Q'
+; then DBEDIT will exit, saving all previous changes.
+;
+; EXAMPLE:
+; Suppose V magnitudes (V_MAG) in a database STARS with unknown values
+; were assigned a value of 99.9. Once the true values become known, the
+; database can be edited
+;
+; IDL> !PRIV=2 & dbopen,'STARS',1 ;Open database for update
+; IDL> list = dbfind('V_MAG=99.9') ;Get list of bad V_MAG values
+; IDL> dbedit,list,'V_MAG' ;Interactively insert good V_MAG values
+;
+; REVISION HISTORY:
+; Written W. Landsman STX April, 1989
+; Rename DBEDIT_BASIC from DBEDIT July, 1993
+; Converted to IDL V5.0 W. Landsman September 1997
+; Change DATATYPE() to size(/TNAME) W. Landsman November 2001
+;-
+ On_error,2
+
+ zparcheck, 'DBEDIT_BASIC', list, 1, [1,2,3], [0,1], 'Database entry numbers'
+
+ dbname = db_info( 'NAME', 0 ) ;Database name
+ if not db_info( 'UPDATE' ) then $
+ message, 'Database ' + dbname + ' must be opened for update
+
+ if ( N_params() LT 2 ) then begin ;Did user specify items string?
+ nitems = db_info( 'ITEMS', 0 ) -1 ;If not then use every item but ENTRY
+ items = indgen(nitems) + 1
+ endif
+
+ nlist = N_elements(list)
+
+ if ( list[0] EQ -1 ) then begin ;Edit all entries?
+ nlist = db_info( 'ENTRIES', 0 ) ;Get number of entries
+ list = lindgen(nlist) + 1
+ endif
+
+ db_item, items, itnum, ivalnum, dtype, sbyte, numvals, nbytes
+
+ nitems = N_elements(itnum) ;Number of items to be edited
+ names = db_item_info( 'NAME', itnum ) ;Get names of each item
+ newflag = bytarr(nlist,nitems) ;Keeps track of fields actually updated
+ yesno = ''
+
+for i = 0, nlist-1 do begin ;Loop over each entry to be edited
+ ll = list[i]
+
+ if ll GT 0 then begin ;Existing entry?
+ dbprint,ll,'*',TEXT = 1
+ read,'Edit values in this entry (Y(es),N(o),Q(uit), def=Y)? ',yesno
+ yesno = strupcase(strmid(yesno,0,1))
+ if yesno eq 'Q' then goto, UPDATE $
+ else if yesno EQ 'N' then goto, ENTRY_DONE
+ endif else message,'Adding new entry to database '+dbname,/inform
+
+ print,'Hit [RETURN] to leave values unaltered'
+ READVAL: dbrd,ll,entry
+ for j = 0,nitems - 1 do begin
+ val = ''
+ name = strtrim(names[j],2)
+ curval = dbxval( entry, dtype[j], numvals[j], sbyte[j], nbytes[j] )
+; Convert byte to integer to avoid string conversion problems
+ if (dtype[j] EQ 1) and ( N_elements(curval) EQ 1 ) then $
+ curval = fix(curval)
+ if ( numvals[j] EQ 1 ) then oldval = strtrim(curval,2) else $
+ oldval = strtrim(curval[0],2) + '...'
+ read,name+' New Value (' + oldval + '): ',val
+ TESTVAL:
+ if ( val NE '' ) then begin
+ oldval = make_array( size = [1,numvals[j],dtype[j],numvals[j]] )
+ On_IOerror, BADVAL
+ oldval[0] = val
+ On_IOerror, NULL
+ newflag[i,j] = 1
+ dbxput, oldval, entry, dtype[j], sbyte[j], nbytes[j]
+ endif
+ endfor
+
+ if ( total(newflag[i,*]) GT 0 ) then begin
+ print,'' & print,'Updated Values' & print,''
+
+ for j = 0,nitems-1 do begin
+ name = strtrim(names[j],2)
+ print,name,': ',dbxval( entry,dtype[j],numvals[j],sbyte[j],nbytes[j] )
+ endfor
+ print,''
+ yesno = ''
+ read,' Are these values correct [Y]? ', yesno
+ if ( strupcase(yesno) NE 'N' ) then begin
+ if ( ll EQ 0 ) then begin
+ dbwrt,entry,0,1
+ ll = db_info('entries',0) + 1
+ endif else dbwrt,entry
+ print,'' & print,'Entry ',strtrim(ll,2), ' now updated
+ endif else begin
+ newflag[i,*] = 0
+ goto, READVAL
+ endelse
+ endif else print,'No values updated for entry',ll
+ ENTRY_DONE:
+endfor
+
+UPDATE:
+ newitem = total(newflag, 1)
+ indexnum = where(newitem, nindex)
+
+ if ( nindex GT 0 ) then begin ;Any mods made?
+ indexnum = itnum[indexnum]
+ indextype = db_item_info('INDEX',indexnum) ;Index type of modified fields
+ good = where(indextype GE 1, ngood) ;Which fields are indexed?
+ if ngood GT 0 then dbindex,indexnum[good]
+ dbopen,dbname,1
+ dbprint,list,[0,itnum],TEXT=1
+ endif
+ return
+BADVAL:
+ print,'Item '+name+ ' must be of type '+ size(oldval[0],/TNAME)
+ val = ''
+ j = j-1
+ goto, TESTVAL
+
+ end
diff --git a/Code/script_idl_mv/astrolib/dbext.pro b/Code/script_idl_mv/astrolib/dbext.pro
new file mode 100644
index 0000000000000000000000000000000000000000..28250cf561a29bc4cbad2bf3cb3e8b343ec09756
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbext.pro
@@ -0,0 +1,85 @@
+pro dbext,list,items,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12
+;+
+; NAME:
+; DBEXT
+; PURPOSE:
+; Extract values of up to 12 items from an IDL database
+; EXPLANATION:
+; Procedure to extract values of up to 12 items from
+; data base file, and place into IDL variables
+;
+; CALLING SEQUENCE:
+; dbext,list,items,v1,[v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12]
+;
+; INPUTS:
+; list - list of entry numbers to be printed, vector or scalar
+; If list = -1, then all entries will be extracted.
+; list may be converted to a vector by DBEXT
+; items - standard item list specification. See DBPRINT for
+; the 6 different ways that items may be specified.
+;
+; OUTPUTS:
+; v1...v12 - the vectors of values for up to 12 items.
+;
+; EXAMPLE:
+; Extract all RA and DEC values from the currently opened database, and
+; place into the IDL vectors, IDLRA and IDLDEC.
+;
+; IDL> DBEXT,-1,'RA,DEC',idlra,idldec
+;
+; HISTORY
+; version 2 D. Lindler NOV. 1987
+; check for INDEXED items W. Landsman Feb. 1989
+; Converted to IDL V5.0 W. Landsman September 1997
+; Avoid EXECUTE() call for V6.1 or later W. Landsman December 2006
+; Assume since V6.1 W. Landsman June 2009
+;-
+;*****************************************************************
+ On_error,2
+ compile_opt idl2
+
+ if N_params() lt 3 then begin
+ print,'Syntax - dbext, list, items, v1, [ v2, v3....v12 ]'
+ return
+ endif
+
+ zparcheck,'DBEXT',list,1,[1,2,3,4,5],[0,1],'Entry List'
+
+ db_item,items,it,ivalnum,idltype,sbyte,numvals,nbytes
+
+ nitems = N_elements(it)
+ nentries = db_info('entries')
+ if max(list) GT nentries[0] then $
+ message,db_info('name',0)+' entry numbers must be between 1 and ' + $
+ strtrim(nentries[0],2)
+ if nitems GT N_params()-2 then $
+ message,'Insufficient output variables supplied'
+ if nitems LT N_params()-2 then message, /INF, $
+ 'WARNING - More output variables supplied than items specified'
+
+; get item info.
+
+ dbno = db_item_info('dbnumber',it)
+ if max(dbno) eq 0 then dbno=0 $ ;flag that it is first db only
+ else dbno=-1
+ index = db_item_info('index',it)
+ ind = where( (index ge 1) and (index ne 3), Nindex )
+
+ if (Nindex eq nitems) and (dbno eq 0) then begin ;All indexed items?
+
+ if N_elements(list) eq 1 then list = lonarr(1) + list
+ for i=0,nitems - 1 do begin ;Get indexed items
+ itind = it[ind[i]]
+ dbext_ind,list,itind,dbno,scope_varfetch('v' + strtrim(ind[i]+1,2))
+ endfor
+
+ endif else begin
+
+ nvalues = db_item_info('nvalues',it)
+ dbext_dbf,list,dbno,sbyte,nbytes*nvalues,idltype,nvalues, $
+ v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12
+
+ endelse
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbext_dbf.pro b/Code/script_idl_mv/astrolib/dbext_dbf.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d56cadeac51ed8d58c993a0026b4ef786e0dfcb8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbext_dbf.pro
@@ -0,0 +1,152 @@
+pro dbext_dbf,list,dbno,sbyte,nbytes,idltype,nval,v1,v2,v3,v4,v5,v6, $
+ v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18, item_dbno=item_dbno
+
+;+
+; NAME:
+; DBEXT_DBF
+; PURPOSE:
+; Subroutine of DBEXT to extract values of up to 18 items from a database
+; EXPLANATION:
+; This is a subroutine of DBEXT, which is the routine a user should
+; normally use.
+;
+; CALLING SEQUENCE:
+; dbext_dbf,list,dbno,sbyte,nbytes,idltype,nval,v1,[ v2,v3,v4,v5,v6,v7,
+; v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18 ITEM_DBNO = ]
+;
+; INPUTS:
+; list - list of entry numbers to extract desired items. It is the
+; entry numbers in the primary data base unless dbno is greater
+; than or equal to -1. In that case it is the entry number in
+; the specified data base.
+; dbno - number of the opened db file
+; if set to -1 then all data bases are included
+; sbyte - starting byte in the entry. If single data base then it must
+; be the starting byte for that data base only and not the
+; concatenation of db records
+; nbytes - number of bytes in the entry
+; idltype - idl data type of each item to be extracted
+; nval - number of values per entry of each item to be extracted
+;
+; OUTPUTS:
+; v1...v18 - the vectors of values for up to 18 items
+;
+; OPTIONAL INPUT KEYWORD:
+; item_dbno - A vector of the individual database numbers for each item.
+; Simplifies the code for linked databases
+; PROCEDURE CALLS:
+; DB_INFO(), DB_ITEM_INFO(), DBRD, DBXVAL(), IS_IEEE_BIG(), IEEE_TO_HOST
+; HISTORY
+; version 1 D. Lindler Nov. 1987
+; Extract multiple valued entries W. Landsman May 1989
+; William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Added support for external (IEEE) representation.
+; Work with multiple element string items W. Landsman August 1995
+; Increase speed for external databases on IEEE machines WBL August 1996
+; IEEE conversion implemented on blocks of entries using BIG
+; Added keyword ITEM_DBNO R. Schwartz, GSFC/SDAC, August 1996
+; Return a vector even if only 1 value W. Thompson October 1996
+; Change variable name of BYTESWAP to BSWAP W. Thompson Mar 1997
+; Use /OVERWRITE with reform W. Landsman May 1997
+; Increase maximum number of items to 18 W. Landsman November 1999
+; 2 May 2003, W. Thompson, Use DBXVAL with BSWAP instead of IEEE_TO_HOST.
+; Avoid EXECUTE() for V6.1 or later W. Landsman Jan 2007
+; Assume since V6.1 W. Landsman June 2009
+; Change arrays to LONG to support entries >32767 bytes WL Oct 2010
+;-
+;
+ compile_opt idl2
+;*****************************************************************
+;
+COMMON db_com,qdb,qitems,qdbrec
+nitems=n_elements(sbyte) ;number of items
+external = db_info('external') ;External format?
+bswap = external * (~IS_IEEE_BIG() ) ;Need to byteswap?
+if dbno ge 0 then bswap = bswap[dbno] + bytarr(nitems) else $
+ if n_elements(item_dbno) eq nitems then bswap=bswap[item_dbno] $
+ else begin
+ sbyte1 = db_item_info('bytepos')
+ itnums = intarr(nitems)
+ for i=0,nitems-1 do itnums[i] = (where( sbyte[i] eq sbyte1))[0]
+ dbno1 = db_item_info('dbnumber', itnums)
+ bswap = bswap[dbno1]
+endelse
+
+scalar=0
+if n_elements(list) eq 1 then begin
+ scalar=1
+ savelist=list
+ list=lonarr(1)+list
+ if list[0] eq -1 then list=lindgen(db_info('entries',0))+1
+end
+nlist=n_elements(list)
+;
+; create a big array to hold all extracted values in
+; byte format
+;
+totbytes=total(nbytes)
+big=bytarr(totbytes,nlist)
+;
+; generate vector of bytes in entries to extract
+;
+index=lonarr(totbytes)
+ipos=0
+for i=0,nitems-1 do begin
+ for j=0,nbytes[i]-1 do index[ipos+j]=sbyte[i]+j
+ ipos=ipos+nbytes[i]
+endfor
+;
+; generate vector of byte positions in big for each item
+;
+bpos=lonarr(nitems)
+if nitems gt 1 then for i=1,nitems-1 do bpos[i]=bpos[i-1]+nbytes[i-1]
+;
+; loop on records and extract info into big
+;
+if dbno ge 0 then begin
+ ;
+ ; bypass dbrd for increased performance
+ ;
+ if dbno eq 0 then begin
+ for i=0L,nlist-1 do begin
+ if list[i] ge 0 then begin
+ entry=qdbrec[list[i]]
+ big[0,i] = entry[index]
+ endif
+ endfor
+ end else begin ;mapped I/O
+ unit=db_info('unit_dbf',dbno)
+ rec_size=db_info('length',dbno)
+ for i=0L,nlist-1 do begin
+ if list[i] ge 0 then begin
+ p=assoc(unit,bytarr(rec_size,/nozero),rec_size*list[i])
+ entry=p[0]
+ big[0,i] = entry[index]
+ end
+ endfor
+ end
+ end else begin
+ for i = 0L, nlist-1 do begin
+ if list[i] GE 0 then begin
+ dbrd,list[i],entry, /noconvert
+ big[0,i] = entry[index]
+ endif
+ end
+end
+;
+; now extract each value and convert to correct type
+;
+last = bpos + nbytes -1
+
+for i = 0,nitems-1 do begin
+ item = dbxval(big, idltype[i], nval[i], bpos[i], nbytes[i], bswap=bswap[i])
+ st = 'v' + strtrim(i+1,2)
+ if nlist GT 1 then $
+ (SCOPE_VARFETCH(st)) = reform(item,/overwrite) else $
+ (SCOPE_VARFETCH(st)) = [item]
+
+ endfor;for i loop on items
+;
+if scalar then list=savelist ;restore scalar value
+return
+end
diff --git a/Code/script_idl_mv/astrolib/dbext_ind.pro b/Code/script_idl_mv/astrolib/dbext_ind.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a9466e70af9ca788046b9b5e0b4efaff881915a8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbext_ind.pro
@@ -0,0 +1,143 @@
+pro dbext_ind,list,item,dbno,values
+;+
+; NAME:
+; DBEXT_IND
+; PURPOSE:
+; routine to read a indexed item values from index file
+;
+; CALLING SEQUENCE:
+; dbext_ind,list,item,dbno,values
+;
+; INPUTS:
+; list - list of entry numbers to extract values for
+; (if it is a scalar, values for all entries are extracted)
+; item - item to extract
+; dbno - number of the opened data base
+;
+; OUTPUT:
+; values - vector of values returned as function value
+; HISTORY:
+; version 1 D. Lindler Feb 88
+; Faster processing of string values W. Landsman April, 1992
+; William Thompson, GSFC/CDS (ARC), 30 May 1994
+; Added support for external (IEEE) data format
+; Allow multiple valued (nonstring) index items W. Landsman November 2000
+; Use 64bit integer index for large databases W. Landsman February 2001
+; Fix sublisting of multiple valued index items W. Landsman March 2001
+; Check whether any supplied entries are valid W. Landsman Jan 2009
+; Remove IEEE_TO_HOST W. Landsman Apr 2016
+;-
+On_error,2
+compile_opt idl2
+;
+if N_params() LT 4 then begin
+ print,'Syntax - DBEXT_IND, list, item, dbno, values'
+ return
+endif
+
+; Determine first and last block to extract
+;
+s=size(list) & ndim=s[0]
+if (ndim GT 0) then if (list[0] EQ -1) then ndim=0
+zeros = 0 ;flag if zero's present in list
+if ndim EQ 0 then begin
+ minl = 1
+ maxl = db_info('ENTRIES',dbno)
+ end else begin
+ minl = min(list)
+ if minl EQ 0 then begin ;any zero values in list
+ zeros = 1
+ nonzero = where(list GT 0, Ngood, comp=bad)
+ if Ngood EQ 0 then message,'ERROR - No valid entry numbers supplied'
+ minl = min(list[nonzero])
+ endif
+ maxl=max(list)
+ end
+;
+; get item info
+;
+db_item,item,it,ivalnum,dtype,sbyte,numvals,nbytes
+nbytes = nbytes[0]
+if N_elements(it) GT 1 then $
+ message,'ERROR - Only one item can be extracted by dbext_ind'
+
+itnum = db_item_info('itemnumber',it[0]) ;item number in this dbno
+;
+; determine if indexed
+;
+index_type = db_item_info('index',it[0])
+if index_type EQ 0 then $
+ message,'ERROR - Requested item is not indexed'
+
+if index_type EQ 3 then $
+ message,'ERROR - Unsorted values of item not recorded in index file'
+;
+; get unit number of index file and read header info
+;
+ unit=db_info('UNIT_DBX',dbno)
+ external = db_info('EXTERNAL',dbno) ;External (IEEE) data format?
+ p=assoc(unit,lonarr(2))
+ h=p[0]
+ if external then swap_endian_inplace,h,/swap_if_little
+ p = assoc(unit,lonarr(7,h[0]),8)
+ header = p[0]
+ if external then swap_endian_inplace,header,/swap_if_little
+ items = header[0,*]
+ pos = where(items EQ itnum, Nindex) & pos=pos[0]
+ if Nindex LT 1 then $
+ message,'Item not indexed, DBNO may be wrong'
+
+;
+; find starting location to read
+;
+if index_type NE 4 then sblock=header[4,pos] else sblock=header[6,pos]
+;
+numvals = numvals[0]
+sbyte = 512LL*sblock
+sbyte = sbyte+(minl-1L)*nbytes*numvals
+nv = (maxl-minl+1L) ;number of bytes to extract
+;
+; create mapped i/o variable
+;
+dtype = dtype[0]
+
+if dtype NE 7 then begin
+ if numvals GT 1 then $
+ p = assoc(unit, make_array(size=[2,numvals,nv,dtype,0],/NOZERO), sbyte ) else $
+ p = assoc(unit, make_array(size=[1,nv,dtype,0],/NOZERO), sbyte )
+ endif else p = assoc(unit, make_array(size=[2,nbytes,nv,1,0],/NOZERO), sbyte )
+
+;
+; read values from file
+; Modified, April 92 to delay conversion to string until the last step WBL
+;
+values = p[0]
+if external then swap_endian_inplace,values,/swap_if_little
+;
+; if subset list specified perform extraction
+;
+
+if ndim NE 0 then begin
+ if zeros then begin ;zero out bad values
+ if dtype NE 7 then begin ;not a string?
+ if numvals EQ 1 then begin
+ values = values[(list-minl)>0 ]
+ values[bad]=0
+ endif else begin
+ values = values[*,(list-minl)>0 ]
+ values[*,bad] = intarr(numvals)
+ endelse
+ end else begin ;string
+ values = values[*, (list-minl)>0 ]
+ if N_elements(bad) EQ 1 then bad = bad[0]
+ values[0,bad] = replicate( 32b, nbytes )
+ endelse
+ end else begin
+ if (dtype EQ 7) || (numvals GT 1) then $
+ values = values[*, list-minl] $
+ else values = values[ list-minl ]
+ end
+end
+if dtype EQ 7 then values = string(values)
+return
+end
diff --git a/Code/script_idl_mv/astrolib/dbfind.pro b/Code/script_idl_mv/astrolib/dbfind.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f2bc14469e06fa96d54f1d86595f7f1f69b1f0ec
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbfind.pro
@@ -0,0 +1,382 @@
+function dbfind,spar,listin,SILENT=silent,fullstring = Fullstring, $
+ errmsg=errmsg, Count = count
+;+
+; NAME:
+; DBFIND()
+; PURPOSE:
+; Search data base for entries with specified characteristics
+; EXPLANATION:
+; Function to search data base for entries with specified
+; search characteristics.
+;
+; CALLING SEQUENCE:
+; result = dbfind(spar,[ listin, /SILENT, /FULLSTRING, ERRMSG=, Count = ])
+;
+; INPUTS:
+; spar - search_parameters (string)...each search parameter
+; is of the form:
+;
+; option 1) min_val < item_name < max_val
+; option 2) item_name = value
+; option 3) item_name = [value_1, value_10]
+; Note: option 3 is also the slowest.
+; option 4) item_name > value
+; option 5) item_name < value
+; option 6) item_name = value(tolerance) ;eg. temp=25.0(5.2)
+; option 7) item_name ;must be non-zero
+;
+; Multiple search parameters are separated by a comma.
+; eg. 'cam_no=2,14 is interpreted as greater than or equal.
+;
+; RA and DEC keyfields are stored as floating point numbers
+; in the data base may be entered as HH:MM:SEC and
+; DEG:MIN:SEC. Where:
+;
+; HH:MM:SEC equals HH + MM/60.0 + SEC/3600.
+; DEG:MIN:SEC equals DEG + MIN/60.0 + SEC/3600.
+;
+; For example:
+; 40:34:10.5 < dec < 43:25:19 , 8:22:1.0 < ra < 8:23:23.0
+;
+; Specially encoded date/time in the data base may
+; be entered by CCYY/DAY:hr:min:sec which is
+; interpreted as
+; CCYY*1000+DAY+hr/24.0+min/24.0/60.+sec/24.0/3600.
+; If a two digit year is supplied and YY GE 40 then it is
+; understood to refer to year 1900 +YY; if YY LT 40 then it is
+; understood to refer to year 2000 +YY
+
+; For example
+; 1985/201:10:35:3032767 bytes W.L. Oct. 2010
+; Delay warning now for 10000 instead of 2000 entries W.L. Aug 2014
+;-
+;
+; ---------------------------------------------------------------------
+
+On_error,2 ;return to caller
+;
+; Check parameters. If LISTIN supplied, make sure all entry values are
+; less than total number of entries.
+;
+ count = 0
+ zparcheck,'dbfind',spar,1,7,[0,1],'search parameters'
+
+ catch, error_status
+ if error_status NE 0 then begin
+ print,!ERR_STRING
+ if N_elements(listin) NE 0 then return,listin else return, -1
+ endif
+ nentries = db_info( 'ENTRIES',0 ) ;number of entries
+ if ( N_params() LT 2 ) then listin = -1 else begin
+ zparcheck,'dbfind',listin,2,[1,2,3],[0,1],'entry list'
+ maxlist = max(listin)
+ if ( maxlist GT nentries ) then begin
+ message = 'Entry list values (second parameter) must be less than '+ $
+ strtrim(nentries,2)
+ goto, handle_error
+ endif
+ endelse
+ if nentries eq 0 then begin ;Return if database is empty
+ !err = 0
+ if not keyword_set(SILENT) then message, $
+ 'ERROR - No entries in database ' + db_info("NAME",0),/INF
+ return,listin
+ endif
+;
+; parse search parameter string
+;
+ dbfparse,spar,items,stype,search_values
+ nitems = N_elements(items) ;number of items
+;
+; set up initial search list
+;
+list = listin
+s=size(list) & ndim=s[0]
+if ndim EQ 0 then list=lonarr(1)+list
+;
+; get some item info
+;
+db_item,items,it,ivalnum,idltype,sbyte,numvals,nbytes,errmsg=errmsg
+IF N_ELEMENTS(ERRMSG) NE 0 THEN IF ERRMSG NE '' THEN BEGIN
+ MESSAGE = ERRMSG
+ GOTO, HANDLE_ERROR
+ENDIF
+index = db_item_info('INDEX',it) ;index type
+dbno = db_item_info('DBNUMBER',it) ;data base number
+ ; particular db.
+;
+; get info on the need to byteswap item by item
+;
+external = db_info('external') ;External format?
+bswap = external * (not IS_IEEE_BIG() ) ;Need to byteswap?
+dbno1 = db_item_info('dbnumber', it)
+bswap = bswap[dbno1]
+
+done=bytarr(nitems) ;flag for completed
+ ; items
+;----------------------------------------------------------------------
+; ENTRY number is a search parameter?
+;
+for pos = 0,nitems-1 do begin
+ if (it[pos] eq 0) then begin
+ dbfind_entry,stype[pos],search_values[pos,*],nentries,list,count=count
+ done[pos]=1 ;flag as done
+ if count LT 1 then goto, FINI ;any found
+ end
+end
+;----------------------------------------------------------------------
+;
+; perform search on sorted items in the first db
+;
+
+for pos=0,nitems-1 do begin
+ if(not done[pos]) and (dbno[pos] eq 0) and $
+ (index[pos] ge 2) then begin
+ dbfind_sort,it[pos],stype[pos],search_values[pos,*],list, $
+ fullstring=fullstring, Count = count
+ if !err ne -2 then begin
+ if count lt 1 then goto,FINI
+ done[pos]=1
+ end
+ end
+end
+; ------------------------------------------------------------------------
+; Perform search on items in lookup file (indexed items) in first db
+;
+if total(done) eq nitems then goto,FINI
+for pos=0,nitems-1 do begin
+ if(not done[pos]) and (dbno[pos] eq 0) and (index[pos] ne 0) then begin
+ dbext_ind,list,it[pos],0,values
+ dbsearch, stype[pos], search_values[pos,*], values, good, $
+ Fullstring = fullstring, Count = count
+ if !err eq -2 then begin
+ print,'DBFIND - Illegal search value for item ', $
+ db_item_info('name',it[pos])
+ return,listin
+ endif
+ if count lt 1 then goto, FINI ;any found
+ if list[0] ne -1 then list=list[good] else list=good+1
+ done[pos]=1 ; DONE with that item
+ end
+end
+
+;------------------------------------------------------------------------
+;
+; search index items in other opened data bases (if any)
+;
+found=where( (index gt 0) and (dbno ne 0 ), Nfound)
+if Nfound gt 0 then begin
+ db = dbno[ where(dbno NE 0) ]
+ for i = 0, n_elements(db)-1 do begin
+;
+; find entry numbers of second database corresponding to entry numbers
+; in the first data base.
+;
+ pointer=db_info('pointer',db[i]) ;item which points to it
+;
+ dbext,list,pointer,list2 ;extract entry numbers in 2nd db
+ good=where(list2 ne 0,ngood) ;is there a valid pointer
+ if ngood lt 1 then goto, FINI
+ if list[0] eq -1 then list=good+1 else list=list[good]
+ list2=list2[good]
+ for pos=0,nitems-1 do begin
+ if (not done[pos]) and (dbno[pos] eq db[i]) and (index[pos] ne 0) $
+ and (index[pos] ne 3) then begin
+ dbext_ind,list2,it[pos],dbno[pos],values
+ dbsearch, stype[pos], search_values[pos,*], values, good, $
+ fullstring = fullstring, count = count
+ if !err eq -2 then begin
+ message = 'Illegal search value for item ' + $
+ db_item_info('name',it[pos])
+ goto, handle_error
+ endif
+ if count lt 1 then goto, FINI ;any found
+ if list[0] ne -1 then list=list[good] else list=good+1
+ list2=list2[good]
+ done[pos]=1 ; DONE with that item
+ endif
+ endfor
+ endfor
+endif
+;---------------------------------------------------------------------------
+; search remaining items
+;
+
+ if list[0] eq -1 then list= lindgen(nentries)+1 ;Fixed WBL Feb. 1989
+ count = N_elements(list)
+ !err = count
+ if total(done) eq nitems then goto, FINI ;all items searched
+
+ nlist = N_elements(list) ;number of entries to search
+ if nlist GT 10000 then begin
+ print,'Non-indexed search on ',strtrim(nlist,2),' entries'
+ print,'Expect Delay'
+ end
+;
+; Create array to hold values of all remaining items...a big one.
+;
+ left = where( done EQ 0, N_left ) ;items left
+ nbytes = nbytes[left]
+ sbyte = sbyte[left]
+ idltype = idltype[left]
+ bswap = bswap[left]
+ totbytes = total(nbytes) ;total number of bytes to extract
+ big = bytarr(totbytes,nlist) ;array to store values of the items
+;
+; generate starting position in big for each item
+;
+ bpos = lonarr(N_left) ;starting byte in bpos of each item
+ if N_left GT 1 then for i=1,N_left-1 do bpos[i] = bpos[i-1]+nbytes[i-1]
+
+ index = lonarr(totbytes) ;indices of bytes to extract
+ ipos = 0 ;position in index array
+ for i = 0,N_left-1 do begin ;loop on items
+ for j=0,nbytes[i]-1 do index[ipos+j]=sbyte[i]+j ;position in entry
+ ipos = ipos + nbytes[i]
+ end;for
+
+;
+; loop on entries and extract info
+;
+ for ii = 0L, nlist-1L do begin
+ dbrd,list[ii],entry, /noconvert ;read entry
+ big[0,ii]= entry[index]
+ endfor
+
+;
+; now extract values for each item and search for valid ones
+;
+ stillgood = lindgen( nlist )
+
+ for i = 0l,N_left-1 do begin
+ if i Eq 0 then val = big[ bpos[i]:bpos[i]+nbytes[i]-1, 0:nlist-1 ] else $
+ val = big[ bpos[i]:bpos[i]+nbytes[i]-1, stillgood ]
+ if bswap[i] then ieee_to_host, val, idltype=idltype[i]
+ case idltype[i] of
+ 1: v = byte(val,0,nlist) ;byte
+ 2: v = fix(val,0,nlist) ;i*2
+ 3: v = long(val,0,nlist) ;i*4
+ 4: v = float(val,0,nlist) ;r*4
+ 5: v = double(val,0,nlist) ;r*8
+ 7: v = string(val) ;string
+ 12: v = uint(val,0,nlist) ;u*2
+ 13: v = ulong(val,0,nlist) ;u*4
+ 14: v = long64(val,0,nlist) ;i*8
+ 15: v = ulong64(val,0,nlist) ;u*8
+ endcase
+ dbsearch, stype[left[i]], search_values[left[i],*], v, good, $
+ Fullstring = fullstring, count = count
+ if count LT 1 then goto, FINI
+ stillgood=stillgood[good]
+ nlist = count
+ endfor
+ list = list[stillgood]
+ count = N_elements(list) & !ERR = count
+
+FINI:
+if not keyword_set(SILENT) then begin
+ print,' ' & print,' '
+ if count LE 0 then $
+ print,'No entries found by dbfind in '+ db_info('name',0) $
+ else $
+ print,count,' entries found in '+ db_info('name',0)
+endif
+if count LE 0 then return,intarr(1) else return,list[sort(list)]
+;
+; Error handling point.
+;
+HANDLE_ERROR:
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = 'DBFIND: ' + MESSAGE $
+ ELSE MESSAGE, MESSAGE
+end
diff --git a/Code/script_idl_mv/astrolib/dbfind_entry.pro b/Code/script_idl_mv/astrolib/dbfind_entry.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f15fdbd00f19e5afd74958b50347fc4506039e7a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbfind_entry.pro
@@ -0,0 +1,117 @@
+pro dbfind_entry,type,svals,nentries,values,Count = count
+;+
+; NAME:
+; DBFIND_ENTRY
+; PURPOSE:
+; Subroutine of DBFIND to perform an entry number search
+; EXPLANATION:
+; This is a subroutine of dbfind and is not a standalone procedure
+; It performs a entry number search.
+;
+; CALLING SEQUENCE:
+; dbfind_entry, type, svals, nentries, values, [COUNT = ]
+;
+; INPUTS:
+; type - type of search (output from dbfparse)
+; svals - search values (output from dbfparse)
+; values - array of values to search
+; OUTPUT:
+; good - indices of good values
+; OPTIONAL OUTPUT KEYWORD:
+; Count - integer scalar giving the number of valid matches
+; SIDE EFFECTS"
+; The obsolete system variable !err is set to number of good values
+;
+; REVISION HISTORY:
+; D. Lindler July,1987
+; Fixed test for final entry number W. Landsman Sept. 95
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added COUNT keyword, deprecate !ERR W. Landsman March 2000
+; Better checking of out of range values W. Landsman February 2002
+;-
+sv0=long(strtrim(svals[0],2)) & sv1=long(strtrim(svals[1],2))
+
+if values[0] eq -1 then begin ;start with all entries
+ case type of
+
+ 0: begin
+ if (sv0 gt 0) and (sv0 le nentries) then begin ;Update Sep 95
+ values=lonarr(1)+sv0
+ count=1
+ end else count= 0
+ end
+ -1: begin
+ if nentries LT sv0 then count = 0 else begin
+ values=lindgen(nentries-sv0+1) + sv0 ;value>sv0
+ count=nentries-sv0+1
+ endelse
+ end
+ -2: begin
+ values= lindgen(sv1>111
+ sv1=sv11
+ maxv=(sv0+abs(sv1))sv0
+ -2: good=where(values le sv1, count) ;value2
+sv=replicate(values[0],nvals)
+for i=0L,nvals-1 do sv[i]=strtrim(svals[i],2)
+sv0 = sv[0] & sv1 = sv[1]
+
+;
+;--------------------------------------------------------------------------
+; FIND RANGE OF VALID SUBSCRIPTS IN LIST
+;
+;
+if nv EQ 1 then begin
+ first = 0 & last = 1
+endif else begin
+
+case type of
+
+ 0: begin ;value=sv0
+ first = value_locate(values,sv0) > 0
+ last = (first +1) < nv
+ while values[first] EQ sv0 do begin
+ if first EQ 0 then break
+ first = first-1
+ endwhile
+
+ end
+
+ -1: begin ;value>sv0
+ first = value_locate(values,sv0) > 0
+ last = nv
+ while values[first] EQ sv0 do begin
+ if first EQ 0 then break
+ first = first-1
+ endwhile
+ end
+
+ -2: begin ;value first
+ while values[first] EQ sv0 do begin
+ if first EQ 0 then break
+ first = first-1
+ endwhile
+ end
+
+ -3: begin ;sv0 0
+ last = (value_locate(values,sv1) + 1) < nv > 0
+ while values[first] EQ sv0 do begin
+ if first EQ 0 then break
+ first = first-1
+ endwhile
+
+ end
+ -5: begin ;sv1 is tolerance
+
+ minv = sv0-abs(sv1)
+ maxv = sv0+abs(sv1)
+ good = where(values LT minv, N)
+ if N LT 1 then first=0 else first=N-1
+ good = where(values GT maxv, N)
+ if N LT 1 then last=nv else last=good[0]
+ while values[first] EQ sv0 do begin
+ if first EQ 0 then break
+ first = first-1
+ endwhile
+ end
+
+ -4: begin ;non-zero
+ if values[0] EQ 0 then begin
+ good=where(values EQ 0, N)
+ first=N-1
+ last=nv
+ end else begin ;not allowed
+ !err=-2
+ return
+ end
+ end
+ else: begin ;set of values
+ sv0 = min(sv[0:type-1]) & sv1 = max(sv[0:type-1])
+ good=where(values LT sv0, N)
+ if N LT 1 then first=0 else first=N-1
+ good=where(values GT sv1, N)
+ if N LT 1 then last=nv else last=good[0]
+ end
+endcase
+endelse
+;-----------------------------------------------------------------------------
+; we now know valid values are between index numbers first*512 to last*512
+;
+if first EQ last then begin
+ !err=0
+ return
+end
+;
+; extract data values for blocks first to last
+;
+sblock=header[4,pos] ;starting block for sorted data
+sbyte=512LL*sblock ;starting byte
+first=first*512L+1
+last=(last*512L) < db_info('entries',0)
+number=last-first+1
+if dtype NE 7 then $
+p = assoc(unit,make_array(size=[1,number,dtype,0],/nozero), $
+ sbyte+(first-1)*num_bytes) else $
+ p = assoc(unit,make_array( size=[2,nbytes,number,1,0],/NOZERO), $
+ sbyte+(first-1)*num_bytes)
+
+values=p[0]
+
+if dtype EQ 7 then values = string(values) else $
+if external then swap_endian_inplace,values,/swap_if_little
+;
+; if index type is 2, data base is sorted on this item, first and last
+; give range of valid entry numbers
+;
+
+if index_type EQ 2 then begin
+ if list[0] EQ -1 then begin
+ list=lindgen(number)+first
+ end else begin
+ good=where((list ge first) and (list le last), number)
+ if number GT 0 then begin
+ list=list[good]
+ values=values[list-first]
+ endif
+ end
+;
+; if index type wasn't 2 the item was sorted and index numbers must
+; be read
+;
+
+end else begin
+;
+; find starting location to read
+;
+ sblock=header[5,pos]
+ sbyte=512LL*sblock
+;
+; read values from file
+;
+p = assoc(unit,make_array(size=[1,number,3,0],/nozero),sbyte+(first-1)*4)
+ if list[0] EQ -1 then begin
+ list=p[0]
+ if external then byteorder,list, /NTOHL
+ end else begin
+ list2=p[0]
+ if external then byteorder,list2,/NTOHL ;Fixed typo Jan 2010
+ match,list,list2,suba,subb, Count = number
+ if number GT 0 then begin
+ list=list[suba]
+ values=values[subb]
+ end
+ end
+end
+;
+; now search indiviual entries
+;
+if number GT 0 then begin
+ dbsearch,type,svals,values,good,fullstring=fullstring, Count = number
+ if number GT 0 then list=list[good]
+end
+!err=number
+return
+end
diff --git a/Code/script_idl_mv/astrolib/dbfparse.pro b/Code/script_idl_mv/astrolib/dbfparse.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0218c20d93b7430bfaec16d7ded5ea6fe5e52ba4
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbfparse.pro
@@ -0,0 +1,240 @@
+pro dbfparse, spar, items, stype, values
+;+
+; NAME:
+; DBFPARSE
+; PURPOSE:
+; Parse the search string supplied to DBFIND. Not a standalone routine
+;
+; CALLING SEQUENCE:
+; DBFPARSE, [ spar, items, stype, values ]
+;
+; INPUTS:
+; spar - search parameter specification, scalar string
+;
+; OUTPUTS:
+; items - list of items to search on
+; stype - search type, numeric scalar
+; 0 item=values[j,0]
+; -1 item>values[j,0]
+; -2 itemvalues(j,0)
+ ; -2 itemvalue
+ ;
+ (strpos(next,'>') gt 0): begin
+ items[nitems]=gettok(next,'>');get item name
+ values[nitems,0]=next ;get minimum value
+ stype[nitems]=-1
+ end
+ ;
+ ; Range specified or maximum specified.
+ ;
+ (strpos(next,'<') gt 0): begin ; form is min dbopen, 'YALE_BS'
+; IDL> hdno = [1141,2363,3574,4128,6192,6314,6668] ;Desired HD numbers
+; IDL> list = dbget( 'HD', hdno ) ;Get corresponding entry numbers
+;
+; SYSTEM VARIABLES:
+; The obsolete system variable !ERR is set to number of entries found
+; REVISION HISTORY:
+; Written, W. Landsman STX February, 1989
+; William Thompson, GSFC, 14 March 1995 Added keyword FULLSTRING
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added COUNT keyword, deprecate !ERR W. Landsman March 2000
+; Fix bug introduced March 2000 W. Landsman November 2000
+; Fix possible bug when sublist supplied W. Landsman August 2008
+;-
+;
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ if N_params() LT 2 then begin
+ print,'Syntax -- list = ' + $
+ 'DBGET( item, values, [listin, /SILENT, /FULLSTRING, Count=]'
+ return,-1
+ endif
+
+ if N_params() LT 3 then listin = lonarr(1)-1
+
+ nvals = N_elements(values)
+
+ if nvals EQ 0 then message,'No search values supplied'
+
+ db_item, item, itnum
+ index = db_item_info( 'INDEX', itnum)
+ list = listin
+
+ if nvals EQ 1 then val = [values,values] $ ;Need at least 2 elements
+ else val = values
+
+ if index[0] GE 2 then begin ;Sorted item
+ if N_elements(list) EQ 1 then list = lonarr(1) + list
+ dbfind_sort, itnum[0], nvals, val, list, $
+ FULLSTRING = fullstring, Count =count
+
+ endif else begin ;Non-sorted item
+ dbext, list, itnum, itvals
+ dbsearch, nvals, val, itvals, good, FULLSTRING = fullstring, Count = count
+ if count GT 0 then $ ;Updated Aug 2008
+ if list[0] NE -1 then list = list[good] else list = good+1
+ endelse
+
+ if count LE 0 then begin
+ if not keyword_set(SILENT) then $
+ print, 'No entries found by DBGET in ' + db_info( 'NAME',0 )
+ list = intarr(1)
+
+ endif else if not keyword_set( SILENT ) then $
+ print,count,' entries found in '+db_info('name',0)
+
+ return, list[ sort(list) ]
+
+ end
diff --git a/Code/script_idl_mv/astrolib/dbhelp.pro b/Code/script_idl_mv/astrolib/dbhelp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e2bb8b5ab4bccef95f6f7674b253d62645c175fd
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbhelp.pro
@@ -0,0 +1,275 @@
+pro dbhelp,flag,TEXTOUT=textout,sort=sort
+;+
+; NAME:
+; DBHELP
+; PURPOSE:
+; List available databases or items in the currently open database
+; EXPLANATION:
+; Procedure to either list available databases (if no database is
+; currently open) or the items in the currently open database.
+;
+; CALLING SEQUENCE:
+; dbhelp, [ flag , TEXTOUT=, /SORT ]
+;
+; INPUT:
+; flag - (optional) if set to nonzero then item or database
+; descriptions are also printed
+; default=0
+; If flag is a string, then it is interpreted as the
+; name of a data base (if no data base is opened) or a name
+; of an item in the opened data base. In this case, help
+; is displayed only for the particular item or database
+;
+; OUTPUTS:
+; None
+; OPTIONAL INPUT KEYWORDS:
+; TEXTOUT - Used to determine output device. If not present, the
+; value of !TEXTOUT system variable is used (see TEXTOPEN )
+;
+; textout=0 Nowhere
+; textout=1 if a TTY then TERMINAL using /more option
+; otherwise standard (Unit=-1) output
+; textout=2 if a TTY then TERMINAL without /more option
+; otherwise standard (Unit=-1) output
+; textout=3 .prt
+; textout=4 laser.tmp
+; textout=5 user must open file
+; textout=7 same as 3 but text is appended to .prt
+; file if it already exists.
+; textout = filename (default extension of .prt)
+;
+; /SORT - If set and non-zero, then the help items will be displayed
+; sorted alphabetically. If more than one database is open,
+; then this keyword does nothing.
+; METHOD:
+; If no data base is opened then a list of data bases are
+; printed, otherwise the items in the open data base are printed.
+;
+; If a string is supplied for flag and a data base is opened
+; flag is assumed to be an item name. The information for that
+; item is printed along with contents in a optional file
+; zdbase:dbname_itemname.hlp
+; if a string is supplied for flag and no data base is opened,
+; then string is assumed to be the name of a data base file.
+; only information for that file is printed along with an
+; optional file zdbase:dbname.hlp.
+; PROCEDURES USED:
+; DB_INFO(),DB_ITEM_INFO(),FIND_WITH_DEF(), TEXTOPEN, TEXTCLOSE, UNIQ()
+; IDL VERSION:
+; V5.3 or later (uses vectorized FDECOMP)
+; HISTORY:
+; Version 2 D. Lindler Nov 1987 (new db format)
+; Faster printing of title desc. W. Landsman May 1989
+; Keyword textout added, J. Isensee, July, 1990
+; Modified to work on Unix, D. Neill, ACC, Feb 1991.
+; William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Added support for external (IEEE) representation.
+; William Thompson, GSFC, 3 November 1994
+; Modified to allow ZDBASE to be a path string.
+; Remove duplicate database names Wayne Landsman December 1994
+; 8/17/95 jkf/acc - force lowercase filenames for .hlp files.
+; Added /SORT keyword J. Sandoval/W. Landsman October 1998
+; V5.3 version use vectorized FDECOMP W. Landsman February 2001
+; Recognize 64 bit, unsigned integer datatypes W. Landsman September 2001
+; Fix display of number of bytes with /SORT W. Landsman February 2002
+; Assume since V5.2 W. Landsman February 2002
+; Assume since V5.5 W. Landsman
+; Define !TEXTOUT if not already defined W. Landsman April 2016
+;-
+;****************************************************************************
+
+ defsysv,'!TEXTUNIT',exist=i
+ if i EQ 0 then astrolib
+
+;
+; get flag value
+;
+
+ stn=''
+ if N_params() GT 0 then begin
+ if size(flag,/TNAME) EQ 'STRING' then $ ;item name or db name
+ stn=strtrim(flag)
+ endif else flag = 0 ;flag not supplied
+;
+; Are any data bases opened?
+;
+opened = db_info('OPEN')
+if opened then begin
+ if stn EQ '' then xtype=1 $ ;all items
+ else xtype=2 ;single item
+ end else begin
+ if stn EQ '' then xtype=3 $ ;all db's
+ else xtype=4 ;single db
+end
+;
+; determine where user wants output...default terminal.
+;
+if N_elements(textout) EQ 0 then textout = !textout ;use default output dev.
+;
+textopen,'dbhelp',textout=textout
+;
+;--------------------------------------------------------------------
+; if data base open then print info for it
+;
+if opened then begin ;data base opened?
+;
+; get list of items to print
+;
+ if xtype eq 1 then begin ;all items?
+ nitems=db_info('items') ;number of items
+ itnums=indgen(nitems)
+ end else begin
+ nitems=1
+ db_item,stn,itnums
+ end
+;
+; get information on the items
+;
+ names = db_item_info('NAME',itnums) ;item names
+ idltype = db_item_info('IDLTYPE',itnums) ;data type
+ nbytes = db_item_info('NBYTES',itnums) ;number of bytes
+ desc = db_item_info('DESCRIPTION',itnums) ;description
+ pointer = db_item_info('POINTER',itnums) ;file it points to
+ index = db_item_info('INDEX',itnums) ;index type
+ pflag = db_item_info('PFLAG',itnums) ;pointer item flag
+ dbnumber = db_item_info('DBNUMBER',itnums) ;opened data base number
+ pnumber = db_item_info('PNUMBER',itnums) ;opened data base it points to
+ nvalues = db_item_info('NVALUES',itnums) ;number of values for vector
+ if keyword_set(sort) && (max(dbnumber) EQ 0) then begin
+ nsort = sort(names)
+ names = names[nsort]
+ idltype = idltype[nsort]
+ desc = desc[nsort]
+ nvalues = nvalues[nsort]
+ nbytes = nbytes[nsort]
+ endif
+;
+; get names and descriptions of opened db's
+;
+
+ if flag then begin ;print descrip.?
+ desc = strtrim(desc)
+ printf,!textunit,' '
+ printf,!textunit,'----- '+db_info('name',dbnumber[0]) +' '+ $
+ db_info('title',dbnumber[0])
+ printf,!textunit,' ITEM TYPE DESCRIPTION'
+ for i=0,nitems-1 do begin
+ if i NE 0 then if dbnumber[i] ne dbnumber[i-1] then begin
+ printf,!textunit,' '
+ printf,!textunit,'----- '+db_info('name',dbnumber[i]) +' '+ $
+ db_info('title',dbnumber[i])
+ printf,!textunit,' ITEM TYPE DESCRIPTION'
+ end
+ case idltype[i] of
+ 1: type = 'byte'
+ 2: type = 'int*2'
+ 3: type = 'int*4'
+ 4: type = 'real*4'
+ 5: type = 'real*8'
+ 7: type = 'char*'+strtrim(nbytes[i],2)
+ 12: type = 'uint*2'
+ 13: type = 'uint*4'
+ 14: type = 'int*8'
+ 15: type = 'uint*8'
+ end
+ while strlen(type) lt 8 do type=type+' '
+ qname = names[i]
+ if nvalues[i] GT 1 then begin
+ qname=strtrim(qname)
+ qname=qname+'('+strtrim(nvalues[i],2)+')'
+ while strlen(qname) lt 20 do qname=qname+' '
+ end
+ printf,!textunit,strmid(qname,0,18),' ',type,' ', desc[i]
+ end
+ end else begin ;just print item names
+ printf,!textunit,form='(1x,7a11)',names
+ end
+;
+; print index information -----------------------------------------
+;
+ if (xtype EQ 1) && (total(index) GT 0) then begin
+ if xtype EQ 1 then begin
+ printf,!textunit,' '
+ printf,!textunit,'------- Indexed Items ------'
+ indexed=where(index)
+ printf,!textunit,names[indexed]
+ end else begin
+ printf,!textunit,'The item is indexed'
+ end
+ end
+;
+; print pointer information ----------------------------------------
+;
+ if (total(pflag) GT 0) && (xtype EQ 1) then begin
+ good = where( pflag, n)
+ printf,!textunit,' '
+ printf,!textunit,'----- Pointer Information ----'
+ for i=0,n-1 do begin
+ pos=good[i]
+ if pnumber[pos] GT 0 then popen=' (presently opened)' $
+ else popen=''
+ printf,!textunit,strtrim(db_info('name',dbnumber[pos]))+ $
+ '.'+strtrim(names[pos])+' ---> '+ $
+ strtrim(pointer[pos])+popen
+ end
+ end
+;
+; print information on data base size ----------------------------
+;
+ printf,!textunit,' '
+ if xtype EQ 1 then printf,!textunit,'data base contains', $
+ db_info('ENTRIES',0),' entries'
+;
+; print data base information --------------------------------
+;
+ end else begin ;list data bases
+ if stn EQ '' then begin
+ names=list_with_path('*.dbh', 'ZDBASE', COUNT=n) ;get list
+ if n EQ 0 then message,'No databases found in ZDBASE directory'
+ endif else begin
+ names=list_with_path(stn+'*.dbh', 'ZDBASE', COUNT=n) ;get list
+ if n EQ 0 then message,'Unable to locate database '+stn
+ endelse
+ fdecomp,names,disk,dir,fnames
+ fsort = uniq(fnames,sort(fnames))
+ n = N_elements(fsort)
+ if flag then begin ;print description from .DBH file
+ get_lun,unit
+ names = names[fsort]
+ b=bytarr(79) ;Database title is 79 bytes
+ for i=0,n-1 do begin
+ openr,unit,names[i],error=err
+ if err NE 0 then message,/CON, 'Error opening ' + names[i]
+ readu,unit,b
+ printf,!TEXTUNIT,strtrim(b[0:78],2)
+ close,unit
+ endfor
+ free_lun,unit
+ endif else $ ;just print names
+ printf,!textunit,form='(A,T20,A,T40,A,T60,A)',fnames[fsort]
+endelse
+;
+; now print aux help file info if flag was a string ---------------------
+;
+if stn NE '' then begin
+ if xtype EQ 4 then file=find_with_def(stn+'.hlp', 'ZDBASE') $
+ else file=find_with_def(strlowcase( $
+ strtrim(db_info( 'NAME', dbnumber[0]))+ $
+ '_' + strtrim(names[0]) + '.hlp'), 'ZDBASE')
+ openr,unit,strlowcase(file),error=err,/get_lun
+ if err EQ 0 then begin
+ st=''
+ while not eof(unit) do begin
+ readf,unit,st
+ printf,!textunit,st
+ end; while
+ free_lun,unit
+ endif
+end
+;
+; close unit opened by TEXTOPEN
+;
+textclose, TEXTOUT = textout
+
+return
+end
diff --git a/Code/script_idl_mv/astrolib/dbindex.pro b/Code/script_idl_mv/astrolib/dbindex.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8359e9bba586b2519e9b31fc59ab804cdb12863b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbindex.pro
@@ -0,0 +1,218 @@
+pro dbindex,items
+;+
+; NAME:
+; DBINDEX
+; PURPOSE:
+; Procedure to create index file for data base
+;
+; CALLING SEQUENCE:
+; dbindex, [ items ]
+;
+; OPTIONAL INPUT:
+; items - names or numbers of items to be index -- if not supplied,
+; then all indexed fields will be processed.
+;
+; OUTPUT:
+; Index file .dbx is created on disk location ZDBASE:
+;
+; OPERATIONAL NOTES:
+; (1) Data base must have been previously opened for update
+; by DBOPEN
+;
+; (2) Only 18 items can be indexed at one time. If the database has
+; more than 18 items, then two separate calls to DBINDEX are needed.
+; PROCEDURES CALLED:
+; DBINDEX_BLK, DB_INFO(), DB_ITEM, DB_ITEM_INFO(), IS_IEEE_BIG()
+; HISTORY:
+; version 2 D. Lindler Nov 1987 (new db format)
+; W. Landsman added optional items parameter Feb 1989
+; William Thompson, GSFC/CDS (ARC), 30 May 1994
+; Added support for external (IEEE) data format
+; Test if machine is bigendian W. Landsman May, 1996
+; Change variable name of BYTESWAP to BSWAP W. Thompson Mar, 1997
+; Increased number of fields to 15 W. Landsman June, 1997
+; Increase number of items to 18 W. Landsman November 1999
+; Allow multiple valued (nonstring) index items W. Landsman November 2000
+; Use 64 bit integers for V5.2 or later W. Landsman February 2001
+; Do not use EXECUTE() for V6.1 or later, improve efficiency
+; W. Landsman December 2006
+; Automatically enlarge .dbx file if needed, fix major bug in last
+; update W. Landsman Dec 2006
+; Assume since V6.1 W. Landsman June 2009
+; Allow sorted string items W. Landsman October 2009
+; Use Swap_Endian_Inplace instead of IEEE_TO_HOST W. Landsman April 2016
+;-
+;*****************************************************************
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+; Check to see if data base is opened for update
+
+ if db_info('UPDATE') EQ 0 then message, $
+ 'Database must be opened for update'
+
+; Extract index items from data base
+
+ if N_params() EQ 1 then db_item,items,itnum else begin
+ nitems = db_info('ITEMS',0)
+ itnum = indgen(nitems)
+ endelse
+
+ indextype = db_item_info('INDEX',itnum)
+ indexed = where(indextype, Nindex) ;Select only indexed items
+ if Nindex LE 0 then begin
+ message,'Database has no indexed items',/INF
+ return
+ endif else if Nindex GT 18 then begin
+ message,'ERROR - Only 18 items can be indexed at one time',/INF
+ return
+ endif
+
+ indextype = indextype[indexed]
+ if N_params() EQ 1 then indexed = itnum[indexed]
+
+; get info on indexed items
+
+ nbytes = db_item_info('NBYTES',indexed) ;Number of bytes
+ idltype = db_item_info('IDLTYPE',indexed) ;IDL type
+ sbyte = db_item_info('SBYTE',indexed) ;Starting byte
+ nval = db_item_info('NVALUES',indexed) ;Number of values per entry
+
+; get db info
+
+ nentries = db_info('ENTRIES',0)
+ if nentries EQ 0 then begin
+ message, 'ERROR - database contains no entries',/INF
+ return
+ endif
+ unit = db_info('UNIT_DBX',0) ;unit number of index file
+ external = db_info('EXTERNAL',0) ;external format?
+ bswap = external ? not IS_IEEE_BIG() : 0
+
+; read header info of index file (mapped file)
+
+ reclong = assoc(unit,lonarr(2),0)
+ h = reclong[0] ;first two longwords
+ if bswap then swap_endian_inplace,h,/swap_if_little
+ maxentries = h[1] ;max allowed entries
+; If necessary, enlarge the size of the .dbx file. All indexed items must
+; then be reindexed.
+ if maxentries lt nentries then begin
+ message,'Enlarging index (.dbx) file to support ' + $
+ strtrim(nentries,2) + ' entries',/INF
+ dbname = db_info('name',0)
+ dbcreate,dbname,1,maxentry=nentries,external=db_info('external')
+ dbopen, dbname, 1
+ nitems = db_info('ITEMS',0)
+ itnum = indgen(nitems)
+ endif
+
+ nindex2 = h[0] ;number of indexed items
+ if nindex2 LT nindex then goto, NOGOOD
+ reclong = assoc(unit,lonarr(7,nindex2),8)
+ header = reclong[0] ;index header
+ if bswap then swap_endian_inplace,header,/swap_if_little
+ hitem = header[0,*] ;indexed item numbers
+ hindex = header[1,*] ;index type
+ htype = header[2,*] ;idl data type
+ hblock = header[3,*] ;starting block of header
+ sblock = header[4,*] ;starting block of data values
+ iblock = header[5,*] ;starting block of indices (type=3)
+ ublock = header[6,*] ;starting block of unsorted data (type=4)
+
+; extract index items...maximum of 18 indexed fields.
+
+ list = lindgen(nentries)+1l
+ dbext_dbf,list,0,sbyte,nbytes*nval,idltype,nval, $
+ v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18
+
+ for i = 0,nindex-1 do begin
+ ;
+ ; place item in variable v
+ ;
+ v = (scope_varfetch('v' + strtrim(i+1,2)))
+ pos = where(hitem EQ indexed[i], N_found)
+ if N_found LE 0 then goto, NOGOOD
+ pos = pos[0]
+ if hindex[pos] NE indextype[i] then goto, NOGOOD
+ if ( idltype[i] EQ 7 ) then v = byte(v)
+;
+; process according to index type ---------------------------------------
+;
+ reclong = assoc(unit,lonarr(1),(iblock[pos]*512LL))
+ case indextype[i] of
+
+ 1: begin ;indexed (unsorted)
+
+ datarec = dbindex_blk(unit, sblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(v,/swap_if_little) : v
+ end
+;
+ 2: begin ;values are already sorted
+
+ nb=(nentries+511L)/512 ;number of 512 value blocks
+ ind=indgen(nb)*512LL ;position at start of each block
+ sval=v[ind] ;value at start of each block
+;
+ datarec = dbindex_blk(unit, hblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(sval,/swap_if_little) : sval
+ ;
+ datarec = dbindex_blk(unit, sblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(v,/swap_if_little) : v
+ end
+
+ 3: begin ; sort item before storage
+
+ if idltype[i] EQ 7 then begin
+ svv = string(v)
+ sub= bsort(svv)
+ v = byte(svv[sub])
+ endif else begin
+ sub=bsort(v) ;sort values
+ v=v[sub]
+ endelse
+ nb=(nentries+511)/512 ;number of 512 value blocks
+ ind=l64indgen(nb)*512LL ;position at start of each block
+ if idltype[i] EQ 7 then sval=v[*,ind] else sval = v[ind]
+ ;value at start of each block
+ datarec = dbindex_blk(unit, hblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(sval,/swap_if_little) : sval
+;
+ datarec = dbindex_blk(unit, sblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(v,/swap_if_little) : v
+ reclong[0] = bswap ? swap_endian(sub+1,/swap_if_little) : sub+1 ;indices
+ end
+ 4: begin ; sort item before storage
+
+ datarec = dbindex_blk(unit, ublock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(v,/swap_if_little) : v
+ if idltype[i] EQ 7 then begin
+ svv = string(v)
+ sub= bsort(svv)
+ v = byte(svv[sub])
+ endif else begin
+ sub=bsort(v) ;sort values
+ v=v[sub]
+ endelse
+
+
+ nb=(nentries+511)/512 ;number of 512 value blocks
+ ind=l64indgen(nb)*512LL ;position at start of each block
+ if idltype[i] EQ 7 then sval=v[*,ind] else sval = v[ind]
+ ;value at start of each block
+ datarec = dbindex_blk(unit, hblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(sval,/swap_if_little) : sval
+ ;
+ datarec = dbindex_blk(unit, sblock[pos], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(v,/swap_if_little) : v
+;
+ reclong[0] = bswap ?swap_endian(sub+1,/swap_if_little) : sub+1 ;indices
+ end
+ endcase
+endfor
+return
+NOGOOD:
+ print,'DBINDEX-- Inconsistency in .dbh and .dbx file'
+ print,'Run dbcreate to create a new index file'
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/dbindex_blk.pro b/Code/script_idl_mv/astrolib/dbindex_blk.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7048570264a1cbc554a522983f5fe1403ecc25b7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbindex_blk.pro
@@ -0,0 +1,49 @@
+FUNCTION dbindex_blk, unit, nb, bsz, ofb, dtype
+;+
+; NAME:
+; DBINDEX_BLK
+; PURPOSE:
+; Subroutine of DBINDEX to create associated variable of correct datatype
+; EXPLANATION:
+; DBINDEX_BLK will offset into the file by a specified amount in
+; preparation for writing to the file. V5.2 or later
+;
+; CALLING SEQUENCE:
+; res = dbindex_blk(unit, nb, bsz, ofb, dtype)
+;
+; INPUTS:
+; unit The unit number assigned to the file.
+; nb The number of blocks to offset into the file.
+; bsz The size of each block, in bytes, to offset into the file.
+; ofb The offset into the block, in bytes.
+; dtype The IDL datatype as defined in the SIZE function
+;
+; OUTPUTS:
+; res The returned variable. This is an associated variable.
+;
+; RESTRICTIONS:
+; The file must have been previously opened.
+;
+; MODIFICATION HISTORY:
+; Written by Michael R. Greason, STX, 14 June 1990.
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use 64 bit integer for very large databases W. Landsman February 2001
+; Added new unsigned & 64bit integer datatypes W. Landsman July 2001
+;-
+offset = long64(nb) * long64(bsz) + long64(ofb)
+case dtype of
+ 7: datarec=assoc(unit,bytarr(1),offset) ; string
+ 1: datarec=assoc(unit,bytarr(1),offset) ; byte
+ 2: datarec=assoc(unit,intarr(1),offset) ; integer
+ 4: datarec=assoc(unit,fltarr(1),offset) ; floating point
+ 3: datarec=assoc(unit,lonarr(1),offset) ; longword
+ 5: datarec=assoc(unit,dblarr(1),offset) ; double
+ 6: datarec=assoc(unit,complexarr(1),offset) ; complex
+ 12: datarec=assoc(unit,uintarr(1),offset) ; unsigned integer
+ 13: datarec=assoc(unit,ulonarr(1),offset) ; unsigned longword
+ 14: datarec=assoc(unit,lon64arr(1),offset) ; 64 bit longword
+ 15: datarec=assoc(unit,ulon64arr(1),offset) ; unsigned 64bit longword
+endcase
+;
+RETURN, datarec
+END
diff --git a/Code/script_idl_mv/astrolib/dbmatch.pro b/Code/script_idl_mv/astrolib/dbmatch.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e733a5e518714c2719df05dfaadcac291582daa8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbmatch.pro
@@ -0,0 +1,173 @@
+function dbmatch, item, values, listin, FULLSTRING = fullstring
+;+
+; NAME:
+; DBMATCH
+; PURPOSE:
+; Find the entry number in a database for each element of item values
+; EXPLANATION:
+; DBMATCH() is especially useful for finding a one-to-one
+; correspondence between entries in different databases, and thus to
+; create the vector needed for database pointers.
+;
+; CALLING SEQUENCE:
+; list = DBMATCH( item, values, [ listin, /FULLSTRING ] )
+;
+; INPUTS:
+; ITEM - Item name or number, scalar
+; VALUES - scalar or vector containing item values to search for.
+;
+; OPTIONAL INPUTS:
+; LISTIN - list of entries to be searched. If not supplied, or
+; set to -1, then all entries are searched
+; OUTPUT:
+; LIST - vector of entry numbers with the same number of elements as
+; VALUES. Contains a value of 0 wherever the corresponding item
+; value was not found.
+;
+; OPTIONAL INPUT:
+; /FULLSTRING - By default, one has a match if a search string is
+; included in any part of a database value (substring match).
+; But if /FULLSTRING is set, then all characters in the database
+; value must match the search string (excluding leading and
+; trailing blanks). Both types of string searches are case
+; insensitive.
+;
+; NOTES:
+; DBMATCH is meant to be used for items which do not have duplicate values
+; in a database (e.g. catalog numbers). If more than one entry is found
+; for a particular item value, then only the first one is stored in LIST.
+;
+; When linked databases are opened together, DBMATCH can only be
+; used to search on items in the primary database.
+;
+; EXAMPLE:
+; Make a vector which points from entries in the Yale Bright Star catalog
+; to those in the Hipparcos catalog, using the HD number
+;
+; IDL> dbopen, 'yale_bs' ;Open the Yale Bright star catalog
+; IDL> dbext, -1, 'HD', hd ;Get the HD numbers
+; IDL> dbopen, 'hipparcos' ;Open the Hipparcos catalog
+; IDL> list = dbmatch( 'HD', HD) ;Get entries in Hipparcos catalog
+; ;corresponding to each HD number.
+; PROCEDURE CALLS:
+; DB_ITEM, DB_ITEM_INFO(), DBEXT, DBFIND_SORT()
+; REVISION HISTORY:
+; Written, W. Landsman STX February, 1990
+; Fixed error when list in parameter used May, 1992
+; Faster algorithm with sorted item when listin parameter supplied
+; Added keyword FULLSTRING,check for empty database, William Thompson,
+; GSFC, 15 March 1995
+; Work for more than 32767 values, added CATCH W. Landsman July 1997
+; Change some loop variables to type LONG, W. Landsman July 1999
+; Remove loop for substring searches (faster) W. landsman August 1999
+; Replace DATATYPE() with size(/TNAME) W. Landsman November 2001
+; Fixed typo when search on sorted items W. Landsman February 2002
+; Fixed bug from Nov 2001 where /FULLSTRING was always set. W.L Feb 2007
+;-
+ On_error,2
+
+ if N_params() LT 2 then begin
+ print,'Syntax -- list = DBMATCH( item, values, [ listin, /FULLSTRING] )'
+ return,-1
+ endif
+
+
+ catch, error_status
+ if error_status NE 0 then begin
+ print,!ERR_STRING
+ if N_elements(listin) NE 0 then return,listin else return, -1
+ endif
+
+ nvals = N_elements( values )
+ if nvals EQ 0 then message, $
+ 'ERROR - No search values (second parameter) supplied'
+
+ if N_params() LT 3 then listin = lonarr(1) - 1
+
+ db_item,item,itnum
+ index = db_item_info( 'INDEX', itnum) ;Get index type of item
+ list = lonarr( nvals )
+
+ nentries = db_info('entries')
+ if nentries[0] eq 0 then begin ;Return if database is empty
+ message,'ERROR - No entries in database ' + db_info("NAME",0),/INF
+ return,listin*0
+ endif
+
+ if index[0] GE 2 then begin ;Sorted item
+
+ if listin[0] NE -1 then min_listin = min( listin, MAX = max_listin)
+
+ for i = 0l,nvals-1 do begin
+
+ val = [values[i],values[i]]
+
+; We don't supply the LISTIN parameter directly to DBFIND_SORT. Since
+; we know that we need only 1 match for each item value, we can do
+; the restriction to the LISTIN values faster than DBFIND_SORT can
+
+ tmplist = -1
+ dbfind_sort,itnum[0],1,val, tmplist, $ ;Search all entries to start
+ fullstring=fullstring, Count = Nmatch_sort
+
+ if ( listin[0] NE -1 ) then begin
+
+ if Nmatch_sort EQ 0 then goto, FOUND_MATCH
+
+ good = where( ( tmplist LE max_listin ) and $
+ ( tmplist GE min_listin ), Ngood)
+
+ if ( Ngood EQ 0 ) then goto, FOUND_MATCH
+
+ tmplist = tmplist[good]
+
+ for j = 0L, Ngood - 1 do begin
+ test = where( listin EQ tmplist[j], Nfound )
+ if Nfound GE 1 then begin
+ list[i] = tmplist[j]
+ goto, FOUND_MATCH
+ endif
+ endfor
+
+ endif else if ( Nmatch_sort GT 0 ) then list[i] = tmplist[0]
+
+ FOUND_MATCH:
+ endfor
+
+ endif else begin ;Non-sorted item
+
+ if listin[0] EQ -1 then tmplist = lindgen( nentries[0] )+1 else $
+ tmplist = listin
+ dbext, tmplist, itnum, itvals
+ typ = size(itvals,/TNAME)
+ if typ EQ 'STRING' then begin
+ itvals = strupcase( strtrim(itvals,2) )
+ vals = strupcase( strtrim(values,2) )
+ endif else vals = values
+ for i=0L,nvals-1 do begin
+ if typ NE 'STRING' then begin ;Fixed Feb 2007
+ good = where( itvals EQ vals[i], Nfound )
+ if Nfound GT 0 then list[i] = tmplist[ good[0] ] ;Fixed May-92
+
+ endif else begin ;Can't use WHERE on string arrays
+ ;unless FULLSTRING is set
+
+ if keyword_set(fullstring) then begin
+ good = where( itvals EQ vals[i], Nfound)
+ if Nfound GT 0 then list[i] = tmplist[ good[0] ]
+ end else begin
+ good = where(strpos( itvals, vals[i]) GE 0, Nfound)
+ if Nfound GT 0 then begin
+ list[i] = tmplist[good[0]]
+ goto, DONE
+ endif
+
+ endelse
+ endelse
+ DONE:
+ endfor
+endelse
+
+return,list
+
+end
diff --git a/Code/script_idl_mv/astrolib/dbopen.pro b/Code/script_idl_mv/astrolib/dbopen.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2b10da69a1beb2f6de40550eab8caf670e482bfc
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbopen.pro
@@ -0,0 +1,411 @@
+pro dbopen,name,update,UNAVAIL=unavail
+;+
+; NAME:
+; DBOPEN
+; PURPOSE:
+; Routine to open an IDL database
+;
+; CALLING SEQUENCE:
+; dbopen, name, update
+;
+; INPUTS:
+; name - (Optional) name or names of the data base files to open.
+; It has one of the following forms:
+;
+; 'name' -open single data base file
+; 'name1,name2,...,nameN' - open N files which are
+; connected via pointers.
+; 'name,*' -Open the data base with all data
+; bases connected via pointers
+; '' -Interactively allow selection of
+; the data base files.
+;
+; If not supplied then '' is assumed.
+; name may optionally be a string array with one name
+; per element.
+;
+; update - (Optional) Integer flag specifying opening for update.
+; 0 - Open for read only
+; 1 - Open for update
+; 2 - Open index file for update only
+; !PRIV must be 2 or greater to open a file for update.
+; If a file is opened for update only a single data base
+; can be specified.
+;
+; OUTPUTS:
+; none
+;
+; INPUT-OUTPUT KEYWORD:
+; UNAVAIL - If present, a "database doesn't exit" flag is returned
+; through it. 0 = the database exists and was opened (if
+; no other errors arose). 1 = the database doesn't exist.
+; Also if present, the error message for non-existent databases
+; is suppressed. The action, however, remains the same.
+; SIDE EFFECTS:
+; The .DBF and .dbx files are opened using unit numbers obtained by
+; GET_LUN. Descriptions of the files are placed in the common block
+; DB_COM.
+;
+; PROCEDURES CALLED:
+; DBCLOSE, DB_INFO(), SELECT_W, ZPARCHECK
+; HISTORY:
+; For IDL Version 2 W. Landsman May 1990 -- Will require further
+; modfication once SCREEN_SELECT is working
+; Modified to work under Unix, D. Neill, ACC, Feb 1991.
+; UNAVAIL keyword added. M. Greason, Hughes STX, Feb 1993.
+; William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Added support for external (IEEE) representation.
+; William Thompson, GSFC, 3 November 1994
+; Modified to allow ZDBASE to be a path string.
+; 8/29/95 JKF/ACC - forces lowercase for input database names.
+; W. Landsman, Use CATCH to catch errors July, 1997
+; W. Landsman Use vector call to FDECOMP, STRSPLIT() Sep 2006
+; W. Landsman Remove obsolete keywords to OPEN Sep 2006
+; Replace SCREEN_SELECT with SELECT_W, remove IEEE_TO_HOST WL Jan 2009
+; Fix typos in BYTEORDER introduced Jan 2009 G. Scandariato/W.L.Feb. 2009
+; Support new DB format which allows entry lengths > 32767 bytes
+; W.L. October 2010
+; William Thompson, fixed bug opening multiple databases Dec 2010
+; Fix problem with external databases WL Sep 2011
+; Use tooltips when no parameters called WL Aug 2013
+;
+;-
+;
+;------------------------------------------------------------------------
+On_error,2
+;
+; data base common block
+;
+common db_com,QDB,QITEMS,QDBREC
+;
+; QDB[*,i] contains the following for each data base opened
+;
+; bytes
+; 0-18 data base name character*19
+; 19-79 data base title character*61
+; 80-81 number of items (integer*2)
+; 82-83 record length of DBF file (integer*2)
+; 84-87 number of entries in file (integer*4)
+; 88-89 position of first item for this file in QITEMS (I*2)
+; 90-91 position of last item for this file (I*2)
+; 92-95 Last Sequence number used (item=SEQNUM) (I*4)
+; 96 Unit number of .DBF file
+; 97 Unit number of .dbx file (0 if none exists)
+; 98-99 Index number of item pointing to this file (0 for first db)
+; 100-103 Number of entries with space allocated
+; 104 Update flag (0 open for read only, 1 open for update)
+; 105-108 record length of DBF file (integer*4)
+; 118 Equals 1 if more 32767 bytes can be stored in database (new format)
+; 119 Equals 1 if external data representation (IEEE) is used
+;
+; QITEMS[*,i] contains description of item number i with following
+; byte assignments:
+;
+; 0-19 item name (character*20)
+; 20-21 IDL data type (integer*2)
+; 22-23 Number of values for item (1 for scalar) (integer*2)
+; in bytes 179-182 in new format
+; 24-25 Starting byte position in original DBF record
+; In bytes 183-186 (integer*2) New DB format
+; 26-27 Number of bytes per data value (integer*2)
+; 28 Index type
+; 29-97 Item description
+; 98-99 print format field length
+; 100 flag (1 if this items points to a data base)
+; 101-119 Data base this item points to
+; 120-125 Print format
+; 126-170 Print headers
+; 171-172 Starting byte in record returned by DBRD
+; 173-174 Data base number in QDB
+; 175-176 Data base number this item points to
+; 177-178 Item number within the specific data base
+; 179-182 Number of values for item (1 for scalar) (integer*4)
+; 183-186 Starting byte position in original DBF record (integer*4)
+; 187-190 Starting byte in record returned by DBRD
+;
+;
+;-------------------------------------------------------------------------
+;
+;
+; check for valid input parameters
+;
+if N_params() lt 1 then name=''
+if N_params() lt 2 then update=0
+ catch, error_status
+ if error_status NE 0 then begin
+ print,!ERR_STRING
+ return
+ endif
+
+zparcheck,'DBOPEN',name,1,7,[0,1],'Data base name[s]'
+zparcheck,'DBOPEN',update,2,[1,2,3,4,5],0,'Update flag'
+;
+; check privilege
+;
+if update && (!priv lt 2) then $
+ message,'!PRIV must be 2 or greater to open with update'
+;
+; check UNAVAIL
+;
+unav_flg = arg_present(unavail)
+unavail = 0
+totret = 1
+;---------------------------------------------------------------------
+; PROCESS INPUT NAMES (CREATE STRING ARRAY)
+;
+; Process scalar name
+;
+s=size(name) & ndim=s[0]
+if ndim eq 0 then begin
+;
+; process name=''
+;
+ if strtrim(name) EQ '' then begin
+ names = list_with_path('*.dbh', 'ZDBASE', Count = N)
+ if n EQ 0 then message, $
+ 'No database (.dbh) files found in ZDBASE or current directory'
+ fdecomp,names,disk,dir,fnames,qual
+ db_titles, fnames, titles
+ select_w,fnames,isel,titles, $
+ 'Select data base file to open',1
+ fnames=fnames[intarr(1)+isel]
+ end else $
+;
+; separate names into string array
+;
+ fnames = strlowcase( strsplit(name,',',/extract))
+ end else begin
+;
+; name is already a string vector
+;
+ fnames=name
+end
+;
+; if update, only one data base can be opened
+;
+if update then if N_elements(fnames) gt 1 then $
+ message,'Only one file can be specified if mode is update'
+;
+;---------------------------------------------------------------
+;
+; LOOP AND OPEN EACH DATA BASE
+;
+; close any data bases already open
+;
+dbclose
+;
+;
+offset=0 ;byte offset in dbrd record for data base
+tot_items=0 ;total number of items all opened data bases
+get_lun,unit ;get unit number to use for .dbh files
+dbno=0 ;present data base number
+while dbno lt n_elements(fnames) do begin
+ dbname=strtrim(fnames[dbno])
+;
+; process * if second in list -----------------------
+;
+ if dbname eq '*' then begin ;get data base names from pointers
+ if dbno ne 1 then begin ;* must be second data base
+ message,'Invalid use of * specification',/continue
+ goto,ABORT
+ endif
+ pointers=qitems[100,*] ;find pointer items
+ good=where(pointers,n)
+ if n eq 0 then goto,done ;no pointers
+ pnames=string(qitems[101:119,*]);file names for pointers
+ fnames=[fnames[0],pnames[good]] ;new file list
+ dbname=strtrim(fnames[1]) ;new second name
+ end
+;
+; open .dbh file and read contents ------------------------
+;
+ dbhname = find_with_def(dbname+'.dbh', 'ZDBASE')
+
+ openr,unit,dbhname,ERROR=err
+
+ if err NE 0 then begin
+ if unav_flg EQ 0 then begin
+ message,'Error opening .dbh file '+ dbname,/CONTINUE
+ print,!SYSERR_STRING
+ endif else totret = 0
+ unavail = 1
+ goto, ABORT
+ end
+ db=bytarr(120)
+ readu,unit,db
+
+ external = db[119] eq 1 ;Is external data rep. being used?
+ newdb = db[118] eq 1 ; New db format allowing longwords
+ totbytes = newdb ? long(db,105,1) : fix(db,82,1)
+ totbytes = totbytes[0] ;Make sure is scalar
+ nitems=fix(db,80,1) & nitems=nitems[0] ;number of items or fields in file
+
+ if external then begin
+ if newdb then begin
+ byteorder, totbytes, /NTOHL & db[105] = byte(totbytes,0,4)
+ endif else begin
+ byteorder, totbytes, /NTOHS & db[82] = byte(totbytes,0,2)
+ endelse
+ byteorder, nitems,/NTOHS & db[80] = byte(nitems,0,2)
+ endif
+ items=bytarr(200,nitems)
+ readu,unit,items
+ close,unit
+ if external then begin
+ tmp = fix(items[20:27,*],0,4,nitems)
+ byteorder,tmp, /ntohs
+ items[20,0] = byte(tmp,0,8,nitems)
+;
+ tmp = fix(items[98:99,*],0,1,nitems)
+ byteorder,tmp,/NTOHS
+ items[98,0] = byte(tmp,0,2,nitems)
+;
+ tmp = fix(items[171:178,*],0,4,nitems)
+ byteorder,tmp,/NTOHS
+ items[171,0] = byte(tmp,0,8,nitems)
+
+ if newdb then begin
+ tmp = long(items[179:186,*],0,2,nitems)
+ byteorder,tmp,/NTOHL
+
+ items[179,0] = byte(tmp,0,8,nitems)
+ endif
+ endif
+
+;
+; add computed information to items ---------------------------
+;
+ sbyte = newdb ? long(items[183:186,*],0,nitems)+offset : $
+ fix(items[24:25,*],0,nitems)+offset
+
+ for i=0,nitems-1 do begin
+ if newdb then items[187,i]= byte(sbyte[i],0,4) else $
+ items[171,i] = byte(sbyte[i],0,2)
+ ;starting byte in DBRD record
+ items[173,i]=byte(dbno,0,2) ;data base number
+ items[177,i]=byte(i,0,2) ;item number
+ end
+ offset=offset+totbytes
+;
+; open .dbf file ---------------------------------
+;
+ get_lun,unitdbf
+ dbf_file = find_with_def(dbname+'.dbf', 'ZDBASE')
+
+ if update eq 1 then $
+ openu,unitdbf,dbf_file else $
+ openr,unitdbf,dbf_file,error=err
+ if err ne 0 then begin
+ message,'Error opening '+dbname+'.dbf',/continue
+ free_lun,unitdbf
+ goto,abort
+ end
+
+ p=assoc(unitdbf,lonarr(2))
+ head = p[0]
+ if external then byteorder, head, /NTOHL
+ db[96]=unitdbf ;unit number of .dbf file
+ db[84]=byte(head[0],0,4) ;number of entries
+ db[92]=byte(head[1],0,4) ;last seqnum used
+ db[88]=byte(tot_items,0,2) ;starting item number for this db
+ tot_items=tot_items+nitems ;new total number of items
+ db[90]=byte(tot_items-1,0,2) ;last item number for this db
+ db[104]=update ;opened for update
+;
+; open index file if necessary -----------------------------
+;
+
+ index=where(items[28,*] gt 0,nindex) ;indexed items
+
+ if nindex gt 0 then begin ;need to open index file.
+ get_lun,unitind
+ dbx_file = find_with_def(dbname+'.dbx', 'ZDBASE')
+ if update gt 0 then $
+ openu,unitind,dbx_file,error=err $
+ else openr,unitind,dbx_file,error=err
+ if err ne 0 then begin
+ message,'Error opening index file for '+dbname,/continue
+ free_lun,unitdbf
+ free_lun,unitind
+ goto,abort
+ endif
+ db[97]=unitind ;unit number for index file
+ end
+;
+; add to common block ---------------------
+;
+
+ if dbno eq 0 then begin
+ qdb=db
+ qitems=items
+ end else begin
+ old=qdb
+ qdb=bytarr(120,dbno+1)
+ qdb[0,0] = old
+ qdb[0,dbno] = db
+ old=qitems
+ qitems=bytarr(200,tot_items)
+ qitems[0,0] = old
+ qitems[0,tot_items-nitems] = items
+ end
+;
+ dbno=dbno+1
+end; loop on data bases
+done: free_lun,unit
+
+
+;--------------------------------------------------------------------
+; LINK PROCESSING
+;
+; determine linkages between data bases
+;
+numdb = N_elements(fnames)
+if numdb gt 1 then begin
+ pnames=strupcase(qitems[101:119,*])
+ for i=1,numdb-1 do begin
+ dbname=strupcase(qdb[0:18,i]) ;name of the data base
+ for j=0,tot_items-1 do if pnames[j] eq dbname then goto,found
+;
+; if we made it here we can not link the file -----------
+;
+ message,'Unable to link data base file '+dbname,/continue
+ goto,abort
+;
+; found linkage item ------------------------------------
+;
+
+found:
+ item_number=j ;number of item supplying link
+ item_db=fix(qitems[173:174,item_number],0,1) & item_db=item_db[0]
+ if item_db ge i then begin
+ message,'Unable to link data base '+dbname + $
+ 'to previous data base.',/continue
+ print,' Possible incorrect ordering of input data bases'
+ goto,abort
+ endif
+ qitems[175,item_number]=byte(i,0,2) ;data base number pointed to
+ qdb[98,i]=byte(item_number,0,2) ;item number pointing to this db
+nextdb:
+ endfor
+endif
+
+;
+; create an assoc variable for the first db
+;
+
+unit=db_info('unit_dbf',0)
+len=db_info('length',0)
+qdbrec=assoc(unit,bytarr(len))
+;----------------------------------------------------------------------------
+; done
+;
+
+return
+;
+; abort
+;
+abort:
+dbclose ;close any open data bases
+free_lun,unit
+if (totret NE 0) then retall else return
+end
diff --git a/Code/script_idl_mv/astrolib/dbprint.pro b/Code/script_idl_mv/astrolib/dbprint.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6229081b4819d44168800284f9fa31fbacf5f150
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbprint.pro
@@ -0,0 +1,318 @@
+pro dbprint,list,items, FORMS=forms, TEXTOUT=textout, NoHeader = noheader, $
+ Adjustformat = adjustformat
+;+
+; NAME:
+; DBPRINT
+; PURPOSE:
+; Procedure to print specified items from a list of database entries
+;
+; CALLING SEQUENCE:
+; dbprint, list, [items, FORMS= , TEXTOUT= , /AdjustFormat, /NoHeader]
+;
+; INPUTS:
+; list - list of entry numbers to be printed, vector or scalar
+; if list = -1, then all entries will be printed.
+; An error message is returned if any entry number is larger
+; than the number of entries in the database
+;
+; OPTIONAL INPUT-OUTPUT:
+; items - items to be printed, specified in any of the following ways:
+;
+; form 1 scalar string giving item(s) as list of names
+; separated by commas
+; form 2 string array giving list of item names
+; form 3 string of form '$filename' giving name
+; of text file containing items (one item per
+; line)
+; form 4 integer scalar giving single item number or
+; integer vector list of item numbers
+; form 5 Null string specifying interactive selection. This
+; is the default if 'items' is not supplied
+; form 6 '*' select all items, printout will be in
+; table format.
+;
+; If items was undefined or a null string on input, then
+; on output it will contain the items interactively selected.
+;
+; OPTIONAL INPUT KEYWORDS:
+; /ADJUSTFORMAT - If set, then the format length for string items will
+; be adjusted to the maximum length for the entries to be printed.
+; This option will slow down DBPRINT because it requires the
+; string items be extracted and their maximum length determined
+; prior to any printing. However, it enables the display of
+; string items without any truncation or wasted space.
+;
+; FORMS - The number of printed lines per page. If forms is not
+; present, output assumed to be in PORTRAIT form, and
+; a heading and 47 lines are printed on each page, with
+; a page eject between each page. For LANDSCAPE form with
+; headings on each page, and a page eject between pages, set
+; forms = 34. For a heading only on the first page, and no
+; page eject, set forms = 0. This is the default for output
+; to the terminal.
+;
+; TEXTOUT - Integer (0-7) or string used to determine output device (see
+; TEXTOPEN for more info). If not present, the !TEXTOUT system
+; variable is used.
+; textout=0 Nowhere
+; textout=1 if a TTY then TERMINAL using /more option
+; otherwise standard (Unit=-1) output
+; textout=2 if a TTY then TERMINAL without /more option
+; otherwise standard (Unit=-1) output
+; textout=3 dbprint.prt (file)
+; textout=4 laser.tmp
+; textout=5 user must open file
+; textout=7 same as 3 but text is appended to .prt
+; textout = filename (default extension of .prt)
+;
+; /NOHEADER - If this keyword is set, then the column headers will not
+; be printed
+;
+; EXAMPLE:
+; The following example shows how a multiple valued item DATAMAX can be
+; printed as separate columns. In the WFPC2 target database, DATAMAX
+; is an item with 4 values, one for each of the 4 chips
+;
+; IDL> dbopen,'wflog'
+; IDL> dbprint,list,'entry,datamax(0),datamax(1),datamax(2),datamax(3)'
+;
+; SYSTEM VARIABLES:
+; Output device controlled by non-standard system varaible !TEXTOUT, if
+; TEXTOUT keyword is not used.
+;
+; NOTES:
+; Users may want to adjust the default lines_per_page value given at
+; the beginning of the program for their own particular printer.
+; PROCEDURE CALLS:
+; db_info(), db_item_info(), dbtitle(), dbxval(), textopen, textclose
+; zparcheck
+; HISTORY:
+; version 2 D. Lindler Nov. 1987 (new db format)
+; Test if user pressed 'Q' in response to /MORE W. Landsman Sep 1991
+; Apply STRTRIM to free form (table) output W. Landsman Dec 1992
+; Test for string value of TEXTOUT W. Landsman Feb 1994
+; William Thompson, GSFC, 3 November 1994
+; Modified to allow ZDBASE to be a path string.
+; W. Landsman, GSFC, July, 1997, Use CATCH to catch errors
+; Removed STRTRIM in table format output to handle byte values April 1999
+; Fixed occasional problem when /NOHEADER is supplied Sep. 1999
+; Only byteswap when necessary for improved performance Feb. 2000
+; Change loop index for table listing to type LONG W. Landsman Aug 2000
+; Entry vector can be any integer type W. Landsman Aug. 2001
+; Replace DATATYPE() with size(/TNAME) W. Landsman Nov. 2001
+; No page eject for TEXTOUT =5 W. Landsman Nov. 2001
+; No initial page eject W. Landsman Jan. 2002
+; Added AdjustFormat keyword W. Landsman Sep. 2002
+; Assume since V5.3 (STRJOIN) W. Landsman Feb. 2004
+; Fix display on GUI terminals W. Landsman March 2006
+; Remove VMS statements W. Landsman Sep 2006
+; Remove EXECUTE statement W. Landsman Jan 2007
+; Fix display of multi element items W. Landsman Aug 2010
+; Fix problem with linked databases W. Landsman Dec 2011
+;-
+;
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ if N_params() EQ 0 then begin
+ print,'Syntax - DBPRINT, list, items, '
+ print,' [ FORMS = , TEXTOUT =, /NoHeader, /AdjustFormat ]'
+ return
+ endif
+
+ lines_per_page = 47 ;Default # of lines per page
+ zparcheck, 'DBPRINT', list, 1, [1,2,3,4,5,12,13,14,15], [0,1], $
+ 'Entry List Vector'
+
+ catch, error_status
+ if error_status NE 0 then begin
+ print,!ERR_STRING
+ return
+ endif
+
+
+; Make list a vector
+
+ nentry = db_info( 'ENTRIES', 0)
+ if nentry EQ 0 then message,'ERROR - Database contains no entries'
+ if list[0] EQ -1 then list = lindgen(nentry) + 1
+ dbname = strlowcase( db_info( 'NAME', 0 ))
+
+ if max(list) GT nentry then message, dbname + $
+ ' entry numbers must be between 1 and ' + strtrim( nentry, 2 )
+ nv = N_elements(list) ;number of entries requested
+
+; No need for byteswapping if data is not external or it is a big endian machine
+
+ noconvert = ~db_info('EXTERNAL',0) || is_ieee_big() ;Updated Dec 11
+
+; Determine items to print
+
+ if N_params() EQ 1 then begin
+
+ file = find_with_def(dbname +'.items', 'ZDBASE')
+ if file NE '' then items = '$' + file else items = ''
+
+ endif
+
+ db_item, items, it, ivalnum, dtype, sbyte, numvals, nbytes
+ numvals = numvals<1 ;can't print vectors
+ nvalues = db_item_info( 'NVALUES', it ) ;number of values in item
+ qnumit = db_info( 'ITEMS' ) ;number of items
+ nitems = N_elements( it ) ;number of items requested
+ qnames = db_item_info( 'NAME', it )
+ qtitle = db_info( 'TITLE', 0 ) ;data base title
+
+; Open output text file
+
+ if ~keyword_set(TEXTOUT) then textout = !textout ;use default output dev.
+textopen, dbname, TEXTOUT = textout, more_set = more_set
+ if size(TEXTOUT,/TNAME) EQ 'STRING' then text_out = 5 else text_out = textout
+ if (nitems EQ qnumit) then begin
+
+; Create table listing of each item specified. -------------------------
+
+ for i = 0L, nv-1 do begin
+ dbrd, list[i], entry, noconvert = noconvert ; read an entry.
+ printf, !TEXTUNIT, ' ' ; print blank line.
+
+; display name and value for each entry
+
+ for k = 0, qnumit-1 do begin
+ ;.
+ ; only print entries of reasonable size... < 5 values in item.
+
+ if ( nvalues[k] LT 5 ) then begin
+ somvar = $
+ dbxval(entry,dtype[k],nvalues[k],sbyte[k],nvalues[k]*nbytes[k])
+ if dtype[k] EQ 1 then somvar=fix(somvar)
+ printf,!textunit,k,') ',qnames[k], strtrim(somvar,2)
+ ;display name,value
+ endif
+ endfor ; k
+
+ endfor ; i
+
+ printf,!textunit,' ' ;Added 11/90
+
+ end else begin
+
+; get info on items
+
+ formats = db_item_info( 'FORMAT', it )
+ flen = db_item_info( 'FLEN', it ) ;field lengths
+ nvals = db_item_info( 'NVALUES', it ) ;larger than one for vector items
+;
+; If /AdjustFormat set, then extract all string vectors and find their maximum
+; length. Then update the formats and flen vectors accordingly
+;
+ if keyword_set(adjustFormat) then begin
+ stringvar = where(dtype EQ 7, Nstring)
+ if Nstring GT 0 then begin
+ alen = intarr(Nstring)
+ varnames = 'v' + strtrim(indgen(Nstring)+1,2)
+ stringitems = strjoin(varnames,',')
+ for i=0, Nstring-1 do begin
+ dbext,list,it[stringvar[i]], vv
+ alen[i] = max(strlen(strtrim(temporary(vv),2)))
+ endfor
+ flen[stringvar] = alen
+ formats[stringvar] = 'A' + strtrim(alen,2)
+ endif
+ endif
+
+; Set up format array
+
+ form = '(' + strtrim(formats,2) + ')' ;remove blanks, and add paren
+
+ linelength = total(flen) + nitems ;length of output lines
+ dash = byte('-') & dash = dash[0]
+ dashes = ' '+string( replicate( dash, linelength ) )
+;
+ if ~keyword_set( NoHeader) then begin
+
+ title = string( replicate(byte(32), linelength>42) )
+ strput, title, qtitle, (linelength-40)/2>1 ;center title
+
+; Extract headers
+
+ headers = db_item_info( 'HEADERS', it )
+ c1 = strmid( headers,0,15 )
+ c2 = strmid( headers,15,15 )
+ c3 = strmid( headers,30,15 )
+
+; Place value numbers for multiple valued items in h3
+ for i = 0,nitems-1 do begin
+ if nvals[i] GT 1 then $ ;multiple values?
+ c3[i] = '[' + strtrim(string(ivalnum[i]),2) + ']'
+ endfor ;i
+
+ h1 = dbtitle( c1,flen )
+ h2 = dbtitle( c2,flen )
+ h3 = dbtitle( c3,flen )
+
+ endif
+
+; Loop on entries
+
+ hardcopy = (text_out GE 2) and (text_out NE 5) ;Keep track of page eject?
+ if ( N_elements(forms) GT 0 ) then begin
+ if ( forms GT 0 ) then pcount = forms $ ;lines per page
+ else pcount = N_elements(list) ;no page breaks
+ endif else if not hardcopy then pcount = N_elements(list) $
+ else pcount = lines_per_page ;Portrait form default
+ limit = pcount - 1
+
+ for j = 0L, N_elements(list)-1 do begin
+
+ if not keyword_set( NoHeader) then begin
+
+ if pcount GT limit then begin ;new page?
+ pcount = 0
+ if (j GT 0) and hardcopy then $
+ printf,!textunit,string(byte(12)) $;eject
+ else printf,!textunit,' '
+ printf,!textunit,title ;print title
+ printf,!textunit,dashes ;print headings
+ printf,!textunit,h1
+ printf,!textunit,h2
+ printf,!textunit,h3
+ printf,!textunit,dashes
+ endif
+
+ endif
+ dbrd, list[j], entry, noconvert = noconvert ;read entry
+ ;
+ ; loop on items
+ ;
+ st = '' ;output string
+ for i = 0,nitems-1 do begin
+
+ val = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
+ if dtype[i] EQ 1 then val = fix(val)
+ if dtype[i] EQ 7 then begin
+ b = byte(val)
+ bad = where(b EQ 0, nbad)
+ if nbad GT 0 then begin
+ b[bad] = 32b
+ val = string(b)
+ endif
+ endif
+ st = st+' ' + string(val,form[i])
+
+ endfor
+
+ printf, !TEXTUNIT, st ;print line
+ if more_set then $ ;Did user press 'Q' in /MORE ?
+ if ( !ERR EQ 1 ) then return
+ pcount = pcount+1 ;increment line counter
+ end ; loop on entries
+
+ endelse ; N_params > 1
+
+; Clean up
+
+ textclose, TEXTOUT = textout ;close text file
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbput.pro b/Code/script_idl_mv/astrolib/dbput.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9dfe5d21c767d4e026275490a1b8985a15c5b667
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbput.pro
@@ -0,0 +1,78 @@
+pro dbput,item,val,entry
+;+
+; NAME:
+; DBPUT
+; PURPOSE:
+; Procedure to place a new value for a specified item into
+; a data base file entry.
+;
+; CALLING SEQUENCE:
+; dbput, item, val, entry
+;
+; INPUTS:
+; item - item name or number
+; val - item value(s)
+;
+; INPUT/OUTPUT:
+; entry - entry (byte array) or scalar entry number.
+; if entry is a scalar entry number then the data
+; base file will be updated. Otherwise the change
+; will be only made to the entry array which must
+; be written latter using DBWRT.
+;
+; OPERATIONAL NOTES:
+; If entry is a scalar entry number or the input file name
+; is supplied, the entry in the data base will be updated
+; instead of a supplied entry variable. In this case, !priv
+; must be greater than 1.
+; EXAMPLE:
+; IDL> dbput,'WAVELEN',1215.6,entry
+; PROCEDURES USED:
+; DB_ITEM, DBRD, DBXPUT, DBWRT
+; HISTORY:
+; version 2 D. Lindler Feb 1988 (new db formats)
+; modified to convert blanks into zeros correctly D. Neill Jan 1991
+; Converted to IDL V5.0 W. Landsman September 1997
+; V5.2 version support unsigned, 64bit integers W. Landsman Sep. 2001
+;-
+;-----------------------------------------------------------------------
+;
+; get item number
+;
+ db_item, item, inum, ivalnum, dtype, sbyte, numvals, nbytes
+;
+; convert val to correct type and check size
+;
+ if (dtype[0] NE 7) and ( size(val,/type) EQ 7) then val = strtrim(val)
+ case dtype[0] of
+ 1: v = byte(fix(val))
+ 2: v = fix(val)
+ 3: v = long(val)
+ 4: v = float(val)
+ 5: v = double(val)
+ 7: v = string(val)
+ 12: v = uint(val)
+ 13: v = ulong(val)
+ 14: v = long64(val)
+ 15: v = ulong64(val)
+ endcase
+;
+ if N_elements(v) NE numvals[0] then begin
+ print,'DBPUT - Invalid number of data values'
+ print,'Item '+item+' requires ',strtrim(numvals[0],2),' values'
+ print,'DBPUT aborting'
+ retall
+ endif
+;
+; determine if entry number supplied
+;
+ if size(entry,/n_dimen) EQ 0 then begin ;scalar entry number supplied
+ dbrd,entry,e
+ dbxput,v,e,dtype[0],sbyte[0],nbytes[0]*numvals[0] ;update entry
+ dbwrt,e ;update file
+ end else begin ;array supplied, just update it
+ dbxput,v,entry,dtype[0],sbyte[0],nbytes[0]*numvals[0]
+ end
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbrd.pro b/Code/script_idl_mv/astrolib/dbrd.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0697ddd5bda20d40011e0889cdaf5ef5d8866320
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbrd.pro
@@ -0,0 +1,115 @@
+pro dbrd,enum,entry,available,dbno, noconvert=noconvert
+;+
+; NAME:
+; DBRD
+; PURPOSE:
+; procedure to read an entry from a data base file or from
+; linked multiple databases.
+;
+; CALLING SEQUENCE:
+; dbrd, enum, entry, [available, dbno, /NoConvert]
+;
+; INPUTS:
+; enum - entry number to read, integer scalar
+;
+; OUTPUT:
+; entry - byte array containing the entry
+;
+; OPTIONAL OUTPUT:
+; available - byte array with length equal to number of data
+; bases opened. available(i) eq 1 if an entry (pointed
+; to) is available. It always equals 1 for the first
+; data base, otherwise it is an error condition.
+;
+; OPTIONAL INPUT:
+; dbno - specification of the data base number to return. If
+; supplied, only the record for the requested data base
+; number is returned in entry. Normally this input should
+; not be supplied. dbno is numbered for 0 to n-1 and gives
+; the number of the data base opened. The data bases are
+; numbered in the order supplied to dbopen. If dbno is supplied
+; then the entry number refers to that data base and not the
+; primary or first data base. If set to -1, then it means all
+; data bases opened (same as not supplying it)
+; OPTIONAL INPUT KEYWORD:
+; noconvert - if set then don't convert external to host format.
+; Assumes that calling program will take care of this
+; requirement.
+; OPERATIONAL NOTES:
+; If multiple data base files are opened, the records are
+; concatenated with each other
+; HISTORY
+; version 2 D. Lindler Nov. 1987
+; William Thompson, GSFC/CDS (ARC), 1 June 1994
+; Added support for external (IEEE) representation.
+; Version 3, Richard Schwartz, GSFC/SDAC, 23-Aug-1996
+; Add noconvert keyword
+;
+; Converted to IDL V5.0 W. Landsman September 1997
+; Version 4, 2 May 2003, W. Thompson
+; Use BSWAP keyword to DBXVAL instead of calling IEEE_TO_HOST.
+;-
+;
+;-----------------------------------------------------------------------
+On_error,2
+
+ if N_params() LT 2 then begin
+ print,'Syntax - dbrd, enum, entry, [available, dbno, /NoConvert]'
+ return
+ endif
+
+ COMMON db_com,qdb,qitems,qdbrec
+
+; Find out if databases are in external format.
+ externali= db_info('EXTERNAL')
+ external = externali * (1-keyword_set(noconvert))
+ if N_params() LT 4 then dbno = -1
+
+ if dbno GE 0 then begin ;get only requeseted data base entry
+ available = bytarr(1)+1b
+ if dbno EQ 0 then begin
+ entry = qdbrec[enum]
+ if external[0] then db_ent2host, entry, 0
+ end else begin
+ len = db_info( 'LENGTH', dbno)
+ unit = db_info( 'UNIT_DBF', dbno)
+ p = assoc(unit,bytarr(len, /NOZERO), enum)
+ entry = p[0] ;read entry
+ if external[dbno] then db_ent2host, entry, dbno
+ end
+ return
+ end
+
+; get info on open data bases
+
+ len = db_info( 'LENGTH' ) ;record lengths
+ units = db_info( 'UNIT_DBF' ) ;unit numbers
+ n = N_elements(len) ;number of db's opened
+ entry = qdbrec[enum] ;read entry for first db
+ if external[0] then db_ent2host, entry, 0
+ irec = enum ;record number
+ available = bytarr(n)+1B ;entry available
+
+ if n GT 1 then begin
+ for i = 1,n-1 do begin ;loop on db's
+ pointer = db_info('pointer',i) ;what points to it
+ db_item, pointer,itnum,ival,dtype,sb,nv,nb
+
+ ;Make sure irec is in internal format!
+ if externali[db_item_info('dbnumber',itnum[0])] and keyword_set(noconvert) $
+ then bswap=1 else bswap=0
+ irec = dbxval(entry,dtype[0],1,sb[0],nb[0],bswap=bswap)
+ if irec GT 0 then begin
+ p = assoc( units[i], bytarr( len[i],/NOZERO ))
+ tmp = p[irec]
+ if external[i] then db_ent2host, tmp, i
+ entry = [ entry, tmp ] ;add to end
+ end else begin
+ available[i] = 0B
+ entry = [ entry, bytarr(len[i])]
+ end
+ end
+ end
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbsearch.pro b/Code/script_idl_mv/astrolib/dbsearch.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4c955e85ae59959234a204c0d7bd6a8baeb46c3f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbsearch.pro
@@ -0,0 +1,139 @@
+pro dbsearch,type,svals,values,good, FULLSTRING = fullstring, COUNT = count
+;+
+; NAME:
+; DBSEARCH
+; PURPOSE:
+; Subroutine of DBFIND() to search a vector for specified values
+;
+; CALLING SEQUENCE:
+; dbsearch, type, svals, values, good, [ /FULLSTRING, COUNT = ]
+;
+; INPUT:
+; type - type of search (output from dbfparse)
+; svals - search values (output from dbfparse)
+; values - array of values to search
+;
+; OUTPUT:
+; good - indices of good values
+;
+; OPTIONAL INPUT KEYWORD:
+; /FULLSTRING - By default, one has a match if a search string is
+; included in any part of a database value (substring match).
+; But if /FULLSTRING is set, then all characters in the database
+; value must match the search string (excluding leading and
+; trailing blanks). Both types of string searches are case
+; insensitive.
+; OPTIONAL OUTPUT KEYWORD:
+; COUNT - Integer scalar giving the number of valid matches
+; SIDE EFFECTS:
+; The obsolete system variable !ERR is set to number of good values
+; REVISION HISTORY:
+; D. Lindler July,1987
+; Added COUNT keyword, deprecate !ERR W. Landsman March 2000
+; Some speed improvements W.L. August 2008
+; Add compound operators, slightly faster WL November 2009
+; D. Lindler Aug 2013, added strtrim on values for a string search
+; Fix problem with "less than" string searches WL November 2014
+; November 2014 fix actually broke things, reverting WL January 2015
+;-
+;-----------------------------------------------------------
+ On_error,2
+ compile_opt idl2
+
+ svals = strupcase(svals)
+;
+; determine data type of values to be searched
+;
+ datatype=size(values,/type) & nv = N_elements(values)
+
+;
+; convert svals to correct data type
+;
+ nvals = type>2
+ if datatype NE 7 then sv = replicate(values[0],nvals) else $
+ sv = replicate(' ',nvals)
+ On_ioerror, BADVAL ;Trap any type conversions
+ sv[0]= svals[0:nvals-1]
+ On_ioerror, NULL
+ sv0=sv[0] & sv1=sv[1]
+;
+; -----------------------------------------------------------
+; STRING SEARCHES (Must use STRPOS to search for substring match)
+;
+if datatype EQ 7 then begin
+ values = strupcase(strtrim(values))
+ case type of
+
+ 0: if keyword_set(FULLSTRING) then $ ;Exact string match?
+ valid = strtrim(values,2) EQ strtrim(sv0,2) else $
+ valid = strpos(values,strtrim(sv0,2)) GE 0 ;substring search
+ -1: valid = values GE sv0 ;greater than
+ -2: valid = values LE sv1 ;less than
+ -3: valid = (values GE sv0) and (values LE sv1) ;in range
+ -4: valid = strtrim(values) NE '' ;non zero (i.e. not null)
+ -5: message, $ ;Tolerance value
+ ' Tolerance specification for strings is not valid'
+ else: begin
+ sv = strtrim(sv,2)
+ sv = sv[uniq(sv,sort(sv))] ;Remove duplicates
+ type = N_elements(sv)
+ valid = bytarr(nv)
+
+ if keyword_set(FULLSTRING) then begin
+ values = strtrim(values,2)
+ for ii = 0l,type-1 do valid OR= (values EQ sv[ii])
+
+ endif else begin
+
+ for ii=0L,type-1 do begin ;within set of substring
+ valid OR= (strpos(values,sv[ii]) GE 0)
+ endfor
+
+ endelse
+ end
+ endcase
+ good = where(valid, count)
+ return
+end
+;
+;---------------------------------------------------------------------
+; ALL OTHER DATA TYPES
+
+case type of
+
+ 0: good = where( values EQ sv0, count ) ;value=sv0
+ -1: good = where( values GE sv0, count ) ;value>sv0
+ -2: good = where( values LE sv1, count ) ;value NEWLIST = DBSORT( -1, 'RA,DEC' )
+;
+; If for some reason, one wanted the DEC sorted in descending order, but
+; the RA in ascending order
+;
+; IDL> NEWLIST = DBSORT( -1, 'RA,DEC', REV = [ 0, 1 ] )
+;
+; METHOD:
+; The list is sorted such that each item is sorted into
+; asscending order starting with the last item.
+; COMMON BLOCKS:
+; DBCOM
+; PROCEDURES USED:
+; ZPARCHECK, BSORT, DBEXT, DB_ITEM
+; HISTORY
+; VERSION 1 D. Lindler Oct. 86
+; Added REVERSE keyword W. Landsman August, 1991
+; Avoid use of EXECUTE() for V6.1 or later W. Landsman Dec 2006
+; Assume since V6.1 W. Landsman June 2009
+; Add TEMPORARY call W. Lnadsman July 2009
+;-
+ On_error,2
+ compile_opt idl2
+ if N_params() LT 2 then begin
+ print,'Syntax: newlist = dbsort( list, items, [ REVERSE = ] )'
+ return, -1
+ endif
+;---------------------------------------------------------
+; data base common block, see DBOPEN for meanings
+
+ common db_com,QDB,QITEMS,QLINK
+
+; check parameters
+
+ zparcheck, 'DBSORT', list, 1, [1,2,3], [0,1], 'entry list'
+ zparcheck, 'DBSORT', items, 2, [1,2,3,7], [0,1], 'item list'
+
+; extract values of items
+
+ db_item, items, it
+ nitems = N_elements(it) ;Number of items
+ if nitems GT 9 then message, $
+ 'ERROR - Can only sort on nine items or less'
+
+ ;Verify REVERSE vector
+ if not keyword_set(REV) then rev = bytarr(nitems) else $
+ if N_elements(rev) NE nitems then $
+ message,'ERROR - REVERSE vector must contain ' + $
+ strtrim(nitems,2) + ' elements'
+
+; make list vector
+
+ qnentry = long(qdb,84)
+ if list[0] EQ -1 then vlist = lindgen(qnentry)+1 else vlist = list
+
+; create line to execute in the form:
+; dbext, vlist, it, v1,v2,...,v(nitems)
+ case nitems of
+ 1: dbext, vlist, it, v1
+ 2: dbext, vlist, it, v1, v2
+ 3: dbext, vlist, it, v1, v2, v3
+ 4: dbext, vlist, it, v1, v2, v3, v4
+ 5: dbext, vlist, it, v1, v2, v3, v4, v5
+ 6: dbext, vlist, it, v1, v2, v3, v4, v5, v6
+ 7: dbext, vlist, it, v1, v2, v3, v4, v5, v6, v7
+ 8: dbext, vlist, it, v1, v2, v3, v4, v5, v6, v7, v8
+ 9: dbext, vlist, it, v1, v2, v3, v4, v5, v6, v7, v8, v9
+ endcase
+
+; sort on each item
+
+ sub = lindgen(N_elements(vlist)) ;list of subscripts
+ for i = 0,nitems-1 do begin
+
+; get item
+
+ j = nitems-i
+ vv = 'v' + strtrim(j,2)
+ v = temporary(scope_varfetch(vv, level=0))
+
+; perform previous sorts on item
+
+ if i GT 0 then v = v[sub]
+
+; sort item
+
+ sub = sub[ bsort( v, REVERSE = rev[j-1] ) ]
+
+ end
+
+; return sorted list
+
+ return, vlist[sub]
+ end
diff --git a/Code/script_idl_mv/astrolib/dbtarget.pro b/Code/script_idl_mv/astrolib/dbtarget.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8c7f8f8e6ad52a0fea225c22943bd8cdbcb28685
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbtarget.pro
@@ -0,0 +1,93 @@
+function dbtarget, target, radius, sublist,SILENT=silent, $
+ TO_B1950 = to_B1950, DIS = dis
+;+
+; NAME:
+; DBTARGET
+; PURPOSE:
+; Find sources in a database within specified radius of specified target
+; EXPLANATION:
+; Uses QuerySimbad to translate target name to RA and Dec, and then uses
+; DBCIRCLE() to find any entries within specified radius. Database must
+; include items named 'RA' (in hours) and 'DEC' (in degrees) and must
+; have previously been opened with DBOPEN
+;
+; CALLING SEQUENCE:
+; list = DBTARGET(target, [radius, sublist, /SILENT, DIS= ,/TO_B1950 ] )
+;
+; INPUTS:
+; TARGET - A scalar string giving an astronomical target name, which
+; will be translated into J2000 celestial coordinates by QuerySimbad
+;
+; OPTIONAL INPUT:
+; RADIUS - Radius of the search field in arc minutes, scalar.
+; Default is 5 arc minutes
+; SUBLIST - Vector giving entry numbers in currently opened database
+; to be searched. Default is to search all entries
+;
+; OUTPUTS:
+; LIST - Vector giving entry numbers in the currently opened catalog
+; which have positions within the specified search circle
+; LIST is set to -1 if no sources fall within the search circle
+; !ERR is set to the number sources found.
+;
+; OPTIONAL OUTPUT
+; DIS - The distance in arcminutes of each entry specified by LIST
+; to the search center specified by the target.
+;
+; OPTIONAL KEYWORD INPUT:
+; /SILENT - If this keyword is set, then DBTARGET will not print the
+; number of entries found at the terminal
+; /TO_B1950 - If this keyword is set, then the SIMBAD J2000 coordinates
+; are converted to B1950 before searching the database
+; NOTE: The user must determine on his own whether the database
+; is in B1950 or J2000 coordinates.
+;
+; RESTRICTIONS;
+; The database must have items 'RA' (in hours) and 'DEC' (in degrees).
+; Alternatively, the database could have items RA_OBJ and DEC_OBJ
+; (both in degrees)
+; EXAMPLE:
+; (1) Use the HST_CATALOG database to find all HST observations within
+; 5' (the default) of M33
+;
+; IDL> dbopen,'hst_catalog'
+; IDL> list = dbtarget('M33')
+;
+; (2) As above but restrict targets within 2' of the nucleus using the
+; WFPC2 camara
+;
+; IDL> dbopen,'hst_catalog'
+; IDL> sublist = dbfind('config=WFPC2')
+; IDL> list = dbtarget('M33',2,sublist)
+;
+;
+; PROCEDURE CALLS:
+; QuerySimbad, DBCIRCLE()
+; REVISION HISTORY:
+; Written W. Landsman SSAI September 2002
+; Propagate /SILENT keyword to QuerySimbad W. Landsman Oct 2009
+; Make sure a database is open W.L. Oct 2010
+;-
+ On_error,2
+
+ if N_params() LT 1 then begin
+ print,'Syntax - list = DBTARGET( targetname_or_coord, [radius, sublist '
+ print,' DIS =, /SILENT, /TO_B1950 ] )'
+ if N_elements(sublist) GT 0 then return, sublist else return,lonarr(1)-1
+ endif
+
+ if ~db_info('open') then message,'ERROR - No database open'
+
+ QuerySimbad, target, ra,dec, Found = Found,Silent=silent
+ if found EQ 0 then message,'Target name ' + target + $
+ ' could not be translated by SIMBAD'
+ ra = ra/15.
+
+ if N_elements(radius) EQ 0 then radius = 5
+ if n_elements(sublist) EQ 0 then $
+ return, dbcircle(ra, dec, radius, dis, SILENT=silent, $
+ TO_B1950 = to_b1950 )
+ return, dbcircle(ra, dec, radius, dis, sublist, SILENT=silent, $
+ TO_B1950 = to_b1950 )
+
+ end
diff --git a/Code/script_idl_mv/astrolib/dbtitle.pro b/Code/script_idl_mv/astrolib/dbtitle.pro
new file mode 100644
index 0000000000000000000000000000000000000000..18232b9ffb23cda701d8b04930d3feae65d55b4c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbtitle.pro
@@ -0,0 +1,38 @@
+function dbtitle,c,f
+;+
+; NAME:
+; DBTITLE
+; PURPOSE:
+; function to create title line for routine dbprint
+;
+; CALLING SEQUENCE:
+; result = dbtitle( c, f )
+;
+; INPUTS:
+; c = string array of titles for each item
+; f = field length of each item
+;
+; OUTPUT:
+; header string returned as function value
+;
+; OPERATIONAL NOTES:
+; this is a subroutine of DBPRINT.
+;
+; HISTORY:
+; version 1 D. Lindler Sept 86
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;------------------------------------------------------------
+n=n_elements(c)
+h=' '
+com = strtrim(c,0) ;header for item with trailing blanks removed
+ncom = strlen(com)
+for i=0,n-1 do begin ;loop on items
+ flen=f[i] ;field length
+ st=string(replicate(byte(32),flen+1));blank field
+ ipos=((flen-ncom[i]+1)/2)>1 ;starting position in field for comment
+ strput,st,com[i],ipos ;insert into field
+ h=h+st ;add to header
+end; loop on items
+return,h ;return header
+end
diff --git a/Code/script_idl_mv/astrolib/dbupdate.pro b/Code/script_idl_mv/astrolib/dbupdate.pro
new file mode 100644
index 0000000000000000000000000000000000000000..73d252e7f31b3d480d80fcdeb9e971ef48e7cc66
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbupdate.pro
@@ -0,0 +1,163 @@
+pro dbupdate,list,items,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14, $
+ NOINDEX = noindex
+;+
+; NAME:
+; DBUPDATE
+; PURPOSE:
+; Update columns of data in a database -- inverse of DBEXT
+; EXPLANATION:
+; Database must be open for update before calling DBUPDATE
+;
+; CALLING SEQUENCE:
+; dbupdate, list, items, v1, [ v2, v3, v4......v14 ]
+;
+; INPUTS:
+; list - entries in database to be updated, scalar or vector
+; If list=-1 then all entries will be updated
+; items -standard list of items that will be updated.
+; v1,v2....v14 - vectors containing values for specified items. The
+; number of vectors supplied must equal the number of items
+; specified. The number of elements in each vector should be
+; the same.
+;
+; OPTIONAL KEYWORD INPUT:
+; /NOINDEX - If set, then DBUPDATE will not update the index file. This
+; keyword is useful to save if additional updates will occur,
+; and the index file need only be updated on the last call.
+;
+; EXAMPLES:
+; A database STAR contains RA and DEC in radians, convert to degrees
+;
+; IDL> !PRIV=2 & dbopen,'STAR',1 ;Open database for update
+; IDL> dbext,-1,'RA,DEC',ra,dec ;Extract RA and DEC, all entries
+; IDL> ra = ra*!RADEG & dec=dec*!RADEG ;Convert to degrees
+; IDL> dbupdate,-1,'RA,DEC',ra,dec ;Update database with new values
+;
+; NOTES:
+; It is quicker to update several items simultaneously rather than use
+; repeated calls to DBUPDATE.
+;
+; It is possible to update multiple valued items. In this case, the
+; input vector should be of dimension (NVAL,NLIST) where NVAL is the
+; number of values per item, and NLIST is the number of entries to be
+; updated. This vector will be temporarily transposed by DBUPDATE but
+; will be restored before DBUPDATE exits.
+;
+; REVISION HISTORY
+; Written W. Landsman STX March, 1989
+; Work for multiple valued items May, 1991
+; String arrays no longer need to be fixed length December 1992
+; Transpose multiple array items back on output December 1993
+; Faster update of external databases on big endian machines November 1997
+; Converted to IDL V5.0 W. Landsman 24-Nov-1997
+; Added /NOINDEX keyword W. Landsman July 2001
+;-
+ On_error,2 ;Return to caller
+
+ if N_params() LT 3 then begin
+ print,'Syntax - dbupdate, list, items, v1, [ v2, v3, v4, v5,...v14 ]'
+ return
+ endif
+ ;Get number of entries to update
+ nlist = N_elements(list)
+ if nlist EQ 0 then message, $
+ 'ERROR - no entry values supplied'
+
+ nentries = db_info( 'ENTRIES' ) ;Number of entries in database
+ external = db_info( 'EXTERNAL', 0 )
+ if external then noconvert = is_ieee_big() else noconvert = 1b
+
+ if list[0] LT 0 then begin ;If LIST = -1, then update all entries
+ nlist = nentries[0]
+ list = lindgen(nlist) + 1
+ endif
+
+ db_item, items, itnum, ivalnum, idltype, sbyte, numvals, nbyte
+ nitem = N_elements(itnum) ;Number of items in database
+ if N_params() LT nitem+2 then $
+ message,'ERROR - ' + strtrim(nitem,2) + ' items specified, but only ' + $
+ strtrim(N_params()-2,2) + ' input variables supplied'
+
+; Make sure user supplied enough values for all desired entries
+
+ for i = 0,nitem-1 do begin
+
+ ii = strtrim(i+1,2)
+ test = execute('good = N_elements(v' + ii +') EQ nlist*numvals[i]')
+ if good NE 1 then $
+ message,'Supplied values for item ' + $
+ strtrim(db_item_info('name',itnum[i]),2) + ' must contain '+ $
+ strtrim(nlist*numvals[i],2)+' elements'
+
+ test = execute('s=size(v' + ii +')' )
+ if s[s[0] + 1] NE idltype[i] then $
+ message,'Item ' + strtrim(db_item_info('name',itnum[i]),2)+ $
+ ' has an incorrect data type'
+
+ if numvals[i] GT 1 then begin
+ test = execute('v'+ ii + '= transpose(v'+ ii + ')' )
+ endif
+
+ endfor
+
+ nitems = (nitem GT indgen(14) )
+ nbyte = nbyte*numvals
+
+ for i = 0l,nlist-1 do begin
+
+ dbrd,list[i],entry,noconvert=noconvert
+ dbxput,v1[i,*],entry,idltype[0],sbyte[0],nbyte[0]
+ if nitems[1] then begin
+ dbxput,v2[i,*],entry,idltype[1],sbyte[1],nbyte[1]
+ if nitems[2] then begin
+ dbxput,v3[i,*],entry,idltype[2],sbyte[2],nbyte[2]
+ if nitems[3] then begin
+ dbxput,v4[i,*],entry,idltype[3],sbyte[3],nbyte[3]
+ if nitems[4] then begin
+ dbxput,v5[i,*],entry,idltype[4],sbyte[4],nbyte[4]
+ if nitems[5] then begin
+ dbxput,v6[i,*],entry,idltype[5],sbyte[5],nbyte[5]
+ if nitems[6] then begin
+ dbxput,v7[i,*],entry,idltype[6],sbyte[6],nbyte[6]
+ if nitems[7] then begin
+ dbxput,v8[i,*],entry,idltype[7],sbyte[7],nbyte[7]
+ if nitems[8] then begin
+ dbxput,v9[i,*],entry,idltype[8],sbyte[8],nbyte[8]
+ if nitems[9] then begin
+ dbxput,v10[i,*],entry,idltype[9],sbyte[9],nbyte[9]
+ if nitems[10] then begin
+ dbxput,v11[i,*],entry,idltype[10],sbyte[10],nbyte[10]
+ if nitems[11] then begin
+ dbxput,v12[i,*],entry,idltype[11],sbyte[11],nbyte[11]
+ if nitems[12] then begin
+ dbxput,v13[i,*],entry,idltype[12],sbyte[12],nbyte[12]
+ if nitems[13] then $
+ dbxput,v14[i,*],entry,idltype[13],sbyte[13],nbyte[13]
+ endif & endif & endif & endif & endif & endif & endif & endif & endif
+ endif & endif & endif
+ dbwrt,entry, noconvert = noconvert
+
+ endfor
+
+; Transpose back any multiple value items
+
+ for i = 0,nitem-1 do begin
+ if numvals[i] GT 1 then begin
+ ii = strtrim(i+1,2)
+ test = execute('v'+ ii + '= transpose(v'+ ii + ')' )
+ endif
+ endfor
+
+; Check if the indexed file needs to be updated
+
+ if keyword_set(NOINDEX) then return
+
+ indextype = db_item_info( 'INDEX', itnum)
+ index = where( indextype, nindex) ;Indexed items
+ if nindex GT 0 then begin
+ message, 'Now updating indexed file', /INFORM
+ dbindex, itnum[index]
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbval.pro b/Code/script_idl_mv/astrolib/dbval.pro
new file mode 100644
index 0000000000000000000000000000000000000000..747f2142dd25f9315bb3f94a9c3acbeeb0db1aca
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbval.pro
@@ -0,0 +1,50 @@
+function dbval,entry,item
+;+
+; NAME:
+; DBVAL
+; PURPOSE:
+; procedure to extract value(s) of the specified item from
+; a data base file entry.
+;
+; CALLING SEQUENCE:
+; result = dbval( entry, item )
+;
+; INPUTS:
+; entry - byte array containing the entry, or a scalar entry number
+; item - name (string) or number (integer) of the item
+;
+; OUTPUT:
+; the value(s) will be returned as the function value
+;
+; EXAMPLE:
+; Extract a flux vector from entry 28 of the database FARUV
+; ==> flux = dbval(28,'FLUX')
+;
+; HISTORY:
+; version 2 D. Lindler Nov, 1987 (new db format)
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;-------------------------------------------------------------------
+;
+; get item info
+;
+db_item,item,itnum,ival,idltype,sbyte,numvals,nbytes
+;
+; check to see if entry is a valid array
+;
+s=size(entry)
+if s[0] gt 0 then begin ;array supplied
+ if(s[0] ne 1) then begin ;is entry a 1-d array
+ print,'entry must be a 1-d byte array, dbval aborting'
+ retall
+ endif
+ if(s[2] ne 1) then begin ;check if byte array
+ print,'entry must be a byte array, dbval aborting'
+ retall
+ endif
+ return,dbxval(entry,idltype[0],numvals[0],sbyte[0],nbytes[0])
+end else begin ;scalar supplied (assume entry number)
+ dbrd,entry,e ;read entry
+ return,dbxval(e,idltype[0],numvals[0],sbyte[0],nbytes[0]);return value(s)
+end
+end
diff --git a/Code/script_idl_mv/astrolib/dbwrt.pro b/Code/script_idl_mv/astrolib/dbwrt.pro
new file mode 100644
index 0000000000000000000000000000000000000000..34f39f4d0aa2cf316e9bd3dce8d953ad119a9263
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbwrt.pro
@@ -0,0 +1,195 @@
+pro dbwrt,entry,index,append,noconvert=noconvert
+;+
+; NAME:
+; DBWRT
+; PURPOSE:
+; procedure to update or add a new entry to a data base
+;
+; CALLING SEQUENCE:
+; dbwrt, entry, [ index, append, /NoConvert ]
+;
+; INPUTS:
+; entry - entry record to be updated or added if first
+; item (entry number=0)
+;
+; OPTIONAL INPUTS:
+; index - optional integer flag, if set to non zero then index
+; file is updated. (default=0, do not update index file)
+; (Updating the index file is time-consuming, and should
+; normally be done after all changes have been made.
+; append - optional integer flag, if set to non-zero the record
+; is appended as a new entry, regardless of what the
+; entry number in the record is. The entry number will
+; be reset to the next entry number in the file.
+; OUTPUTS:
+; data base file is updated.
+; If index is non-zero then the index file is updated.
+; OPTIONAL INPUT KEYWORD:
+; NoConvert - If set then don't convert to host format with an external
+; database. Useful when the calling program decides that
+; conversion isn't needed (i.e. on a big-endian machine), or
+; takes care of the conversion itself.
+; OPERATIONAL NOTES:
+; !PRIV must be greater than 1 to execute
+; HISTORY:
+; version 2 D. Lindler Feb. 1988 (new db format)
+; converted to IDL Version 2. M. Greason, STX, June 1990.
+; William Thompson, GSFC/CDS (ARC), 28 May 1994
+; Added support for external (IEEE) representation.
+; Faster handling of byte swapping W. L. August 2010
+;-
+;-------------------------------------------------------------------
+ COMMON db_com,qdb,qitems,qdbrec
+
+ if N_params() LT 2 then index=0
+ if N_params() LT 3 then append=0
+
+; Byte swapping is needed if database is in external format, and user is on
+; a little endian machine, and /noconvert is not st
+
+ bswap = (qdb[119] eq 1) && ~keyword_set(noconvert) && ~is_ieee_big()
+
+
+; get some info on the data base
+
+ update = db_info( 'UPDATE' )
+ if update EQ 0 then message,'Database opened for read only'
+
+ len = db_info( 'LENGTH', 0 ) ;record length
+ qnentry = db_info( 'ENTRIES', 0 )
+
+; determine if entry is correct size
+
+ s = size(entry)
+ if s[0] NE 1 then message,'Entry must be a 1-dimensional array'
+
+ if s[1] NE len then $
+ message,'Entry not the proper length of '+strtrim(len,2)+' bytes'
+
+ if s[2] NE 1 then $
+ message,'Entry vector (first parameter) must be a byte array'
+
+; get entry number
+
+ enum = append ? 0 : dbxval(entry,3,1,0,4)
+ if ( enum GT qnentry ) || ( enum LT 0 ) then $
+ message,'Invalid entry number of '+strtrim(enum,2)+' (first value in entry)'
+
+ if enum EQ 0 then begin ;add new entry
+ qnentry = qnentry+1
+ qdb[84] = byte(qnentry,0,4)
+ enum = qnentry
+ dbxput,long(enum),entry,3,0,4
+ newentry = 1b
+ endif else newentry =0b
+ if bswap then begin
+ tmp = entry
+ db_ent2ext, tmp
+ qdbrec[enum]=tmp
+ endif else qdbrec[enum] = entry
+
+; update index file if necessary
+
+ if index EQ 0 then return
+ nitems = db_info( 'ITEMS', 0 ) ;Total number of items
+ indextype = db_item_info( 'INDEX', indgen(nitems)) ;Which ones are indexed?
+ indexed = where(indextype,nindex)
+ if nindex LE 0 then return ;If no indexed items, then we are done
+ indextype = indextype[indexed] ;Now contains only indexed items
+ unit = db_info( 'UNIT_DBX', 0 )
+ reclong = assoc(unit,lonarr(2),0)
+ h = reclong[0]
+ maxentries = h[1]
+ if bswap then swap_endian_inplace, maxentries
+ if newentry then $
+ if (maxentries LT qnentry) then begin ;Enough room for new indexed items?
+ print,'DBWRT -- maxentries too small'
+ print,'Rerun DBCREATE with maxentries in .dbd file at least ',qnentry
+ return
+ endif
+
+ reclong = assoc(unit,lonarr(7,nindex),8)
+ header = reclong[0]
+ if bswap then swap_endian_inplace,header
+ hitem = header[0,*] ;indexed item number
+ hblock = header[3,*]
+ sblock = header[4,*] & sblock = sblock[*]
+ iblock = header[5,*] & iblock = iblock[*]
+ ublock = header[6,*] & ublock = ublock[*]
+ db_item, indexed, itnum, ivalnum, idltype, startbyte, numvals, nbytes
+ pos = where(hitem EQ itnum )
+ for i = 0, nindex-1 do begin
+ v = dbxval( entry, idltype[i], numvals[i], startbyte[i], nbytes[i] )
+ sbyte = nbytes[i] * (enum-1)
+ isort = (indextype[i] EQ 3) || (indextype[i] EQ 4)
+
+ datarec = dbindex_blk(unit, sblock[pos[i]], 512, sbyte, idltype[i])
+ reclong = assoc(unit,lonarr(1),(iblock[pos]*512L))
+
+ case indextype[i] of
+
+ 1: datarec[0] = bswap ? swap_endian(v) : v
+
+
+ 2: begin
+ datarec[0] = bswap ? swap_endian(v) : v
+ if (qnentry mod 512) EQ 0 then begin ;Update
+ nb = qnentry/512
+ hbyte = nbytes[i] * nb
+ datarec = dbindex_blk(unit,hblock[pos[i]],512,hbyte,idltype[i])
+ datarec[0] = bswap ? swap_endian(v) : v
+ endif
+ end
+ 3: begin ;SORT
+
+ datarec = dbindex_blk(unit,sblock[pos[i]],512,0,idltype[i])
+ values = datarec[0:(qnentry-1)] ;Read in old values
+ if bswap then swap_endian_inplace, values
+ reclong = dbindex_blk(unit,iblock[pos[i]],512,0,3)
+ sub = reclong[0:(qnentry-1)] ;Read in old indices
+ if bswap then swap_endian_inplace, sub
+ if enum lt qnentry then begin ;Change an old value?
+ sort_index = where(sub EQ enum) ;Which value to change
+ sort_index = sort_index[0]
+ if values[sort_index] EQ v $ ;Value remains the same so
+ then isort =0 $ ;don't bother sorting again
+ else values[sort_index] = v ;Update with new value
+ endif else values = [values,v] ;Append a new value
+ end
+
+ 4: begin ;SORT/INDEX
+
+ values = datarec[qnentry-1,ublock*512] ;Update index record
+ if bswap then swap_endian_inplace, values
+ if enum lt qnentry then begin
+ if values[enum-1] EQ v then isort = 0 else values[enum-1] = v
+ endif else values = [values,v]
+ datarec = dbindex_blk(unit,ublock[pos[i]],512,sbyte,idltype[i])
+ datarec[0] = bswap ? swap_endian(v) : v
+ end
+
+ else:
+
+ endcase
+
+ if isort then begin ;resort values?
+ sub = bsort(values)
+ values = values[sub]
+ nb = (qnentry + 511)/512
+ ind = indgen(nb)*512L
+ sval = values[ind]
+;
+ datarec = dbindex_blk(unit, hblock[pos[i]], 512, 0, idltype[i])
+ datarec[0] = bswap ? swap_endian(sval) : sval
+;
+ datarec = dbindex_blk(unit, sblock[pos[i]], 512, 0, idltype[i])
+ datarec[0] = bswap ?swap_endian(values) : values
+;
+ reclong = dbindex_blk(unit, iblock[pos[i]], 512, 0, 3)
+ reclong[0] = bswap ?swap_endian(sub+1) : sub+1
+ endif
+
+ endfor
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dbxput.pro b/Code/script_idl_mv/astrolib/dbxput.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5de3f6c19edad9a6a6a19cc8cdc0a2d161e320e7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbxput.pro
@@ -0,0 +1,56 @@
+pro dbxput,val,entry,idltype,sbyte,nbytes
+;+
+; NAME:
+; DBXPUT
+; PURPOSE:
+; routine to replace value of an item in a data base entry
+;
+; CALLING SEQUENCE:
+; dbxput, val, entry, idltype, sbyte, nbytes
+;
+; INPUT:
+; val - value(s) to be placed into entry, string values might be
+; truncated to fit number of allowed bytes in item
+; entry - entry or entries to be updated
+; idltype - idl data type for item (1-7)
+; sbyte - starting byte in record
+; nbytes - total number of bytes in value added
+;
+; OUTPUT:
+; entry - (updated)
+;
+; OPERATIONAL NOTES:
+; This routine assumes that the calling procedure or user knows what he
+; or she is doing. String items are truncated or padded to the fixed
+; size specified by the database but otherwise no validity checks are
+; made.
+;
+; HISTORY:
+; version 1, D. Lindler Aug, 1986
+; converted to IDL Version 2. M. Greason, STX, June 1990.
+; Work with multiple element string items W. Landsman August 1995
+; Really work with multiple element string items
+; R. Bergman/W. Landsman July 1996
+; Work with multiple entries, R. Schwartz, GSFC/SDAC August 1996
+; Use /overwrite with REFORM() W. Landsman May 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;-------------------------------------------------------
+;
+nentry = n_elements(entry[0,*])
+case idltype of ;case of data type
+
+ 7: begin ;string
+ numvals = N_elements(val) ;Number of input values
+ nbyte = nbytes/numvals ;Number of bytes/value
+ val = strmid(val,0,nbyte) ;Truncate string
+ temp = replicate( 32b, nbyte, numvals, nentry) ;Array of blanks
+ for i = 0, numvals-1 do temp[0,i,0] = byte(val[i,*]) ;Fill with values
+ entry[sbyte:sbyte+nbytes-1,*] = reform(temp,nbytes,nentry, /over)
+ end
+ 1: entry[sbyte:sbyte+nbytes-1,*]=val
+ else: entry[sbyte:sbyte+nbytes-1,*] = byte(val,0,nbytes,nentry)
+
+endcase
+return
+end
diff --git a/Code/script_idl_mv/astrolib/dbxval.pro b/Code/script_idl_mv/astrolib/dbxval.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4b0693dfc4dadefc2d4cf67faf69623a91c10c4f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dbxval.pro
@@ -0,0 +1,71 @@
+function dbxval,entry,idltype,nvalues,sbyte,nbytes,bswap=bswap
+;+
+; NAME:
+; DBXVAL
+;
+; PURPOSE:
+; Quickly return a value of the specified item number
+; EXPLANATION:
+; Procedure to quickly return a value of the specified item number
+; from the entry.
+;
+; CALLING SEQUENCE:
+; result = dbxval( entry, idltype, nvalues, sbyte, nbytes )
+;
+; INPUTS
+; entry - entry or entries from data base (bytarr)
+; idltype - idl data type (obtained with db_item_info)
+; nvalues - number of values to return (obtained with db_item)
+; sbyte - starting byte in the entry (obtained with db_item)
+; nbytes - number of bytes (needed only for string type)
+; (obtained with db_item)
+;
+; OUTPUTS:
+; function value is value of the specified item in entry
+;
+; KEYWORDS:
+; bswap - If set, then IEEE_TO_HOST is called.
+;
+; RESTRICTIONS:
+; To increase speed the routine assumes that entry and item are
+; valid and that the data base is already opened using dbopen.
+;
+; REVISION HISTORY:
+; version 0 D. Lindler Nov. 1987 (for new db format)
+; Version 1, William Thompson, GSFC, 28 March 1994.
+; Incorporated into CDS library.
+; Version 2, Richard Schwartz, GSFC/SDAC, 23 August 1996
+; Allowed Entry to have 2 dimensions
+; Version 2.1, 22 Feb 1997, JK Feggans,
+; avoid reform for strings arrays.
+; Version 2.2 Use overwrite with REFORM(), W. Landsman, May 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+; Work for multiple-valued strings W. Landsman October 2000
+; Add new 64bit & unsigned integer datatypes W.Landsman July 2001
+; Version 3, 2-May-2003, JK Feggans/Sigma, W.T. Thompson
+; Added BSWAP keyword to avoid floating errors on some platforms.
+;-
+;----------------------------------------------------------------
+;
+;
+nentry = n_elements(entry[0,*])
+
+case idltype of ;case of data type
+ 1: val = byte(entry[sbyte:sbyte+nvalues-1,*],0,nvalues,nentry)
+ 2: val = fix(entry[sbyte:sbyte+nvalues*2-1,*],0,nvalues,nentry)
+ 3: val = long(entry[sbyte:sbyte+nvalues*4-1,*],0,nvalues,nentry)
+ 4: val = float(entry[sbyte:sbyte+nvalues*4-1,*],0,nvalues,nentry)
+ 5: val = double(entry[sbyte:sbyte+nvalues*8-1,*],0,nvalues,nentry)
+ 7: val = string( reform( entry[sbyte:sbyte+nbytes-1,*], nbytes/nvalues, $
+ nvalues, nentry))
+ 12: val = uint(entry[sbyte:sbyte+nvalues*2-1,*],0,nvalues,nentry)
+ 13: val = ulong(entry[sbyte:sbyte+nvalues*4-1,*],0,nvalues,nentry)
+ 14: val = long64(entry[sbyte:sbyte+nvalues*8-1,*],0,nvalues,nentry)
+ 15: val = ulong64(entry[sbyte:sbyte+nvalues*8-1,*],0,nvalues,nentry)
+endcase
+;
+if keyword_set(bswap) then ieee_to_host,val,idltype=idltype
+
+if ( nvalues EQ 1 and nentry EQ 1) then return,val[0] else $
+ if idltype eq 7 then return,val else return,reform(val,/overwrite)
+end
diff --git a/Code/script_idl_mv/astrolib/delvarx.pro b/Code/script_idl_mv/astrolib/delvarx.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c7565058111c2700755db4c8dc86075219f7aa96
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/delvarx.pro
@@ -0,0 +1,52 @@
+;+
+; NAME:
+; DELVARX
+; PURPOSE:
+; Delete up to 10 variables for memory management (can call from routines)
+; EXPLANATION:
+; Like intrinsic DELVAR function, but can be used from any calling level
+;
+; Modified in January 2012 to always free memory associated with
+; pointers/objects and remove the use of EXECUTE()
+; Also look at the Coyote routine UNDEFINE
+; http://www.idlcoyote.com/programs/undefine.pro
+;
+; CALLING SEQUENCE:
+; DELVARX, p0, [p1, p2......p9]
+;
+; INPUTS:
+; p0, p1...p9 - variables to delete
+;
+; OBSOLETE KEYWORD:
+; /FREE_MEM - formerly freed memory associated with pointers
+; and objects. Since this is now the DELVARX default this
+; keyword does nothing.
+;
+; METHOD:
+; Uses HEAP_FREE and PTR_NEW(/NO_COPY) to delete variables and free
+; memory
+;
+; REVISION HISTORY:
+; Copied from the Solar library, written by slf, 25-Feb-1993
+; Added to Astronomy Library, September 1995
+; Modified, 26-Mar-2003, Zarro (EER/GSFC) 26-Mar-2003
+; - added FREE_MEM to free pointer/objects
+; Modified, 28-Jan-2012, E. Rykoff (SLAC), W. Landsman -
+; replace EXECUTE calls with SCOPE_VARFETCH.
+;-
+
+PRO delvarx, p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,free_mem = free_mem
+
+ npar = N_params() ; Number of parameters
+ pp = 'p'+strtrim(indgen(npar),1)
+
+ for i=0,npar-1 do begin
+ defined = N_elements( SCOPE_VARFETCH(pp[i],LEVEL=0))
+ if LOGICAL_TRUE(defined) then $
+ heap_free, ptr_new( SCOPE_VARFETCH(pp[i],LEVEL=0),/no_copy)
+
+ endfor
+
+ return
+ end
+
diff --git a/Code/script_idl_mv/astrolib/deredd.pro b/Code/script_idl_mv/astrolib/deredd.pro
new file mode 100644
index 0000000000000000000000000000000000000000..880f0d4256f631b775bf7e718e7d60954049635c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/deredd.pro
@@ -0,0 +1,55 @@
+pro deredd,Eby,by,m1,c1,ub,by0,m0,c0,ub0, update = update
+;+
+; NAME:
+; DEREDD
+;
+; PURPOSE:
+; Deredden stellar Stromgren parameters given for a value of E(b-y)
+; EXPLANATION:
+; See the procedure UVBYBETA for more info.
+;
+; CALLING SEQUENCE:
+; deredd, eby, by, m1, c1, ub, by0, m0, c0, ub0, /UPDATE
+;
+; INPUTS:
+; Eby - color index E(b-y),scalar (E(b-y) = 0.73*E(B-V) )
+; by - b-y color (observed)
+; m1 - Stromgren line blanketing parameter (observed)
+; c1 - Stromgren Balmer discontinuity parameter (observed)
+; ub - u-b color (observed)
+;
+; These input values are unaltered unless the /UPDATE keyword is set
+; OUTPUTS:
+; by0 - b-y color (dereddened)
+; m0 - Line blanketing index (dereddened)
+; c0 - Balmer discontinuity parameter (dereddened)
+; ub0 - u-b color (dereddened)
+;
+; OPTIONAL INPUT KEYWORDS:
+; /UPDATE - If set, then input parameters are updated with the dereddened
+; values (and output parameters are not used).
+; REVISION HISTORY:
+; Adapted from FORTRAN routine DEREDD by T.T. Moon
+; W. Landsman STX Co. April, 1988
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ if N_Params() LT 2 then begin
+ print,'Syntax - DEREDD, eby, by, m1, c1, ub, by0, m0, c0, ub0'
+ return
+ endif
+
+ Rm1 = -0.33 & Rc1 = 0.19 & Rub = 1.53
+ Eby0 = Eby >0
+ if keyword_set(update) then begin
+ by = by - eby0
+ if N_elements(m1) GT 0 then m1 = m1 - Rm1*Eby0
+ if N_elements(c1) GT 0 then c1 = c1 - Rc1*Eby0
+ if N_elements(ub) GT 0 then ub = ub - Rub*Eby0
+ endif else begin
+ by0 = by - Eby0
+ m0 = m1 - Rm1*Eby0
+ c0 = c1 - Rc1*Eby0
+ ub0 = ub - Rub*Eby0
+ endelse
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/detabify.pro b/Code/script_idl_mv/astrolib/detabify.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c57f7c698568535a25b2699ab6c9e0c48db83a3b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/detabify.pro
@@ -0,0 +1,62 @@
+ FUNCTION DETABIFY, CHAR_STR
+;+
+; NAME:
+; DETABIFY
+; PURPOSE:
+; Replaces tabs in character strings with appropriate number of spaces
+; EXPLANATION:
+; The number of space characters inserted is calculated to space
+; out to the next effective tab stop, each of which is eight characters
+; apart.
+;
+; CALLING SEQUENCE:
+; Result = DETABIFY( CHAR_STR )
+;
+; INPUT PARAMETERS:
+; CHAR_STR = Character string variable (or array) to remove tabs from.
+;
+; OUTPUT:
+; Result of function is CHAR_STR with tabs replaced by spaces.
+;
+; RESTRICTIONS:
+; CHAR_STR must be a character string variable.
+;
+; MODIFICATION HISTORY:
+; William Thompson, Feb. 1992.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE,'Syntax: Result = DETABIFY(CHAR_STR)'
+;
+; Make sure CHAR_STR is of type string.
+;
+ SZ = SIZE(CHAR_STR)
+ IF SZ[SZ[0]+1] NE 7 THEN BEGIN
+ MESSAGE,/INFORMATIONAL,'CHAR_STR must be of type string'
+ RETURN, CHAR_STR
+ ENDIF
+;
+; Step through each element of CHAR_STR.
+;
+ STR = CHAR_STR
+ FOR I = 0,N_ELEMENTS(STR)-1 DO BEGIN
+;
+; Keep looking for tabs until there aren't any more.
+;
+ REPEAT BEGIN
+ TAB = STRPOS(STR[I],STRING(9B))
+ IF TAB GE 0 THEN BEGIN
+ NBLANK = 8 - (TAB MOD 8)
+ STR[I] = STRMID(STR[I],0,TAB) + $
+ STRING(REPLICATE(32B,NBLANK)) + $
+ STRMID(STR[I],TAB+1,STRLEN(STR[I])-TAB-1)
+ ENDIF
+ ENDREP UNTIL TAB LT 0
+ ENDFOR
+;
+ RETURN, STR
+ END
diff --git a/Code/script_idl_mv/astrolib/dist_circle.pro b/Code/script_idl_mv/astrolib/dist_circle.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a5457bfdaa32f87dda0d94a0f7ca5e3e4090a38e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dist_circle.pro
@@ -0,0 +1,97 @@
+pro dist_circle ,im, n, xcen ,ycen, DOUBLE = double
+;+
+; NAME:
+; DIST_CIRCLE
+; PURPOSE:
+; Form a square array where each value is its distance to a given center.
+; EXPLANATION:
+; Returns a square array in which the value of each element is its
+; distance to a specified center. Useful for circular aperture photometry.
+;
+; CALLING SEQUENCE:
+; DIST_CIRCLE, IM, N, [ XCEN, YCEN, /DOUBLE ]
+;
+; INPUTS:
+; N = either a scalar specifying the size of the N x N square output
+; array, or a 2 element vector specifying the size of the
+; N x M rectangular output array.
+;
+; OPTIONAL INPUTS:
+; XCEN,YCEN = Scalars designating the X,Y pixel center. These need
+; not be integers, and need not be located within the
+; output image. If not supplied then the center of the output
+; image is used (XCEN = YCEN = (N-1)/2.).
+;
+; OUTPUTS:
+; IM - N by N (or M x N) floating array in which the value of each
+; pixel is equal to its distance to XCEN,YCEN
+;
+; OPTIONAL INPUT KEYWORD:
+; /DOUBLE - If this keyword is set and nonzero, the output array will
+; be of type DOUBLE rather than floating point.
+;
+; EXAMPLE:
+; Total the flux in a circular aperture within 3' of a specified RA
+; and DEC on an 512 x 512 image IM, with a header H.
+;
+; IDL> adxy, H, RA, DEC, x, y ;Convert RA and DEC to X,Y
+; IDL> getrot, H, rot, cdelt ;CDELT gives plate scale deg/pixel
+; IDL> cdelt = cdelt*3600. ;Convert to arc sec/pixel
+; IDL> dist_circle, circle, 512, x, y ;Create a distance circle image
+; IDL> circle = circle*abs(cdelt[0]) ;Distances now given in arcseconds
+; IDL> good = where(circle LT 180) ;Within 3 arc minutes
+; IDL> print,total( IM[good] ) ;Total pixel values within 3'
+;
+; RESTRICTIONS:
+; The speed of DIST_CIRCLE decreases and the the demands on virtual
+; increase as the square of the output dimensions. Users should
+; dimension the output array as small as possible, and re-use the
+; array rather than re-calling DIST_CIRCLE
+;
+; MODIFICATION HISTORY:
+; Adapted from DIST W. Landsman March 1991
+; Allow a rectangular output array W. Landsman June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+; Add /DOUBLE keyword, make XCEN,YCEN optional W. Landsman Jun 1998
+;-
+ On_error,2 ;Return to caller if an error occurs
+
+ if N_params() LT 2 then begin
+ print,'Syntax - DIST_CIRCLE, im, n,[ xcen, ycen, /DOUBLE ]'
+ print,'IM - output image array'
+ print,'N - size of the output image array, scalar or 2 element vector'
+ print,'XCEN,YCEN - position from which to specify distances'
+ return
+ endif
+
+ if N_elements(N) EQ 2 then begin
+ nx = n[0]
+ ny = n[1]
+ endif else if N_elements(N) EQ 1 then begin
+ ny = n
+ nx = n ;Make a row
+ endif else message, $
+ 'ERROR - Output size parameter N must contain 1 or 2 elements'
+
+
+ if N_params() LT 4 then begin
+ xcen = (nx-1)/2. & ycen = (ny-1)/2.
+ endif
+
+
+ if keyword_set(DOUBLE) then begin
+ x_2 = (dindgen(nx) - xcen) ^ 2 ;X distances (squared)
+ y_2 = (dindgen(ny) - ycen) ^ 2 ;Y distances (squared)
+ im = dblarr( nx, ny, /NOZERO) ;Make uninitialized output array
+ endif else begin
+ x_2 = (findgen(nx) - xcen) ^ 2 ;X distances (squared)
+ y_2 = (findgen(ny) - ycen) ^ 2 ;Y distances (squared)
+ im = fltarr( nx, ny, /NOZERO) ;Make uninitialized output array
+ endelse
+
+ for i = 0L, ny-1 do begin ;Row loop
+ im[0,i] = sqrt(x_2 + y_2[i]) ;Euclidian distance
+ endfor
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/dist_ellipse.pro b/Code/script_idl_mv/astrolib/dist_ellipse.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0e23c31fb22906a6d59890f6e635de55a38766be
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/dist_ellipse.pro
@@ -0,0 +1,121 @@
+pro dist_ellipse,im,n,xc,yc,ratio,pos_ang, DOUBLE = double
+;+
+; NAME:
+; DIST_ELLIPSE
+; PURPOSE:
+; Create a mask array useful for elliptical aperture photemetry
+; EXPLANATION:
+; Form an array in which the value of each element is equal to the
+; semi-major axis of the ellipse of specified center, axial ratio, and
+; position angle, which passes through that element. Useful for
+; elliptical aperture photometry.
+;
+; CALLING SEQUENCE:
+; DIST_ELLIPSE, IM, N, XC, YC, RATIO, [ POS_ANG] , /DOUBLE
+;
+; INPUTS:
+; N = either a scalar specifying the size of the N x N square output
+; array, or a 2 element vector specifying the size of the
+; M x N rectangular output array.
+; XC,YC - Scalars giving the position of the ellipse center. This does
+; not necessarily have to be within the image
+; RATIO - Scalar giving the ratio of the major to minor axis. This
+; should be greater than 1 for position angle to have its
+; standard meaning.
+;
+; OPTIONAL INPUTS:
+; POS_ANG - Position angle of the major axis in degrees, measured counter-clockwise
+; from the Y axis. For an image in standard orientation
+; (North up, East left) this is the astronomical position angle.
+; Default is 0 degrees.
+;
+; OPTIONAL INPUT KEYWORD:
+; /DOUBLE - If this keyword is set and nonzero, the output array will
+; be of type DOUBLE rather than floating point.
+;
+; OUTPUT:
+; IM - REAL*4 elliptical mask array, of size M x N. THe value of each
+; pixel is equal to the semi-major axis of the ellipse of center
+; XC,YC, axial ratio RATIO, and position angle POS_ANG, which
+; passes through the pixel.
+;
+; EXAMPLE:
+; Total the flux in a elliptical aperture with a major axis of 3', an
+; axial ratio of 2.3, and a position angle of 25 degrees centered on
+; a specified RA and DEC. The image array, IM is 200 x 200, and has
+; an associated FITS header H.
+;
+; ADXY, H, ra, dec, x, y ;Get X and Y corresponding to RA and Dec
+; GETROT, H, rot, cdelt ;CDELT gives plate scale degrees/pixel
+; cdelt = abs( cdelt)*3600. ;CDELT now in arc seconds/pixel
+; DIST_ELLIPSE, ell, 200, x, y, 2.3, 25 ;Create a elliptical image mask
+; ell = ell*cdelt(0) ;Distances now given in arcseconds
+; good = where( ell lt 180 ) ;Within 3 arc minutes
+; print,total( im(good) ) ;Total pixel values within 3'
+;
+; RESTRICTIONS:
+; The speed of DIST_ELLIPSE decreases and the the demands on virtual
+; increase as the square of the output dimensions. Users should
+; dimension the output array as small as possible, and re-use the
+; array rather than re-calling DIST_ELLIPSE
+;
+; REVISION HISTORY:
+; Written W. Landsman April, 1991
+; Somewhat faster algorithm August, 1992
+; Allow rectangular output array June, 1994
+; Added /DOUBLE keyword W. Landsman July 2000
+; Make POS_ANG optional, as documented W. Landsman Aug 2015
+;-
+ On_error,2 ;Return to caller
+
+ if N_params() LT 5 then begin
+ print,'Syntax - DIST_ELLIPSE, im, n, xc, yc, ratio, [pos_ang], /DOUBLE'
+ print,' im - output elliptical mask image array'
+ print,' n - size of output image mask, scalar or 2 element vector'
+ print,' xc,yc - coordinates of ellipse center, scalars'
+ print,' ratio - ratio of major to minor axis of ellipse, scalar'
+ print,' pos_ang - position angle, counterclockwise from up'
+ return
+ endif
+ ;Check some parameters
+ if N_elements(ratio) NE 1 then message, $
+ 'ERROR - Axial ratio (fifth parameter) must be a scalar value'
+
+ if N_elements(pos_ang) GT 1 then message, $
+ 'ERROR - Position angle (sixth parameter) must be a scalar value'
+
+ if N_elements(pos_ang) EQ 0 then pos_ang = 0
+ ang = pos_ang /!RADEG ;Convert to radians
+ cosang = cos(ang)
+ sinang = sin(ang)
+
+ if N_elements(N) EQ 2 then begin
+ nx = n[0]
+ ny = n[1]
+ endif else if N_elements(N) EQ 1 then begin
+ ny = n
+ nx = n ;Make a row
+ endif else message, $
+ 'ERROR - Output size parameter N must contain 1 or 2 elements'
+
+ if keyword_set(double) then begin
+ x = dindgen(nx) - xc
+ y = dindgen(ny) - yc
+ im = dblarr(nx, ny, /NOZERO)
+ endif else begin
+ x = findgen( nx ) - xc
+ y = findgen( ny ) - yc
+ im = fltarr( nx, ny, /NOZERO )
+ endelse
+ ;Rotate pixels to match ellipse orientation
+ xcosang = x*cosang
+ xsinang = x*sinang
+
+ for i = 0,ny-1 do begin
+ xtemp = xcosang + y[i]*sinang
+ ytemp = -xsinang + y[i]*cosang
+ im[0,i] = sqrt( (xtemp*ratio)^2 + ytemp^2 )
+ endfor
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/eci2geo.pro b/Code/script_idl_mv/astrolib/eci2geo.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c39625ec71094c4e56ea98062b66e61994afb4d8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/eci2geo.pro
@@ -0,0 +1,81 @@
+;+
+; NAME:
+; ECI2GEO
+;
+; PURPOSE:
+; Convert Earth-centered inertial coordinates to geographic spherical coords
+; EXPLANATION:
+; Converts from ECI (Earth-Centered Inertial) (X,Y,Z) rectangular
+; coordinates to geographic spherical coordinates (latitude, longitude,
+; altitude). JD time is also needed as input.
+;
+; ECI coordinates are in km from Earth center at the supplied time (True of
+; Date). Geographic coordinates are in degrees/degrees/km
+; Geographic coordinates assume the Earth is a perfect sphere, with radius
+; equal to its equatorial radius.
+;
+; CALLING SEQUENCE:
+; gcoord=eci2geo(ECI_XYZ,JDtime)
+;
+; INPUT:
+; ECI_XYZ : the ECI [X,Y,Z] coordinates (in km), can be an array [3,n]
+; of n such coordinates. These should be at the supplied
+; Julian Date (TOD - true of date).
+; JDtime: the Julian Day time, double precision. Can be a 1-D array of n
+; such times.
+;
+; KEYWORD INPUTS:
+; None
+;
+; OUTPUT:
+; a 3-element array of geographic [latitude,longitude,altitude], or an
+; array [3,n] of n such coordinates, double precision
+;
+; COMMON BLOCKS:
+; None
+;
+; PROCEDURES USED:
+; CT2LST - Convert Local Civil Time to Local Mean Sidereal Time
+;
+; EXAMPLE:
+; IDL> gcoord=eci2geo([6378.137+600,0,0], 2452343.38982663D)
+; IDL> print,gcoord
+; 0.0000000 232.27096 600.00000
+;
+; (The above is the geographic direction of the vernal point on
+; 2002/03/09 21:21:21.021, in geographic coordinates. The chosen
+; altitude was 600 km.)
+;
+; gcoord can be further transformed into geodetic coordinates (using
+; geo2geodetic.pro) or into geomagnetic coordinates (using geo2mag.pro)
+;
+; MODIFICATION HISTORY:
+; Written by Pascal Saint-Hilaire (Saint-Hilaire@astro.phys.ethz.ch) on
+; 2001/05/13
+; Modified on 2002/05/13, PSH : vectorization + use of JD times
+; Document use of TOD epoch R. Redmon April 2014 NOAA/NGDC
+;-
+
+;=============================================================================
+FUNCTION eci2geo,ECI_XYZ,JDtim
+
+ Re=6378.137 ; Earth's equatorial radius, in km
+ coord=DOUBLE(ECI_XYZ)
+ JDtime= DOUBLE(JDtim)
+
+ theta=atan(coord[1,*],coord[0,*]) ; azimuth
+ ct2lst,gst,0,0,JDtime
+ angle_sid=gst*2.*!DPI/24. ; sidereal angle
+ lon= (theta - angle_sid ) MOD (2* !DPI) ;longitude
+ r=sqrt(coord[0,*]^2+coord[1,*]^2)
+ lat=atan(coord[2,*],r) ; latitude
+ alt=r/cos(lat) - Re ; altitude
+
+ lat=lat*180./(!DPI) ; to convert from radians into degrees...
+ lon=lon*180./(!DPI)
+ ss=WHERE(lon LT 0.)
+ IF ss[0] NE -1 THEN lon[ss]=lon[ss]+360.
+
+ RETURN,[lat,lon,alt]
+END
+;====================================================================================
diff --git a/Code/script_idl_mv/astrolib/eq2hor.pro b/Code/script_idl_mv/astrolib/eq2hor.pro
new file mode 100644
index 0000000000000000000000000000000000000000..fdb8bf3950c3ea10926ec86c93803967cbc4a2f5
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/eq2hor.pro
@@ -0,0 +1,300 @@
+;+
+; NAME:
+; EQ2HOR
+;
+; PURPOSE:
+; Convert celestial (ra-dec) coords to local horizon coords (alt-az).
+;
+; CALLING SEQUENCE:
+;
+; eq2hor, ra, dec, jd, alt, az, [ha, LAT= , LON= , /WS, OBSNAME= , $
+; /B1950 , PRECESS_= 0, NUTATE_= 0, REFRACT_= 0, $
+; ABERRATION_= 0, ALTITUDE= , /VERBOSE, _EXTRA= ]
+;
+; DESCRIPTION:
+; This code calculates horizon (alt,az) coordinates from equatorial
+; (ra,dec) coords. It is typically accurate to about 1 arcsecond or better (I
+; have checked the output against the publicly available XEPHEM software). It
+; performs precession, nutation, aberration, and refraction corrections. The
+; perhaps best thing about it is that it can take arrays as inputs, in all
+; variables and keywords EXCEPT Lat, lon, and Altitude (the code assumes these
+; aren't changing), and uses vector arithmetic in every calculation except
+; when calculating the precession matrices.
+;
+; INPUT-OUTPUT VARIABLES:
+; RA : Right Ascension of object (J2000) in degrees (FK5); scalar or
+; vector.
+; Dec : Declination of object (J2000) in degrees (FK5), scalar or vector.
+; INPUT VARIABLES:
+; JD : Julian Date [scalar or vector]
+;
+; Note: if RA and DEC are arrays, then alt and az will also be arrays.
+; If RA and DEC are arrays, JD may be a scalar OR an array of the
+; same dimensionality.
+;
+; OPTIONAL INPUT KEYWORDS:
+; lat : north geodetic latitude of location in degrees
+; lon : EAST longitude of location in degrees (Specify west longitude
+; with a negative sign.)
+; /WS : Set this to get the azimuth measured westward from south (not
+; East of North).
+; obsname: Set this to a valid observatory name to be used by the
+; astrolib OBSERVATORY procedure, which will return the latitude
+; and longitude to be used by this program.
+; /B1950 : Set this if your ra and dec are specified in B1950, FK4
+; coordinates (instead of J2000, FK5)
+; precess_ : Set this to 1 to force precession [default], 0 for no
+; precession correction
+; nutate_ : Set this to 1 to force nutation [default], 0 for no nutation.
+; aberration_ : Set this to 1 to force aberration correction [default],
+; 0 for no correction.
+; refract_ : Set to 1 to force refraction correction [default], 0 for no
+; correction.
+; altitude: The altitude of the observing location, in meters. [default=0].
+; verbose: Set this for verbose output. The default is verbose=0.
+; _extra: This is for setting TEMPERATURE or PRESSURE explicitly, which are
+; used by CO_REFRACT to calculate the refraction effect of the
+; atmosphere. If you don't set these, the program will make an
+; intelligent guess as to what they are (taking into account your
+; altitude). See CO_REFRACT for more details.
+;
+; OUTPUT VARIABLES: (all double precision)
+; alt : altitude (in degrees)
+; az : azimuth angle (in degrees, measured EAST from NORTH, but see
+; keyword WS above.)
+; ha : hour angle (in degrees) (optional)
+;
+; DEPENDENCIES:
+; NUTATE, PRECESS, OBSERVATORY, SUNPOS, ADSTRING()
+; CO_NUTATE, CO_ABERRATION, CO_REFRACT, ALTAZ2HADEC, SETDEFAULTVALUE
+;
+; BASIC STEPS
+; Apply refraction correction to find apparent Alt.
+; Calculate Local Mean Sidereal Time
+; Calculate Local Apparent Sidereal Time
+; Do Spherical Trig to find apparent hour angle, declination.
+; Calculate Right Ascension from hour angle and local sidereal time.
+; Nutation Correction to Ra-Dec
+; Aberration correction to Ra-Dec
+; Precess Ra-Dec to current equinox.
+;
+;
+;CORRECTIONS I DO NOT MAKE:
+; * Deflection of Light by the sun due to GR. (typically milliarcseconds,
+; can be arseconds within one degree of the sun)
+; * The Effect of Annual Parallax (typically < 1 arcsecond)
+; * and more (see below)
+;
+; TO DO
+; * Better Refraction Correction. Need to put in wavelength dependence,
+; and integrate through the atmosphere.
+; * Topocentric Parallax Correction (will take into account elevation of
+; the observatory)
+; * Proper Motion (but this will require crazy lookup tables or something).
+; * Difference between UTC and UT1 in determining LAST -- is this
+; important?
+; * Effect of Annual Parallax (is this the same as topocentric Parallax?)
+; * Polar Motion
+; * Better connection to Julian Date Calculator.
+;
+; EXAMPLE
+;
+; Find the position of the open cluster NGC 2264 at the Effelsburg Radio
+; Telescope in Germany, on June 11, 2023, at local time 22:00 (METDST).
+; The inputs will then be:
+;
+; Julian Date = 2460107.250
+; Latitude = 50d 31m 36s
+; Longitude = 06h 51m 18s
+; Altitude = 369 meters
+; RA (J2000) = 06h 40m 58.2s
+; Dec(J2000) = 09d 53m 44.0s
+;
+; IDL> eq2hor, ten(6,40,58.2)*15., ten(9,53,44), 2460107.250d, alt, az, $
+; lat=ten(50,31,36), lon=ten(6,51,18), altitude=369.0, /verb, $
+; pres=980.0, temp=283.0
+;
+; The program produces this output (because the VERBOSE keyword was set)
+;
+;Latitude = +50 31 36.0 Longitude = +06 51 18.0
+; **************************
+;Julian Date = 2460107.250000
+;LMST = +11 46 42.0
+;LAST = +11 46 41.4
+;
+;Ra, Dec: 06 40 58.2 +09 53 44 (J2000)
+;Ra, Dec: 06 42 15.7 +09 52 19 (J2023.4422)
+;Ra, Dec: 06 42 13.8 +09 52 27 (fully corrected)
+;Hour Angle = +05 04 27.6 (hh:mm:ss)
+;Az, El = 17 42 25.6 +16 25 10 (Apparent Coords)
+;Az, El = 17 42 25.6 +16 28 23 (Observer Coords)
+;
+; Compare this with the result from XEPHEM:
+; Az, El = 17h 42m 25.6s +16d 28m 21s
+;
+; This 1.8 arcsecond discrepancy in elevation arises primarily from slight
+; differences in the way I calculate the refraction correction from XEPHEM, and
+; is pretty typical.
+;
+; AUTHOR:
+; Chris O'Dell
+; Assistant Professor of Atmospheric Science
+; Colorado State University
+; Email: odell@atmos.colostate.edu
+;
+; Revision History:
+; August 2012 Use Strict_Extra to flag spurious keywords W. Landsman
+; May 2013 Fix case of scalar JD but vector RA, Dec W. Landsman
+; Jun 2014 Fix case of vector JD but scalar RA, Dec W. Landsman
+;-
+
+pro eq2hor, ra, dec, jd, alt, az, ha, lat=lat, lon=lon, WS=WS, obsname=obsname,$
+ B1950 = B1950, verbose=verbose, precess_=precess_, nutate_=nutate_, $
+ refract_ = refract_, aberration_ = aberration_, $
+ altitude = altitude, _extra= _extra
+
+ On_error,2
+ compile_opt idl2
+
+if N_params() LT 4 then begin
+ print,'Syntax - EQ2HOR, ra, dec, jd, alt, az, [ha, LAT= , LON= , /WS, '
+ print,' OBSNAME= ,/B1950 , PRECESS_= 0, NUTATE_= 0, REFRACT_= 0 '
+ print,' ABERRATION_= 0, ALTITUDE= , /VERBOSE, TEMPERATURE=, ' +$
+ 'PRESSURE = ]'
+ return
+ endif
+
+;*******************************************************************************
+; INITIALIZE STUFF
+
+; If no lat or lng entered, use Pine Bluff Observatory values!
+; (near Madison, Wisconsin, USA)
+; * Feel free to change these to your favorite observatory *
+v = keyword_set(verbose)
+if keyword_set(obsname) then begin
+ ;override lat,lon, altitude if observatory name has been specified
+ observatory, obsname, obs
+ lat = obs.latitude
+ lon = -1*obs.longitude ; minus sign is because OBSERVATORY uses west
+; longitude as positive.
+ altitude = obs.altitude
+endif
+if ~v && ((N_elements(lat) EQ 0 ) || N_elements(lon) Eq 0) then $
+ message,'Using latitude and longitude for Pine Bluff Observatory',/con
+setdefaultvalue, lat, 43.0783d ; (this is the declination of the zenith)
+setdefaultvalue, lon, -89.865d
+setdefaultvalue, altitude, 0. ; [meters]
+
+setdefaultvalue, precess_, 1
+setdefaultvalue, nutate_, 1
+setdefaultvalue, aberration_, 1
+setdefaultvalue, refract_ , 1
+
+
+; conversion factors
+d2r = !dpi/180.
+h2r = !dpi/12.
+h2d = 15.d
+
+npos = N_elements(ra)
+njd = N_elements(jd)
+
+if ~((npos EQ njd) || (npos EQ 1) || (njd EQ 1)) then message,'Error - ' + $
+ 'Either JD or (ra,dec) must be scalars, or have the same # of elements'
+
+if (npos EQ 1) && (njd GT 1) then begin
+ ra_ = replicate(double(ra[0]),njd)
+ dec_ = replicate(double(dec[0]),njd)
+endif else begin
+ ra_ = ra
+ dec_ = dec
+endelse
+
+if keyword_set(B1950) then begin
+ tstart = 1950.0
+ s_now=' (B1950)'
+endif else begin
+ tstart = 2000.0
+ s_now=' (J2000)'
+endelse
+
+;******************************************************************************
+; PRECESS coordinates to current date
+; (uses astro lib procedure PRECESS.pro)
+J_now = (JD - 2451545.)/365.25 + 2000.0 ; compute current equinox
+if precess_ then begin
+ if njd GT 1 then begin
+ for i=0,n_elements(jd)-1 do begin
+ tmpra = ra_[i] & tmpdec = dec_[i]
+ precess, tmpra, tmpdec, tstart, J_now[i], FK4 = keyword_set(B1950)
+ ra_[i] = tmpra & dec_[i] = tmpdec
+ endfor
+ endif else $
+ precess, ra_, dec_, tstart, J_now, FK4 = keyword_set(B1950)
+ endif
+if v then begin
+ rap = ra_
+ decp = dec_
+endif
+;******************************************************************************
+; calculate NUTATION and ABERRATION Corrections to Ra-Dec
+
+co_nutate, jd, ra_, dec_, dra1, ddec1, eps=eps, d_psi=d_psi
+co_aberration, jd, ra_, dec_, dra2, ddec2, eps=eps
+
+; make nutation and aberration corrections
+ra_ += (dra1*nutate_ + dra2*aberration_)/3600.
+dec_ += (ddec1*nutate_ + ddec2*aberration_)/3600.
+
+;**************************************************************************************
+;Calculate LOCAL MEAN SIDEREAL TIME
+ct2lst, lmst, lon, 0, jd ; get LST (in hours) - note:this is independent of
+ ;time zone since giving jd
+lmst = lmst*h2d ; convert LMST to degrees (btw, this is the RA of the zenith)
+; calculate local APPARENT sidereal time
+LAST = lmst + d_psi *cos(eps)/3600. ; add correction in degrees
+
+;******************************************************************************
+; Find hour angle (in DEGREES)
+ha = last - ra_
+w = where(ha LT 0, Nw)
+if Nw GT 0 then ha[w] = ha[w] + 360.
+ha = ha mod 360.
+
+;******************************************************************************
+; Now do the spherical trig to get APPARENT alt,az.
+hadec2altaz, ha, dec_, lat, alt, az, WS=WS
+
+;*******************************************************************************************
+; Make Correction for ATMOSPHERIC REFRACTION
+; (use this for visible and radio wavelengths; author is unsure about other wavelengths.
+; See the comments in CO_REFRACT.pro for more details.)
+if v then alt_app = alt
+if refract_ then alt = $
+ co_refract(alt, altitude=altitude, _strict_extra=_extra, /to_observed)
+if v then begin
+ print, 'Latitude = ', adstring(lat), ' Longitude = ', adstring(lon)
+ for j=0,njd-1 do begin
+ print,' ************************** '
+
+ print, 'Julian Date = ', jd[j], format='(A,f15.6)'
+ print, 'LMST = ', adstring(lmst/15.)
+ print, 'LAST = ', adstring(last/15.)
+ print,' '
+ for i=0,npos-1 do begin
+ print, 'Ra, Dec: ', adstring(ra[i],dec[i]), s_now
+ print, 'Ra, Dec: ', adstring(rap[i],decp[i]), ' (J' + $
+ strcompress(string(J_now),/rem)+')'
+
+ print, 'Ra, Dec: ', adstring(ra_[i],dec_[i]), $
+ ' (fully corrected)'
+ print, 'Hour Angle = ', adstring(ha[i]/15.), ' (hh:mm:ss)'
+
+ print,'Az, El = ', adstring(az[i],alt_app[i]), ' (Apparent Coords)'
+ print,'Az, El = ', adstring(az[i],alt[i]), ' (Observer Coords)'
+ print,' '
+ endfor
+ endfor
+ endif
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/eqpole.pro b/Code/script_idl_mv/astrolib/eqpole.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e81654c69d9b57d69c9b1a289b1050a702c50238
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/eqpole.pro
@@ -0,0 +1,57 @@
+pro eqpole,l,b,x,y,southpole=southpole
+;+
+; NAME:
+; EQPOLE
+; PURPOSE:
+; Convert RA and Dec to X,Y using an equal-area polar projection.
+; EXPLANATION:
+; The output X and Y coordinates are scaled to be between
+; -90 and +90 to go from equator to pole to equator. Output map points
+; can be centered on the north pole or south pole.
+;
+; CALLING SEQUENCE:
+; EQPOLE, L, B, X, Y, [ /SOUTHPOLE ]
+;
+; INPUTS:
+; L - longitude - scalar or vector, in degrees
+; B - latitude - same number of elements as RA, in degrees
+;
+; OUTPUTS:
+; X - X coordinate, same number of elements as RA. X is normalized to
+; be between -90 and 90.
+; Y - Y coordinate, same number of elements as DEC. Y is normalized to
+; be between -90 and 90.
+;
+; KEYWORDS:
+;
+; /SOUTHPOLE - Keyword to indicate that the plot is to be centered
+; on the south pole instead of the north pole.
+;
+; REVISION HISTORY:
+; J. Bloch LANL, SST-9 1.1 5/16/91
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+
+ if N_params() NE 4 then begin
+ print,'Syntax - EQPOLE,L, B, X, Y, [/SOUTHPOLE]'
+ print,' Input longitude L, latitude B in *degrees*'
+ return
+ endif
+
+ if keyword_set(southpole) then begin
+ l1 = double(-l/!RADEG)
+ b1 = double(-b/!RADEG)
+ endif else begin
+ l1 = double(l/!RADEG)
+ b1 = double(b/!RADEG)
+ endelse
+
+ sq = 2.0d0*(1.0d0 - sin(double(b1)))
+ chk = where(sq lt 0.0d0)
+ if chk[0] ge 0 then sq[chk] = 0.0d0
+ r = 18.0d0*3.53553391d0*sqrt(sq)
+ y =r*cos(l1)
+ x =r*sin(l1)
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/eqpole_grid.pro b/Code/script_idl_mv/astrolib/eqpole_grid.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f400d174ff3f2f986edb76e9dc4c2c8d2ce141b5
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/eqpole_grid.pro
@@ -0,0 +1,147 @@
+;+
+; NAME:
+; EQPOLE_GRID
+;
+; PURPOSE:
+; Produce an equal area polar projection grid overlay
+; EXPLANATION:
+; Grid is written on the current graphics device using the equal area
+; polar projection. EQPOLE_GRID assumes that the output plot
+; coordinates span the x and y ranges of -90 to 90 for a region that
+; covers the equator to the chosen pole. The grid is assumed to go from
+; the equator to the chosen pole.
+;
+; CALLING SEQUENCE:
+;
+; EQPOLE_GRID[,DLONG,DLAT,[/SOUTHPOLE, LABEL = , /NEW, _EXTRA=]
+;
+; INPUTS:
+;
+; DLONG = Optional input longitude line spacing in degrees. If left
+; out, defaults to 30.
+; DLAT = Optional input lattitude line spacing in degrees. If left
+; out, defaults to 30.
+;
+; INPUT KEYWORDS:
+;
+; /SOUTHPOLE = Optional flag indicating that the output plot is
+; to be centered on the south rather than the north
+; pole.
+; LABEL = Optional flag for creating labels on the output
+; grid on the prime meridian and the equator for
+; lattitude and longitude lines. If set =2, then
+; the longitude lines are labeled in hours and minutes.
+; CHARSIZE = If /LABEL is set, then CHARSIZE specifies the size
+; of the label characters (passed to XYOUTS)
+; CHARTHICK = If /LABEL is set, then CHARTHICK specifies the
+; thickness of the label characters (passed to XYOUTS)
+; /NEW = If this keyword is set, then EQPOLE_GRID will create
+; a new plot, rather than overlay an existing plot.
+;
+; Any valid keyword to OPLOT such as COLOR, LINESTYLE, THICK can be
+; passed to AITOFF_GRID (though the _EXTRA facility) to to specify the
+; color, style, or thickness of the grid lines.
+; OUTPUTS:
+; Draws grid lines on current graphics device.
+;
+; EXAMPLE:
+; Create a labeled equal area projection grid of the Galaxy, centered on
+; the South pole, and overlay stars at specified Galactic longitudes,
+; glong and latitudes, glat
+;
+; IDL> eqpole_grid,/label,/new,/south ;Create labeled grid
+; IDL> eqpole, glong, glat, x,y ;Convert to X,Y coordinates
+; IDL> plots,x,y,psym=2 ;Overplot "star" positions.
+;
+;
+; COPYRIGHT NOTICE:
+;
+; Copyright 1992, The Regents of the University of California. This
+; software was produced under U.S. Government contract (W-7405-ENG-36)
+; by Los Alamos National Laboratory, which is operated by the
+; University of California for the U.S. Department of Energy.
+; The U.S. Government is licensed to use, reproduce, and distribute
+; this software. Neither the Government nor the University makes
+; any warranty, express or implied, or assumes any liability or
+; responsibility for the use of this software.
+;
+; AUTHOR AND MODIFICATIONS:
+;
+; J. Bloch 1.4 10/28/92
+; Converted to IDL V5.0 W. Landsman September 1997
+; Create default plotting coords, if needed W. Landsman August 2000
+; Added _EXTRA, CHARTHICK, CHARSIZE keywords W. Landsman March 2001
+;-
+PRO EQPOLE_GRID,DLONG,DLAT,_EXTRA=E,LABELS=LABEL,SOUTHPOLE=SOUTHPOLE,NEW=NEW, $
+ CHARSIZE = charsize, CHARTHICK =charthick
+
+ if n_params() lt 2 then dlong = 30.0
+ if n_params() lt 1 then dlat = 30.0
+
+
+; If no plotting axis has been defined, then create a default one
+
+ new = keyword_set(new)
+ if not new then new = (!X.crange[0] EQ 0) and (!X.crange[1] EQ 0)
+ if new then plot,[-130,130],[-130,130],/nodata,xsty=5,ysty=5
+
+;
+; Do lines of constant longitude
+;
+ lat=90.0-findgen(180)
+ if keyword_set(southpole) then lat = -lat
+ lng=fltarr(180)
+ lngtot = long(360.0/dlong)
+ for i=0,lngtot do begin
+ lng[*]=-180.0+(i*dlong)
+ eqpole,lng,lat,x,y,southpole=southpole
+ oplot,x,y,_EXTRA=e
+ endfor
+;
+; Do lines of constant latitude
+;
+ lng=findgen(360)
+ lat=fltarr(360)
+ lattot=long(180.0/dlat)
+ for i=1,lattot do begin
+ if not keyword_set(southpole) then lat[*]=90.0-(i*dlat) $
+ else lat[*]=-90.0+(i*dlat)
+ eqpole,lng,lat,x,y,southpole=southpole
+ oplot,x,y,_EXTRA=e
+ endfor
+;
+; Do labeling if requested
+;
+ if keyword_set(label) then begin
+;
+; Label equator
+;
+ for i=0,lngtot-1 do begin
+ lng = (i*dlong)
+ eqpole,lng,0.0,x,y,southpole=southpole
+ if label eq 1 then xyouts,x[0],y[0],noclip=0,$
+ charsize = charsize, charthick = charthick, $
+ strcompress(string(lng,format="(I4)"),/remove_all) $
+ else begin
+ tmp=sixty(lng*24.0/360.0)
+ xyouts,x[0],y[0],noclip=0,$
+ charsize = charsize, charthick = charthick, $
+ strcompress(string(tmp[0],tmp[1],$
+ format='(I2,"h",I2,"m")'),/remove_all),alignment=0.5
+ endelse
+ endfor
+;
+; Label prime meridian
+;
+ for i=1,lattot-1 do begin
+ if not keyword_set(southpole) then $
+ lat=90-(i*dlat) else lat=-90+(i*dlat)
+ eqpole,0.0,lat,x,y,southpole=southpole
+ xyouts,x[0],y[0],noclip=0,$
+ charsize = charsize, charthick = charthick, $
+ strcompress(string(lat,format="(I4)"),/remove_all)
+ endfor
+ endif
+ return
+end
+
diff --git a/Code/script_idl_mv/astrolib/euler.pro b/Code/script_idl_mv/astrolib/euler.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9ab363d05f68a10db833ab1bf7f0a4db46340a1c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/euler.pro
@@ -0,0 +1,169 @@
+PRO EULER,AI,BI,AO,BO,SELECT, FK4 = FK4, SELECT = select1, RADIAN=radian
+;+
+; NAME:
+; EULER
+; PURPOSE:
+; Transform between Galactic, celestial, and ecliptic coordinates.
+; EXPLANATION:
+; Use the procedure ASTRO to use this routine interactively
+;
+; CALLING SEQUENCE:
+; EULER, AI, BI, AO, BO, [ SELECT, /FK4, /RADIAN, SELECT = ]
+;
+; INPUTS:
+; AI - Input Longitude, scalar or vector. In DEGREES unless /RADIAN
+; is set. If only two parameters are supplied, then AI and BI
+; will be modified to contain the output longitude and latitude.
+; BI - Input Latitude in DEGREES
+;
+; OPTIONAL INPUT:
+; SELECT - Integer (1-6) specifying type of coordinate transformation.
+;
+; SELECT From To | SELECT From To
+; 1 RA-Dec (2000) Galactic | 4 Ecliptic RA-Dec
+; 2 Galactic RA-DEC | 5 Ecliptic Galactic
+; 3 RA-Dec Ecliptic | 6 Galactic Ecliptic
+;
+; If not supplied as a parameter or keyword, then EULER will prompt for
+; the value of SELECT
+; Celestial coordinates (RA, Dec) should be given in equinox J2000
+; unless the /FK4 keyword is set.
+; OUTPUTS:
+; AO - Output Longitude in DEGREES, always double precision
+; BO - Output Latitude in DEGREES, always double precision
+;
+; OPTIONAL INPUT KEYWORD:
+; /FK4 - If this keyword is set and non-zero, then input and output
+; celestial and ecliptic coordinates should be given in equinox
+; B1950.
+; /RADIAN - if set, then all input and output angles are in radians rather
+; than degrees.
+; SELECT - The coordinate conversion integer (1-6) may alternatively be
+; specified as a keyword
+; EXAMPLE:
+; Find the Galactic coordinates of Cyg X-1 (ra=299.590315, dec=35.201604)
+; IDL> ra = 299.590315d
+; IDL> dec = 35.201604d
+; IDL> euler,ra,dec,glong,glat,1 & print,glong,glat
+; 71.334990, 3.0668335
+; REVISION HISTORY:
+; Written W. Landsman, February 1987
+; Adapted from Fortran by Daryl Yentis NRL
+; Made J2000 the default, added /FK4 keyword W. Landsman December 1998
+; Add option to specify SELECT as a keyword W. Landsman March 2003
+; Use less virtual memory for large input arrays W. Landsman June 2008
+; Added /RADIAN input keyword W. Landsman Sep 2008
+;-
+ On_error,2
+ compile_opt idl2
+
+ npar = N_params()
+ if npar LT 2 then begin
+ print,'Syntax - EULER, AI, BI, A0, B0, [ SELECT, /FK4, /RADIAN, SELECT= ]'
+ print,' AI,BI - Input longitude,latitude in degrees'
+ print,' AO,BO - Output longitude, latitude in degrees'
+ print,' SELECT - Scalar (1-6) specifying transformation type'
+ return
+ endif
+
+ twopi = 2.0d*!DPI
+ fourpi = 4.0d*!DPI
+ rad_to_deg = 180.0d/!DPI
+
+; J2000 coordinate conversions are based on the following constants
+; (see the Hipparcos explanatory supplement).
+; eps = 23.4392911111d Obliquity of the ecliptic
+; alphaG = 192.85948d Right Ascension of Galactic North Pole
+; deltaG = 27.12825d Declination of Galactic North Pole
+; lomega = 32.93192d Galactic longitude of celestial equator
+; alphaE = 180.02322d Ecliptic longitude of Galactic North Pole
+; deltaE = 29.811438523d Ecliptic latitude of Galactic North Pole
+; Eomega = 6.3839743d Galactic longitude of ecliptic equator
+
+ if keyword_set(FK4) then begin
+
+ equinox = '(B1950)'
+ psi = [ 0.57595865315D, 4.9261918136D, $
+ 0.00000000000D, 0.0000000000D, $
+ 0.11129056012D, 4.7005372834D]
+ stheta =[ 0.88781538514D,-0.88781538514D, $
+ 0.39788119938D,-0.39788119938D, $
+ 0.86766174755D,-0.86766174755D]
+ ctheta =[ 0.46019978478D, 0.46019978478D, $
+ 0.91743694670D, 0.91743694670D, $
+ 0.49715499774D, 0.49715499774D]
+ phi = [ 4.9261918136D, 0.57595865315D, $
+ 0.0000000000D, 0.00000000000D, $
+ 4.7005372834d, 0.11129056012d]
+
+
+ endif else begin
+
+ equinox = '(J2000)'
+ psi = [ 0.57477043300D, 4.9368292465D, $
+ 0.00000000000D, 0.0000000000D, $
+ 0.11142137093D, 4.71279419371D]
+ stheta =[ 0.88998808748D,-0.88998808748D, $
+ 0.39777715593D,-0.39777715593D, $
+ 0.86766622025D,-0.86766622025D]
+ ctheta =[ 0.45598377618D, 0.45598377618D, $
+ 0.91748206207D, 0.91748206207D, $
+ 0.49714719172D, 0.49714719172D]
+ phi = [ 4.9368292465D, 0.57477043300D, $
+ 0.0000000000D, 0.00000000000D, $
+ 4.71279419371d, 0.11142137093d]
+
+ endelse
+;
+ if N_elements(select) EQ 0 then $
+ if N_elements(select1) EQ 1 then select=select1
+ if N_elements(select) EQ 0 then begin
+ print,' '
+ print,' 1 RA-DEC ' + equinox + ' to Galactic'
+ print,' 2 Galactic to RA-DEC' + equinox
+ print,' 3 RA-DEC ' + equinox + ' to Ecliptic'
+ print,' 4 Ecliptic to RA-DEC' + equinox
+ print,' 5 Ecliptic to Galactic'
+ print,' 6 Galactic to Ecliptic'
+;
+ select = 0
+ read,'Enter selection: ',select
+ endif
+
+ I = select - 1 ; IDL offset
+ if npar EQ 2 then begin
+
+ if keyword_set(radian) then begin
+ ao = temporary(ai) - phi[i]
+ bo = temporary(bi)
+ endif else begin
+ ao = temporary(ai)/rad_to_deg - phi[i]
+ bo = temporary(bi)/rad_to_deg
+ endelse
+
+ endif else begin
+ if keyword_set(radian) then begin
+ ao = ai - phi[i]
+ bo = bi
+ endif else begin
+ ao = ai/rad_to_deg - phi[i]
+ bo = bi/rad_to_deg
+ endelse
+ endelse
+ sb = sin(bo) & cb = cos(bo)
+ cbsa = cb * sin(ao)
+ bo = -stheta[i] * cbsa + ctheta[i] * sb
+ bo = asin(bo<1.0d)
+ if ~keyword_set(radian) then bo = bo*rad_to_deg
+;
+ ao = atan( ctheta[i] * cbsa + stheta[i] * sb, cb * cos(ao) )
+ ao = ( (ao+psi[i]+fourpi) mod twopi)
+ if ~keyword_set(radian) then ao = ao*rad_to_deg
+
+
+ if ( npar EQ 2 ) then begin
+ ai = temporary(ao) & bi=temporary(bo)
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/expand_tilde.pro b/Code/script_idl_mv/astrolib/expand_tilde.pro
new file mode 100644
index 0000000000000000000000000000000000000000..728bee66f14969344ec25ddfb93e0e5a8bf1eed7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/expand_tilde.pro
@@ -0,0 +1,67 @@
+;+
+; NAME:
+; EXPAND_TILDE()
+;
+; PURPOSE:
+; Expand tilde in UNIX directory names
+;
+; CALLING SEQUENCE:
+; IDL> output=expand_tilde(input)
+;
+; INPUTS:
+; INPUT = input file or directory name, scalar string
+;
+; OUTPUT:
+; Returns expanded filename, scalar string
+;
+; EXAMPLES:
+; output=expand_tilde('~zarro/test.doc')
+; ---> output='/usr/users/zarro'
+;
+; NOTES:
+; This version of EXPAND_TILDE differs from the version in the Solar
+; Library in that it does not call the functions EXIST and IDL_RELEASE.
+; However, it should work identically.
+; PROCEDURE CALLS:
+; None.
+; REVISION HISTORY:
+; Version 1, 17-Feb-1997, D M Zarro. Written
+; Transfered from Solar Library W. Landsman Sep. 1997
+; Made more robust D. Zarro/W. Landsman Sep. 2000
+; Made even more robust (since things like ~zarro weren't being expanded)
+; Zarro (EITI/GSFC, Mar 2001)
+;-
+
+ function expand_tilde,name
+ if N_elements(name) EQ 0 then return,''
+ if size(name,/TNAME) ne 'STRING' then return,name
+ tpos=strpos(name,'~')
+ if tpos eq -1 then return,name
+ apos = strpos(name,'~/')
+ bpos = strpos(name,'/~')
+
+ tilde=name
+ if apos GT -1 then begin
+ tilde = strmid(name,0,apos+1)
+ post = strmid(name,apos+1,strlen(name))
+ endif else begin
+ if bpos gt -1 then begin
+ pre = strmid(name,0,bpos+1)
+ tilde = strmid(name,bpos+1,strlen(name))
+ endif
+ endelse
+
+ error=0
+ catch,error
+ if error ne 0 then begin
+ catch,/cancel
+ return,name
+ endif
+
+ cd,tilde,curr=curr
+ cd,curr,curr=dcurr
+ tname = dcurr
+ if N_elements(pre) GT 0 then tname = pre+tname else $
+ if N_elements(post) GT 0 then tname = tname + post
+
+ return,tname & end
diff --git a/Code/script_idl_mv/astrolib/extast.pro b/Code/script_idl_mv/astrolib/extast.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b6ba118f9c58fc27087d6195dd7513fa6f0faf44
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/extast.pro
@@ -0,0 +1,714 @@
+pro extast,hdr,astr,noparams, alt=alt
+;+
+; NAME:
+; EXTAST
+; PURPOSE:
+; Extract ASTrometry parameters from a FITS image header.
+; EXPLANATION:
+; Extract World Coordinate System information
+; ( http://fits.gsfc.nasa.gov/fits_wcs.html ) from a FITS header and
+; place it into an IDL structure.
+;
+; CALLING SEQUENCE:
+; EXTAST, hdr, astr, [ noparams, ALT= ]
+;
+; INPUT:
+; HDR - variable containing the FITS header (string array)
+;
+; OUTPUTS:
+; In the following, index 1 & 2 refer to the first and second astrometry
+; axes respectively. The actual axis numbers are stored in .AXIS
+;
+; ASTR - Anonymous structure containing astrometry info from the FITS
+; header ASTR always contains the following tags (even though
+; some projections do not require all the parameters)
+; .NAXIS - 2 element array giving image size
+; .CD - 2 x 2 array containing the astrometry parameters CD1_1 CD1_2
+; in DEGREES/PIXEL CD2_1 CD2_2
+; .CDELT - 2 element double vector giving physical increment at the
+; reference pixel
+; .CRPIX - 2 element double vector giving X and Y coordinates of reference
+; pixel (def = NAXIS/2) in FITS convention (first pixel is 1,1)
+; .CRVAL - 2 element double precision vector giving R.A. and DEC of
+; reference pixel in DEGREES
+; .CTYPE - 2 element string vector giving projection types, default
+; ['RA---TAN','DEC--TAN']
+; .LONGPOLE - scalar giving native longitude of the celestial pole
+; (default = 180 for zenithal projections)
+; .LATPOLE - scalar giving native latitude of the celestial pole default=0)
+; .PV2 - Vector of projection parameters associated with latitude axis
+; PV2 will have up to 21 elements for the ZPN projection, up to 3
+; for the SIN projection and no more than 2 for any other
+; projection
+;
+; Fields added for version 2:
+; .PV1 - Vector of projection parameters associated with longitude axis
+; .AXES - 2 element integer vector giving the FITS-convention axis
+; numbers associated with astrometry, in ascending order.
+; Default [1,2].
+; .REVERSE - byte, true if first astrometry axis is Dec/latitude
+; .COORD_SYS - 1 or 2 character code giving coordinate system, including
+; 'C' = RA/Dec, 'G' = Galactic, 'E' = Ecliptic, 'X' = unknown.
+; .PROJECTION - 3-letter WCS projection code
+; .KNOWN - true if IDL WCS routines recognise this projection
+; .RADECSYS - String giving RA/Dec system e.g. 'FK4', 'ICRS' etc.
+; .EQUINOX - Double giving the epoch of the mean equator and equinox
+; .DATEOBS - Text string giving (start) date/time of observations
+; .MJDOBS - Modified julian date of start of observations.
+; .X0Y0 - Implied offset in intermediate world coordinates (x,y)
+; if a non-standard fiducial point is set via PV1 and also
+; PV1_0a =/ 0, indicating that an offset should be
+; applied to place CRVAL at the (x,y) origin.
+; Should be *added* to the IWC derived from application of
+; CRPIX, CDELT, CD to the pixel coordinates.
+;
+; .DISTORT - optional substructure specifying any distortion parameters
+; currently implement only for "SIP" (Spitzer Imaging
+; Polynomial), "TPV" (tangent PV* polynomial) distortion
+; parameters, and "TNX" (tangent plus iraf distortion)
+;
+; NOPARAMS - Scalar indicating the results of EXTAST
+; -1 = Failure - Header missing astrometry parameters
+; 1 = Success - Header contains CROTA + CDELT (AIPS-type) astrometry
+; 2 = Success - Header contains CDn_m astrometry, rec.
+; 3 = Success - Header contains PCn_m + CDELT astrometry.
+; 4 = Success - Header contains ST Guide Star Survey astrometry
+; (see gsssextast.pro )
+; OPTIONAL INPUT/OUTPUT KEYWORDS:
+; ALT - single character 'A' through 'Z' or ' ' specifying an alternate
+; astrometry system present in the FITS header. The default is
+; to use the primary astrometry or ALT = ' '. If /ALT is set,
+; then this is equivalent to ALT = 'A'. See Section 3.3 of
+; Greisen & Calabretta (2002, A&A, 395, 1061) for information about
+; alternate astrometry keywords. If not set on input, then
+; ALT is set to ' ' on output.
+; PROCEDURE:
+; EXTAST checks for astrometry parameters in the following order:
+;
+; (1) the CD matrix PC1_1,PC1_2...plus CDELT*, CRPIX and CRVAL
+; (2) the CD matrix CD1_1,CD1_2... plus CRPIX and CRVAL.
+; (3) CROTA2 (or CROTA1) and CDELT plus CRPIX and CRVAL.
+;
+; All three forms are valid FITS according to the paper "Representations
+; of World Coordinates in FITS by Greisen and Calabretta (2002, A&A, 395,
+; 1061 http://fits.gsfc.nasa.gov/fits_wcs.html ) although form (1) is
+; preferred.
+;
+; NOTES:
+; 1. An anonymous structure is created to avoid structure definition
+; conflicts. This is needed because some projection systems
+; require additional dimensions (i.e. spherical cube
+; projections require a specification of the cube face).
+;
+; 2, FITS headers created by SCAMP
+; (http://www.astromatic.net/software/scamp) contain a tangent
+; projection with distortion polynomial coefficients in the PV[1|2]_?
+; keywords. These will be flagged as being a TPV projection
+; (http://fits.gsfc.nasa.gov/registry/tpvwcs.html) in the
+; astr.projection keyword.
+;
+; PROCEDURES CALLED:
+; GSSSEXTAST, ZPARCHECK
+; REVISION HISTORY
+; Written by B. Boothman 4/15/86
+; Accept CD001001 keywords 1-3-88
+; Accept CD1_1, CD2_1... keywords W. Landsman Nov. 92
+; Recognize GSSS FITS header W. Landsman June 94
+; Get correct sign, when converting CDELT* to CD matrix for right-handed
+; coordinate system W. Landsman November 1998
+; Consistent conversion between CROTA and CD matrix October 2000
+; CTYPE = 'PIXEL' means no astrometry params W. Landsman January 2001
+; Don't choke if only 1 CTYPE value given W. Landsman August 2001
+; Recognize PC00n00m keywords again (sigh...) W. Landsman December 2001
+; Recognize GSSS in ctype also D. Finkbeiner Jan 2002
+; Introduce ALT keyword W. Landsman June 2003
+; Fix error introduced June 2003 where free-format values would be
+; truncated if more than 20 characters. W. Landsman Aug 2003
+; Further fix to free-format values -- slash need not be present Sep 2003
+; Default value of LATPOLE is 90.0 W. Landsman February 2004
+; Allow for distortion substructure, currently implemented only for
+; SIP (Spitzer Imaging Polynomial) W. Landsman February 2004
+; Correct LONGPOLE computation if CTYPE = ['*DEC','*RA'] W. L. Feb. 2004
+; Assume since V5.3 (vector STRMID) W. Landsman Feb 2004
+; Yet another fix to free-format values W. Landsman April 2004
+; Introduce PV2 tag to replace PROJP1, PROJP2.. etc. W. Landsman May 2004
+; Convert NCP projection to generalized SIN W. Landsman Aug 2004
+; Add NAXIS tag to output structure W. Landsman Jan 2007
+; .CRPIX tag now Double instead of Float W. Landsman Apr 2007
+; If duplicate keywords use the *last* value W. Landsman Aug 2008
+; Fix typo for AZP projection, nonzero longpole N. Cunningham Feb 2009
+; Give warning if reverse SIP coefficient not present W. Landsman Nov 2011
+; Allow obsolete CD matrix representations W. Landsman May 2012
+; Work for Paritel headers with extra quotes R. Gutermuth/WL April 2013
+;
+; Version 2: J. P. Leahy, July 2013
+; - Support long & lat axes not being the first 2.
+; - Implemented PV1 and hence non-default phi0 and theta0
+; - Added AXES, REVERSE, COORD_SYS, PROJECTION, RADECSYS, EQUINOX,
+; DATEOBS, MJDOBS, PV1, and X0Y0 tags to the structure.
+; - More checks for inconsistencies in the keywords.
+; v2.1 21/7/13 Missing mjdobs & equinox changed to NaN (was -1 & 0);
+; Converts GLS to SFL if possible; added KNOWN tag.
+; v2.2 21/9/13 GLS conversion fixed.
+; v2.3 1 Dec 13 Add warning if distortions from SCAMP astrometry present
+; v2.4. Extract SCAMP or TPV distortion astrometry, if present Jan 2014
+; v2.5 Fix bug when SIP parameters not recognized when NAXIS=0 May 2014
+; v2.5.1 Make sure CROTA defined for GLS projection WL Sep 2015
+;-
+ On_error, 0
+ compile_opt idl2
+ ;
+ ; List of known map types copied from wcsxy2sph. Needs to be kept up
+ ; to date!
+ ;
+ map_types=['DEF','AZP','TAN','SIN','STG','ARC','ZPN','ZEA','AIR','CYP',$
+ 'CAR','MER','CEA','COP','COD','COE','COO','BON','PCO','SFL',$
+ 'PAR','AIT','MOL','CSC','QSC','TSC','SZP','HPX','HCT','XPH']
+
+ if ( N_params() LT 2 ) then begin
+ print,'Syntax - EXTAST, hdr, astr, [ noparams, ALT = ]'
+ return
+ endif
+
+ proj0 = ['CYP','CEA','CAR','MER','SFL','PAR','MOL','AIT','BON','PCO', $
+ 'TSC','CSC','QSC']
+ radeg = 180.0D0/!DPI
+ keyword = STRUPCASE(strtrim(strmid( hdr, 0, 8), 2))
+
+; Extract values from the FITS header. This is either up to the first slash
+; (free format) or first space
+
+ space = strpos( hdr, ' ', 10) + 1
+ slash = strpos( hdr, '/', 10) > space
+
+ N = N_elements(hdr)
+ len = (slash -10) > 20
+ len = reform(len,1,N)
+ lvalue = strtrim(strmid(hdr, 10, len),2)
+ remchar,lvalue,"'"
+ zparcheck,'EXTAST',hdr,1,7,1,'FITS image header' ;Make sure valid header
+ noparams = -1 ;Assume no astrometry to start
+
+ if N_elements(alt) EQ 0 then begin
+ alt = '' & altstr = ''
+ endif else BEGIN
+ if (alt EQ '1') then alt = 'A' else alt = strupcase(alt)
+ altstr = ' for alternate system '+alt
+ ENDELSE
+
+ ; Search for astrometric axes:
+ test = STREGEX(keyword,'^CTYPE[1-9][0-9]{0,2}'+alt+'$', LENGTH = ctlen)
+ typ = WHERE(test GE 0, ntyp)
+ lon = -1 & lat = -1
+ lon_form = -1 & lat_form = -1
+
+ IF ntyp GT 0 THEN BEGIN
+ ctlen = ctlen[typ] - STRLEN('CTYPE'+alt) ; gives # digits in axis number
+
+ lon0 = WHERE(STRMID(lvalue[typ],0,5) EQ 'RA---')
+ lon1 = WHERE(STRMID(lvalue[typ],1,4) EQ 'LON-')
+ lon2 = WHERE(STRMID(lvalue[typ],2,4) EQ 'LN-')
+ lon = [lon0, lon1, lon2]
+ form = [REPLICATE(0,N_ELEMENTS(lon0)),REPLICATE(1,N_ELEMENTS(lon1)), $
+ REPLICATE(2,N_ELEMENTS(lon2))]
+ good = WHERE(lon GT 0, ngood)
+ IF ngood GT 1 THEN MESSAGE, /INFORMATIONAL, $
+ 'Multiple longitude axes'+altstr+': Using last.'
+ lon = MAX(lon, subs)
+ lon_form = lon GE 0 ? form[subs] : -1
+
+ lat0 = WHERE(STRMID(lvalue[typ],0,5) EQ 'DEC--')
+ lat1 = WHERE(STRMID(lvalue[typ],1,4) EQ 'LAT-')
+ lat2 = WHERE(STRMID(lvalue[typ],2,4) EQ 'LT-')
+ lat = [lat0, lat1, lat2]
+ form = [REPLICATE(0,N_ELEMENTS(lat0)),REPLICATE(1,N_ELEMENTS(lat1)), $
+ REPLICATE(2,N_ELEMENTS(lat2))]
+ good = WHERE(lat GT 0, ngood)
+ IF ngood GT 1 THEN MESSAGE, /INFORMATIONAL, $
+ 'Multiple latitude axes'+altstr+': Using last.'
+ lat = MAX(lat,subs)
+ lat_form = lat GE 0 ? form[subs] : -1
+ ENDIF
+
+;
+; Longitude axis data is initially stored in element 0 and latitude
+; axis data in element 1 of the various arrays. For backwards compatibility,
+; if latitude has a lower axis number in the FITS header, they will be swapped
+; into the (latitude, longitude) order in the final structure, and the .REVERSE
+; field will be set to true (ie. 1B).
+;
+ lonc = lon GE 0 ? STRMID(keyword[typ[lon]],5,ctlen[lon]) : '1'
+ latc = lat GE 0 ? STRMID(keyword[typ[lat]],5,ctlen[lat]) : '2'
+
+ ctype = ['','']
+ l = where(keyword EQ 'CTYPE'+lonc+alt, N_ctype1)
+ if N_ctype1 GT 0 then ctype[0] = lvalue[l[N_ctype1-1]]
+ l = where(keyword EQ 'CTYPE'+latc+alt, N_ctype2)
+ if N_ctype2 GT 0 then ctype[1] = lvalue[l[N_ctype2-1]]
+ ctype = strtrim(ctype,2)
+
+ badco = lon_form NE lat_form
+ CASE lon_form OF
+ -1: coord = 'X' ; unknown type of coordinate
+ 0: coord = 'C' ; celestial coords, i.e. RA/Dec
+ 1: BEGIN ; longitude format is xLON where x = G, E, etc.
+ coord = STRMID(ctype[0],0,1)
+ badco = badco || coord NE STRMID(ctype[1],0,1)
+ END
+ 2: BEGIN ; longitude format is yzLN
+ coord = STRMID(ctype[0],0,2)
+ badco = badco || coord NE STRMID(ctype[2],0,2)
+ END
+ ELSE: MESSAGE, 'Internal error: unexpected lon_form'
+ ENDCASE
+
+ naxis = lonarr(2)
+ l = where(keyword EQ 'NAXIS'+lonc, N_axis1)
+ if N_axis1 GT 0 then naxis[0] = lvalue[l[N_axis1-1]]
+ l = where(keyword EQ 'NAXIS'+latc, N_axis2)
+ if N_axis2 GT 0 then naxis[1] = lvalue[l[N_axis2-1]]
+
+ tpv = strmid(ctype[0],2,3,/reverse) EQ 'TPV'
+ tnx = strmid(ctype[0],2,3,/reverse) EQ 'TNX'
+
+ IF (TPV || tnx) THEN BEGIN
+ proj = 'TAN'
+ ENDIF ELSE BEGIN
+ proj = STRMID(ctype[0], 5, 3)
+
+ badco = badco || proj NE STRMID(ctype[1], 5, 3)
+ IF badco THEN BEGIN
+ MESSAGE, 'ERROR' + altstr + $
+ ': longitude and latitude coordinate types must match:', /CONTINUE
+ MESSAGE, 'Coords were CTYPE'+lonc+alt+': ' + ctype[0] + $
+ '; CTYPE'+latc+alt+': ' + ctype[1]
+ ENDIF
+
+; If the standard CTYPE* astrometry keywords not found, then check if the
+; ST guidestar astrometry is present
+
+ check_gsss = (N_ctype1 EQ 0)
+ if N_ctype1 GE 1 then check_gsss = (strmid(ctype[0], 5, 3) EQ 'GSS')
+
+ if check_gsss then begin
+
+ l = where(keyword EQ 'PPO1'+alt, N_ppo1)
+ if N_ppo1 EQ 1 then begin
+ gsssextast, hdr, astr, gsssparams
+ if gsssparams EQ 0 then noparams = 4
+ return
+ endif
+ ctype = ['RA---TAN','DEC--TAN']
+ endif
+
+ if (ctype[0] EQ 'PIXEL') then return
+ if N_ctype2 EQ 1 then if (ctype[1] EQ 'PIXEL') then return
+ ENDELSE
+
+ crval = dblarr(2)
+
+ l = where(keyword EQ 'CRVAL'+lonc+alt, N_crval1)
+ if N_crval1 GT 0 then crval[0] = lvalue[l[N_crval1-1]]
+ l = where(keyword EQ 'CRVAL'+latc+alt, N_crval2)
+ if N_crval2 GT 0 then crval[1] = lvalue[l[N_crval2-1]]
+ if (N_crval1 EQ 0) || (N_crval2 EQ 0) then return
+
+ crpix = dblarr(2)
+ l = where(keyword EQ 'CRPIX'+lonc+alt, N_crpix1)
+ if N_crpix1 GT 0 then crpix[0] = lvalue[l[N_crpix1-1]]
+ l = where(keyword EQ 'CRPIX'+latc+alt, N_crpix2)
+ if N_crpix2 GT 0 then crpix[1] = lvalue[l[N_crpix2-1]]
+ if (N_crpix1 EQ 0) || (N_crpix2 EQ 0) then return
+
+
+ cd = dblarr(2,2)
+ cdelt = [1.0d,1.0d]
+
+GET_CD_MATRIX:
+
+ l = where(keyword EQ 'PC'+lonc+'_'+lonc + alt, N_pc11)
+ if N_PC11 GT 0 then begin
+ cd[0,0] = lvalue[l]
+ l = where(keyword EQ 'PC'+lonc+'_'+latc + alt, N_pc12)
+ if N_pc12 GT 0 then cd[0,1] = lvalue[l[N_pc12-1]]
+ l = where(keyword EQ 'PC'+latc+'_'+lonc + alt, N_pc21)
+ if N_pc21 GT 0 then cd[1,0] = lvalue[l[N_pc21-1]]
+ l = where(keyword EQ 'PC'+latc+'_'+latc + alt, N_pc22)
+ if N_pc22 GT 0 then cd[1,1] = lvalue[l[N_pc22-1]]
+ l = where(keyword EQ 'CDELT'+lonc+ alt, N_cdelt1)
+ if N_cdelt1 GT 0 then cdelt[0] = lvalue[l[N_cdelt1-1]]
+ l = where(keyword EQ 'CDELT'+latc+ alt, N_cdelt2)
+ if N_cdelt2 GT 0 then cdelt[1] = lvalue[l[N_cdelt2-1]]
+ det = cd[0,0]*cd[1,1] - cd[0,1]*cd[1,0]
+ if det LT 0 then sgn = -1 else sgn = 1
+ crota = atan( sgn*cd[0,1], sgn*cd[0,0] )
+ noparams = 3
+ endif else begin
+
+ l = where(keyword EQ 'CD'+lonc+'_'+lonc + alt, N_cd11)
+ if N_CD11 GT 0 then begin ;If CD parameters don't exist, try CROTA
+ cd[0,0] = strtrim(lvalue[l[N_cd11-1]],2)
+ l = where(keyword EQ 'CD'+lonc+'_'+latc + alt, N_cd12)
+ if N_cd12 GT 0 then cd[0,1] = lvalue[l[N_cd12-1]]
+ l = where(keyword EQ 'CD'+latc+'_'+lonc + alt, N_cd21)
+ if N_cd21 GT 0 then cd[1,0] = lvalue[l[N_cd21-1]]
+ l = where(keyword EQ 'CD'+latc+'_'+latc + alt, N_cd22)
+ if N_cd22 GT 0 then cd[1,1] = lvalue[l[N_cd22-1]]
+ noparams = 2
+ endif else begin
+
+; Now get rotation, first try CROTA2, if not found try CROTA1, if that
+; not found assume North-up. Then convert to CD matrix - see Section 5 in
+; Greisen and Calabretta
+
+ l = where(keyword EQ 'CDELT'+lonc + alt, N_cdelt1)
+ if N_cdelt1 GT 0 then cdelt[0] = lvalue[l[N_cdelt1-1]]
+ l = where(keyword EQ 'CDELT'+latc + alt, N_cdelt2)
+ if N_cdelt2 GT 0 then cdelt[1] = lvalue[l[N_cdelt2-1]]
+ if (N_cdelt1 EQ 0) || (N_Cdelt2 EQ 0) then return
+ ;Must have CDELT1 and CDELT2
+
+ l = where(keyword EQ 'CROTA'+latc + alt, N_crota)
+ if N_Crota EQ 0 then $
+ l = where(keyword EQ 'CROTA'+lonc + alt, N_crota)
+ if N_crota EQ 0 then begin
+ l = where(keyword EQ 'PC001001', N_PC00)
+ l = where(keyword EQ 'CD001001', N_CD00)
+ if (N_PC00 GT 0) || (N_CD00 GT 0) then begin
+ message,'Updating obsolete CD matrix representation',/INF
+ FITS_CD_FIX, hdr
+ keyword = strtrim(strmid(hdr,0,8),2)
+ goto, GET_CD_MATRIX
+ endif else crota = 0.0d
+ endif else crota = double(lvalue[l[N_crota-1]])/RADEG
+ cd = [ [cos(crota), -sin(crota)],[sin(crota), cos(crota)] ]
+
+ noparams = 1 ;Signal AIPS-type astrometry found
+
+ endelse
+ endelse
+
+; Kluge to test for non-standard PVi_j distortion terms used by SCAMP
+ scamp_distort = 0b
+ if ~tpv && (proj EQ 'TAN') then $
+ tpv = ~array_equal(strmatch(keyword,'PV1_[5-9]'),0) && $ ;Updated 1-8-14
+ ~array_equal(strmatch(keyword,'PV2_[3-9]'),0)
+
+;Extract PV_* keywords. Special case for TPV distortion
+ if tpv then begin
+ g= where(strmatch(keyword,'PV1_*'), Ng)
+ key_pv1 = keyword[g]
+ temp = gettok(key_pv1,'_')
+ key_pv1 = fix(key_pv1)
+ pv1 = dblarr(max(key_pv1)+1)
+ pv1[key_pv1] = lvalue[g]
+
+ g= where(strmatch(keyword,'PV2_*'), Ng)
+ key_pv2 = keyword[g]
+ temp = gettok(key_pv2,'_')
+ key_pv2 = fix(key_pv2)
+ pv2 = dblarr(max(key_pv2)+1) ;Corrected 13-Jan-2014
+ pv2[key_pv2] = lvalue[g]
+
+ latpole = 90.0D
+ longpole = 180.0D
+ known = 1.0
+ x0y0 = [0d0, 0d0]
+ distort_flag = 'TPV'
+ENDIF ELSE BEGIN
+ ;; extract the tnx coefficients from the WAT keywords
+
+ IF(tnx)THEN BEGIN
+ g=where(strmatch(keyword,'WAT1_*'),Ng)
+ key_wat1=keyword[g]
+ val_wat1=STRTRIM(strmid(hdr[g], 10),2)
+ remchar,val_wat1,"'"
+ remchar,val_wat1,'"'
+ remchar,val_wat1,'/'
+ temp=STRMID(key_wat1,0,3,/REVERSE)
+ s=SORT(temp)
+ val_wat1=val_wat1[s]
+ val_wat1=STRJOIN(val_wat1)
+ val_wat1=STRSPLIT(val_wat1,/EXTRACT)
+
+ g=where(strmatch(keyword,'WAT2_*'),Ng)
+ key_wat2=keyword[g]
+ val_wat2=STRTRIM(strmid(hdr[g], 10),2)
+ remchar,val_wat2,"'"
+ remchar,val_wat2,'"'
+ remchar,val_wat2,'/'
+ temp=STRMID(key_wat2,0,3,/REVERSE)
+ s=SORT(temp)
+ val_wat2=val_wat2[s]
+ val_wat2=STRJOIN(val_wat2)
+ val_wat2=STRSPLIT(val_wat2,/EXTRACT)
+ IF(val_wat1[2] NE 'lngcor' || val_wat2[2] NE 'latcor')THEN BEGIN
+ MESSAGE,'WARNING: TNX projection parameters not parsed correctly',/CON
+ ctype = ['RA---TAN','DEC--TAN']
+ tnx=0
+ ENDIF
+ IF(val_wat1[4] NE 3 || val_wat2[4] NE 3)THEN BEGIN
+ MESSAGE,'WARNING - only polynomials supported for TNX projection.',/CON
+ ctype = ['RA---TAN','DEC--TAN']
+ tnx=0
+ ENDIF
+
+ IF(tnx)THEN BEGIN
+ ;; tnx coefficients get stored in two structures
+ ncoeff=N_ELEMENTS(val_wat1)-12
+ lngcor={functype:0,xiorder:0,etaorder:0,xterms:0,ximin:0d0,ximax:0d0,etamin:0d0,etamax:0d0,coeff:DBLARR(ncoeff)}
+ lngcor.functype=FIX(val_wat1[4])
+ lngcor.xiorder=FIX(val_wat1[5])
+ lngcor.etaorder=FIX(val_wat1[6])
+ lngcor.xterms=FIX(val_wat1[7])
+ lngcor.ximin=DOUBLE(val_wat1[8])
+ lngcor.ximax=DOUBLE(val_wat1[9])
+ lngcor.etamin=DOUBLE(val_wat1[10])
+ lngcor.etamax=DOUBLE(val_wat1[11])
+ lngcor.coeff=DOUBLE(val_wat1[12:*])
+
+ ncoeff=N_ELEMENTS(val_wat2)-12
+ latcor={functype:0,xiorder:0,etaorder:0,xterms:0,ximin:0d0,ximax:0d0,etamin:0d0,etamax:0d0,coeff:DBLARR(ncoeff)}
+ latcor.functype=FIX(val_wat2[4])
+ latcor.xiorder=FIX(val_wat2[5])
+ latcor.etaorder=FIX(val_wat2[6])
+ latcor.xterms=FIX(val_wat2[7])
+ latcor.ximin=DOUBLE(val_wat2[8])
+ latcor.ximax=DOUBLE(val_wat2[9])
+ latcor.etamin=DOUBLE(val_wat2[10])
+ latcor.etamax=DOUBLE(val_wat2[11])
+ latcor.coeff=DOUBLE(val_wat2[12:*])
+ distort_flag = 'TNX'
+ ENDIF ELSE distort_flag=''
+ ENDIF ELSE BEGIN
+ distort_flag = strlen(ctype[0]) GE 12 ? strmid(ctype[0],9,3) : ''
+ ENDELSE
+ case proj of
+ 'ZPN': npv = 21
+ 'SZP': npv = 3
+ else: npv = 2
+ endcase
+
+ index = proj EQ 'ZPN' ? strtrim(indgen(npv),2) : strtrim(indgen(npv)+1,2)
+ pv2 = dblarr(npv)
+ if proj EQ 'HPX' then pv2[0] = [4.d,3.d] ;Default for Healpix
+
+ for i=0,npv-1 do begin
+ l = where(keyword EQ 'PV'+latc+ '_' + index[i] + alt, N_pv2)
+ if N_pv2 GT 0 then pv2[i] = lvalue[l[N_pv2-1]]
+ endfor
+
+ pv1 = DBLARR(5)
+ pv1_set = BYTARR(5)
+ FOR i=0,4 DO BEGIN
+ l = WHERE(keyword EQ 'PV'+lonc+'_' + STRTRIM(i,2) + alt, N_pv1)
+ pv1_set[i] = N_pv1 GT 0
+ IF pv1_set[i] THEN pv1[i] = DOUBLE(lvalue[l[N_pv1-1]])
+ ENDFOR
+ xyoff = pv1[0] NE 0d0
+ phi0 = pv1[1]
+ if pv1_set[2] THEN theta0 = pv1[2]
+ if pv1_set[3] then longpole = pv1[3] else begin
+ l = where(keyword EQ 'LONPOLE' + alt, N_lonpole)
+ if N_lonpole GT 0 then longpole = double(lvalue[l[N_lonpole-1]])
+ endelse
+ if pv1_set[4] then latpole = pv1[4] else begin
+ l = where(keyword EQ 'LATPOLE' + alt, N_latpole)
+ latpole = N_latpole GT 0 ? double(lvalue[l[N_latpole-1]]) : 90d0
+ endelse
+
+; Convert NCP projection to generalized SIN projection (see Section 6.1.2 of
+; Calabretta and Greisen (2002)
+
+ if proj EQ 'NCP' then begin
+ ctype = repstr(ctype,'NCP','SIN')
+ proj = 'SIN'
+ PV2 = [0d0, 1d0/tan(crval[1]/radeg) ]
+ longpole = 180d0
+ endif
+
+; Convert GLS projection (Sect 6.1.4, ibid), but per e-mail from Mark
+; Calabretta the correction to CRPIX and CRVAL should only be applied
+; to the second axis.
+ IF proj EQ 'GLS' THEN BEGIN
+ IF crota EQ 0d0 THEN BEGIN
+ crpix[1] -= crval[1]/cdelt[1] ; Shift reference point to dec = 0
+ crval[1] = 0d0
+ ctype = repstr(ctype,'GLS','SFL')
+ proj = 'SFL'
+ ENDIF
+ ENDIF
+
+ test = WHERE(proj EQ map_types)
+ known = test GE 0
+
+ ; If LONPOLE (or PV1_3) is not defined in the header, then we must determine
+; its default value. This depends on the value of theta0 (the native
+; longitude of the fiducial point) of the particular projection)
+
+ conic = (proj EQ 'COP') || (proj EQ 'COE') || (proj EQ 'COD') || $
+ (proj EQ 'COO')
+
+ IF conic THEN BEGIN
+ IF N_pv2 EQ 0 THEN message, $
+ 'ERROR -- Conic projections require a PV2_1 keyword in FITS header'
+ theta_a = pv2[0]
+ ENDIF ELSE BEGIN ; Is it a zenithal projection?
+ if (proj EQ 'AZP') || (proj EQ 'SZP') || (proj EQ 'TAN') || $
+ (proj EQ 'STG') || (proj EQ 'SIN') || (proj EQ 'ARC') || $
+ (proj EQ 'ZPN') || (proj EQ 'ZEA') || (proj EQ 'AIR') || $
+ (proj EQ 'XPH') then begin
+ theta_a = 90d0
+ endif else theta_a = 0d0
+ ENDELSE
+
+ IF ~pv1_set[2] THEN BEGIN
+ theta0 = theta_a
+ pv1[2] = theta_a
+ ENDIF
+
+ if N_elements(longpole) EQ 0 then begin
+ if crval[1] GE theta0 then longpole = 0d0 else longpole = 180d0
+ if pv1_set[1] THEN longpole += phi0
+ endif
+
+ pv1[3] = longpole
+ pv1[4] = latpole
+
+
+ IF xyoff && (phi0 NE 0d0 || theta0 NE theta_a) THEN BEGIN
+ ; calculate IWC offsets x_0, y_0
+ WCSSPH2XY, phi0, theta0, x0, y0, CTYPE = ctype, PV2 = pv2
+ x0y0 = [x0, y0]
+ ENDIF ELSE x0y0 = [0d0, 0d0]
+ENDELSE
+
+ axes = FIX([lonc,latc])
+ flip = axes[0] GT axes[1]
+ IF flip THEN BEGIN
+ naxis = REVERSE(naxis)
+ axes = REVERSE(axes)
+ cdelt = REVERSE(cdelt)
+ crpix = REVERSE(crpix)
+ crval = REVERSE(crval)
+ ctype = REVERSE(ctype)
+ cd = ROTATE(cd,2)
+ x0y0 = REVERSE(x0y0)
+ ENDIF
+
+ equinox = GET_EQUINOX( hdr,eq_code, ALT = alt)
+ IF equinox EQ 0 THEN equinox = !values.D_NAN
+ radecsys = ''
+ mjdobs = !values.D_NAN
+ dateobs = 'UNKNOWN'
+ l = WHERE(keyword EQ 'RADESYS' + alt, N_rdsys)
+ IF N_rdsys GT 0 THEN radecsys = lvalue[l[N_rdsys-1]] ELSE BEGIN
+ l = WHERE(keyword EQ 'RADECSYS', N_rdsys)
+ IF N_rdsys GT 0 THEN radecsys = lvalue[l[N_rdsys-1]]
+ ENDELSE
+ IF N_rdsys GT 0 THEN radecsys = STRUPCASE(STRTRIM(radecsys,2))
+
+ l = WHERE(keyword EQ 'MJD-OBS', N_mjd)
+ IF N_mjd GT 0 THEN mjdobs = DOUBLE(lvalue[l[N_mjd-1]])
+ l = WHERE(keyword EQ 'DATE-OBS', N_date)
+ IF N_date GT 0 THEN dateobs = STRUPCASE(lvalue[l[N_date-1]])
+
+ IF N_mjd GT 0 && N_date EQ 0 THEN dateobs = date_conv(mjdobs+2400000.5d0,'FITS')
+ IF N_date GT 0 THEN BEGIN
+ ; try to convert to standard format:
+ dateobs = date_conv(dateobs,'FITS', BAD_DATE=bad_date)
+ IF ~bad_date THEN BEGIN
+ mjdtest = date_conv(dateobs,'MODIFIED')
+ IF N_mjd EQ 0 THEN mjdobs = mjdtest ELSE $
+ IF ABS(mjdtest - mjdobs) GT 1 THEN MESSAGE, $
+ 'DATE-OBS and MJD-OBS are inconsistent'
+ ENDIF ELSE dateobs = 'UNKNOWN'
+ ENDIF
+
+ IF (coord EQ 'C' || coord EQ 'E' || coord EQ 'H') THEN BEGIN
+ IF N_rdsys EQ 0 THEN CASE eq_code OF
+ -1: radecsys = 'ICRS' ; default if no header info.
+ 0: radecsys = equinox GE 1984d0 ? 'FK5' : 'FK4'
+ 1: radecsys = equinox GE 1984d0 ? 'FK5' : 'FK4'
+ 2: radecsys = 'FK4'
+ 3: radecsys = 'FK5'
+ 4: ; shouldn't get here as implies radecsys exists.
+ else: MESSAGE, 'Internal error: unrecognised eq_code'
+ ENDCASE
+ ENDIF
+
+; Note that the dimensions and datatype of each tag must be explicit, so that
+; there is no conflict with structure definitions from different FITS headers
+
+ ASTR = {NAXIS:naxis, CD: cd, CDELT: cdelt, CRPIX: crpix, CRVAL: crval, $
+ CTYPE: string(ctype), $
+ LONGPOLE: double( longpole[0]), LATPOLE: double(latpole[0]), $
+ PV2: pv2, PV1: pv1, $
+ AXES: axes, REVERSE: flip, $
+ COORD_SYS: coord, PROJECTION: proj, KNOWN: known, $
+ RADECSYS: radecsys, EQUINOX: DOUBLE(equinox), $
+ DATEOBS: dateobs, MJDOBS: DOUBLE(mjdobs), X0Y0: x0y0}
+
+; Check for any distortion keywords
+
+
+ case distort_flag of
+ 'SIP': begin
+ l = where(keyword EQ 'A_ORDER', N)
+ if N GT 0 then a_order = lvalue[l[N-1]] else a_order = 0
+ l = where(keyword EQ 'B_ORDER', N)
+ if N GT 0 then b_order = lvalue[l[N-1]] else b_order = 0
+ l = where(keyword EQ 'AP_ORDER', N)
+ if N GT 0 then ap_order = lvalue[l[N-1]] else ap_order = 0
+ l = where(keyword EQ 'BP_ORDER', N)
+ if N GT 0 then bp_order = lvalue[l[N-1]] else bp_order = 0
+ a = dblarr(a_order+1,a_order+1)
+ b = dblarr(b_order+1,b_order+1)
+ ap = dblarr(ap_order+1,ap_order+1)
+ bp = dblarr(bp_order+1,bp_order+1)
+
+ for i=0, a_order do begin
+ for j=0, a_order do begin
+ l = where(keyword EQ 'A_' + strtrim(i,2) + '_' + strtrim(j,2), N)
+ if N GT 0 then a[i,j] = lvalue[l[N-1]]
+ endfor
+ endfor
+
+ for i=0, b_order do begin
+ for j=0, b_order do begin
+ l = where(keyword EQ 'B_' + strtrim(i,2) + '_' + strtrim(j,2), N)
+ if N GT 0 then b[i,j] = lvalue[l[N-1]]
+ endfor
+ endfor
+
+ for i=0, bp_order do begin
+ for j=0, bp_order do begin
+ l = where(keyword EQ 'BP_' + strtrim(i,2) + '_' + strtrim(j,2), N)
+ if N GT 0 then bp[i,j] = lvalue[l[N-1]]
+ endfor
+ endfor
+
+ for i=0, ap_order do begin
+ for j=0, ap_order do begin
+ l = where(keyword EQ 'AP_' + strtrim(i,2) + '_' + strtrim(j,2), N)
+ if N GT 0 then ap[i,j] = lvalue[l[N-1]]
+ endfor
+ endfor
+
+ distort = {name:distort_flag, a:a, b:b, ap:ap, bp:bp}
+ astr = create_struct(temporary(astr), 'distort', distort)
+ end
+ 'TPV': begin
+ distort = {name:'TPV', a:0.0d, b:0.0d, ap:0.0d, bp:0.0d}
+ astr = create_struct(temporary(astr), 'distort', distort)
+ end
+ 'TNX' : begin
+ distort = {name:'TNX', lngcor:lngcor, latcor:latcor}
+ astr = create_struct(temporary(astr), 'distort', distort)
+ end
+ '':
+ else: message,/con,'Unrecognized distortion acronym: ' + distort_flag
+ endcase
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/extgrp.pro b/Code/script_idl_mv/astrolib/extgrp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0764cefefc43ddf5f2e6345c046cdfdc59c60081
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/extgrp.pro
@@ -0,0 +1,88 @@
+pro extgrp,hdr,par
+;+
+; NAME:
+; EXTGRP
+; PURPOSE:
+; Extract the group parameter information out of SXREAD output
+; EXPLANATION:
+; This procedure extracts the group parameter information out of a
+; header and parameter variable obtained from SXREAD. This allows
+; astrometry, photometry and other parameters to be easily SXPARed by
+; conventional methods and allows the image and header to be saved in
+; a SIMPLE format.
+;
+; CALLING SEQUENCE:
+; ExtGrp, hdr, par
+;
+; INPUT:
+; HDR - The header which is to be converted (input and output)
+; PAR - The Parameter string returned from a call to SXREAD
+;
+; OUTPUT:
+; HDR - The converted header, string array
+;
+; OTHER PROCEDURES CALLED:
+; SXPAR(), SXADDPAR, SXGPAR(), STRN()
+;
+; HISTORY:
+; 25-JUN-90 Version 1 written
+; 13-JUL-92 Header finally added to this ancient procedure, code spiffed up
+; a bit. Now 3 times faster. Added PTYPE comment inclusion. E. Deutsch
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+
+ arg=n_params(0)
+ if (arg lt 2) then begin
+ print,'Call: IDL> EXTGRP,header,params_string'
+ print,"e.g.: IDL> EXTGRP,h,par"
+ return
+ endif
+
+ h=hdr
+ pcount=sxpar(h,'PCOUNT')
+ if (pcount le 0) then begin
+ print,'[EXTGRP] Error: PCOUNT not >0 in header'
+ return
+ endif
+
+ htmp=h & ih=0
+ while (strmid(h[ih],0,4) ne 'PTYP') do ih=ih+1
+ itmp=ih & stbyt=0
+ hquick=strarr(4) & hquick[3]='END ' ; tiny temp. header for speed
+
+ for t2=0,pcount-1 do begin
+ hquick=h[ih+3*t2:ih+3*t2+2]
+
+ pty=sxpar(hquick,'PTYPE'+strn(t2+1))
+ comment=strmid(hquick[0],30,50)
+ pdty=sxpar(hquick,'PDTYPE'+strn(t2+1))
+ psz=sxpar(hquick,'PSIZE'+strn(t2+1))/8
+ pvl=sxgpar(h,par,pty,pdty,stbyt,psz)
+
+ sz=size(pvl) & stbyt=stbyt+psz
+ if (sz[1] eq 7) then pvl="'"+strn(pvl,length=18)+"'"
+ tmp=pty+'='+strn(pvl,length=21)+comment
+
+ htmp[itmp]=tmp
+ itmp=itmp+1
+ endfor
+
+ while (strmid(h[ih],0,1) eq 'P') do ih=ih+1
+
+ while (strmid(h[ih],0,3) ne 'END') do begin
+ htmp[itmp]=h[ih]
+ itmp=itmp+1
+ ih=ih+1
+ endwhile
+
+ htmp[itmp]=h[ih]
+ hdr=htmp[0:itmp]
+
+ sxaddpar,hdr,'SIMPLE','T',' Group Parameters extracted'
+ sxaddpar,hdr,'PCOUNT',0,' All group parameters extracted'
+ sxaddpar,hdr,'PSIZE',0,' All group parameters extracted'
+ sxaddpar,hdr,'GROUPS','T'
+ sxaddpar,hdr,'GCOUNT',1,' Number of groups'
+
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/f_format.pro b/Code/script_idl_mv/astrolib/f_format.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ba7814d8d0976cfd35941d9da311a12b14ccff5d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/f_format.pro
@@ -0,0 +1,112 @@
+function f_format, minval, maxval, factor, length
+;+
+; NAME:
+; F_FORMAT
+; PURPOSE:
+; Choose a nice floating format for displaying an array of REAL data.
+; EXPLANATION:
+; Called by TVLIST, IMLIST.
+;
+; CALLING SEQUENCE:
+; fmt = F_FORMAT( minval, maxval, factor, [ length ] )
+;
+; INPUTS:
+; MINVAL - REAL scalar giving the minimum value of an array of numbers
+; for which one desires a nice format.
+; MAXVAL - REAL scalar giving maximum value in array of numbers
+;
+; OPTIONAL INPUT:
+; LENGTH - length of the output F format (default = 5)
+; must be an integer scalar > 2
+;
+; OUTPUT:
+; FMT - an F or I format string, e.g. 'F5.1'
+; FACTOR - factor of 10 by which to multiply array of numbers to achieve
+; a pretty display using format FMT.
+;
+; EXAMPLE:
+; Find a nice format to print an array of numbers with a minimum of 5.2e-3
+; and a maximum of 4.2e-2.
+;
+; IDL> fmt = F_FORMAT( 5.2e-3, 4.2e-2, factor )
+;
+; yields fmt = '(F5.2)' and factor = .01, i.e. the array can be displayed
+; with a F5.2 format after multiplication by 100.
+;
+; REVISION HISTORY:
+; Written W. Landsman December 1988
+; Deal with factors < 1. August 1991
+; Deal with factors < 1. *and* a large range October 1992
+; Now returns In format rather than Fn.0 February, 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+; Fix display problem for large negative numbers W. Landsman Mar 2016
+;-
+ On_error,2
+
+ if N_params() LT 3 then begin
+ print,'Syntax - fmt = F_FORMAT( minval, maxval, factor, [ length ])'
+ return,''
+ endif
+
+ if N_params() LT 4 then length = 5 else length = length > 2
+ factor = 1.
+
+ RANGE: if ( maxval GT 0) then begin
+ mxlog = fix( alog10( maxval ) )
+ mxval = (mxlog>0) + 1
+ endif else if ( maxval LT 0) then begin
+ mxlog = fix( alog10( abs( maxval ) ) )
+ mxval = (mxlog>0) + 2
+ endif else begin
+ mxlog = 0
+ mxval = 1
+ endelse
+
+ if ( minval GT 0 ) then begin
+ mnlog = fix( alog10( minval ))
+ mnval = (mnlog>0) + 1
+ endif else if ( minval LT 0) then begin
+ mnlog = fix(alog10(abs(minval)))
+ mnval = (mnlog>0) + 2
+ endif else begin
+ mnlog = 0
+ mnval = 1
+ endelse
+
+ if ( mnlog LT 0 ) and ( mxlog LT 0 ) then begin ;All numbers are < 1.0
+ expon = max( [ mnlog,mxlog ] ) -1
+ factor = factor*10.^(expon)
+ maxval = maxval / factor
+ minval = minval / factor
+ goto, RANGE
+ endif
+
+ dif = abs( mxlog - mnlog )
+ if ( dif GE length-3 ) then begin
+ mxlen = max([mnlog,mxlog])
+ factor = factor*10.^(mxlen-(length-3))
+ abs = 0
+
+ endif else begin
+
+ TEST: tpairv = abs( [mxval,mnval] )
+ test = max( tpairv )
+
+ if ( test LE length-3 ) then begin ;No factor needed
+ abs = length - test - 2
+ endif else begin
+ expon = min( [mxlog, mnlog] )
+ if expon EQ 0 then expon = 1 ;Avoid infinite loop
+ factor = factor*10.^(expon)
+ mxval -= expon
+ mnval -= expon
+ goto, TEST
+ endelse
+ endelse
+
+ if abs EQ 0 then begin
+ factor = factor/10
+ return,'I' + strtrim(length,2)
+ endif else return,'F' + strtrim( length, 2 ) + '.' + strtrim( abs, 2 )
+
+ end
diff --git a/Code/script_idl_mv/astrolib/factor.pro b/Code/script_idl_mv/astrolib/factor.pro
new file mode 100644
index 0000000000000000000000000000000000000000..683932bdc56c46c2b3b56e7d506874a4a85f0841
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/factor.pro
@@ -0,0 +1,277 @@
+;-------------------------------------------------------------
+;+
+; NAME:
+; FACTOR
+; PURPOSE:
+; Find prime factors of a given number.
+; CATEGORY:
+; CALLING SEQUENCE:
+; factor, x, p, n
+; INPUTS:
+; x = Number to factor (>1). in
+; KEYWORD PARAMETERS:
+; Keywords:
+; /QUIET means do not print factors.
+; /DEBUG Means list steps as they happen.
+; /TRY Go beyond 20000 primes.
+; OUTPUTS:
+; p = Array of prime numbers. out
+; n = Count of each element of p. out
+; COMMON BLOCKS:
+; NOTES:
+; Note: see also prime, numfactors, print_fact.
+; MODIFICATION HISTORY:
+; R. Sterner. 4 Oct, 1988.
+; RES 25 Oct, 1990 --- converted to IDL V2.
+; R. Sterner, 1999 Jun 30 --- Improved (faster, bigger).
+; R. Sterner, 1999 Jul 7 --- Bigger values (used unsigned).
+; R. Sterner, 1999 Jul 9 --- Tried to make backward compatable.
+; R. Sterner, 2000 Jan 06 --- Fixed to ignore non-positive numbers.
+; Johns Hopkins University Applied Physics Laboratory.
+;
+; Copyright (C) 1988, Johns Hopkins University/Applied Physics Laboratory
+; This software may be used, copied, or redistributed as long as it is not
+; sold and this copyright notice is reproduced on each copy made. This
+; routine is provided as is without any express or implied warranties
+; whatsoever. Other limitations apply as described in the file disclaimer.txt.
+;-
+;-------------------------------------------------------------
+; NAME:
+; SPC
+; PURPOSE:
+; Return a string with the specified number of spaces (or other char).
+; CATEGORY:
+; CALLING SEQUENCE:
+; s = spc(n, [text])
+; INPUTS:
+; n = number of spaces (= string length). in
+; text = optional text string. in
+; # spaces returned is n-strlen(strtrim(text,2))
+; KEYWORD PARAMETERS:
+; Keywords:
+; CHARACTER=ch Character other than a space.
+; Ex: CHAR='-'.
+; /NOTRIM means do not do a strtrim on text.
+; OUTPUTS:
+; s = resulting string. out
+; COMMON BLOCKS:
+; NOTES:
+; Note: Number of requested spaces is reduced by the
+; length of given string. Useful for text formatting.
+; MODIFICATION HISTORY:
+; Written by R. Sterner, 16 Dec, 1984.
+; RES --- rewritten 14 Jan, 1986.
+; R. Sterner, 27 Jun, 1990 --- added text.
+; R. Sterner, 1994 Sep 7 --- Allowed text arrays.
+; R. Sterner, 1999 Jul 2 --- Added /NOTRIM keyword.
+; Johns Hopkins University Applied Physics Laboratory.
+;
+; Copyright (C) 1984, Johns Hopkins University/Applied Physics Laboratory
+; This software may be used, copied, or redistributed as long as it is not
+; sold and this copyright notice is reproduced on each copy made. This
+; routine is provided as is without any express or implied warranties
+; whatsoever. Other limitations apply as described in the file disclaimer.txt.
+;-------------------------------------------------------------
+
+ function spc,n, text, character=char, notrim=notrim, help=hlp
+
+ if (n_params(0) lt 1) or keyword_set(hlp) then begin
+ print,' Return a string with the specified number of spaces (or '+$
+ 'other char).'
+ print,' s = spc(n, [text])'
+ print, ' n = number of spaces (= string length). in '
+ print,' text = optional text string. in'
+ print,' # spaces returned is n-strlen(strtrim(text,2))'
+ print,' s = resulting string. out'
+ print,' Keywords:'
+ print,' CHARACTER=ch Character other than a space.'
+ print," Ex: CHAR='-'."
+ print,' /NOTRIM means do not do a strtrim on text.'
+ print,' Note: Number of requested spaces is reduced by the'
+ print,' length of given string. Useful for text formatting.'
+ return, -1
+ endif
+
+ if n_params(0) eq 1 then begin
+ n2 = n
+ endif else begin
+ if keyword_set(notrim) then $
+ ntxt=strlen(text) else ntxt=strlen(strtrim(text,2))
+; n2 = n - strlen(strtrim(text,2))
+ n2 = n - ntxt
+ endelse
+
+ ascii = 32B
+ if n_elements(char) ne 0 then ascii = (byte(char))[0]
+
+ num = n_elements(n2)
+ out = strarr(num)
+ for i = 0, num-1 do begin
+ if n2[i] le 0 then out[i] = '' else $
+ out[i] = string(bytarr(n2[i]) + ascii)
+ endfor
+
+ if n_elements(out) eq 1 then out=out[0]
+ return, out
+
+ end
+
+
+;-------------------------------------------------------------
+; NAME:
+; PRINT_FACT
+; PURPOSE:
+; Print prime factors found by the factor routine.
+; CATEGORY:
+; CALLING SEQUENCE:
+; print_fact, p, n
+; INPUTS:
+; p = prime factors. in
+; n = number of each factor. in
+; KEYWORD PARAMETERS:
+; OUTPUTS:
+; COMMON BLOCKS:
+; NOTES:
+; MODIFICATION HISTORY:
+; R. Sterner 4 Oct, 1988.
+; RES 25 Oct, 1990 --- converted to IDL V2.
+; R. Sterner, 26 Feb, 1991 --- Renamed from print_factors.pro
+; R. Sterner, 1999 Jun 30 --- Better output format.
+; R. Sterner, 1999 Jul 7 --- Bigger values (used unsigned).
+; R. Sterner, 1999 Jul 9 --- Made backward compatable.
+;
+; Copyright (C) 1988, Johns Hopkins University/Applied Physics Laboratory
+; This software may be used, copied, or redistributed as long as it is not
+; sold and this copyright notice is reproduced on each copy made. This
+; routine is provided as is without any express or implied warranties
+; whatsoever. Other limitations apply as described in the file disclaimer.txt.
+;-------------------------------------------------------------
+
+ pro print_fact, p, n, help=hlp
+
+ if (n_params(0) lt 2) or keyword_set(hlp) then begin
+ print,' Print prime factors found by the factor routine.'
+ print,' print_fact, p, n'
+ print,' p = prime factors. in'
+ print,' n = number of each factor. in'
+ return
+ endif
+
+ ;------- Drop unused primes ---------------
+ w = where(n gt 0) ; Find only primes used.
+ p2 = p[w]
+ n2 = n[w]
+
+ ;------- Use largest available integer type --------------
+ flag = !version.release ge 5.2
+ if flag eq 1 then begin
+ err=execute('t=1ULL') ; Use 64 bit int (hide from old IDL).
+ endif else begin
+ t = 1L ; Use long int (best available in old).
+ endelse
+
+ ;------- Compute number from it's prime factors. ----------
+ for i = 0, n_elements(p2)-1 do t = t * p2[i]^n2[i]
+
+ ;------- Prepare output -----------------------
+ a = strtrim(t,2)+' = ' ; Start factors string.
+ b = '' ; Start exponents string.
+ last = n_elements(p2)-1 ; Last factors index.
+ for i=0, last do begin
+ a = a + strtrim(p2[i],2) ; Insert next factor.
+ lena = strlen(a) ; Length of factor string.
+ nxtb = strtrim(n2[i],2) ; Next exponent.
+ if nxtb eq '1' then nxtb=' ' ; Weed out 1s.
+ b = b+spc(lena,b,/notrim)+nxtb ; Insert next exponent.
+ if i ne last then a=a+' x ' ; Not last, add x.
+ endfor
+
+ ;------ Print exponents and factors -----------
+ print,' '
+ print,' '+b
+ print,' '+a
+
+ return
+ end
+
+
+
+ pro factor, x, p, n, quiet=quiet, debug=debug, try=try, help=hlp
+
+ if (n_params(0) lt 1) or keyword_set(hlp) then begin
+ print,' Find prime factors of a given number.'
+ print,' factor, x, p, n'
+ print,' x = Number to factor (>1). in'
+ print,' p = Array of prime numbers. out'
+ print,' n = Count of each element of p. out'
+ print,' Keywords:'
+ print,' /QUIET means do not print factors.'
+ print,' /DEBUG Means list steps as they happen.'
+ print,' /TRY Go beyond 20000 primes.'
+ print,' Note: see also prime, numfactors, print_fact.'
+ return
+ endif
+
+ if x le 0 then return
+
+ flag = !version.release ge 5.2
+
+ s = sqrt(x) ; Only need primes up to sqrt(x).
+ g = long(50 + 0.13457*s) ; Upper limit of # primes up to s.
+ np = 50 ; Start with np (50) primes.
+ p = prime(np) ; Find np primes.
+ n = intarr(n_elements(p)) ; Divisor count.
+
+ if flag eq 1 then $ ; Working number.
+ err=execute('t=ulong64(x)') $ ; Use best integer available.
+ else t=long(x) ; Best pre-5.2 integer.
+ i = 0L ; Index of test prime.
+
+loop: pt = p[i] ; Pull test prime.
+ if keyword_set(debug) then $
+ print,' Trying '+strtrim(pt,2)+' into '+strtrim(t,2)
+ if flag eq 1 then $
+ err=execute('t2=ulong64(t/pt)') $
+ else t2=long(t/pt)
+ if t eq t2*pt then begin ; Check if it divides.
+ if keyword_set(debug) then $
+ print,' Was a factor. Now do '+strtrim(t2,2)
+ n[i] = n[i] + 1 ; Yes, count it.
+ t = t2 ; Result after division.
+ if t2 eq 1 then goto, done ; Check if done.
+ goto, loop ; Continue.
+ endif else begin
+ i = i + 1 ; Try next prime.
+ if i ge np then begin
+ s = sqrt(t) ; Only need primes up to sqrt(x).
+ g = long(50 + 0.13457*s) ; Upper limit of # primes up to s.
+ if g le np then goto, last ; Must be done.
+ np = (np+50) FDECOMP, file, disk, dir, name, qual
+; will return the following
+;
+; Disk Dir Name Qual
+; Unix: '' '/itt/idl71/' 'avg' 'pro'
+; Windows: 'd:' \itt\idl71\ 'avg' 'pro'
+;
+; NOTES:
+; (1) The period is removed between the name and qualifier
+; (2) Unlike the intrinsic FILE_BASENAME() and FILE_DIRNAME() functions,
+; one can use FDECOMP to decompose a Windows file name on a Unix machine
+; or a Unix filename on a Windows machine.
+;
+; ROUTINES CALLED:
+; None.
+; HISTORY
+; version 1 D. Lindler Oct 1986
+; Include VMS DECNET machine name in disk W. Landsman HSTX Feb. 94
+; Converted to Mac IDL, I. Freedman HSTX March 1994
+; Major rewrite to accept vector filenames V5.3 W. Landsman June 2000
+; Fix cases where disk name not always present W. Landsman Sep. 2000
+; Make sure version defined for Windows W. Landsman April 2004
+; Include final delimiter in directory under Windows as advertised
+; W. Landsman May 2006
+; Remove VMS support, W. Landsman September 2006
+; Remove MacOS branch (same as Unix) W. Landsman August 2009
+;-
+;--------------------------------------------------------
+;
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ if N_params() LT 2 then begin
+ print, 'Syntax - FDECOMP, filename, disk, [dir, name, qual ] '
+ return
+ endif
+
+
+ if ~keyword_set(osfamily) then osfamily = !Version.OS_Family
+ st = filename
+ disk = st
+ replicate_inplace,disk,''
+ dir = disk
+ qual = disk
+
+
+ if OSFAMILY EQ "Windows" then begin
+
+ lpos = strpos( st, ':') ; DOS diskdrive (i.e. c:)
+ good = where(lpos GT 0, Ngood)
+ if Ngood GT 0 then begin
+ stg = st[good]
+ lpos = reform( lpos[good], 1, Ngood)
+ disk[good] = strmid( stg, 0, lpos+1)
+ st[good] = strmid(stg,lpos+1 )
+ endif
+
+; Search the path name (i.e. \dos\idl\) and locate last backslash
+
+ lpos = strpos(st,'\',/reverse_search)
+ good = where(lpos Gt 0, Ngood)
+
+
+ endif ELSE begin ;Unix
+
+
+; Unix directory name ends at last slash
+
+ lpos = strpos(st,'/',/reverse_search)
+ good = where(lpos GE 0, Ngood)
+
+ endelse
+
+ if Ngood GT 0 then begin ;Extract directory name if present
+ stg = st[good]
+ lpos = reform( lpos[good],1, Ngood )
+
+ dir[good] = strmid(stg,0, lpos+1)
+ st[good] = strmid(stg,lpos+1 )
+ endif
+
+; get name and qualifier (extension)...qual is optional
+
+ lpos = strpos(st,'.',/reverse_search)
+ good = where(lpos GE 0, Ngood)
+ name = st
+
+ if Ngood GT 0 then begin
+ stg = st[good]
+ lpos = reform(lpos[good], 1, Ngood)
+
+ name[good] = strmid(stg,0,lpos )
+ qual[good] = strmid(stg,lpos+1 )
+ endif
+
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/file_launch.pro b/Code/script_idl_mv/astrolib/file_launch.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3cf2677c235db649d5f44ab8aa626caa498fb312
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/file_launch.pro
@@ -0,0 +1,108 @@
+; docformat = 'rst'
+;+
+; NAME:
+; FILE_LAUNCH
+;
+; PURPOSE:
+; Launch a file using the default application of the operating system
+;
+; EXPLANATION:
+; The FILE_LAUNCH procedure procedure will launch a file (e.g. a .pdf, .docx or .html
+; file) using the default application of the operating system. By default, it
+; first tries to use the Java desktop class.
+; https://docs.oracle.com/javase/tutorial/uiswing/misc/desktop.html
+; If this fails, it uses the appropriate Spawn command for the oS to launch
+;
+; CALLING SEQUENCE:
+; file_launch, file, [ buseJava, ojDesktop = ojDesktop, /QUIET ]
+;
+; INPUT PARMAMTER:
+; file: in, required, type=string
+; scalar filename (with path if required) to launch
+;
+; OPTIONAL INPUT KEYWORD:
+; bUseJava: in, optional, type=boolean, default=1
+; Flag to indicate if java should be used to launch browser.
+; True by default. Routine falls back to spawn commands if desktop is
+; not supported.
+;
+; /NoWait - if set, then if using Spawn, wait for the command to return
+; This is slower but is useful for debugging
+;
+; /quiet - if set, then don't print a message when forced to use SPAWN
+;
+; OPTIONAL OUTPUT KEYWORD:
+; ojDesktop : in, out, optional, type=object
+; reference to a java AWT desktop instance
+;
+; EXAMPLE:
+;
+; Open a PDF file test.pdf in the current directory
+; IDL> file_launch, 'test.pdf'
+;
+;
+; HISTORY:
+; First release W. Landsman March 2016
+; Heavily based on code by Derek Sabatke
+;
+;-
+;-----------------------------------------------------------------------------
+
+pro file_launch, file, ojDesktop = ojDesktop, bUseJava = bUseJava, quiet=quiet, $
+ Nowait = nowait
+ COMPILE_OPT idl2, HIDDEN
+
+ if ~file_test(file) then begin
+ message,/CON,'ERROR -- File not found ' + file
+ return
+ endif
+ ;set option defaults
+ setdefaultvalue, bUseJava, 1L
+ setdefaultvalue, NoWait, 0
+
+ Catch,theError
+ if theError NE 0 then begin
+ Catch,/Cancel
+ if bUseJava EQ 1 then bUseJava = 0 else begin ;If Java failed then use Spawn
+ void = cgErrorMsg(/quiet)
+ return
+ endelse
+ endif
+
+ ;initialize variables
+ if bUseJava && ((N_elements(ojDesktop) eq 0) || (~obj_valid(ojDesktop))) then begin
+ oJavaAWTDesktop = OBJ_NEW('IDLJavaObject$Static$JAVA_AWT_DESKTOP', 'java.awt.Desktop')
+ if oJavaAWTDesktop.isDesktopSupported() then ojDesktop = ojavaAWTDesktop.getDesktop() $
+ else bUseJava = 0L
+ endif
+
+ if bUseJava && ojDesktop.isDesktopSupported() then begin ; have java do the launching if possible
+ if !VERSION.OS_FAMILY NE 'WINDOWS' then fname = file_search(file,/full) $
+ else fname = file
+ sCleanOutputFN = strjoin(strsplit(fname, '\\', /extract), '/') ;purge (possible) backslashes
+ oJURI = OBJ_NEW('IDLJavaObject$Static$JAVA_NET_URI', 'java.net.URI')
+ oJString = OBJ_NEW('IDLJavaObject$JAVA_LANG_STRING', 'java.lang.String', 'file://'+sCleanOutputFN)
+ oURI = oJURI.create(oJString)
+
+ ojDesktop.browse, oURI
+
+ endif else begin; no java, so try spawning a command
+ if ~keyword_set(quiet) then message,'Using Spawn',/INF
+ if !VERSION.OS_NAME EQ 'Mac OS X' then begin
+ cmd = 'open "'+ file +'" '
+ if ~nowait then cmd += '&'
+ spawn,cmd
+ endif else begin
+ case StrUpCase(!Version.OS_Family) OF
+ 'WINDOWS': spawn, 'start "" "'+ file +'"', nowait = nowait
+ 'UNIX': begin
+ cmd = 'xdg-open "'+ file +'" '
+ if ~nowait then cmd+= '&'
+ spawn,cmd
+ end
+ else: print, 'Unable to launch ' + file + ' automatically.'
+ endcase
+ endelse
+
+ endelse
+end
diff --git a/Code/script_idl_mv/astrolib/filter_image.pro b/Code/script_idl_mv/astrolib/filter_image.pro
new file mode 100644
index 0000000000000000000000000000000000000000..22e9c56b6e1a99e9125ee5411a7f9739aa532641
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/filter_image.pro
@@ -0,0 +1,196 @@
+function filter_image, image, SMOOTH=width_smooth, ITERATE_SMOOTH=iterate, $
+ MEDIAN=width_median, ALL_PIXELS=all_pixels, $
+ FWHM_GAUSSIAN=fwhm, NO_FT_CONVOL=no_ft, PSF=psf
+;+
+; NAME:
+; FILTER_IMAGE
+;
+; PURPOSE:
+; Identical to MEDIAN or SMOOTH but handle edges and allow iterations.
+; EXPLANATION:
+; Computes the average and/or median of pixels in moving box,
+; replacing center pixel with the computed average and/or median,
+; (using the IDL SMOOTH() or MEDIAN() functions).
+; The main reason for using this function is the options to
+; also process the pixels at edges and corners of image, and,
+; to apply iterative smoothing simulating convolution with Gaussian,
+; and/or to convolve image with a Gaussian kernel. Users might also
+; look at the function ESTIMATOR_FILTER() introduced in IDL 7.1.
+;
+; CALLING SEQUENCE:
+; Result = filter_image( image, SMOOTH=width, MEDIAN = width, /ALL_PIXELS
+; /ITERATE, FWHM =, /NO_FT_CONVOL)
+;
+; INPUT:
+; image = 2-D array (matrix)
+;
+; OPTIONAL INPUT KEYWORDS:
+; SMOOTH = scalar (odd) integer specifying the width of a square box
+; for moving average, in # pixels. /SMOOTH means use box
+; width = 3 pixels for smoothing.
+;
+; MEDIAN = scalar (usually odd) integer specifying the width of square
+; moving box for median filter, in # pixels. /MEDIAN means use
+; box width = 3 pixels for median filter.
+;
+; /ALL_PIXELS causes the edges of image to be filtered as well. This
+; is accomplished by reflecting pixels adjacent to edges outward
+; (similar to the /EDGE_WRAP keyword in CONVOL).
+; Note that this is a different algorithm from the /EDGE_TRUNCATE
+; keyword to SMOOTH or CONVOL, which duplicates the nearest pixel.
+;
+; /ITERATE means apply smooth(image,3) iteratively for a count of
+; (box_width-1)/2 times (=radius), when box_width >= 5.
+; This is equivalent to convolution with a Gaussian PSF
+; of FWHM = 2 * sqrt( radius ) as radius gets large.
+; Note that /ALL_PIXELS is automatically applied,
+; giving better results in the iteration limit.
+; (also, MEDIAN keyword is ignored when /ITER is specified).
+;
+; FWHM_GAUSSIAN = Full-width half-max of Gaussian to convolve with image.
+; FWHM can be a single number (circular beam),
+; or 2 numbers giving axes of elliptical beam.
+;
+; /NO_FT_CONVOL causes the convolution to be computed directly,
+; with intrinsic IDL CONVOL function. The default is to use
+; FFT when factors of size are all LE 13. Note that
+; external function convolve.pro handles both cases)
+;
+; OPTIONAL INPUT/OUTPUT KEYWORD:
+; PSF = Array containing the PSF used during the convolution. This
+; keyword is only active if the FWHM_GAUSSIAN keyword is also
+; specified. If PSF is undefined on input, then upon output it
+; contains the Gaussian convolution specified by the FWHM_GAUSSIAN
+; keyword. If the PSF array is defined on input then it is used
+; as the convolution kernel, the value of the FWHM_GAUSSIAN keyword
+; is ignored. Typically, on a first call set PSF to an undefined
+; variable, which can be reused for subsequent calls to prevent
+; recalculation of the Gaussian PSF.
+; RESULT:
+; Function returns the smoothed, median filtered, or convolved image.
+; If both SMOOTH and MEDIAN are specified, median filter is applied first.
+; If only SMOOTH is applied, then output is of same type as input. If
+; either MEDIAN or FWHM_GAUSSIAN is supplied than the output is at least
+; floating (double if the input image is double).
+;
+; EXAMPLES:
+; To apply 3x3 moving median filter and
+; then 3x3 moving average, both applied to all pixels:
+;
+; Result = filter_image( image, /SMOOTH, /MEDIAN, /ALL )
+;
+; To iteratively apply 3x3 moving average filter for 4 = (9-1)/2 times,
+; thus approximating convolution with Gaussian of FWHM = 2*sqrt(4) = 4 :
+;
+; Result = filter_image( image, SMOOTH=9, /ITER )
+;
+; To convolve all pixels with Gaussian of FWHM = 3.7 x 5.2 pixels:
+;
+; Result = filter_image( image, FWHM=[3.7,5.2], /ALL )
+;
+; EXTERNAL CALLS:
+; function psf_gaussian
+; function convolve
+; pro factor
+; function prime ;all these called only if FWHM is specified
+;
+; PROCEDURE:
+; If both /ALL_PIXELS (or /ITERATE) keywords are set then
+; create a larger image by reflecting the edges outward, then call the
+; IDL MEDIAN() or SMOOTH() function on the larger image, and just return
+; the central part (the original size image).
+;
+; NAN values are recognized during calls to MEDIAN() or SMOOTH(), but
+; not for convolution with a Gaussian (FWHM keyword supplied).
+; HISTORY:
+; Written, 1991, Frank Varosi, NASA/GSFC.
+; FV, 1992, added /ITERATE option.
+; FV, 1993, added FWHM_GAUSSIAN= option.
+; Use /EVEN call to median, recognize NAN values in SMOOTH
+; W. Landsman June 2001
+; Added PSF keyword, Bjorn Heijligers/WL, September 2001
+; Keep same output data type if /ALL_PIXELS supplied A. Steffl Mar 2011
+;-
+ compile_opt idl2
+
+ if N_params() LT 1 then begin
+ print,'Syntax - Result = filter_image( image, SMOOTH=width, /ALL_PIXELS'
+ print,' MEDIAN= width, ITERATE, FWHM=, /NO_FT_CONVOL'
+ return, -1
+ endif
+
+ sim = size( image )
+ Lx = sim[1]-1
+ Ly = sim[2]-1
+
+ if (sim[0] NE 2) || (sim[4] LE 4) then begin
+ message,"input must be an image (a matrix)",/INFO
+ return,image
+ endif
+
+ if keyword_set( iterate ) then begin
+ if N_elements( width_smooth ) NE 1 then return,image
+ if (width_smooth LT 1) then return,image
+ imf = image
+ nit = (width_smooth>3)/2
+ for i=1,nit do imf = filter_image( imf, /SMOOTH, /ALL )
+ return,imf
+ endif
+
+ box_wid = 0
+ if keyword_set( width_smooth ) then box_wid = width_smooth > 3
+ if keyword_set( width_median ) then box_wid = (width_median > box_wid)>3
+
+ if keyword_set( fwhm ) then begin
+ npix = ( 3 * fwhm[ 0: ( (N_elements( fwhm )-1) < 1 ) ] ) > 3
+ npix = 2 * fix( npix/2 ) + 1 ;make # pixels odd.
+ box_wid = box_wid > max( [npix] )
+ endif
+
+ if (box_wid LT 3) then return, image
+
+ if keyword_set(all_pixels) then begin
+
+ box_wid = fix( box_wid )
+ radius = (box_wid/2) > 1
+ Lxr = Lx+radius
+ Lyr = Ly+radius
+ rr = 2*radius
+ imf = make_array(sim[1]+rr, sim[2]+rr, type = sim[3])
+ imf[radius,radius] = image ; reflect edges outward
+ ; to make larger image.
+ imf[ 0,0] = rotate( imf[radius:rr,*], 5 ) ;Left
+ imf[Lxr,0] = rotate( imf[Lx:Lxr,*], 5 ) ;right
+ imf[0, 0] = rotate( imf[*,radius:rr], 7 ) ;bottom
+ imf[0,Lyr] = rotate( imf[*,Ly:Lyr], 7 ) ;top
+
+ endif else begin
+ radius=0
+ imf = image
+ endelse
+
+ if keyword_set( width_median ) then $
+ imf = median(/even, imf, width_median>3 )
+
+ if keyword_set( width_smooth ) then $
+ imf = smooth( imf, width_smooth>3, /NAN )
+
+ if keyword_set( fwhm ) then begin
+
+ if N_elements( no_ft ) NE 1 then begin
+ sim = size( imf )
+ factor,sim[1],pfx,nfx,/quiet
+ factor,sim[2],pfy,nfy,/quiet
+ no_ft = max( [pfx,pfy] ) GT 13
+ endif
+
+ if N_elements(PSF) EQ 0 then $
+ psf=psf_gaussian( NP=npix,FWHM=fwhm,/NORM )
+
+ imf = convolve( imf, NO_FT=no_ft, psf)
+ endif
+
+ if radius GT 0 then $
+ return, imf[ radius:(Lx+radius), radius:(Ly+radius) ] $
+ else return, imf
+end
diff --git a/Code/script_idl_mv/astrolib/find.pro b/Code/script_idl_mv/astrolib/find.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1ed8d14e278d7e01b6214dbe5f05c6370024787
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/find.pro
@@ -0,0 +1,464 @@
+pro find, image, x, y, flux, sharp, roundness, hmin, fwhm, roundlim, sharplim,$
+ PRINT = print, SILENT=silent, MONITOR= monitor
+;+
+; NAME:
+; FIND
+; PURPOSE:
+; Find positive brightness perturbations (i.e stars) in an image
+; EXPLANATION:
+; Also returns centroids and shape parameters (roundness & sharpness).
+; Adapted from 1991 version of DAOPHOT, but does not allow for bad pixels
+; and uses a slightly different centroid algorithm.
+;
+; Modified in March 2008 to use marginal Gaussian fits to find centroids
+; CALLING SEQUENCE:
+; FIND, image, [ x, y, flux, sharp, round, hmin, fwhm, roundlim, sharplim
+; PRINT= , /SILENT, /MONITOR]
+;
+; INPUTS:
+; image - 2 dimensional image array (integer or real) for which one
+; wishes to identify the stars present
+;
+; OPTIONAL INPUTS:
+; FIND will prompt for these parameters if not supplied
+;
+; hmin - Threshold intensity for a point source - should generally
+; be 3 or 4 sigma above background RMS
+; fwhm - FWHM (in pixels) to be used in the convolve filter
+; sharplim - 2 element vector giving low and high cutoff for the
+; sharpness statistic (Default: [0.2,1.0] ). Change this
+; default only if the stars have significantly larger or
+; or smaller concentration than a Gaussian
+; roundlim - 2 element vector giving low and high cutoff for the
+; roundness statistic (Default: [-1.0,1.0] ). Change this
+; default only if the stars are significantly elongated.
+;
+; OPTIONAL INPUT KEYWORDS:
+; /MONITOR - Normally, FIND will display the results for each star
+; only if no output variables are supplied. Set /MONITOR
+; to always see the result of each individual star.
+; /SILENT - set /SILENT keyword to suppress all output display
+; PRINT - if set and non-zero then FIND will also write its results to
+; a file find.prt. Also one can specify a different output file
+; name by setting PRINT = 'filename'.
+;
+; OPTIONAL OUTPUTS:
+; x - vector containing x position of all stars identified by FIND
+; y- vector containing y position of all stars identified by FIND
+; flux - vector containing flux of identified stars as determined
+; by a Gaussian fit. Fluxes are NOT converted to magnitudes.
+; sharp - vector containing sharpness statistic for identified stars
+; round - vector containing roundness statistic for identified stars
+;
+; NOTES:
+; (1) The sharpness statistic compares the central pixel to the mean of
+; the surrounding pixels. If this difference is greater than the
+; originally estimated height of the Gaussian or less than 0.2 the height of the
+; Gaussian (for the default values of SHARPLIM) then the star will be
+; rejected.
+;
+; (2) More recent versions of FIND in DAOPHOT allow the possibility of
+; ignoring bad pixels. Unfortunately, to implement this in IDL
+; would preclude the vectorization made possible with the CONVOL function
+; and would run extremely slowly.
+;
+; (3) Modified in March 2008 to use marginal Gaussian distributions to
+; compute centroid. (Formerly, find.pro determined centroids by locating
+; where derivatives went to zero -- see cntrd.pro for this algorithm.
+; This was the method used in very old (~1984) versions of DAOPHOT. )
+; As discussed in more detail in the comments to the code, the centroid
+; computation here is the same as in IRAF DAOFIND but differs slightly
+; from the current DAOPHOT.
+; PROCEDURE CALLS:
+; GETOPT()
+; REVISION HISTORY:
+; Written W. Landsman, STX February, 1987
+; ROUND now an internal function in V3.1 W. Landsman July 1993
+; Change variable name DERIV to DERIVAT W. Landsman Feb. 1996
+; Use /PRINT keyword instead of TEXTOUT W. Landsman May 1996
+; Changed loop indices to type LONG W. Landsman Aug. 1997
+; Replace DATATYPE() with size(/TNAME) W. Landsman Nov. 2001
+; Fix problem when PRINT= filename W. Landsman October 2002
+; Fix problems with >32767 stars D. Schlegel/W. Landsman Sep. 2004
+; Fix error message when no stars found S. Carey/W. Landsman Sep 2007
+; Rewrite centroid computation to use marginal Gaussians W. Landsman
+; Mar 2008
+; Added Monitor keyword, /SILENT now suppresses all output
+; W. Landsman Nov 2008
+; Work when threshold is negative (difference images) W. Landsman May 2010
+;-
+;
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ npar = N_params()
+ if npar EQ 0 then begin
+ print,'Syntax - FIND, image,' + $
+ '[ x, y, flux, sharp, round, hmin, fwhm, roundlim, sharplim'
+ print,' PRINT= , /SILENT, /MONITOR ]'
+ return
+ endif
+;Determine if hardcopy output is desired
+ doprint = keyword_set( PRINT)
+ silent = keyword_set( SILENT )
+ if N_elements(monitor) EQ 0 then $
+ monitor = (not silent) and (not arg_present(flux) )
+
+ maxbox = 13 ;Maximum size of convolution box in pixels
+
+; Get information about the input image
+
+ type = size(image)
+ if ( type[0] NE 2 ) then message, $
+ 'ERROR - Image array (first parameter) must be 2 dimensional'
+ n_x = type[1] & n_y = type[2]
+ message, NoPrint=Silent, $
+ 'Input Image Size is '+strtrim(n_x,2) + ' by '+ strtrim(n_y,2),/INF
+
+ if ( N_elements(fwhm) NE 1 ) then $
+ read, 'Enter approximate FWHM: ', fwhm
+ if fwhm LT 0.5 then message, $
+ 'ERROR - Supplied FWHM must be at least 0.5 pixels'
+
+ radius = 0.637*FWHM > 2.001 ;Radius is 1.5 sigma
+ radsq = radius^2
+ nhalf = fix(radius) < (maxbox-1)/2 ;
+ nbox = 2*nhalf + 1 ;# of pixels in side of convolution box
+ middle = nhalf ;Index of central pixel
+
+ lastro = n_x - nhalf
+ lastcl = n_y - nhalf
+ sigsq = ( fwhm/2.35482 )^2
+ mask = bytarr( nbox, nbox ) ;Mask identifies valid pixels in convolution box
+ g = fltarr( nbox, nbox ) ;g will contain Gaussian convolution kernel
+
+ dd = indgen(nbox-1) + 0.5 - middle ;Constants need to compute ROUND
+ dd2 = dd^2
+
+ row2 = (findgen(Nbox)-nhalf)^2
+
+ for i = 0, nhalf do begin
+ temp = row2 + i^2
+ g[0,nhalf-i] = temp
+ g[0,nhalf+i] = temp
+ endfor
+
+
+ mask = fix(g LE radsq) ;MASK is complementary to SKIP in Stetson's Fortran
+ good = where( mask, pixels) ;Value of c are now equal to distance to center
+
+; Compute quantities for centroid computations that can be used for all stars
+ g = exp(-0.5*g/sigsq)
+
+; In fitting Gaussians to the marginal sums, pixels will arbitrarily be
+; assigned weights ranging from unity at the corners of the box to
+; NHALF^2 at the center (e.g. if NBOX = 5 or 7, the weights will be
+;
+; 1 2 3 4 3 2 1
+; 1 2 3 2 1 2 4 6 8 6 4 2
+; 2 4 6 4 2 3 6 9 12 9 6 3
+; 3 6 9 6 3 4 8 12 16 12 8 4
+; 2 4 6 4 2 3 6 9 12 9 6 3
+; 1 2 3 2 1 2 4 6 8 6 4 2
+; 1 2 3 4 3 2 1
+;
+; respectively). This is done to desensitize the derived parameters to
+; possible neighboring, brighter stars.
+
+
+ xwt = fltarr(nbox,nbox)
+ wt = nhalf - abs(findgen(nbox)-nhalf ) + 1
+ for i=0,nbox-1 do xwt[0,i] = wt
+ ywt = transpose(xwt)
+ sgx = total(g*xwt,1)
+ p = total(wt)
+ sgy = total(g*ywt,2)
+ sumgx = total(wt*sgy)
+ sumgy = total(wt*sgx)
+ sumgsqy = total(wt*sgy*sgy)
+ sumgsqx = total(wt*sgx*sgx)
+ vec = nhalf - findgen(nbox)
+ dgdx = sgy*vec
+ dgdy = sgx*vec
+ sdgdxs = total(wt*dgdx^2)
+ sdgdx = total(wt*dgdx)
+ sdgdys = total(wt*dgdy^2)
+ sdgdy = total(wt*dgdy)
+ sgdgdx = total(wt*sgy*dgdx)
+ sgdgdy = total(wt*sgx*dgdy)
+
+
+ c = g*mask ;Convolution kernel now in c
+ sumc = total(c)
+ sumcsq = total(c^2) - sumc^2/pixels
+ sumc = sumc/pixels
+ c[good] = (c[good] - sumc)/sumcsq
+ c1 = exp(-.5*row2/sigsq)
+ sumc1 = total(c1)/nbox
+ sumc1sq = total(c1^2) - sumc1
+ c1 = (c1-sumc1)/sumc1sq
+
+ message,/INF,Noprint=Silent, $
+ 'RELATIVE ERROR computed from FWHM ' + strtrim(sqrt(total(c[good]^2)),2)
+ if N_elements(hmin) NE 1 then read, $
+ 'Enter minimum value above background for threshold detection: ',hmin
+
+ if N_elements(sharplim) NE 2 then begin
+ print,'Enter low and high cutoffs, press [RETURN] for defaults:'
+GETSHARP:
+ ans = ''
+ read, 'Image Sharpness Statistic (DEFAULT = 0.2,1.0): ', ans
+ if ans EQ '' then sharplim = [0.2,1.0] else begin
+ sharplim = getopt(ans,'F')
+ if N_elements(sharplim) NE 2 then begin
+ message, 'ERROR - Expecting 2 scalar values',/CON
+ goto, GETSHARP
+ endif
+ endelse
+
+GETROUND:
+ ans = ''
+ read, 'Image Roundness Statistic [DEFAULT = -1.0,1.0]: ',ans
+ if ans EQ '' then roundlim = [-1.,1.] else begin
+ roundlim = getopt( ans, 'F' )
+ if N_elements( roundlim ) NE 2 then begin
+ message,'ERROR - Expecting 2 scalar values',/CON
+ goto, GETROUND
+ endif
+ endelse
+ endif
+
+ message,'Beginning convolution of image', /INF, NoPrint=Silent
+
+ h = convol(float(image),c) ;Convolve image with kernel "c"
+
+ minh = min(h)
+ h[0:nhalf-1,*] = minh & h[n_x-nhalf:n_x-1,*] = minh
+ h[*,0:nhalf-1] = minh & h[*,n_y-nhalf:n_y-1] = minh
+
+ message,'Finished convolution of image', /INF, NoPrint=Silent
+
+ mask[middle,middle] = 0 ;From now on we exclude the central pixel
+ pixels = pixels -1 ;so the number of valid pixels is reduced by 1
+ good = where(mask) ;"good" identifies position of valid pixels
+ xx= (good mod nbox) - middle ;x and y coordinate of valid pixels
+ yy = fix(good/nbox) - middle ;relative to the center
+ offset = yy*n_x + xx
+SEARCH: ;Threshold dependent search begins here
+
+ index = where( h GE hmin, nfound) ;Valid image pixels are greater than hmin
+ if nfound EQ 0 then begin ;Any maxima found?
+
+ message,'ERROR - No maxima exceed input threshold of ' + $
+ string(hmin,'(F9.1)'),/CON
+ goto,FINISH
+
+ endif
+
+ for i= 0L, pixels-1 do begin
+
+ stars = where (h[index] GE h[index+offset[i]], nfound)
+ if nfound EQ 0 then begin ;Do valid local maxima exist?
+ message,'ERROR - No maxima exceed input threshold of ' + $
+ string(hmin,'(F9.1)'),/CON
+ goto,FINISH
+ endif
+ index = index[stars]
+
+ endfor
+
+ ix = index mod n_x ;X index of local maxima
+ iy = index/n_x ;Y index of local maxima
+ ngood = N_elements(index)
+ message,/INF,Noprint=Silent, $
+ strtrim(ngood,2)+' local maxima located above threshold'
+
+ nstar = 0L ;NSTAR counts all stars meeting selection criteria
+ badround = 0L & badsharp=0L & badcntrd=0L
+ if (npar GE 2) or (doprint) then begin ;Create output X and Y arrays?
+ x = fltarr(ngood) & y = x
+ endif
+
+ if (npar GE 4) or (doprint) then begin ;Create output flux,sharpness arrays?
+ flux = x & sharp = x & roundness = x
+ endif
+
+ if doprint then begin ;Create output file?
+
+ if ( size(print,/TNAME) NE 'STRING' ) then file = 'find.prt' $
+ else file = print
+ message,'Results will be written to a file ' + file,/INF,Noprint=Silent
+ openw,lun,file,/GET_LUN
+ printf,lun,' Program: FIND '+ systime()
+ printf,lun,format='(/A,F7.1)',' Threshold above background:',hmin
+ printf,lun,' Approximate FWHM:',fwhm
+ printf,lun,format='(2(A,F6.2))',' Sharpness Limits: Low', $
+ sharplim[0], ' High',sharplim[1]
+ printf,lun,format='(2(A,F6.2))',' Roundness Limits: Low', $
+ roundlim[0],' High',roundlim[1]
+ printf,lun,format='(/A,i6)',' No of sources above threshold',ngood
+
+ endif
+
+ if (not SILENT) and MONITOR then $
+ print,format='(/8x,a)',' STAR X Y FLUX SHARP ROUND'
+
+; Loop over star positions; compute statistics
+
+ for i = 0L,ngood-1 do begin
+ temp = float(image[ix[i]-nhalf:ix[i]+nhalf,iy[i]-nhalf:iy[i]+nhalf])
+ d = h[ix[i],iy[i]] ;"d" is actual pixel intensity
+
+; Compute Sharpness statistic
+
+ sharp1 = (temp[middle,middle] - (total(mask*temp))/pixels)/d
+ if ( sharp1 LT sharplim[0] ) or ( sharp1 GT sharplim[1] ) then begin
+ badsharp = badsharp + 1
+ goto, REJECT ;Does not meet sharpness criteria
+ endif
+
+; Compute Roundness statistic
+
+ dx = total( total(temp,2)*c1)
+ dy = total( total(temp,1)*c1)
+ if (dx LE 0) or (dy LE 0) then begin
+ badround = badround + 1
+ goto, REJECT ;Cannot compute roundness
+ endif
+
+ around = 2*(dx-dy) / ( dx + dy ) ;Roundness statistic
+ if ( around LT roundlim[0] ) or ( around GT roundlim[1] ) then begin
+ badround = badround + 1
+ goto,REJECT ;Does not meet roundness criteria
+ endif
+
+;
+; Centroid computation: The centroid computation was modified in Mar 2008 and
+; now differs from DAOPHOT which multiplies the correction dx by 1/(1+abs(dx)).
+; The DAOPHOT method is more robust (e.g. two different sources will not merge)
+; especially in a package where the centroid will be subsequently be
+; redetermined using PSF fitting. However, it is less accurate, and introduces
+; biases in the centroid histogram. The change here is the same made in the
+; IRAF DAOFIND routine (see
+; http://iraf.net/article.php?story=7211&query=daofind )
+;
+
+ sd = total(temp*ywt,2)
+
+ sumgd = total(wt*sgy*sd)
+ sumd = total(wt*sd)
+ sddgdx = total(wt*sd*dgdx)
+
+ hx = (sumgd - sumgx*sumd/p) / (sumgsqy - sumgx^2/p)
+
+; HX is the height of the best-fitting marginal Gaussian. If this is not
+; positive then the centroid does not make sense
+
+ if (hx LE 0) then begin
+ badcntrd = badcntrd + 1
+ goto, REJECT
+ endif
+
+ skylvl = (sumd - hx*sumgx)/p
+ dx = (sgdgdx - (sddgdx-sdgdx*(hx*sumgx + skylvl*p)))/(hx*sdgdxs/sigsq)
+ if abs(dx) GE nhalf then begin
+ badcntrd = badcntrd + 1
+ goto, REJECT
+ endif
+
+ xcen = ix[i] + dx ;X centroid in original array
+
+; Find Y centroid
+
+ sd = total(temp*xwt,1)
+
+ sumgd = total(wt*sgx*sd)
+ sumd = total(wt*sd)
+
+ sddgdy = total(wt*sd*dgdy)
+
+ hy = (sumgd - sumgy*sumd/p) / (sumgsqx - sumgy^2/p)
+
+ if (hy LE 0) then begin
+ badcntrd = badcntrd + 1
+ goto, REJECT
+ endif
+
+ skylvl = (sumd - hy*sumgy)/p
+ dy = (sgdgdy - (sddgdy-sdgdy*(hy*sumgy + skylvl*p)))/(hy*sdgdys/sigsq)
+ if abs(dy) GE nhalf then begin
+ badcntrd = badcntrd + 1
+ goto, REJECT
+ endif
+
+ ycen = iy[i] +dy ;Y centroid in original array
+
+
+; This star has met all selection criteria. Print out and save results
+
+ if monitor then $
+ print,FORM = '(12x,i5,2f7.1,f9.1,2f9.2)', $
+ nstar, xcen, ycen, d, sharp1, around
+
+ if (npar GE 2) or (doprint) then begin
+ x[nstar] = xcen & y[nstar] = ycen
+ endif
+
+ if ( npar GE 4 ) or (doprint) then begin
+ flux[nstar] = d & sharp[nstar] = sharp1 & roundness[nstar] = around
+ endif
+
+ nstar = nstar+1
+
+REJECT:
+ endfor
+
+ nstar = nstar-1 ;NSTAR is now the index of last star found
+
+ if doprint then begin
+ printf,lun,' No. of sources rejected by SHARPNESS criteria',badsharp
+ printf,lun,' No. of sources rejected by ROUNDNESS criteria',badround
+ printf,lun,' No. of sources rejected by CENTROID criteria',badcntrd
+ endif
+
+if (not SILENT) and (MONITOR) then begin
+ print,' No. of sources rejected by SHARPNESS criteria',badsharp
+ print,' No. of sources rejected by ROUNDNESS criteria',badround
+ print,' No. of sources rejected by CENTROID criteria',badcntrd
+endif
+
+ if nstar LT 0 then return ;Any stars found?
+
+ if (npar GE 2) or (doprint) then begin
+ x=x[0:nstar] & y = y[0:nstar]
+ endif
+
+ if (npar GE 4) or (doprint) then begin
+ flux= flux[0:nstar] & sharp=sharp[0:nstar]
+ roundness = roundness[0:nstar]
+ endif
+
+ if doprint then begin
+ printf,lun, $
+ format = '(/8x,a)',' STAR X Y FLUX SHARP ROUND'
+ for i = 0L, nstar do $
+ printf,lun,format='(12x,i5,2f8.2,f9.1,2f9.2)', $
+ i+1, x[i], y[i], flux[i], sharp[i], roundness[i]
+ free_lun, lun
+ endif
+
+FINISH:
+
+ if SILENT or (not MONITOR) then return
+
+ print,form='(A,F8.1)',' Threshold above background for this pass was',hmin
+ ans = ''
+ read,'Enter new threshold or [RETURN] to exit: ',ans
+ ans = getopt(ans,'F')
+ if ans GT 0. then begin
+ hmin = ans
+ goto, SEARCH
+ endif
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/find_all_dir.pro b/Code/script_idl_mv/astrolib/find_all_dir.pro
new file mode 100644
index 0000000000000000000000000000000000000000..61ce95878f140670f3cf8f124bf4eeb0ae0a6c08
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/find_all_dir.pro
@@ -0,0 +1,202 @@
+ FUNCTION FIND_ALL_DIR, PATH, PATH_FORMAT=PATH_FORMAT, $
+ PLUS_REQUIRED=PLUS_REQUIRED, RESET=RESET
+;+
+; NAME:
+; FIND_ALL_DIR()
+; PURPOSE:
+; Finds all directories under a specified directory.
+; EXPLANATION:
+; This routine finds all the directories in a directory tree when the
+; root of the tree is specified. This provides the same functionality as
+; having a directory with a plus in front of it in the environment
+; variable IDL_PATH.
+;
+; CALLING SEQUENCE:
+; Result = FIND_ALL_DIR( PATH )
+;
+; PATHS = FIND_ALL_DIR('+mypath', /PATH_FORMAT)
+; PATHS = FIND_ALL_DIR('+mypath1:+mypath2')
+;
+; INPUTS:
+; PATH = The path specification for the top directory in the tree.
+; Optionally this may begin with the '+' character but the action
+; is the same unless the PLUS_REQUIRED keyword is set.
+;
+; One can also path a series of directories separated
+; by the correct character ("," for VMS, ":" for Unix)
+;
+; OUTPUTS:
+; The result of the function is a list of directories starting from the
+; top directory passed and working downward from there. Normally, this
+; will be a string array with one directory per array element, but if
+; the PATH_FORMAT keyword is set, then a single string will be returned,
+; in the correct format to be incorporated into !PATH.
+;
+; OPTIONAL INPUT KEYWORDS:
+; PATH_FORMAT = If set, then a single string is returned, in
+; the format of !PATH.
+;
+; PLUS_REQUIRED = If set, then a leading plus sign is required
+; in order to expand out a directory tree.
+; This is especially useful if the input is a
+; series of directories, where some components
+; should be expanded, but others shouldn't.
+;
+; RESET = Often FIND_ALL_DIR is used with logical names. It
+; can be rather slow to search through these subdirectories.
+; The /RESET keyword can be used to redefine an environment
+; variable so that subsequent calls don't need to look for the
+; subdirectories.
+;
+; To use /RESET, the PATH parameter must contain the name of a
+; *single* environment variable. For example
+;
+; setenv,'FITS_DATA=+/datadisk/fits'
+; dir = find_all_dir('FITS_DATA',/reset,/plus)
+;
+; The /RESET keyword is usually combined with /PLUS_REQUIRED.
+;
+; PROCEDURE CALLS:
+; DEF_DIRLIST, FIND_WITH_DEF(), BREAK_PATH()
+;
+; RESTRICTIONS:
+; PATH must point to a directory that actually exists.
+;
+; REVISION HISTORY:
+; Version 11, Zarro (SM&A/GSFC), 23-March-00
+; Removed all calls to IS_DIR
+; Version 12, William Thompson, GSFC, 02-Feb-2001
+; In Windows, use built-in expand_path if able.
+; Version 13, William Thompson, GSFC, 23-Apr-2002
+; Follow logical links in Unix
+; (Suggested by Pascal Saint-Hilaire)
+; Version 14, Zarro (EER/GSFC), 26-Oct-2002
+; Saved/restored current directory to protect against
+; often mysterious directory changes caused by
+; spawning FIND in Unix
+; Version 15, William Thompson, GSFC, 9-Feb-2004
+; Resolve environment variables in Windows.
+;
+; Version : Version 16 W. Landsman GSFC Sep 2006
+; Remove VMS support
+;-
+;
+ ON_ERROR, 2
+ compile_opt idl2
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE, $
+ 'Syntax: Result = FIND_ALL_DIR( PATH )'
+
+;-- save current directory
+
+ cd,current=current
+
+;
+; If more than one directory was passed, then call this routine reiteratively.
+; Then skip directly to the test for the PATH_FORMAT keyword.
+;
+ PATHS = BREAK_PATH(PATH, /NOCURRENT)
+ IF N_ELEMENTS(PATHS) GT 1 THEN BEGIN
+ DIRECTORIES = FIND_ALL_DIR(PATHS[0], $
+ PLUS_REQUIRED=PLUS_REQUIRED)
+ FOR I = 1,N_ELEMENTS(PATHS)-1 DO DIRECTORIES = $
+ [DIRECTORIES, FIND_ALL_DIR(PATHS[I], $
+ PLUS_REQUIRED=PLUS_REQUIRED)]
+ GOTO, TEST_FORMAT
+ ENDIF
+;
+; Test to see if the first character is a plus sign. If it is, then remove
+; it. If it isn't, and PLUS_REQUIRED is set, then remove any trailing '/'
+; character and skip to the end.
+;
+ DIR = PATHS[0]
+ IF STRMID(DIR,0,1) EQ '+' THEN BEGIN
+ DIR = STRMID(DIR,1,STRLEN(DIR)-1)
+ END ELSE IF KEYWORD_SET(PLUS_REQUIRED) THEN BEGIN
+ DIRECTORIES = PATH
+ IF STRMID(PATH,STRLEN(PATH)-1,1) EQ '/' THEN $
+ DIRECTORIES = STRMID(PATH,0,STRLEN(PATH)-1)
+ GOTO, TEST_FORMAT
+ ENDIF
+;
+; For windows, use the built-in EXPAND_PATH program. However, first
+; resolve any environment variables.
+;
+ IF !VERSION.OS_FAMILY EQ 'Windows' THEN BEGIN
+ WHILE STRMID(DIR,0,1) EQ '$' DO BEGIN
+ FSLASH = STRPOS(DIR,'/')
+ IF FSLASH LT 1 THEN FSLASH = STRLEN(DIR)
+ BSLASH = STRPOS(DIR,'/')
+ IF BSLASH LT 1 THEN BSLASH = STRLEN(DIR)
+ SLASH = FSLASH < BSLASH
+ TEST = STRMID(DIR,1,SLASH-1)
+ DIR = GETENV(TEST) + STRMID(DIR,SLASH,STRLEN(DIR)-SLASH)
+ ENDWHILE
+ TEMP = DIR
+ TEST = STRMID(TEMP, STRLEN(TEMP)-1, 1)
+ IF (TEST EQ '/') OR (TEST EQ '\') THEN $
+ TEMP = STRMID(TEMP,0,STRLEN(TEMP)-1)
+ DIRECTORIES = EXPAND_PATH('+' + TEMP, /ALL, /ARRAY)
+;
+; On Unix machines spawn the Bourne shell command 'find'. First, if the
+; directory name starts with a dollar sign, then try to interpret the
+; following environment variable. If the result is the null string, then
+; signal an error.
+;
+ END ELSE BEGIN
+ IF STRMID(DIR,0,1) EQ '$' THEN BEGIN
+ SLASH = STRPOS(DIR,'/')
+ IF SLASH LT 0 THEN SLASH = STRLEN(DIR)
+ EVAR = GETENV(STRMID(DIR,1,SLASH-1))
+ IF SLASH EQ STRLEN(DIR) THEN DIR = EVAR ELSE $
+ DIR = EVAR + STRMID(DIR,SLASH,STRLEN(DIR)-SLASH)
+ ENDIF
+; IF IS_DIR(DIR) NE 1 THEN MESSAGE, $
+; 'A valid directory must be passed'
+ IF STRMID(DIR,STRLEN(DIR)-1,1) NE '/' THEN DIR = DIR + '/'
+ SPAWN,'find ' + DIR + ' -follow -type d -print | sort -', $
+ DIRECTORIES, /SH
+;
+; Remove any trailing slash character from the first directory.
+;
+ TEMP = DIRECTORIES[0]
+ IF STRMID(TEMP,STRLEN(TEMP)-1,1) EQ '/' THEN $
+ DIRECTORIES[0] = STRMID(TEMP,0,STRLEN(TEMP)-1)
+ ENDELSE
+;
+; Reformat the string array into a single string, with the correct separator.
+; If the PATH_FORMAT keyword was set, then this string will be used. Also use
+; it when the RESET keyword was passed.
+;
+TEST_FORMAT:
+ DIR = DIRECTORIES[0]
+ CASE !VERSION.OS_FAMILY OF
+ 'Windows': SEP = ';'
+ 'MacOS': Sep = ','
+ ELSE: SEP = ':'
+ ENDCASE
+ FOR I = 1,N_ELEMENTS(DIRECTORIES)-1 DO DIR = DIR + SEP + DIRECTORIES[I]
+;
+; If the RESET keyword is set, and the PATH variable contains a *single*
+; environment variable, then call SETENV to redefine the environment variable.
+; If the string starts with a $, then try it both with and without the $.
+;
+ IF KEYWORD_SET(RESET) THEN BEGIN
+ EVAR = PATH
+ TEST = GETENV(EVAR)
+ IF TEST EQ '' THEN IF STRMID(EVAR,0,1) EQ '$' THEN BEGIN
+ EVAR = STRMID(EVAR,1,STRLEN(EVAR)-1)
+ TEST = GETENV(EVAR)
+ ENDIF
+ IF (TEST NE '') AND (TEST NE PATH) AND (DIR NE PATH) THEN $
+ SETENV, STRTRIM(EVAR,2) + '=' + $
+ STRTRIM(STRJOIN(DIR,':'),2)
+ ENDIF
+;
+;-- restore current directory
+
+ cd,current
+
+ IF KEYWORD_SET(PATH_FORMAT) THEN RETURN, DIR ELSE RETURN, DIRECTORIES
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/find_with_def.pro b/Code/script_idl_mv/astrolib/find_with_def.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1fa4ade0328f90792f2146c821d4a973e072f825
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/find_with_def.pro
@@ -0,0 +1,153 @@
+ FUNCTION FIND_WITH_DEF, FILENAME, PATHS, EXTENSIONS, $
+ NOCURRENT=NOCURRENT, RESET=RESET
+;+
+; NAME:
+; FIND_WITH_DEF()
+; PURPOSE:
+; Searches for files with a default path and extension.
+; EXPLANATION:
+; Finds files using default paths and extensions, Using this routine
+; together with environment variables allows an OS-independent approach
+; to finding files.
+; CALLING SEQUENCE:
+; Result = FIND_WITH_DEF( FILENAME, PATHS [, EXTENSIONS ] )
+;
+; INPUTS:
+; FILENAME = Name of file to be searched for. It may either be a
+; complete filename, or the path or extension could be left
+; off, in which case the routine will attempt to find the
+; file using the default paths and extensions.
+;
+; PATHS = One or more default paths to use in the search in case
+; FILENAME does not contain a path itself. The individual
+; paths are separated by commas, although in UNIX, colons
+; can also be used. In other words, PATHS has the same
+; format as !PATH, except that commas can be used as a
+; separator regardless of operating system. The current
+; directory is always searched first, unless the keyword
+; NOCURRENT is set.
+;
+; A leading $ can be used in any path to signal that what
+; follows is an environmental variable, but the $ is not
+; necessary. Environmental variables can themselves contain
+; multiple paths.
+;
+; OPTIONAL INPUTS:
+; EXTENSIONS = Scalar string giving one or more extensions to append to
+; end of filename if the filename does not contain one (e.g.
+; ".dat"). The period is optional. Multiple extensions can
+; be separated by commas or colons.
+; OUTPUTS:
+; The result of the function is the name of the file if successful, or
+; the null string if unsuccessful.
+; OPTIONAL INPUT KEYWORDS:
+; NOCURRENT = If set, then the current directory is not searched.
+;
+; RESET = The FIND_WITH_DEF routine supports paths which are
+; preceeded with the plus sign to signal that all
+; subdirectories should also be searched. Often this is
+; used with logical names. It can be rather slow to search
+; through these subdirectories. The /RESET keyword can be
+; used to redefine an environment variable so that
+; subsequent calls don't need to look for the
+; subdirectories.
+;
+; To use /RESET, the PATHS parameter must contain the name
+; of a *single* environment variable. For example
+;
+; setenv,'FITS_DATA=+/datadisk/fits'
+; file = find_with_def('test.fits','FITS_DATA',/reset)
+;
+; EXAMPLE:
+;
+; FILENAME = ''
+; READ, 'File to open: ', FILENAME
+; FILE = FIND_WITH_DEF( FILENAME, 'SERTS_DATA', '.fix' )
+; IF FILE NE '' THEN ...
+;
+;
+; PROCEDURE CALLS:
+; BREAK_PATH(), FIND_ALL_DIR(), STR_SEP()
+; REVISION HISTORY:
+; Version 1, William Thompson, GSFC, 3 May 1993.
+; Removed trailing / and : characters.
+; Fixed bugs
+; Allow for commas within values of logical names.
+; Added keyword NOCURRENT.
+; Changed to call BREAK_PATH
+; Version 2, William Thompson, GSFC, 3 November 1994
+; Made EXTENSIONS optional.
+; Version 3, William Thompson, GSFC, 30 April 1996
+; Call FIND_ALL_DIR to resolve any plus signs.
+; Version 4, S.V. Haugan, UiO, 5 June 1996
+; Using OPENR,..,ERROR=ERROR to avoid an IDL 3.6
+; internal nesting error.
+; Version 5, R.A. Schwartz, GSFC, 11 July 1996
+; Use SPEC_DIR to interpret PATH under VMS
+; Version 6, William Thompson, GSFC, 5 August 1996
+; Took out call to SPEC_DIR (i.e., reverted to version 4). The
+; use of SPEC_DIR was required to support logical names defined
+; via SETLOG,/CONFINE. However, it conflicted with the ability
+; to use logical names with multiple values. Removing the
+; /CONFINE made it unnecessary to call SPEC_DIR in this routine.
+; Version 7, William Thompson, GSFC, 6 August 1996
+; Added keyword RESET
+; Converted to IDL V5.0 W. Landsman October 1997
+; Use STRTRIM instead of TRIM, W. Landsman November 1998
+; Use STRSPLIT instead of STR_SEP W. Landsman July 2002
+;-
+;
+ ON_ERROR, 2
+;
+; Check the number of parameters:
+;
+ IF N_PARAMS() LT 2 THEN MESSAGE, 'Syntax: Result = ' + $
+ 'FIND_WITH_DEF(FILENAME, PATHS [, EXTENSIONS])'
+;
+; If there are any plus signs, then expand them.
+;
+ PATH = FIND_ALL_DIR(PATHS, /PLUS_REQUIRED, /PATH, RESET=RESET)
+;
+; Reformat PATHS into an array. The first element is the null string.
+;
+ PATH = BREAK_PATH(PATH)
+;
+; If NOCURRENT was set, then remove the first (blank) entry from the PATH
+; array.
+;
+ IF KEYWORD_SET(NOCURRENT) THEN PATH = PATH[1:*]
+;
+; Reformat EXTENSIONS into an array. The first element is the null string.
+;
+ EXT = ''
+ IF N_PARAMS() EQ 3 THEN $
+ EXT = ['',STRSPLIT(EXTENSIONS,',:',/EXTRACT)]
+;
+; Make sure that the extensions begin with a period.
+;
+ FOR I = 0,N_ELEMENTS(EXT)-1 DO IF EXT[I] NE '' THEN $
+ IF STRMID(EXT[I],0,1) NE '.' THEN EXT[I] = '.' + EXT[I]
+;
+; Set up variables used by the loops below.
+;
+ I_PATH = -1
+ GET_LUN, UNIT
+ FNAME = STRTRIM(FILENAME,2) + EXT
+;
+; Step through each of the paths.
+;
+ FOR I_PATH = 0, N_ELEMENTS(PATH)- 1 DO BEGIN
+;
+; If the file is found then terminate the loop and clean up.
+;
+ FILE = FILE_SEARCH(PATH[I_PATH] + FNAME, COUNT = COUNT)
+ IF COUNT GT 0 THEN BREAK
+ ENDFOR
+;
+; Otherwise, we jump directly to here when we find a file.
+;
+DONE:
+ FREE_LUN, UNIT
+ !ERR = COUNT
+ RETURN, FILE[0]
+ END
diff --git a/Code/script_idl_mv/astrolib/findpro.pro b/Code/script_idl_mv/astrolib/findpro.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7f00a89647086f9064d0e511a3ac2825170e3a67
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/findpro.pro
@@ -0,0 +1,173 @@
+pro FindPro, Proc_Name, NoPrint=NoPrint, DirList=DirList, ProList=ProList
+;+
+; NAME:
+; FINDPRO
+; PURPOSE:
+; Find all locations of a procedure in the IDL !PATH
+; EXPLANATION:
+; FINDPRO searces for the procedure name (as a .pro or a .sav file) in all
+; IDL libraries or directories given in the !PATH system variable. This
+; differs from the intrinsic FILE_WHICH() function which only finds the
+; first occurence of the procedure name.
+;
+; CALLING SEQUENCE:
+; FINDPRO, [ Proc_Name, /NoPrint, DirList = , ProList = ]
+;
+; OPTIONAL INPUT:
+; Proc_Name - Character string giving the name of the IDL procedure or
+; function. Do not include the ".pro" extension. If Proc_Name is
+; omitted, the program will prompt for PROC_NAME. "*" wildcards
+; are permitted.
+;
+; OPTIONAL KEYWORD INPUT:
+; /NoPrint - if set, then the file's path is not printed on the screen and
+; absolutely no error messages are printed on the screen. If not
+; set, then - since the MESSAGE routine is used - error messages
+; will be printed but the printing of informational messages
+; depends on the value of the !Quiet variable.
+;
+; OPTIONAL KEYWORD OUTPUTS:
+; DirList - The directories in which the file is located are returned in
+; the keyword as a string array.
+; If the procedure is an intrinsic IDL procedure, then the
+; value of DirList = ['INTRINSIC'].
+; If the procedure is not found, the value of DirList = [''].
+; ProList - The list (full pathnames) of procedures found. Useful if you
+; are looking for the name of a procedure using wildcards.
+;
+; The order of the names in DirList and ProList is identical to the order
+; in which the procedure name appears in the !PATH
+; PROCEDURE:
+; The system variable !PATH is parsed using EXPAND_PATH into individual
+; directories. FILE_SEARCH() is used to search the directories for
+; the procedure name. If not found in !PATH, then the name is compared
+; with the list of intrinsic IDL procedures given by the ROUTINE_INFO()
+; function.
+;
+; EXAMPLE:
+; (1) Find the procedure CURVEFIT. Assume for this example that the user
+; also has a copy of the curvefit.pro procedure in her home directory
+; on a Unix machine.
+;
+; IDL> findpro, 'curvefit', DIRLIST=DirList
+; Procedure curvefit.pro found in directory /home/user/.
+; Procedure curvefit.pro found in directory /software/IDL/idl82/lib/
+; IDL> help, DirList
+; DIRLIST STRING = Array(2)
+; IDL> help, DirList[0], DirList[1]
+; STRING = '/home/user'
+; STRING = '/software/IDL/idl82/lib/'
+;
+; (2) Find all procedures in one's !path containing the characters "zoom"
+;
+; IDL> findpro,'*zoom*'
+; RESTRICTIONS:
+; User will be unable to find a path for a native IDL function
+; or procedure, or for a FORTRAN or C routine added with CALL_EXTERNAL.
+; Remember that Unix is case sensitive, and most procedures will be in
+; lower case.
+; PROCEDURES USED:
+; FDECOMP -- Decompose file name
+;
+; REVISION HISTORY:
+; Based on code extracted from the GETPRO procedure, J. Parker 1994
+; Use the intrinsic EXPAND_PATH function W. Landsman Nov. 1994
+; Use ROUTINE_NAMES() to check for intrinsic procs W. Landsman Jul 95
+; Added Macintosh, WINDOWS compatibility W. Landsman Sep. 95
+; Removed spurious first element in PROLIST W. Landsman March 1997
+; Don't include duplicate directories in !PATH WL May 1997
+; Use ROUTINE_INFO instead of undocumented ROUTINE_NAMES W.L. October 1998
+; Also check for save sets W. Landsman October 1999
+; Force lower case check for VMS W. Landsman January 2000
+; Only return .pro or .sav files in PROLIST W. Landsman January 2002
+; Force lower case check for .pro and .sav D. Swain September 2002
+; Use FILE_SEARCH() if V5.5 or later W. Landsman June 2006
+; Assume since V55, remove VMS support W. Landsman Sep. 2006
+; Assume since V6.0, use file_basename() W.Landsman Feb 2009
+; Specify whether an intrinsic function or procedure W.L. Jan 2013
+;
+;-
+;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+
+ On_error,2 ;Return to caller on error
+ compile_opt idl2
+
+ if (N_params() EQ 0) then begin ;Prompt for procedure name?
+ Proc_Name = ' '
+ read,'Enter name of procedure for which you want the path: ',Proc_Name
+ endif else $
+ if (size(proc_name,/type) NE 7 ) && (N_elements(proc_name) NE 1) then $
+ message,'ERROR - First parameter (.pro name) must be a scalar string'
+
+ NoPrint = keyword_set(NoPrint)
+
+ Name = strtrim( file_basename(proc_name,'.pro'), 2 )
+
+; Set up separate file and directory separators for current OS
+
+ psep = path_sep()
+
+ pathdir = expand_path(!PATH,/ARRAY, Count = N_dir)
+ cd,current = dir
+
+; Remove duplicate directories in !PATH but keep original order
+ path_dir = [dir]
+ for i = 0,N_dir -1 do begin
+ test = where(path_dir EQ pathdir[i], Ndup)
+ if Ndup EQ 0 then path_dir = [path_dir,pathdir[i]]
+ endfor
+ N_dir = N_elements(path_dir)
+
+; Use FILE_PATH() to search all directories for .pro or .sav files
+
+ ProList = file_search(path_dir + psep + name + '.{pro,sav}', COUNT=Nfile)
+
+ if (Nfile ge 1) then begin ;Found by FILE_SEARCH?
+ fdecomp, ProList, ddisk,ddir,fname,ext
+ dirlist = ddisk + ddir
+ found = 1b
+ for j = 0,nfile-1 do begin
+ case strlowcase(ext[j]) of
+ 'pro': message,/Con, NoPrint = NoPrint,/NoPrefix, /Noname, $
+ 'Procedure ' + fname[j] + ' found in directory ' + dirlist[j]
+ 'sav': message,/Con,NoPrint = NoPrint,/NoPrefix, /Noname, $
+ 'Save set ' + fname[j] + '.sav found in directory ' + dirlist[j]
+ endcase
+ endfor
+ endif else begin
+
+
+; At this point !PATH has been searched. If the procedure was not found
+; check if it is an intrinsic IDL procedure or function
+
+ funcnames = routine_info(/system,/func)
+ fcount = ~array_equal( funcnames NE strupcase(name), 1b )
+; test = where ( funcnames EQ strupcase(name), fcount) Slower method
+
+ funcnames = routine_info(/system)
+ pcount = ~array_equal( funcnames NE strupcase(name) , 1b)
+;
+
+ if (fcount EQ 0) && (pcount EQ 0) then begin
+ prolist = strarr(1)
+ dirlist = strarr(1)
+ if ~NoPrint then begin
+ message, 'Procedure '+Name+' not found in a !PATH directory.', /CONT
+ message, 'Check your spelling or search individual directories.', /INF
+ endif
+ endif else begin
+ DirList = ['INTRINSIC']
+ ProList = ['INTRINSIC']
+ if ~NoPrint then begin
+ if pcount NE 0 then $
+ message, 'Procedure ' + Name + ' is an intrinsic IDL procedure.', $
+ /CONT else $
+ message, 'Procedure ' + Name + ' is an intrinsic IDL function.',/CONT
+ message, 'No path information available.', /INF
+ endif
+ endelse
+
+ endelse
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/fitexy.pro b/Code/script_idl_mv/astrolib/fitexy.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5acf3127654b17b258ed6af112690bd1f5a33115
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fitexy.pro
@@ -0,0 +1,205 @@
+;+
+; NAME:
+; FITEXY
+; PURPOSE:
+; Best straight-line fit to data with errors in both coordinates
+; EXPLANATION:
+; Linear Least-squares approximation in one-dimension (y = a + b*x),
+; when both x and y data have errors Users might be interested in
+; Michael Williams MPFITEXY routines which include a number of
+; enhancements to FITEXY.
+; ( http://user.astro.columbia.edu/~williams/mpfitexy/ )
+;
+;
+; CALLING EXAMPLE:
+; FITEXY, x, y, A, B, X_SIG= , Y_SIG= , [sigma_A_B, chi_sq, q, TOL=]
+;
+; INPUTS:
+; x = array of values for independent variable.
+; y = array of data values assumed to be linearly dependent on x.
+;
+; REQUIRED INPUT KEYWORDS:
+; X_SIGMA = scalar or array specifying the standard deviation of x data.
+; Y_SIGMA = scalar or array specifying the standard deviation of y data.
+;
+; OPTIONAL INPUT KEYWORD:
+; TOLERANCE = desired accuracy of minimum & zero location, default=1.e-3.
+;
+; OUTPUTS:
+; A_intercept = constant parameter result of linear fit,
+; B_slope = slope parameter, so that:
+; ( A_intercept + B_slope * x ) approximates the y data.
+; OPTIONAL OUTPUT:
+; sigma_A_B = two element array giving standard deviation of
+; A_intercept and B_slope parameters, respectively.
+; The standard deviations are not meaningful if (i) the
+; fit is poor (see parameter q), or (ii) b is so large that
+; the data are consistent with a vertical (infinite b) line.
+; If the data are consistent with *all* values of b, then
+; sigma_A_B = [1e33,e33]
+; chi_sq = resulting minimum Chi-Square of Linear fit, scalar
+; q - chi-sq probability, scalar (0-1) giving the probability that
+; a correct model would give a value equal or larger than the
+; observed chi squared. A small value of q indicates a poor
+; fit, perhaps because the errors are underestimated. As
+; discussed by Tremaine et al. (2002, ApJ, 574, 740) an
+; underestimate of the errors (e.g. due to an intrinsic dispersion)
+; can lead to a bias in the derived slope, and it may be worth
+; enlarging the error bars to get a reduced chi_sq ~ 1
+;
+; COMMON:
+; common fitexy, communicates the data for computation of chi-square.
+;
+; PROCEDURE CALLS:
+; CHISQ_FITEXY() ;Included in this file
+; MINF_BRACKET, MINF_PARABOLIC, ZBRENT ;In IDL Astronomy Library
+; MOMENT(), CHISQR_PDF() ;In standard IDL distribution
+;
+; PROCEDURE:
+; From "Numerical Recipes" column by Press and Teukolsky:
+; in "Computer in Physics", May, 1992 Vol.6 No.3
+; Also see the 2nd edition of the book "Numerical Recipes" by Press et al.
+;
+; In order to avoid problems with data sets where X and Y are of very
+; different order of magnitude the data are normalized before the fitting
+; process is started. The following normalization is used:
+; xx = (x - xm) / xs and sigx = x_sigma / xs
+; where xm = MEAN(x) and xs = STDDEV(x)
+; yy = (y - ym) / ys and sigy = y_sigma / ys
+; where ym = MEAN(y) and ys = STDDEV(y)
+;
+;
+; MODIFICATION HISTORY:
+; Written, Frank Varosi NASA/GSFC September 1992.
+; Now returns q rather than 1-q W. Landsman December 1992
+; Use CHISQR_PDF, MOMENT instead of STDEV,CHI_SQR1 W. Landsman April 1998
+; Fixed typo for initial guess of slope, this error was nearly
+; always insignificant W. Landsman March 2000
+; Normalize X,Y before calculation (from F. Holland) W. Landsman Nov 2006
+;-
+function chisq_fitexy, B_angle
+;
+; NAME:
+; chisq_fitexy
+; PURPOSE:
+; Function minimized by fitexy (computes chi-square of linear fit).
+; It is called by minimization procedures during execution of fitexy.
+; CALLING SEQUENCE:
+; chisq = chisq_fitexy( B_angle )
+; INPUTS:
+; B_angle = arc-tangent of B_slope of linear fit.
+; OUTPUTS:
+; Result of function = chi_square - offs (offs is in COMMON).
+; COMMON:
+; common fitexy, communicates the data from pro fitexy.
+; PROCEDURE:
+; From "Numerical Recipes" column: Computer in Physics Vol.6 No.3
+; MODIFICATION HISTORY:
+; Written, Frank Varosi NASA/GSFC 1992.
+
+ common fitexy, xx, yy, sigx, sigy, ww, Ai, offs
+
+ B_slope = tan( B_angle )
+ ww = 1/( ( (B_slope * sigx)^2 + sigy^2 ) > 1.e-30 )
+ if N_elements( ww ) EQ 1 then sumw = ww * N_elements( xx ) $
+ else sumw = total( ww )
+ y_Bx = yy - B_slope * xx
+ Ai = total( ww * y_Bx )/sumw
+
+return, total( ww * (y_Bx - Ai)^2 ) - offs
+end
+;-------------------------------------------------------------------------------
+pro fitexy, x, y, A_intercept, B_slope, sigma_A_B, chi_sq, q, TOLERANCE=Tol, $
+ X_SIGMA=x_sigma, Y_SIGMA=y_sigma
+ compile_opt idl2
+ common fitexy, xx, yy, sigx, sigy, ww, Ai, offs
+
+ if N_params() LT 4 then begin
+ print,'Syntax - fitexy, x, y, A, B, X_SIG=sigx, Y_SIG=sigy,'
+ print,' [sigma_A_B, chi_sq, q, TOLERANCE = ]'
+ return
+ endif
+
+; Normalize data before running fitexy
+
+ xm = (MOMENT(x, SDEV = xs, /DOUBLE))[0]
+ ym = (MOMENT(y, SDEV = ys, /DOUBLE))[0]
+ xx = (x - xm) / xs
+ yy = (y - ym) / ys
+ sigx = x_sigma / xs
+ sigy = y_sigma / ys
+
+
+;Compute first guess for B_slope using standard 1-D Linear Least-squares fit,
+; where the non-linear term involving errors in x are ignored.
+; (note that Tx is a transform to reduce roundoff errors)
+
+ ww = sigx^2 + sigy^2
+ if N_elements( ww ) EQ 1 then sumw = ww * N_elements( xx ) $
+ else sumw = total( ww )
+ Sx = total( xx * ww )
+ Tx = xx - Sx/sumw
+ B = total( ww * yy * Tx ) / total( ww * Tx^2 )
+
+;Find the minimum chi-sq while including the non-linear term (B * sigx)^2
+; involving variance in x data (computed by function chisq_fitexy):
+; using minf_bracket (=MNBRAK) and minf_parabolic (=BRENT)
+ offs = 0
+ ang = [ 0, atan( B ), 1.571 ]
+ chi = fltarr( 3 )
+ for j=0,2 do chi[j] = chisq_fitexy( ang[j] ) ;this is for later...
+ if N_elements( Tol ) NE 1 then Tol=1.e-3
+ a0 = ang[0]
+ a1 = ang[1]
+ minf_bracket, a0,a1,a2, c0,c1,c2, FUNC="chisq_fitexy"
+ minf_parabolic, a0,a1,a2, Bang, chi_sq, FUNC="chisq_fitexy", TOL=Tol
+
+ if N_params() EQ 7 then q = 1 - chisqr_pdf( chi_sq, N_elements(x) - 2 )
+ A_intercept = Ai ;computed in function chisq_fitexy
+ ang = [a0,a1,a2,ang]
+ chi = [c0,c1,c2,chi]
+
+;Now compute the variances of estimated parameters,
+; by finding roots of ( (chi_sq + 1) - chisq_fitexy ).
+;Note: ww, Ai are computed in function chisq_fitexy.
+
+ offs = chi_sq + 1
+ wc = where( chi GT offs, nc )
+
+ if (nc GT 0) then begin
+
+ angw = [ang[wc]]
+ d1 = abs( angw - Bang ) MOD !PI
+ d2 = !PI - d1
+ wa = where( angw LT Bang, na )
+
+ if (na GT 0) then begin
+ d = d1[wa]
+ d1[wa] = d2[wa]
+ d2[wa] = d
+ endif
+
+ Bmax = zbrent( Bang,Bang+max(d1),F="chisq_fitexy",T=Tol ) -Bang
+ Amax = Ai - A_intercept
+ Bmin = zbrent( Bang,Bang-min(d2),F="chisq_fitexy",T=Tol ) -Bang
+ Amin = Ai - A_intercept
+
+ if N_elements( ww ) EQ 1 then r2 = 2/( ww * N_elements( x ) ) $
+ else r2 = 2/total( ww )
+
+ sigma_A_B = [ Amin^2 + Amax^2 + r2 , Bmin^2 + Bmax^2 ]
+ sig_A_B = sqrt( sigma_A_B/2 ) / ([1,cos(Bang)^2])
+
+ endif
+
+;Finally, transform parameters back to orignal units.
+
+
+ B_slope = tan( Bang ) *ys /xs
+ A_intercept = A_intercept*ys - tan(Bang) * ys / xs *xm + ym
+ if Nc GT 0 then sigma_A_B = [SQRT( (sig_A_B[0] * ys)^2 + $
+ (sig_A_B[1] * ys / xs * xm)^2 ), sig_A_B[1] * ys / xs] $
+ else sigma_A_B = [1.e33,1.e33]
+
+return
+end
diff --git a/Code/script_idl_mv/astrolib/fits_add_checksum.pro b/Code/script_idl_mv/astrolib/fits_add_checksum.pro
new file mode 100644
index 0000000000000000000000000000000000000000..71492c776ee6669228e87613da9f2d751cf339ba
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_add_checksum.pro
@@ -0,0 +1,104 @@
+pro fits_add_checksum, hdr, im, no_timestamp = no_timestamp, $
+ FROM_IEEE=from_IEEE
+;+
+; NAME:
+; FITS_ADD_CHECKSUM
+; PURPOSE:
+; Add or update the CHECKSUM and DATASUM keywords in a FITS header
+; EXPLANATION:
+; Follows the May 2002 version of the FITS checksum proposal at
+; http://fits.gsfc.nasa.gov/registry/checksum.html
+; CALLING SEQUENCE:
+; FITS_ADD_CHECKSUM, Hdr, [ Data, /No_TIMESTAMP, /FROM_IEEE ]
+; INPUT-OUTPUT:
+; Hdr - FITS header (string array), it will be updated with new
+; (or modified) CHECKSUM and DATASUM keywords
+; OPTIONAL INPUT:
+; Data - data array associated with the FITS header. If not supplied, or
+; set to a scalar, then the program checks whether there is a
+; DATASUM keyword already in the FITS header containing the 32bit
+; checksum for the data. If there is no such keyword then there
+; assumed to be no data array associated with the FITS header.
+; OPTIONAL INPUT KEYWORDS:
+; /FROM_IEEE - If this keyword is set, then the input is assumed to be in
+; big endian format (e.g. an untranslated FITS array). This
+; keyword only has an effect on little endian machines (e.g.
+; a Linux box).
+; /No_TIMESTAMP - If set, then a time stamp is not included in the comment
+; field of the CHECKSUM and DATASUM keywords. Unless the
+; /No_TIMESTAMP keyword is set, repeated calls to FITS_ADD_CHECKSUM
+; with the same header and data will yield different values of
+; CHECKSUM (as the date stamp always changes). However, use of the
+; date stamp is recommended in the checksum proposal.
+; PROCEDURES USED:
+; CHECKSUM32, FITS_ASCII_ENCODE(), GET_DATE, SXADDPAR, SXPAR()
+; REVISION HISTORY:
+; W. Landsman SSAI December 2002
+; Fix problem with images with a multiple of 2880 bytes. W.L. May 2008
+; Avoid conversion error when DATASUM is an empty string W.L. June 2008
+; Don't update DATASUM if not already present and no data array supplied
+; W.L. July 2008
+; Make sure input header array has 80 chars/line W.L. Aug 2009
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() EQ 0 then begin
+ print,'Syntax - FITS_ADD_CHECKSUM, Hdr, Data, /No_TIMESTAMP, /FROM_IEEE'
+ return
+ endif
+
+ datasum = sxpar(hdr,'DATASUM', Count = N_DATASUM)
+ Nim = N_elements(im)
+ datasum_update = 1b
+ if Nim GT 1 then begin
+ checksum32,im, dsum,FROM_IEEE = from_IEEE
+ remain = Nim mod 2880
+ if remain GT 0 then begin
+ exten = sxpar( hdr, 'XTENSION', Count = N_exten)
+ if N_exten GT 0 then if exten EQ 'TABLE ' then $
+ checksum32,[dsum,replicate(32b,2880-remain)],dsum
+ endif
+ sdsum = strtrim(dsum,2)
+ dsum_exist= 1b
+ endif else begin
+ if N_datasum EQ 0 then begin ;Don't update DATASUM keyword
+ datasum_update = 0b
+ sdsum = ' 0'
+ endif else begin
+ if strtrim(datasum,2) EQ '' then dsum=0 else dsum = ulong(datasum)
+ sdsum = strtrim(dsum,2)
+ endelse
+ endelse
+
+ if keyword_set(no_timestamp) then tm = '' else Get_date,tm,/timetag
+
+; Do the Checksum keywords already exist?
+
+ if N_DATASUM GT 0 then verb = 'updated ' else verb = 'created '
+ if datasum_update then sxaddpar,hdr,'DATASUM', sdsum, $
+ ' data unit checksum ' + verb + tm
+
+ test = sxpar(hdr,'CHECKSUM', Count = N_CHECKSUM)
+ if N_CHECKSUM GT 0 then verb = 'updated ' else verb = 'created '
+ sxaddpar,hdr,'CHECKSUM','0000000000000000', $
+ ' HDU checksum ' + verb + tm ;Initialize CHECKSUM keyword
+;Make sure each line in header is 80 characters
+ if ~array_equal(strlen(hdr),80) then begin
+ n = N_elements(hdr)
+ bhdr = replicate(32b,80,n )
+ for i=0, n-1 do bhdr[0,i] = byte(hdr[i])
+ endif else bhdr = byte(hdr)
+
+ remain = N_elements(bhdr) mod 2880
+ if remain NE 0 then $
+ bhdr = [reform(bhdr,N_elements(bhdr)), replicate(32b, 2880 - remain) ]
+ checksum32,bhdr, hsum, /NoSAVE
+ if N_elements(dsum) GT 0 then checksum32, [dsum,hsum], hdusum $
+ else hdusum = hsum
+
+ ch = FITS_ASCII_ENCODE(not hdusum) ;ASCII encode the complement of the checksum
+ sxaddpar,hdr,'CHECKSUM',ch
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/fits_ascii_encode.pro b/Code/script_idl_mv/astrolib/fits_ascii_encode.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1fbb628c91264b4a04565226faf7c2850bbf7489
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_ascii_encode.pro
@@ -0,0 +1,68 @@
+function fits_ascii_encode, sum32
+;+
+; NAME:
+; FITS_ASCII_ENCODE()
+; PURPOSE:
+; Encode an unsigned longword as an ASCII string to insert in a FITS header
+; EXPLANATION:
+; Follows the July 2007 version of the FITS checksum proposal at
+; http://fits.gsfc.nasa.gov/registry/checksum.html
+; CALLING SEQUENCE:
+; result = FITS_ASCII_ENCODE( sum32)
+; INPUTS:
+; sum32 - 32bit *unsigned longword* (e.g. as returned by CHECKSUM32)
+; RESULT:
+; A 16 character scalar string suitable for the CHECKSUM keyword
+; EXAMPLE:
+; A FITS header/data unit has a checksum of 868229149. Encode the
+; complement of this value (3426738146) into an ASCII string
+;
+; IDL> print,FITS_ASCII_ENCODE(3426738146U)
+; ===> "hcHjjc9ghcEghc9g"
+;
+; METHOD:
+; The 32bit value is interpreted as a sequence of 4 unsigned 8 bit
+; integers, and divided by 4. Add an offset of 48b (ASCII '0').
+; Remove non-alphanumeric ASCII characters (byte values 58-64 and 91-96)
+; by simultaneously incrementing and decrementing the values in pairs.
+; Cyclicly shift the string one place to the right.
+;
+; REVISION HISTORY:
+; Written W. Landsman SSAI December 2002
+; Use V6.0 notation W.L. August 2013
+;-
+ if N_Params() LT 1 then begin
+ print,'Syntax - result = FITS_ASCII_ENCODE( sum32)'
+ return,'0'
+ endif
+
+; Non-alphanumeric ASCII characters
+ exclude = [58b,59b,60b,61b,62b,63b,64b,91b,92b,93b,94b,95b,96b]
+ ch = bytarr(16)
+ t = byte(sum32,0,4)
+ byteorder,t,/htonl
+ quot = t/4 + 48b
+ for i=0,12,4 do ch[i] = quot
+
+ remain = t mod 4
+ ch[0] = ch[0:3] + remain ;Insert the remainder in the first 4 bytes
+
+;Step through the 16 bytes, 8 at a time, removing nonalphanumeric characters
+ repeat begin
+ check = 0b
+ for j=0,1 do begin
+ il = j*8
+ for i=il,il+3 do begin
+ bad = where( (exclude EQ ch[i]) or (exclude Eq ch[i+4]) , Nbad)
+ if Nbad GT 0 then begin
+ ch[i]++
+ ch[i+4]--
+ check=1b
+ endif
+ endfor
+ endfor
+ endrep until (check EQ 0b)
+
+ return, string( shift(ch,1))
+ end
+
diff --git a/Code/script_idl_mv/astrolib/fits_cd_fix.pro b/Code/script_idl_mv/astrolib/fits_cd_fix.pro
new file mode 100644
index 0000000000000000000000000000000000000000..40a5219a71555cdaba3045e86165fea85c64ac39
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_cd_fix.pro
@@ -0,0 +1,80 @@
+pro fits_cd_fix,hdr, REVERSE = reverse
+;+
+; NAME:
+; FITS_CD_FIX
+;
+; PURPOSE:
+; Update obsolete representations of the CD matrix in a FITS header
+;
+; EXPLANATION:
+; According the paper, "Representations of Celestial Coordinates in FITS"
+; by Calabretta & Greisen (2002, A&A, 395, 1077, available at
+; http://fits.gsfc.nasa.gov/fits_wcs.html) the rotation of an image from
+; standard coordinates is represented by a coordinate description (CD)
+; matrix. The standard representation of the CD matrix are PCn_m
+; keywords, but CDn_m keywords (which include the scale factors) are
+; also allowed. However, earliers drafts of the standard allowed the
+; keywords forms CD00n00m and PC00n00m. This procedure will convert
+; FITS CD matrix keywords containing zeros into the standard forms
+; CDn_m and PCn_m containing only underscores.
+;
+; CALLING SEQUENCE:
+; FITS_CD_FIX, Hdr
+;
+; INPUT-OUTPUT:
+; HDR - FITS header, 80 x N string array. If the header does not
+; contain 'CD00n00m' or 'PC00n00m' keywords then it is left
+; unmodified. Otherwise, the keywords containing integers are
+; replaced with those containing underscores.
+;
+; OPTIONAL KEYWORD INPUT
+; /REVERSE - this keyword does nothing, but is kept for compatibility with
+; earlier versions.
+; PROCEDURES USED:
+; SXADDPAR, SXDELPAR, SXPAR()
+; REVISION HISTORY:
+; Written W. Landsman Feb 1990
+; Major rewrite Feb 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use double precision formatting of CD matrix W. Landsman April 2000
+; Major rewrite to convert only to forms recognized by the Greisen
+; & Calabretta standard W. Landsman July 2003
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 1 then begin
+ print,'Syntax - FITS_CD_FIX, hdr'
+ return
+ endif
+
+ cd00 = ['CD001001','CD001002','CD002001','CD002002']
+ pc00 = ['PC001001','PC001002','PC002001','PC002002']
+
+ cd_ = ['CD1_1','CD1_2','CD2_1','CD2_2']
+ pc_ = ['PC1_1','PC1_2','PC2_1','PC2_2']
+
+
+ for i= 0 ,3 do begin
+ pc = sxpar(hdr,pc00[i], COUNT = N)
+ if N GE 1 then begin
+ sxaddpar,hdr,pc_[i],pc,'',pc00[i]
+ sxdelpar,hdr,pc00[i]
+ if i EQ 0 then sxaddhist,'FITS_CD_FIX:' + strmid(systime(),4,20) + $
+ ' PC00n00m keywords changed to PCn_m',hdr
+ endif else begin
+
+ cd = sxpar(hdr,cd00[i], COUNT = N )
+ if N GE 1 then begin
+ sxaddpar,hdr,cd_[i],cd,'',cd00[i]
+ sxdelpar,hdr,cd00[i]
+ if i EQ 0 then sxaddhist,'FITS_CD_FIX:' + strmid(systime(),4,20) + $
+ ' CD00n00m keywords changed to CDn_m',hdr
+ endif
+ endelse
+ endfor
+
+
+ return
+ end
+
diff --git a/Code/script_idl_mv/astrolib/fits_close.pro b/Code/script_idl_mv/astrolib/fits_close.pro
new file mode 100644
index 0000000000000000000000000000000000000000..627f4a12a25482773626d50d220bb7bbafea3376
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_close.pro
@@ -0,0 +1,66 @@
+pro fits_close,fcb,no_abort=no_abort,message=message
+;+
+; NAME:
+; FITS_CLOSE
+;
+;*PURPOSE:
+; Close a FITS data file
+;
+;*CATEGORY:
+; INPUT/OUTPUT
+;
+;*CALLING SEQUENCE:
+; FITS_CLOSE,fcb
+;
+;*INPUTS:
+; FCB: FITS control block returned by FITS_OPEN.
+;
+;*KEYWORD PARAMETERS:
+; /NO_ABORT: Set to return to calling program instead of a RETALL
+; when an I/O error is encountered. If set, the routine will
+; return a non-null string (containing the error message) in the
+; keyword MESSAGE. If /NO_ABORT not set, then FITS_CLOSE will
+; print the message and issue a RETALL
+; MESSAGE = value: Output error message
+;
+;*EXAMPLES:
+; Open a FITS file, read some data, and close it with FITS_CLOSE
+;
+; FITS_OPEN,'infile',fcb
+; FITS_READ,fcb,data
+; FITS_READ,fcb,moredata
+; FITS_CLOSE,fcb
+;
+;*HISTORY:
+; Written by: D. Lindler August, 1995
+; Converted to IDL V5.0 W. Landsman September 1997
+; Do nothing if fcb an invalid structure D. Schlegel/W. Landsman Oct. 2000
+; Return Message='' for to signal normal operation W. Landsman Nov. 2000
+;-
+;----------------------------------------------------------------------------
+;
+; print calling sequence if no parameters supplied
+;
+ if N_params() lt 1 then begin
+ print,'Syntax - FITS_CLOSE, fcb'
+ print,'KEYWORD PARAMETERS: /No_abort, message='
+ return
+ end
+;
+; close unit
+;
+ on_ioerror,ioerror
+ message = ''
+
+ sz_fcb = size(fcb) ;Valid structure?
+ if sz_fcb[2] EQ 8 then free_lun,fcb.unit
+ return
+;
+; error exit (probably should never occur)
+;
+ioerror:
+ message = !error_state.msg
+ if keyword_set(no_abort) then return
+ message,' ERROR: '+message,/CON
+ retall
+end
diff --git a/Code/script_idl_mv/astrolib/fits_help.pro b/Code/script_idl_mv/astrolib/fits_help.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8bd193357747895bf8599f0ac7066621c623690f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_help.pro
@@ -0,0 +1,119 @@
+pro fits_help,file_or_fcb
+;+
+; NAME:
+; FITS_HELP
+;
+; PURPOSE:
+; To print a summary of the primary data units and extensions in a
+; FITS file.
+;;
+; CALLING SEQUENCE:
+; FITS_HELP,filename_or_fcb
+;
+; INPUTS:
+; FILENAME_OR_FCB - name of the fits file or the FITS Control Block (FCB)
+; structure returned by FITS_OPEN. The file name is allowed
+; to be gzip compressed (with a .gz extension)
+;
+; OUTPUTS:
+; A summary of the FITS file is printed. For each extension, the values
+; of the XTENSION, EXTNAME EXTVER EXTLEVEL BITPIX GCOUNT, PCOUNT NAXIS
+; and NAXIS* keywords are displayed.
+;
+;
+; EXAMPLES:
+; FITS_HELP,'myfile.fits'
+;
+; FITS_OPEN,'anotherfile.fits',fcb
+; FITS_HELP,fcb
+;
+; PROCEDURES USED:
+; FITS_OPEN, FITS_CLOSE
+; HISTORY:
+; Written by: D. Lindler August, 1995
+; Converted to IDL V5.0 W. Landsman September 1997
+; Don't truncate EXTNAME values at 10 chars W. Landsman Feb. 2005
+; Use V6.0 notation W. Landsman Jan 2012
+;-
+;-----------------------------------------------------------------------------
+ compile_opt idl2
+;
+; print calling sequence
+;
+ if N_params() eq 0 then begin
+ print,'Syntax - FITS_HELP,file_or_fcb'
+ return
+ endif
+;
+; Open file if file name is supplied
+;
+ fcbtype = size(file_or_fcb,/type)
+ fcbsize = n_elements(file_or_fcb)
+ if (fcbsize ne 1) || ((fcbtype ne 7) && (fcbtype ne 8)) then begin
+ message, 'Invalid Filename or FCB supplied',/con
+ return
+ end
+
+ if fcbtype eq 7 then fits_open,file_or_fcb,fcb $
+ else fcb = file_or_fcb
+
+; EXTNAME will always be displayed with a length of at least 10 characters
+; but allow for possibility that lengths might be longer than this
+
+ maxlen = max(strlen(fcb.extname)) > 10
+ if maxlen EQ 10 then space = '' else $
+ space = string(replicate(32b, maxlen -10))
+;
+; print headings
+;
+ print,' '
+ print,FCB.FILENAME
+ print,' '
+ print,' XTENSION EXTNAME '+ space + $
+ 'EXTVER EXTLEVEL BITPIX GCOUNT PCOUNT NAXIS NAXIS*'
+ print,' '
+;
+; loop on extensions
+;
+ for i=0,fcb.nextend do begin
+ st = string(i,'(I4)')
+;
+; xtension, extname, extver, extlevel (except for i=0)
+;
+ if i gt 0 then begin
+ t = fcb.xtension[i]
+ while strlen(t) lt 8 do t += ' '
+ st += ' '+ strmid(t,0,8)
+ t = fcb.extname[i]
+ while strlen(t) lt maxlen do t += ' '
+ st += ' '+ strmid(t,0,maxlen)
+ t = fcb.extver[i]
+ if t eq 0 then st += ' ' $
+ else st += string(t,'(I5)')
+ t = fcb.extlevel[i]
+ if t eq 0 then st += ' ' $
+ else st += string(t,'(I8)')
+ end else st += ' ' + space
+;
+; bitpix, gcount, pcount, naxis
+;
+ st += string(fcb.bitpix[i],'(I6)')
+ st += string(fcb.gcount[i],'(I7)')
+ st += string(fcb.pcount[i],'(I7)')
+ st += string(fcb.naxis[i],'(I6)')
+;
+; naxis*
+;
+ st += ' '
+ if fcb.naxis[i] gt 0 then begin
+ nax1 = fcb.naxis[i] - 1
+ st += strjoin(strtrim(fcb.axis[0:nax1,i],2),' x ')
+ endif
+;
+; print the info
+;
+ print,st
+ end
+ if fcbtype eq 7 then fits_close,fcb
+return
+end
diff --git a/Code/script_idl_mv/astrolib/fits_info.pro b/Code/script_idl_mv/astrolib/fits_info.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c0746d4472b14697848ce728cb825903eae0145d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_info.pro
@@ -0,0 +1,348 @@
+pro fits_info, filename, SILENT=silent,TEXTOUT=textout, N_ext=n_ext, extname=extname
+;+
+; NAME:
+; FITS_INFO
+; PURPOSE:
+; Provide information about the contents of a FITS file
+; EXPLANATION:
+; Information includes number of header records and size of data array.
+; Applies to primary header and all extensions. Information can be
+; printed at the terminal and/or stored in a common block
+;
+; This routine is mostly obsolete, and better results can be usually be
+; performed with FITS_HELP (for display) or FITS_OPEN (to read FITS
+; information into a structure)
+;
+; CALLING SEQUENCE:
+; FITS_INFO, Filename, [ /SILENT , TEXTOUT = , N_ext =, EXTNAME= ]
+;
+; INPUT:
+; Filename - Scalar string giving the name of the FITS file(s)
+; Can include wildcards such as '*.fits', or regular expressions
+; allowed by the FILE_SEARCH() function. One can also search
+; gzip compressed FITS files, but their extension must
+; end in .gz or .ftz.
+; OPTIONAL INPUT KEYWORDS:
+; /SILENT - If set, then the display of the file description on the
+; terminal will be suppressed
+;
+; TEXTOUT - specifies output device.
+; textout=1 TERMINAL using /more option
+; textout=2 TERMINAL without /more option
+; textout=3 .prt
+; textout=4 laser.tmp
+; textout=5 user must open file, see TEXTOPEN
+; textout=7 append to existing file
+; textout = filename (default extension of .prt)
+;
+; If TEXTOUT is not supplied, then !TEXTOUT is used
+; OPTIONAL OUTPUT KEYWORDS:
+; The following keyowrds are for use when only one file is processed
+;
+; N_ext - Returns an integer scalar giving the number of extensions in
+; the FITS file
+; extname - returns a list containing the EXTNAME keywords for each
+; extension.
+;
+; COMMON BLOCKS
+; DESCRIPTOR = File descriptor string of the form N_hdrrec Naxis IDL_type
+; Naxis1 Naxis2 ... Naxisn [N_hdrrec table_type Naxis
+; IDL_type Naxis1 ... Naxisn] (repeated for each extension)
+; For example, the following descriptor
+; 167 2 4 3839 4 55 BINTABLE 2 1 89 5
+;
+; indicates that the primary header containing 167 lines, and
+; the primary (2D) floating point image (IDL type 4)
+; is of size 3839 x 4. The first extension header contains
+; 55 lines, and the byte (IDL type 1) table array is of size
+; 89 x 5.
+;
+; The DESCRIPTOR is *only* computed if /SILENT is set.
+; EXAMPLE:
+; Display info about all FITS files of the form '*.fit' in the current
+; directory
+;
+; IDL> fits_info, '*.fit'
+;
+; Any time a *.fit file is found which is *not* in FITS format, an error
+; message is displayed at the terminal and the program continues
+;
+; PROCEDURES USED:
+; GETTOK(), MRD_SKIP, STRN(), SXPAR(), TEXTOPEN, TEXTCLOSE
+;
+; SYSTEM VARIABLES:
+; The non-standard system variables !TEXTOUT and !TEXTUNIT will be
+; created by FITS_INFO if they are not previously defined.
+;
+; DEFSYSV,'!TEXTOUT',1
+; DEFSYSV,'!TEXTUNIT',0
+;
+; See TEXTOPEN.PRO for more info
+; MODIFICATION HISTORY:
+; Written, K. Venkatakrishna, Hughes STX, May 1992
+; Added N_ext keyword, and table_name info, G. Reichert
+; Work on *very* large FITS files October 92
+; More checks to recognize corrupted FITS files February, 1993
+; Proper check for END keyword December 1994
+; Correctly size variable length binary tables WBL December 1994
+; EXTNAME keyword can be anywhere in extension header WBL January 1998
+; Correctly skip past extensions with no data WBL April 1998
+; Converted to IDL V5.0, W. Landsman, April 1998
+; No need for !TEXTOUT if /SILENT D.Finkbeiner February 2002
+; Define !TEXTOUT if needed. R. Sterner, 2002 Aug 27
+; Work on gzip compressed files for V5.3 or later W. Landsman 2003 Jan
+; Improve speed by only reading first 36 lines of header
+; Count headers with more than 32767 lines W. Landsman Feb. 2003
+; Assume since V5.3 (OPENR,/COMPRESS) W. Landsman Feb 2004
+; EXTNAME keyword can be anywhere in extension header again
+; WBL/S. Bansal Dec 2004
+; Read more than 200 extensions WBL March 2005
+; Work for FITS files with SIMPLE=F WBL July 2005
+; Assume since V5.4, fstat.compress available WBL April 2006
+; Added EXTNAME as an IDL keyword to return values. M. Perrin Dec 2007
+; make Ndata a long64 to deal with large files. E. Hivon Mar 2008
+; For GDL compatibility, first check if file is compressed before using
+; OPENR,/COMPRESS B. Roukema/WL Apr 2010
+; Increased nmax (max number of extensions) from 400 to 2000 Sept 2012
+; Correctly fills EXTNAME when SILENT is set EH Jan 2013
+; Turned ptr to long64 in order to read very large files EH Dec 2013
+; Replaced 2880 with 2880LL to work on very large files EH Mar 2015
+;-
+ On_error,2
+ compile_opt idl2
+ COMMON descriptor,fdescript
+
+ if N_params() lt 1 then begin
+ print,'Syntax - FITS_INFO, filename, [/SILENT, TEXTOUT=, N_ext=, EXTNAME=]'
+ return
+ endif
+
+ defsysv,'!TEXTOUT',exists=ex ; Check if !TEXTOUT exists.
+ if ex eq 0 then defsysv,'!TEXTOUT',1 ; If not define it.
+
+ fil = file_search( filename, COUNT = nfiles)
+ if nfiles EQ 0 then message,'No files found'
+; File is gzip compressed if it ends in .gz or .ftz
+ len = strlen(fil)
+ ext = strlowcase(strmid(fil,transpose(len-3),3))
+ compress = (ext EQ '.gz') || (ext EQ 'ftz')
+
+ silent = keyword_set( SILENT )
+ if ~silent then begin
+ if ~keyword_set( TEXTOUT ) then textout = !TEXTOUT
+ textopen, 'FITS_INFO', TEXTOUT=textout
+ endif
+
+ for nf = 0, nfiles-1 do begin
+
+ file = fil[nf]
+
+ openr, lun1, file, /GET_LUN, COMPRESS = compress[nf]
+
+ N_ext = -1
+ fdescript = ''
+ nmax = 2000 ; MDP was 100, then 400
+ nbuf= nmax
+ extname = strarr(nmax)
+
+ ptr = 0LL
+ START:
+ ON_IOerror, BAD_FILE
+ descript = ''
+; Is this a proper FITS file?
+ test = bytarr(8)
+ readu, lun1, test
+
+ if N_ext EQ -1 then begin
+ if string(test) NE 'SIMPLE ' then goto, BAD_FILE
+ simple = 1
+ endif else begin
+ if string(test) NE 'XTENSION' then goto, END_OF_FILE
+ simple = 0
+ endelse
+ point_lun, lun1, ptr
+
+; Read the header
+ hdr = bytarr(80, 36, /NOZERO)
+ N_hdrblock = 1
+ readu, lun1, hdr
+ ptr += 2880LL
+ hd = string( hdr > 32b)
+
+; Get values of BITPIX, NAXIS etc.
+ bitpix = sxpar(hd, 'BITPIX', Count = N_BITPIX)
+ if N_BITPIX EQ 0 then $
+ message, 'WARNING - FITS header missing BITPIX keyword',/CON
+ Naxis = sxpar( hd, 'NAXIS', Count = N_NAXIS)
+ if N_NAXIS EQ 0 then message, $
+ 'WARNING - FITS header missing NAXIS keyword',/CON
+
+ exten = sxpar( hd, 'XTENSION')
+ Ext_type = strmid( strtrim( exten ,2), 0, 8) ;Use only first 8 char
+ gcount = sxpar( hd, 'GCOUNT') > 1
+ pcount = sxpar( hd, 'PCOUNT')
+
+ if strn(Ext_type) NE '0' then begin
+ if (gcount NE 1) or (pcount NE 0) then $
+ ext_type = 'VAR_' + ext_type
+ descript += ' ' + Ext_type
+ endif
+
+ descript += ' ' + strn(Naxis)
+
+ case BITPIX of
+ 8: IDL_type = 1 ; Byte
+ 16: IDL_type = 2 ; Integer*2
+ 32: IDL_type = 3 ; Integer*4
+ -32: IDL_type = 4 ; Real*4
+ -64: IDL_type = 5 ; Real*8
+ ELSE: begin
+ message, ' Illegal value of BITPIX = ' + strn(bitpix) + $
+ ' in header',/CON
+ goto, SKIP
+ end
+ endcase
+
+ if Naxis GT 0 then begin
+ descript += ' ' + strn(IDL_type)
+ Nax = sxpar( hd, 'NAXIS*')
+ if N_elements(Nax) LT Naxis then begin
+ message, $
+ 'ERROR - Missing required NAXISi keyword in FITS header',/CON
+ goto, SKIP
+ endif
+ for i = 1, Naxis do descript += ' '+strn(Nax[i-1])
+ endif
+
+ end_rec = where( strtrim(strmid(hd,0,8),2) EQ 'END')
+
+ exname = sxpar(hd, 'extname', Count = N_extname)
+ if N_extname GT 0 then extname[N_ext+1] = exname
+ get_extname = (N_ext GE 0) && (N_extname EQ 0)
+
+; Read header records, till end of header is reached
+
+ hdr = bytarr(80, 36, /NOZERO)
+ while (end_rec[0] EQ -1) && (~eof(lun1) ) do begin
+ readu,lun1,hdr
+ ptr = ptr + 2880LL
+ hd1 = string( hdr > 32b)
+ end_rec = where( strtrim(strmid(hd1,0,8),2) EQ 'END')
+ n_hdrblock++
+ if get_extname then begin
+ exname = sxpar(hd1, 'extname', Count = N_extname)
+ if N_extname GT 0 then begin
+ extname[N_ext+1] = exname
+ get_extname = 0
+ endif
+ endif
+ endwhile
+
+ n_hdrec = 36L*(n_hdrblock-1) + end_rec[0] + 1L ; size of header
+ descript = strn( n_hdrec ) + descript
+
+; If there is data associated with primary header, then find out the size
+
+ if Naxis GT 0 then begin
+ ndata = long64(Nax[0])
+ if naxis GT 1 then for i = 2, naxis do ndata *= Nax[i-1]
+ endif else ndata = 0
+
+ nbytes = (abs(bitpix)/8) * gcount * (pcount + ndata)
+ nrec = long(( nbytes +2879)/ 2880)
+
+
+
+; Check if all headers have been read
+
+ if ( simple EQ 0 ) && ( strlen(strn(exten)) EQ 1) then goto, END_OF_FILE
+
+ N_ext++
+ if N_ext GE (nmax-1) then begin
+ extname = [extname,strarr(nbuf)]
+ nmax = N_elements(extname)
+ endif
+
+; Append information concerning the current extension to descriptor
+
+ fdescript += ' ' + descript
+
+; Check for EOF
+; Skip the headers and data records
+
+ ptr += nrec*2880LL
+ if compress[nf] then mrd_skip,lun1,nrec*2880LL else point_lun,lun1,ptr
+ if ~eof(lun1) then goto, START
+;
+ END_OF_FILE:
+
+ extname = extname[0:N_ext] ;strip off bogus first value
+ ;otherwise will end up with '' at end
+
+ if ~SILENT then begin
+ printf,!textunit,file,' has ',strn(N_ext),' extensions'
+ printf,!textunit,'Primary header: ',gettok(fdescript,' '),' records'
+
+ Naxis = gettok( fdescript,' ' )
+
+ If Naxis NE '0' then begin
+
+ case gettok(fdescript,' ') of
+
+ '1': image_type = 'Byte'
+ '2': image_type = 'Integer*2'
+ '3': image_type = 'Integer*4'
+ '4': image_type = 'Real*4'
+ '5': image_type = 'Real*8'
+
+ endcase
+
+ image_desc = 'Image -- ' + image_type + ' array ('
+ for i = 0,fix(Naxis)-1 do image_desc = image_desc + ' '+ gettok(fdescript,' ')
+ image_desc = image_desc+' )'
+
+ endif else image_desc = 'No data'
+ printf,!textunit, format='(a)',image_desc
+
+ if N_ext GT 0 then begin
+ for i = 1,N_ext do begin
+
+ printf, !TEXTUNIT, 'Extension ' + strn(i) + ' -- '+extname[i]
+
+ header_desc = ' Header : '+gettok(fdescript,' ')+' records'
+ printf, !textunit, format = '(a)',header_desc
+
+ table_type = gettok(fdescript,' ')
+
+ case table_type of
+ 'A3DTABLE' : table_desc = 'Binary Table'
+ 'BINTABLE' : table_desc = 'Binary Table'
+ 'VAR_BINTABLE': table_desc = 'Variable length Binary Table'
+ 'TABLE': table_desc = 'ASCII Table'
+ ELSE: table_desc = table_type
+ endcase
+
+ table_desc = ' ' + table_desc + ' ( '
+ table_dim = fix( gettok( fdescript,' ') )
+ if table_dim GT 0 then begin
+ table_type = gettok(fdescript,' ')
+ for j = 0, table_dim-1 do $
+ table_desc += gettok(fdescript,' ') + ' '
+ endif
+ table_desc += ')'
+
+ printf,!textunit, format='(a)',table_desc
+ endfor
+ endif
+
+ printf, !TEXTUNIT, ' '
+ endif
+ SKIP: free_lun, lun1
+ endfor
+ if ~silent then textclose, TEXTOUT=textout
+ return
+
+ BAD_FILE:
+ message, 'Error reading FITS file ' + file, /CON
+ goto,SKIP
+end
diff --git a/Code/script_idl_mv/astrolib/fits_open.pro b/Code/script_idl_mv/astrolib/fits_open.pro
new file mode 100644
index 0000000000000000000000000000000000000000..87bb87b00fe03ca94614d78f28c8b0563bc5cea1
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_open.pro
@@ -0,0 +1,459 @@
+pro fits_open,filename,fcb,write=write,append=append,update=update, $
+ no_abort=no_abort,message=message,hprint=hprint,fpack=fpack
+;+
+; NAME:
+; FITS_OPEN
+;
+; PURPOSE:
+; Opens a FITS (Flexible Image Transport System) data file.
+;
+; EXPLANATION:
+; Used by FITS_READ and FITS_WRITE
+;
+; CALLING SEQUENCE:
+; FITS_OPEN, filename, fcb
+;
+; INPUTS:
+; filename : name of the FITS file to open, scalar string
+; FITS_OPEN can also open gzip compressed (.gz) files or Unix
+; compressed files *for reading only*, although there is a
+; performance penalty. FPACK (
+; http://heasarc.gsfc.nasa.gov/fitsio/fpack/ )
+; compressed FITS files can be read provided that the FPACK
+; software is installed.
+;*OUTPUTS:
+; fcb : (FITS Control Block) a IDL structure containing information
+; concerning the file. It is an input to FITS_READ, FITS_WRITE
+; FITS_CLOSE and MODFITS.
+; INPUT KEYWORD PARAMETERS:
+; /APPEND: Set to append to an existing file.
+; /FPACK - Signal that the file is compressed with the FPACK software.
+; http://heasarc.gsfc.nasa.gov/fitsio/fpack/ ) By default,
+; FITS_OPEN assumes that if the file name extension ends in
+; .fz that it is fpack compressed. The FPACK software must
+; be installed on the system
+; /HPRINT - print headers with routine HPRINT as they are read.
+; (useful for debugging a strange file)
+; /NO_ABORT: Set to quietly return to calling program when an I/O error
+; is encountered, and return a non-null string
+; (containing the error message) in the keyword MESSAGE.
+; If /NO_ABORT not set, then FITS_OPEN will display the error
+; message and return to the calling program.
+; /UPDATE Set this keyword to open an existing file for update
+; /WRITE: Set this keyword to open a new file for writing.
+;
+; OUTPUT KEYWORD PARAMETERS:
+; MESSAGE = value: Output error message. If the FITS file was opened
+; successfully, then message = ''.
+;
+; NOTES:
+; The output FCB should be passed to the other FITS routines (FITS_OPEN,
+; FITS_READ, FITS_HELP, and FITS_WRITE). It has the following structure
+; when FITS_OPEN is called without /WRITE or /APPEND keywords set.
+;
+; FCB.FILENAME - name of the input file
+; .UNIT - unit number the file is opened to
+; .FCOMPRESS - 1 if unit is a FPACK compressed file opened with
+; a pipe to SPAWN
+; .NEXTEND - number of extensions in the file.
+; .XTENSION - string array giving the extension type for each
+; extension.
+; .EXTNAME - string array giving the extension name for each
+; extension. (null string if not defined the extension)
+; .EXTVER - vector of extension version numbers (0 if not
+; defined)
+; .EXTLEVEL - vector of extension levels (0 if not defined)
+; .GCOUNT - vector with the number of groups in each extension.
+; .PCOUNT - vector with parameter count for each group
+; .BITPIX - BITPIX for each extension with values
+; 8 byte data
+; 16 short word integers
+; 32 long word integers
+; -32 IEEE floating point
+; -64 IEEE double precision floating point
+; .NAXIS - number of axes for each extension. (0 for null data
+; units)
+; .AXIS - 2-D array where axis[*,N] gives the size of each axes
+; for extension N
+; .START_HEADER - vector giving the starting byte in the file
+; where each extension header begins
+; .START_DATA - vector giving the starting byte in the file
+; where the data for each extension begins
+;
+; .HMAIN - keyword parameters (less standard required FITS
+; keywords) for the primary data unit.
+; .OPEN_FOR_WRITE - flag (0= open for read, 1=open for write,
+; 2=open for update)
+; .LAST_EXTENSION - last extension number read.
+; .RANDOM_GROUPS - 1 if the PDU is random groups format,
+; 0 otherwise
+; .NBYTES - total number of (uncompressed) bytes in the FITS file
+;
+; When FITS open is called with the /WRITE or /APPEND option, FCB
+; contains:
+;
+; FCB.FILENAME - name of the input file
+; .UNIT - unit number the file is opened to
+; .NEXTEND - number of extensions in the file.
+; .OPEN_FOR_WRITE - flag (1=open for write, 2=open for append
+; 3=open for update)
+;
+;
+; EXAMPLES:
+; Open a FITS file for reading:
+; FITS_OPEN,'myfile.fits',fcb
+;
+; Open a new FITS file for output:
+; FITS_OPEN,'newfile.fits',fcb,/write
+; PROCEDURES USED:
+; GET_PIPE_FILESIZE (for Fcompress'ed files) HPRINT, SXDELPAR, SXPAR()
+; HISTORY:
+; Written by: D. Lindler August, 1995
+; July, 1996 NICMOS Modified to allow open for overwrite
+; to allow primary header to be modified
+; DJL Oct. 15, 1996 corrected to properly extend AXIS when more
+; than 100 extensions present
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use Message = '' rather than !ERR =1 as preferred signal of normal
+; operation W. Landsman November 2000
+; Lindler, Dec, 2001, Modified to use 64 bit words for storing byte
+; positions within the file to allow support for very large
+; files
+; Work with gzip compressed files W. Landsman January 2003
+; Fix gzip compress for V5.4 and earlier W.Landsman/M.Fitzgerald Dec 2003
+; Assume since V5.3 (STRSPLIT, OPENR,/COMPRESS) W. Landsman Feb 2004
+; Treat FTZ extension as gzip compressed W. Landsman Sep 2004
+; Assume since V5.4 fstat.compress available W. Landsman Apr 2006
+; FCB.Filename now expands any wildcards W. Landsman July 2006
+; Make ndata 64bit for very large files B. Garwood/W. Landsman Sep 2006
+; Open with /SWAP_IF_LITTLE_ENDIAN, remove obsolete keywords to OPEN
+; W. Landsman Sep 2006
+; Warn that one cannot open a compressed file for update W.L. April 2007
+; Use post-V6.0 notation W.L. October 2010
+; Support FPACK compressed files, new .FCOMPRESS tag to FCB structure
+; W.L. December 2010
+; Read gzip'ed files even if gzip is not installed W.L. October 2012
+; Handle axis sizes requiring 64 integer W.L. April 2014
+; Support for .Z compressed files M. Zechmeister/W.L. April 2014
+; Wrap filenames in "" when spawning subprocesses, to handle paths
+; with spaces or other atypical characters. M. Perrin Nov 2014
+;-
+;--------------------------------------------------------------------
+ compile_opt idl2
+; if no parameters supplied, print calling sequence
+;
+ if N_params() LT 1 then begin
+ print,'Syntax - FITS_OPEN, filename, fcb'
+ print,' Input Keywords: /Append, /Hprint, /No_abort, /Update, /Write'
+ print,' Output Keyword: Message= '
+ return
+ endif
+;
+; set default keyword parameters
+;
+
+ message = ''
+ open_for_read = 1
+ open_for_update = 0
+ open_for_write = 0
+ open_for_overwrite = 0
+ if keyword_set(write) then begin
+ open_for_read = 0
+ open_for_update = 0
+ open_for_write = 1
+ open_for_overwrite = 0
+ end
+ if keyword_set(append) then begin
+ open_for_read = 0
+ open_for_write = 0
+ open_for_update = 1
+ open_for_overwrite = 0
+ end
+ if keyword_set(update) then begin
+ open_for_read = 1
+ open_for_write = 0
+ open_for_update = 0
+ open_for_overwrite = 1
+ end
+;
+; on I/O errors goto statement ioerror:
+;
+ on_ioerror,ioerror
+;
+; open file
+;
+
+ ext = strlowcase(strmid(filename, 2, /rev))
+ docompress = (ext EQ '.gz') || (ext EQ 'ftz')
+ fcompress = keyword_set(fpack) || ( ext EQ '.fz')
+ zcompress = (strmid(filename, 1, /rev) EQ '.Z')
+ if docompress && open_for_overwrite then begin
+ message = 'Compressed FITS files cannot be open for update'
+ if ~keyword_set(no_abort) then $
+ message,' ERROR: '+message,/CON
+ return
+ endif
+ ;
+; open file
+;
+ if ~fcompress && ~zcompress then get_lun,unit
+ if fcompress then $
+ spawn,'funpack -S "' + filename+'"', unit=unit,/sh else $
+ if zcompress then $
+ spawn,'gzip -cd "'+filename+'"', unit=unit,/sh else $
+ if docompress then $
+ openr,unit,filename, /compress,/swap_if_little else begin
+ case 1 of
+ keyword_set(append): openu,unit,filename,/swap_if_little
+ keyword_set(update): openu,unit,filename,/swap_if_little
+ keyword_set(write) : openw,unit,filename,/swap_if_little
+ else : openr,unit,filename,/swap_if_little
+ endcase
+ endelse
+
+ file = fstat(unit)
+ fname = file.name ;In case the user input a wildcard
+ docompress = file.compress
+
+; Need to spawn to "gzip -l" to get the number of uncompressed bytes in a gzip
+; compressed file. If gzip doesn't work for some reason then use
+; get_pipe_filesize.
+
+ if fcompress then begin
+ get_pipe_filesize,unit, nbytes_in_file
+ free_lun,unit
+ spawn,'funpack -S "' + filename +'"', unit=unit,/sh
+ endif else if docompress then begin
+ if !VERSION.OS_FAMILY Eq 'Windows' then $
+ fname = file_search(fname,/fully_qualify)
+ spawn,'gzip -l "' + fname+'"', output
+ output = strtrim(output,2)
+ g = where(strmid(output,0,8) EQ 'compress', Nfound)
+ if Nfound EQ 0 then begin
+ get_pipe_filesize, unit, nbytes_in_file
+ close,unit
+ openr,unit,filename, /compress,/swap_if_little
+ endif else $
+ nbytes_in_file = long64((strsplit(output[g[0]+1],/extract))[1])
+ endif else if zcompress then begin
+ spawn,'zcat "' + filename+'"' + ' | wc -c', nbytes_in_file
+ if nbytes_in_file EQ 0 then message,'Unable to zcat decompress ' + fname
+ endif else nbytes_in_file = file.size
+
+;
+; create vectors needed to store header information for each extension
+;
+ n = 100
+ xtension = strarr(n)
+ extname = strarr(n)
+ extver = lonarr(n)
+ extlevel = lonarr(n)
+ gcount = lonarr(n)
+ pcount = lonarr(n)
+ bitpix = lonarr(n)
+ naxis = lonarr(n)
+ axis = lon64arr(20,n)
+ start_header = lon64arr(n) ; starting byte in file for header
+ start_data = lon64arr(n) ; starting byte in file for data
+ position = 0ULL ; current byte position in file
+ skip = 0ULL ; Amount to skip from current position
+;
+; read and process each header in the file if open for read or update
+;
+ extend_number = 0 ; current extension number being
+ ; processed
+
+ if open_for_read || open_for_update then begin
+ main_header = 1 ; first header in file flag
+ h = bytarr(80,36,/nozero) ; read buffer
+;
+; loop on headers in the file
+;
+ repeat begin
+ if skip GT 0 then if (fcompress || zcompress) then mrd_skip,unit,skip else $
+ point_lun,unit,position
+ start = position
+;
+; loop on header blocks
+;
+ first_block = 1 ; first block in header flag
+ repeat begin
+
+ if (~fcompress && ~zcompress) && position+2879 ge nbytes_in_file then begin
+ if extend_number eq 0 then begin
+ message = 'EOF encountered while reading header'
+ goto,error_exit
+ endif
+ print,'EOF encountered reading extension header'
+ print,'Only '+strtrim(extend_number-1,2) + $
+ ' extensions processed'
+ goto,done_headers
+ endif
+
+ readu,unit,h
+ position = position + 2880
+ hdr = string(h>32b)
+ endline = where(strmid(hdr,0,8) eq 'END ',nend)
+ if nend gt 0 then hdr = hdr[0:endline[0]]
+ if first_block then begin
+;
+; check for valid header (SIMPLE keyword must be first for PDU and
+; XTENSION keyword for the extensions.
+;
+ header = hdr
+ keyword = strmid(header[0],0,8)
+ if (extend_number eq 0) && $
+ (keyword ne 'SIMPLE ') then begin
+ message = 'Invalid header, no SIMPLE keyword'
+ goto,error_exit
+ endif
+
+ if (extend_number gt 0) && $
+ (keyword ne 'XTENSION') then begin
+ print,'Invalid extension header encountered'
+ print,'XTENSION keyword missing'
+ print,'Only '+strtrim(extend_number-1,2) + $
+ ' extensions processed'
+ goto,done_headers
+ endif
+
+ end else header = [header,hdr]
+ first_block = 0
+ end until (nend gt 0)
+
+;
+; print header if hprint set
+;
+ if keyword_set(hprint) then hprint,header
+;
+; end of loop on header blocks
+;
+; Increase size of vectors if needed
+;
+ if extend_number ge n then begin
+ xtension = [xtension,strarr(n)]
+ extname = [extname,strarr(n)]
+ extver = [extver,lonarr(n)]
+ extlevel = [extver,lonarr(n)]
+ gcount = [gcount,lonarr(n)]
+ pcount = [pcount,lonarr(n)]
+ bitpix = [bitpix,lonarr(n)]
+ naxis = [naxis,lonarr(n)]
+ old_axis = axis
+ axis = lonarr(20,n*2)
+ axis[0,0] = old_axis
+ start_header = [start_header,lonarr(n)]
+ start_data = [start_data,lonarr(n)]
+ n = n*2
+ end
+;
+; extract information from header
+;
+ xtension[extend_number] = strtrim(sxpar(header,'xtension'))
+ st = sxpar(header,'extname', Count = N_extname)
+ if N_extname EQ 0 then st = ''
+ extname[extend_number] = strtrim(st,2)
+ extver[extend_number] = sxpar(header,'extver')
+ extlevel[extend_number] = sxpar(header,'extlevel')
+ gcount[extend_number] = sxpar(header,'gcount')
+ pcount[extend_number] = sxpar(header,'pcount')
+ bitpix[extend_number] = sxpar(header,'bitpix')
+ nax = sxpar(header,'naxis')
+ naxis[extend_number] = nax
+ if nax gt 0 then begin
+ naxisi = sxpar(header,'naxis*')
+ axis[0,extend_number] = naxisi
+ ndata = product(naxisi,/integer)
+ endif else ndata = 0
+
+ start_data[extend_number] = position
+ start_header[extend_number] = start
+;
+; if first header, save without FITS required keywords
+;
+ if extend_number eq 0 then begin
+ hmain = header
+ random_groups = sxpar(header,'groups')
+ sxdelpar,hmain,['SIMPLE','BITPIX','NAXIS','NAXIS1', $
+ 'NAXIS2','NAXIS3','NAXIS4','NAXIS5', $
+ 'NAXIS6','NAXIS7','NAXIS8','EXTEND', $
+ 'PCOUNT','GCOUNT','GROUPS','BSCALE', $
+ 'BZERO','NPIX1','NPIX2','PIXVALUE']
+ if (pcount[0] gt 0) then for i=1,pcount[0] do $
+ sxdelpar,hmain,['ptype','pscal','pzero']+strtrim(i,2)
+ endif
+;
+; skip past data to go to next header
+;
+ nbytes = (abs(bitpix[extend_number])/8) * $
+ (gcount[extend_number]>1)*(pcount[extend_number] + ndata)
+ skip = (nbytes + 2879)/2880*2880
+ position += skip
+
+;
+; end loop on headers
+;
+
+ extend_number += 1
+ end until (position ge nbytes_in_file-2879)
+ end
+;
+; point at end of file in /extend
+;
+done_headers:
+ if open_for_update then point_lun,unit,nbytes_in_file
+;
+; number of extensions
+;
+ if open_for_write then nextend = -1 $
+ else nextend = extend_number - 1
+;
+; set up blank hmain if open for write
+;
+ if open_for_write then begin
+ hmain = strarr(1)
+ hmain[0] = 'END '
+ end
+;
+; create output structure for the file control block
+;
+ if open_for_write or open_for_update then begin
+ fcb = {filename:fname,unit:unit,nextend:nextend, $
+ open_for_write:open_for_write + open_for_update*2}
+ end else begin
+ nx = nextend
+ fcb = {filename:fname,unit:unit,fcompress:fcompress||zcompress, $
+ nextend:nextend, $
+ xtension:xtension[0:nx],extname:extname[0:nx], $
+ extver:extver[0:nx],extlevel:extlevel[0:nx], $
+ gcount:gcount[0:nx],pcount:pcount[0:nx], $
+ bitpix:bitpix[0:nx],naxis:naxis[0:nx], $
+ axis:axis[*,0:nx], $
+ start_header:start_header[0:nx], $
+ start_data:start_data[0:nx],hmain:hmain, $
+ open_for_write:open_for_overwrite*3,$
+ last_extension:-1, $
+ random_groups:random_groups, $
+ nbytes: nbytes_in_file }
+ end
+ if fcompress then begin
+ free_lun,unit
+ spawn,'funpack -S "' + filename+'"', unit=unit,/sh
+ endif else if zcompress then begin
+ free_lun,unit
+ spawn,'gzip -cd "' + filename+'"', unit=unit, /sh
+ endif
+ !err = 1 ;For obsolete users still using !err
+ return
+;
+; error exit
+;
+ioerror:
+ message = !ERROR_STATE.msg
+error_exit:
+ free_lun,unit
+ !err = -1
+ if keyword_set(no_abort) then return
+ message,' ERROR: '+message,/CON
+ return
+end
diff --git a/Code/script_idl_mv/astrolib/fits_read.pro b/Code/script_idl_mv/astrolib/fits_read.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3298d6aec482e7486167dc32daf7b09466081d3c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_read.pro
@@ -0,0 +1,573 @@
+pro fits_read,file_or_fcb,data,header,group_par,noscale=noscale, $
+ exten_no=exten_no, extname=extname, $
+ extver=extver, extlevel=extlevel, xtension=xtension, $
+ no_abort=no_abort, message=message, first=first, last=last, $
+ group=group, header_only=header_only,data_only=data_only, $
+ no_pdu=no_pdu, enum = enum, no_unsigned = no_unsigned, pdu=pdu
+
+;+
+; NAME:
+; FITS_READ
+; PURPOSE:
+; To read a FITS file.
+;
+; CALLING SEQUENCE:
+; FITS_READ, filename_or_fcb, data [,header, group_par]
+;
+; INPUTS:
+; FILENAME_OR_FCB - this parameter can be the FITS Control Block (FCB)
+; returned by FITS_OPEN or the file name of the FITS file. If
+; a file name is supplied, FITS_READ will open the file with
+; FITS_OPEN and close the file with FITS_CLOSE before exiting.
+; When multiple extensions are to be read from the file, it is
+; more efficient for the user to call FITS_OPEN and leave the
+; file open until all extensions are read. FPACK
+; ( http://heasarc.gsfc.nasa.gov/fitsio/fpack/ ) compressed FITS
+; files can be read provided that the FPACK software is installed.
+; Both Gzip compressed (.gz) and Unix compressed (*.Z) files can
+; be read, although there is a performance penalty..
+;
+; OUTPUTS:
+; DATA - data array. If /NOSCALE is specified, BSCALE and BZERO
+; (if present in the header) will not be used to scale the data.
+; If Keywords FIRST and LAST are used to read a portion of the
+; data or the heap portion of an extension, no scaling is done
+; and data is returned as a 1-D vector. The user can use the IDL
+; function REFORM to convert the data to the correct dimensions
+; if desired. If /DATA_ONLY is specified, no scaling is done.
+; HEADER - FITS Header. The STScI inheritance convention is recognized
+; http://fits.gsfc.nasa.gov/registry/inherit/fits_inheritance.txt
+; If an extension is read, and the INHERIT keyword exists with a
+; value of T, and the /NO_PDU keyword keyword is not supplied,
+; then the primary data unit header and the extension header will
+; be combined. The header will have the form:
+;
+;
+; BEGIN MAIN HEADER --------------------------------
+;
+; BEGIN EXTENSION HEADER ---------------------------
+; 1. (Default=0, the first group)
+;
+; OUTPUT KEYWORD PARAMETERS:
+; ENUM - Output extension number that was read.
+; MESSAGE = value: Output error message
+;
+; NOTES:
+; Determination or which extension to read.
+; case 1: EXTEN_NO specified. EXTEN_NO will give the number of the
+; extension to read. The primary data unit is refered
+; to as extension 0. If EXTEN_NO is specified, XTENSION,
+; EXTNAME, EXTVER, and EXTLEVEL parameters are ignored.
+; case 2: if EXTEN_NO is not specified, the first extension
+; with the specified XTENSION, EXTNAME, EXTVER, and
+; EXTLEVEL will be read. If any of the 4 parameters
+; are not specified, they will not be used in the search.
+; Setting EXTLEVEL=0, EXTVER=0, EXTNAME='', or
+; XTENSION='' is the same as not supplying them.
+; case 3: if none of the keyword parameters, EXTEN_NO, XTENSION,
+; EXTNAME, EXTVER, or EXTLEVEL are supplied. FITS_READ
+; will read the next extension in the file. If the
+; primary data unit (PDU), extension 0, is null, the
+; first call to FITS_READ will read the first extension
+; of the file.
+;
+; The only way to read a null PDU is to use EXTEN_NO = 0.
+;
+; If FIRST and LAST are specified, the data is returned without applying
+; any scale factors (BSCALE and BZERO) and the data is returned in a
+; 1-D vector. This will allow you to read any portion of a multiple
+; dimension data set. Once returned, the IDL function REFORM can be
+; used to place the correct dimensions on the data.
+;
+; IMPLICIT IMAGES: FITS_READ will construct an implicit image
+; for cases where NAXIS=0 and the NPIX1, NPIX2, and PIXVALUE
+; keywords are present. The output image will be:
+; image = replicate(PIXVALUE,NPIX1,NPIX2)
+;
+; FPACK compressed files are always closed and reopened when exiting
+; FITS_READ so that the pointer is set to the beginning of the file. (Since
+; FPACK files are opened with a bidirectional pipe rather than OPEN, one
+; cannot use POINT_LUN to move to a specified position in the file.)
+;
+; EXAMPLES:
+; Read the primary data unit of a FITS file, if it is null read the
+; first extension:
+; FITS_READ, 'myfile.fits', data, header
+;
+; Read the first two extensions of a FITS file and the extension with
+; EXTNAME = 'FLUX' and EXTVER = 4
+; FITS_OPEN, 'myfile.fits', fcb
+; FITS_READ, fcb,data1, header2, exten_no = 1
+; FITS_READ, fcb,data1, header2, exten_no = 2
+; FITS_READ, fcb,data3, header3, extname='flux', extver=4
+; FITS_CLOSE, fcb
+;
+; Read the sixth image in a data cube for the fourth extension.
+;
+; FITS_OPEN, 'myfile.fits', fcb
+; image_number = 6
+; ns = fcb.axis[0,4]
+; nl = fcb.axis[1,4]
+; i1 = (ns*nl)*(image_number-1)
+; i2 = i2 + ns*nl-1
+; FITS_READ,fcb,image,header,first=i1,last=i2
+; image = reform(image,ns,nl,/overwrite)
+; FITS_CLOSE, fcb
+;
+; PROCEDURES USED:
+; FITS_CLOSE, FITS_OPEN
+; SXADDPAR, SXDELPAR, SXPAR()
+; WARNINGS:
+; In Sep 2006, FITS_OPEN was modified to open FITS files using the
+; /SWAP_IF_LITTLE_ENDIAN keyword to OPEN, so that subsequent routines
+; (FITS_READ, FITS_WRITE) did not require any byte swapping. An error
+; may result if an pre-Sep 2006 version of FITS_OPEN is used with a
+; post Sep 2006 version of FITS_READ, FITS_WRITE or MODFITS.
+; HISTORY:
+; Written by: D. Lindler, August 1995
+; Avoid use of !ERR W. Landsman August 1999
+; Read unsigned datatypes, added /no_unsigned W. Landsman December 1999
+; Don't call FITS_CLOSE unless fcb is defined W. Landsman January 2000
+; Set BZERO = 0 for unsigned integer data W. Landsman January 2000
+; Only call IEEE_TO_HOST if needed W. Landsman February 2000
+; Ensure EXTEND keyword in primary header W. Landsman April 2001
+; Don't erase ERROR message when closing file W. Landsman April 2002
+; Assume at least V5.1 remove NANValue keyword W. Landsman November 2002
+; Work with compress files (read file size from fcb),
+; requires updated (Jan 2003) version of FITS_OPEN W. Landsman Jan 2003
+; Do not modify BSCALE/BZERO for unsigned integers W. Landsman April 2006
+; Assume FITS_OPEN has opened the file with /SWAP_IF_LITTLE_ENDIAN
+; W. Landsman September 2006
+; Fix problem with /DATA_ONLY keyword M.Buie/W.Landsman October 2006
+; Only append primary header if INHERIT=T W. Landsman April 2007
+; Make ndata 64bit for very large files E. Hivon/W. Landsman May 2007
+; Added /PDU keyword to always append primary header W. Landsman June 2007
+; Use PRODUCT to compute # of data points W. Landsman May 2009
+; Make sure FIRST is long64 when computing position W.L. October 2009
+; Read FPACK compressed files, W.L. December 2010
+; Don't assume FCB has a FCOMPRESS tag W.L./Satori UeNO September 2012
+; Make sure opened pipes are closed if fcb not left open W.L. April 2012
+; Fix bug with /data_only introduced Dec 2010 W. L. April 2014
+;-
+;
+;-----------------------------------------------------------------------------
+ compile_opt idl2
+; print calling sequence
+;
+ if N_params() eq 0 then begin
+ print,'Syntax - FITS_READ,file_or_fcb,data,header,group_par'
+ print,' Input Keywords: /noscale, exten_no=, extname=, '
+ print,' extver=, extlevel=, xtension=, /no_abort, '
+ print,' first, last, group, /header_only, /no_pdu, /pdu'
+ print,' Output Keywords: enum =, message='
+ return
+ endif
+;
+; I/O error processing
+;
+ on_ioerror,ioerror
+;
+; set defaults
+;
+ message = ''
+ if n_elements(noscale) eq 0 then noscale = 0
+ if n_elements(exten_no) eq 0 then exten_no = -1
+ if n_elements(extname) eq 0 then extname = ''
+ if n_elements(extver) eq 0 then extver = 0
+ if n_elements(extlevel) eq 0 then extlevel = 0
+ if n_elements(first) eq 0 then first = 0
+ if n_elements(last) eq 0 then last = 0
+ if n_elements(no_abort) eq 0 then no_abort = 0
+ if n_elements(group) eq 0 then group = 0
+ if n_elements(header_only) eq 0 then header_only = 0
+ if n_elements(data_only) eq 0 then data_only = 0
+ if n_elements(no_pdu) eq 0 then no_pdu = 0
+ if n_elements(pdu) eq 0 then pdu = 0
+ if n_elements(xtension) eq 0 then xtension = ''
+;
+; Open file if file name is supplied
+;
+ fcbtype = size(file_or_fcb,/type)
+ fcbsize = n_elements(file_or_fcb)
+ if (fcbsize ne 1) || ((fcbtype ne 7) && (fcbtype ne 8)) then begin
+ message = 'Invalid Filename or FCB supplied'
+ goto,error_exit
+ end
+
+ if fcbtype eq 7 then begin
+ fits_open,file_or_fcb,fcb,no_abort=no_abort,message=message
+ if message NE '' then goto,error_exit
+ end else fcb = file_or_fcb
+;
+; determine which extension to read ==========================================
+;
+; case 1: exten_no specified
+;
+
+ enum = exten_no
+ if exten_no le -1 then begin
+;
+; case 2: extname, extver, or extlevel specified
+;
+ if (extname ne '') || (extlevel ne 0) || (extver ne 0) || $
+ (xtension ne '') then begin
+;
+; find extensions with supplied extname, extver, extlevel, and xtension
+;
+ good = replicate(1b,fcb.nextend+1)
+ if extname ne '' then good = good and $
+ (strtrim(strupcase(extname)) eq strupcase(fcb.extname))
+ if xtension ne '' then good = good and $
+ (strtrim(strupcase(xtension)) eq strupcase(fcb.xtension))
+ if extver ne 0 then good = good and (extver eq fcb.extver)
+ if extlevel ne 0 then good = good and (extlevel eq fcb.extlevel)
+ good = where(good,ngood)
+;
+; select first one
+;
+ if ngood le 0 then begin
+ message='No extension for given extname, extver, and/or' + $
+ ' extlevel found'
+ goto,error_exit
+ endif
+ enum = good[0]
+ end else begin
+;
+; case 3: read next extension
+;
+ enum = fcb.last_extension + 1
+ if (enum eq 0) && (fcb.naxis[0] eq 0) then enum = 1
+ end
+ end
+;
+; check to see if it is a valid extension
+;
+ if enum gt fcb.nextend then begin
+ message='EOF encountered'
+ goto,error_exit
+ end
+;
+; extract information from FCB for the extension
+;
+ bitpix = fcb.bitpix[enum]
+ naxis = fcb.naxis[enum]
+ if naxis gt 0 then axis = fcb.axis[0:naxis-1,enum]
+ gcount = fcb.gcount[enum]
+ pcount = fcb.pcount[enum]
+ xtension = fcb.xtension[enum]
+ fcompress = tag_exist(fcb,'fcompress') ? fcb.fcompress : 0
+;
+; read header ================================================================
+;
+ if data_only then goto,read_data
+ h = bytarr(80,36,/nozero)
+ nbytes_in_file = fcb.nbytes
+ position = fcb.start_header[enum]
+
+ if fcompress then mrd_skip,fcb.unit,position else $
+ point_lun,fcb.unit,position
+ first_block = 1 ; first block in header flag
+ repeat begin
+ if position ge nbytes_in_file then begin
+ message = 'EOF encountered while reading header'
+ goto,error_exit
+ endif
+
+ readu,fcb.unit,h
+ position += 2880
+ hdr = string(h>32b)
+ endline = where(strcmp(hdr,'END ',8),nend)
+ if nend gt 0 then hdr = hdr[0:endline[0]]
+ if first_block then header = hdr else header = [header,hdr]
+ first_block = 0
+ end until (nend gt 0)
+;
+; extract some header information
+;
+ bscale = sxpar(header,'bscale', Count = N_bscale)
+ bzero = sxpar(header,'bzero', Count = N_bzero)
+ if bscale eq 0.0 then bscale = 1.0
+ unsgn_int = (bitpix EQ 16) && (Bzero EQ 32768) && (bscale EQ 1)
+ unsgn_lng = (bitpix EQ 32) && (Bzero EQ 2147483648) && (bscale EQ 1)
+ if (unsgn_int || unsgn_lng) then $
+ if ~keyword_set(no_unsigned) then noscale = 1
+ if (N_bscale gt 0) &&(noscale eq 0) && (data_only eq 0) && $
+ (last eq 0) && (header_only eq 0) then sxaddpar,header,'bscale',1.0
+ if (N_bzero gt 0) && (noscale eq 0) && (data_only eq 0) && $
+ (last eq 0) && (header_only eq 0) then sxaddpar,header,'bzero',0.0
+ groups = sxpar(header,'groups')
+;
+; create header with form:
+; ! Required Keywords
+; ! BEGIN MAIN HEADER ------------------------------------------
+; ! Primary data unit header keywords
+; ! BEGIN EXTENSION HEADER -------------------------------------
+; ! Extension header keywords
+; ! END
+;
+;
+; add Primary Data Unit header to it portion of the header to it, unless the
+; NO_PDU keyword is set, or the INHERIT keyword is not found or set to false
+;
+
+ if no_pdu EQ 0 then no_pdu = 1 - (sxpar(header,'INHERIT') > 0)
+ if pdu then no_pdu = 0
+ if (no_pdu eq 0) && (enum gt 0) then begin
+
+;
+; delete required keywords
+;
+ sxdelpar,header,['SIMPLE','BITPIX','NAXIS','NAXIS1', $
+ 'NAXIS2','NAXIS3','NAXIS4','NAXIS5', $
+ 'NAXIS6','NAXIS7','NAXIS8','EXTEND', $
+ 'PCOUNT','GCOUNT','GROUPS', $
+ 'XTENSION']
+
+
+; create required keywords
+;
+ hreq = strarr(20)
+ hreq[0] = 'END '
+
+ if enum eq 0 then $
+ sxaddpar,hreq,'SIMPLE','T','image conforms to FITS standard' $
+ else sxaddpar,hreq,'XTENSION',xtension,'extension type'
+
+ sxaddpar,hreq,'bitpix',bitpix,'bits per data value'
+ sxaddpar,hreq,'naxis',naxis,'number of axes'
+ if naxis gt 0 then for i=1,naxis do $
+ sxaddpar,hreq,'naxis'+strtrim(i,2),axis[i-1]
+ if (enum eq 0) && (fcb.nextend GE 1) then $
+ sxaddpar,hreq,'EXTEND','T','file may contain extensions'
+ if groups then sxaddpar,hreq,'GROUPS','T','Group format'
+ if (enum gt 0) || (pcount gt 0) then $
+ sxaddpar,hreq,'PCOUNT',pcount,'Number of group parameters'
+ if (enum gt 0) || (gcount gt 0) then $
+ sxaddpar,hreq,'GCOUNT',gcount,'Number of groups'
+ n0 = where(strcmp(hreq,'END ',8)) & n0=n0[0]
+ hpdu = fcb.hmain
+ n1 = n_elements(hpdu)
+ if n1 gt 1 then begin
+ hreq = [hreq[0:n0-1], $
+ 'BEGIN MAIN HEADER ---------------------------------', $
+ hpdu[0:n1-2], $
+ 'BEGIN EXTENSION HEADER ----------------------------', $
+ 'END ']
+ n0 += n1 + 1
+ end
+;
+; add extension header
+;
+ header = [hreq[0:n0-1],header]
+ end
+ if header_only then begin
+ data = 0
+ goto,done
+ endif
+;
+; Read Data ===================================================================
+;
+read_data:
+ if naxis eq 0 then begin ;null image?
+ data = 0
+;
+; check for implicit data specified by NPIX1, NPIX2, and PIXVALUE (provided
+; the header was red, i.e. data_only was not specified)
+;
+ if data_only eq 0 then begin
+ NPIX1 = sxpar(header,'NPIX1')
+ NPIX2 = sxpar(header,'NPIX2')
+ PIXVALUE = sxpar(header,'PIXVALUE')
+ if (NPIX1*NPIX2) gt 0 then $
+ data = replicate(pixvalue,npix1,npix2)
+ end
+ goto,done
+ endif
+
+ case BITPIX of
+ 8: IDL_type = 1 ; Byte
+ 16: IDL_type = 2 ; Integer*2
+ 32: IDL_type = 3 ; Integer*4
+ -32: IDL_type = 4 ; Real*4
+ -64: IDL_type = 5 ; Real*8
+ else: begin
+ message = 'ERROR - Illegal value of BITPIX (= ' + $
+ strtrim(bitpix,2) + ') in FITS header'
+ goto,error_exit
+ end
+ endcase
+
+ ndata = product( axis, /integer )
+ bytes_per_word = (abs(bitpix)/8)
+ nbytes_per_group = bytes_per_word * (pcount + ndata)
+ nbytes = (gcount>1) * nbytes_per_group
+ nwords = nbytes / bytes_per_word
+;
+; starting data position
+;
+
+ skip = data_only EQ 0 ? fcb.start_data[enum] - position : 0
+ position = fcb.start_data[enum]
+;
+; find correct group
+;
+ if last eq 0 then begin
+ if group ge (gcount>1) then begin
+ message='INVALID group number specified'
+ goto,error_exit
+ end
+ skip += long64(group) * nbytes_per_group
+ position += skip
+ end
+;
+; read group parameters
+;
+ if (enum eq 0) && (fcb.random_groups eq 1) && (pcount gt 0) && $
+ (last eq 0) then begin
+ if N_params() gt 3 then begin
+ group_par = make_array( dim = [pcount], type = idl_type, /nozero)
+
+ if fcompress then mrd_skip,fcb.unit,skip else $
+ point_lun,fcb.unit,position
+
+ readu,fcb.unit,group_par
+ endif
+ skip = long64(pcount) * bytes_per_word
+ position += skip
+ endif
+;
+; create data array
+;
+ if last gt 0 then begin
+;
+; user specified first and last
+;
+ if (first lt 0) || (last le 1) || (first gt last) || $
+ (last gt nwords-1) then begin
+ message = 'INVALID value for parameters FIRST & LAST'
+ goto,error_exit
+ endif
+ data = make_array(dim = [last-first+1], type=idl_type, /nozero)
+ skip += long64(first) * bytes_per_word
+ position += skip
+ endif else begin
+;
+; full array
+;
+ if ndata eq 0 then begin
+ data = 0
+ goto,done
+ endif
+ if naxis gt 8 then begin
+ message = 'Maximum value of NAXIS allowed is 8'
+ goto,error_exit
+ endif
+ data = make_array(dim = axis, type = idl_type, /nozero)
+ endelse
+;
+; read array
+;
+ if fcompress then mrd_skip,fcb.unit,skip else $
+ point_lun,fcb.unit,position
+ readu,fcb.unit,data
+ if fcompress then swap_endian_inplace,data,/swap_if_little
+ if ~keyword_set(No_Unsigned) && (~data_only) then begin
+ if unsgn_int then begin
+ data = uint(data) - uint(32768)
+ endif else if unsgn_lng then begin
+ data = ulong(data) - ulong(2147483648)
+ endif
+ endif
+;
+; scale data if header was read and first and last not used. Do a special
+; check of an unsigned integer (BZERO = 2^15) or unsigned long (BZERO = 2^31)
+;
+ if (data_only eq 0) && (last eq 0) && (noscale eq 0) then begin
+
+ if bitpix lt 32 then begin ;use real*4 for bitpix<32
+ bscale = float(bscale)
+ bzero = float(bzero)
+ endif
+ if bscale ne 1.0 then data *= bscale
+ if bzero ne 0.0 then data += bzero
+ endif
+;
+; done
+;
+done:
+ if fcompress then begin
+ free_lun,fcb.unit
+ ff = strmid(fcb.filename,1,strlen(fcb.filename)-2)
+;Rewind the file to the beginning, if it might be used again
+ if fcbtype NE 7 then begin
+ spawn,ff,unit=unit,/sh, stderr = stderr
+ fcb.unit = unit
+ endif
+ endif else $
+ if fcbtype eq 7 then fits_close,fcb else file_or_fcb.last_extension=enum
+ !err = 1
+ return
+
+;
+; error exit
+;
+ioerror:
+ message = !ERROR_STATE.MSG
+error_exit:
+ if (fcbtype eq 7) && (N_elements(fcb) GT 0) then $
+ fits_close,fcb, no_abort=no_abort
+ !err = -1
+ if keyword_set(no_abort) then return
+ print,'FITS_READ ERROR: '+message
+ retall
+end
diff --git a/Code/script_idl_mv/astrolib/fits_test_checksum.pro b/Code/script_idl_mv/astrolib/fits_test_checksum.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0ca0e512e338f40f4e039a51bb0b77aad950bf2b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_test_checksum.pro
@@ -0,0 +1,109 @@
+ function fits_test_checksum,hdr, data, ERRMSG = errmsg,FROM_IEEE=from_ieee
+;+
+; NAME:
+; FITS_TEST_CHECKSUM()
+; PURPOSE:
+; Verify the values of the CHECKSUM and DATASUM keywords in a FITS header
+; EXPLANATION:
+; Follows the 2007 version of the FITS checksum proposal at
+; http://fits.gsfc.nasa.gov/registry/checksum.html
+;
+; CALLING SEQUENCE:
+; result = FITS_TEST_CHECKSUM(HDR, [ DATA, ERRMSG=, /FROM_IEEE ])
+; INPUTS:
+; HDR - FITS header (vector string)
+; OPTIONAL DATA:
+; DATA - data array associated with the FITS header. An IDL structure is
+; not allowed. If not supplied, or
+; set to a scalar, then there is assumed to be no data array
+; associated with the FITS header.
+; RESULT:
+; An integer -1, 0 or 1 indicating the following conditions:
+; 1 - CHECKSUM (and DATASUM) keywords are present with correct values
+; 0 - CHECKSUM keyword is not present
+; -1 - CHECKSUM or DATASUM keyword does not have the correct value
+; indicating possible data corruption.
+; OPTIONAL INPUT KEYWORD:
+; /FROM_IEEE - If this keyword is set, then the input is assumed to be in
+; big endian format (e.g. an untranslated FITS array). This
+; keyword only has an effect on little endian machines (e.g.
+; a Linux box).
+; OPTIONAL OUTPUT KEYWORD:
+; ERRMSG - will contain a scalar string giving the error condition. If
+; RESULT = 1 then ERRMSG will be an empty string. If this
+; output keyword is not supplied, then the error message will be
+; printed at the terminal.
+; NOTES:
+; The header and data must be *exactly* as originally written in the FITS
+; file. By default, some FITS readers may alter keyword values (e.g.
+; BSCALE) or append information (e.g. HISTORY or an inherited primary
+; header) and this will alter the checksum value.
+; PROCEDURES USED:
+; CHECKSUM32, FITS_ASCII_ENCODE(), SXPAR()
+; EXAMPLE:
+; Verify the CHECKSUM keywords in the primary header/data unit of a FITS
+; file 'test.fits'
+;
+; FITS_READ,'test.fits',data,hdr,/no_PDU,/NoSCALE
+; print,FITS_TEST_CHECKSUM(hdr,data)
+;
+; Note the use of the /No_PDU and /NoSCALE keywords to avoid any alteration
+; of the FITS header
+; REVISION HISTORY:
+; W. Landsman SSAI December 2002
+; Return quietly if CHECKSUM keywords not found W. Landsman May 2003
+; Add /NOSAVE to CHECKSUM32 calls when possible W. Landsman Sep 2004
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_Params() LT 1 then begin
+ print,'Syntax - result = FITS_TEST_CHECKSUM(Hdr, [Data,' + $
+ ' ERRMSG=, /FROM_IEEE ])'
+ return, 0
+ endif
+ result = 1
+ printerr = ~arg_present(errmsg)
+ checksum = sxpar(hdr,'CHECKSUM', Count = N_checksum)
+ datasum = sxpar(hdr,'DATASUM', Count = N_datasum)
+ if (N_checksum EQ 0) then begin
+ errmsg = 'CHECKSUM keyword not present in FITS header'
+ if printerr then message,/con, errmsg
+ return, 0
+ endif
+ if N_datasum EQ 0 then datasum = '0'
+ ch = shift(byte(checksum),-1)
+ checksum32,ch-48b, sum32, /NOSAVE
+ bhdr = byte(hdr)
+ remain = N_elements(bhdr) mod 2880
+ if remain NE 0 then $
+ bhdr = [reform(bhdr,N_elements(bhdr)), replicate(32b, 2880 - remain) ]
+ checksum32,bhdr, hsum, FROM_IEEE = from_ieee, /NOSAVE
+ Ndata = N_elements(data)
+ if Ndata GT 1 then begin
+ checksum32, data, dsum, FROM_IEEE= from_ieee
+ remain = Ndata mod 2880
+ if remain GT 0 then begin
+ exten = sxpar( hdr, 'XTENSION', Count = N_exten)
+ if N_exten GT 0 then if exten EQ 'TABLE ' then $
+ checksum32,[dsum,replicate(32b,2880-remain)],dsum,/NOSAVE
+ endif
+ checksum32, [dsum, hsum], hdusum, /NOSAVE
+ dsum = strtrim(dsum,2)
+ if dsum NE datasum then begin
+ result = 1
+ errmsg = 'Computed Datasum: ' + dsum + $
+ ' FITS header value: ' + datasum
+ if printerr then message,/Con, errmsg
+ endif
+ endif else hdusum = hsum
+
+ csum = FITS_ASCII_ENCODE(not hdusum)
+ if csum NE '0000000000000000' then begin
+ result = -1
+ errmsg = 'Computed Checksum: ' + csum + $
+ ' FITS header value: ' + checksum
+ if printerr then message,/Con, errmsg
+ endif
+ return, result
+ end
diff --git a/Code/script_idl_mv/astrolib/fits_write.pro b/Code/script_idl_mv/astrolib/fits_write.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5ce3af2bdee32b89ed61f1b53000714cbfdd485b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fits_write.pro
@@ -0,0 +1,379 @@
+pro fits_write,file_or_fcb,data,header_in,extname=extname,extver=extver, $
+ xtension=xtension, extlevel=extlevel, $
+ no_abort=no_abort, message = message, header = header, $
+ no_data = no_data
+;+
+; NAME:
+; FITS_WRITE
+;
+; PURPOSE:
+; To write a FITS primary data unit or extension.
+;
+; EXPLANATION:
+; ***NOTE** This version of FITS_READ must be used with a post Sep 2006
+; version of FITS_OPEN.
+;
+; CALLING SEQUENCE:
+; FITS_WRITE, filename_or_fcb, data, [header_in]
+;
+; INPUTS:
+; FILENAME_OR_FCB: name of the output data file or the FITS control
+; block returned by FITS_OPEN (called with the /WRITE or
+; /APPEND) parameters.
+;
+; OPTIONAL INPUTS:
+; DATA: data array to write. If not supplied or set to a scalar, a
+; null image is written.
+; HEADER_IN: FITS header keyword. If not supplied, a minimal basic
+; header will be created. Required FITS keywords, SIMPLE,
+; BITPIX, XTENSION, NAXIS, ... are added by FITS_WRITE and
+; do not need to be supplied with the header. If supplied,
+; their values will be updated as necessary to reflect DATA.
+;
+; INPUT KEYWORD PARAMETERS:
+;
+; XTENSION: type of extension to write (Default="IMAGE"). If not
+; supplied, it will be taken from HEADER_IN. If not in either
+; place, the default is "IMAGE". This parameter is ignored
+; when writing the primary data unit. Note that binary and
+; and ASCII table extensions already have a properly formatted
+; header (e.g. with TTYPE* keywords) and byte array data.
+; EXTNAME: EXTNAME for the extension. If not supplied, it will be taken
+; from HEADER_IN. If not supplied and not in HEADER_IN, no
+; EXTNAME will be written into the output extension.
+; EXTVER: EXTVER for the extension. If not supplied, it will be taken
+; from HEADER_IN. If not supplied and not in HEADER_IN, no
+; EXTVER will be written into the output extension.
+; EXTLEVEL: EXTLEVEL for the extension. If not supplied, it will be taken
+; from HEADER_IN. If not supplied and not in HEADER_IN, no
+; EXTLEVEL will be written into the output extension.
+; /NO_ABORT: Set to return to calling program instead of a RETALL
+; when an I/O error is encountered. If set, the routine will
+; return a non-null string (containing the error message) in the
+; keyword MESSAGE. If /NO_ABORT not set, then FITS_WRITE will
+; print the message and issue a RETALL
+; /NO_DATA: Set if you only want FITS_WRITE to write a header. The
+; header supplied will be written without modification and
+; the user is expected to write the data using WRITEU to unit
+; FCB.UNIT. When FITS_WRITE is called with /NO_DATA, the user is
+; responsible for the validity of the header, and must write
+; the correct amount and format of the data. When FITS_WRITE
+; is used in this fashion, it will pad the data from a previously
+; written extension to 2880 blocks before writting the header.
+;
+; OUTPUT KEYWORD PARAMETERS:
+; MESSAGE: value of the error message for use with /NO_ABORT
+; HEADER: actual output header written to the FITS file.
+;
+; NOTES:
+; If the first call to FITS_WRITE is an extension, FITS_WRITE will
+; automatically write a null image as the primary data unit.
+;
+; Keywords and history in the input header will be properly separated
+; into the primary data unit and extension portions when constructing
+; the output header (See FITS_READ for information on the internal
+; Header format which separates the extension and PDU header portions).
+;
+; EXAMPLES:
+; Write an IDL variable to a FITS file with the minimal required header.
+; FITS_WRITE,'newfile.fits',ARRAY
+;
+; Write the same array as an image extension, with a null Primary data
+; unit.
+; FITS_WRITE,'newfile.fits',ARRAY,xtension='IMAGE'
+;
+; Write 4 additional image extensions to the same file.
+; FITS_OPEN,'newfile.fits',fcb
+; FITS_WRITE,fcb,data1,extname='FLUX',extver=1
+; FITS_WRITE,fcb,err1,extname'ERR',extver=1
+; FITS_WRITE,fcb,data2,extname='FLUX',extver=2
+; FITS_WRITE,fcb,err2,extname='ERR',extver=2
+; FITS_CLOSE,FCB
+;
+; WARNING:
+; FITS_WRITE currently does not completely update the file control block.
+; When mixing FITS_READ and FITS_WRITE commands it is safer to use
+; file names, rather than passing the file control block.
+; PROCEDURES USED:
+; FITS_OPEN, SXADDPAR, SXDELPAR, SXPAR()
+; HISTORY:
+; Written by: D. Lindler August, 1995
+; Work for variable length extensions W. Landsman August 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+; PCOUNT and GCOUNT added for IMAGE extensions J. Graham October 1999
+; Write unsigned data types W. Landsman December 1999
+; Pad data area with zeros not blanks W. McCann/W. Landsman October 2000
+; Return Message='' to signal normal operation W. Landsman Nov. 2000
+; Ensure that required extension table keywords are in proper order
+; W.V. Dixon/W. Landsman March 2001
+; Assume since V5.1, remove NaNValue keyword W. Landsman Nov. 2002
+; Removed obsolete !ERR system variable W. Landsman Feb 2004
+; Check that byte array supplied with table extension W. Landsman Mar 2004
+; Make number of bytes 64bit to avoid possible overflow W.L Apr 2006
+; Assume FITS_OPEN has opened the file with /SWAP_IF_LITTLE_ENDIAN
+; W. Landsman September 2006
+; Removes BZERO and BSCALE for floating point output, D. Lindler, Sep 2008
+;-
+;-----------------------------------------------------------------------------
+;
+; print calling sequence if no parameters supplied
+;
+ if n_params() lt 1 then begin
+ print,'Calling Sequence: FITS_WRITE,file_or_fcb,data,header_in'
+ print,'Input Keywords: extname, extver, xtension, extlevel,' + $
+ '/no_abort, /no_data'
+ print,'Output Keywords: message, header '
+ return
+ end
+;
+; Open file if file name is supplied instead of a FCB
+;
+ message = ''
+ s = size(file_or_fcb) & fcbtype = s[s[0]+1]
+ fcbsize = n_elements(file_or_fcb)
+ if (fcbsize ne 1) || ((fcbtype ne 7) && (fcbtype ne 8)) then begin
+ message = 'Invalid Filename or FCB supplied'
+ goto,error_exit
+ end
+
+ if fcbtype eq 7 then begin
+ if keyword_set(no_data) then begin
+ print,'FITS_WRITE: Must have FCB supplied for NO_DATA'
+ retall
+ endif
+ fits_open,file_or_fcb,fcb,/write, $
+ no_abort=no_abort,message=message
+ if message NE '' then goto,error_exit
+ end else fcb = file_or_fcb
+;
+; if user did not pad data to 2880 blocks, pad it now
+;
+ point_lun,-fcb.unit,current_position
+ npad = 2880 - (current_position mod 2880)
+ if npad eq 2880 then npad = 0
+ if npad gt 0 then writeu,fcb.unit,bytarr(npad)
+;
+; if no_data, just go and write user header as supplied
+;
+ if keyword_set(no_data) then begin
+ header = header_in
+ goto,write_header
+ end
+;
+; if header not supplied then set it to a null header
+;
+ if n_elements(header_in) le 1 then begin
+ header = strarr(1)
+ header[0] = 'END '
+ end else header = header_in
+
+;
+; on I/O error go to statement IOERROR
+;
+; on_ioerror,ioerror
+;
+; verify file is open for writing
+;
+ if fcb.open_for_write eq 0 then begin
+ message,'File is not open for writing'
+ goto,error_exit
+ endif
+;
+; determine bitpix and axis information
+;
+ s = size(data)
+ naxis = s[0]
+ if naxis gt 0 then axis = s[1:naxis]
+ idltype = s[naxis+1]
+
+ if (idltype gt 5) && (idltype NE 12) && (idltype NE 13) then begin
+ message='Data array is an invalid type'
+ goto,error_exit
+ endif
+ bitpixs = [8,8,16,32,-32,-64,0,0,0,0,0,0,16,32]
+ bitpix = bitpixs[idltype]
+;
+; determine extname, extver, xtension and extlevel and delete current values
+;
+ if n_elements(xtension) gt 0 then begin
+ Axtension = xtension
+ end else begin
+ Axtension = sxpar(header,'xtension', Count = N_Axtension)
+ if N_Axtension EQ 0 then Axtension = ''
+ end
+ if Axtension EQ 'BINTABLE' or (Axtension EQ 'TABLE') then $
+ if idltype GT 1 then begin
+ message='A Byte array must be supplied with a ' + $
+ 'BINTABLE or TABLE extension'
+ goto, error_exit
+ endif
+
+ if n_elements(extname) gt 0 then begin
+ Aextname = extname
+ end else begin
+ Aextname = sxpar(header,'extname', Count = N_Aextname)
+ if N_Aextname EQ 0 then Aextname = ''
+ end
+
+ if n_elements(extver) gt 0 then $
+ Aextver = extver $
+ else Aextver = sxpar(header,'extver')
+
+ if n_elements(extlevel) gt 0 then $
+ Aextlevel = extlevel $
+ else Aextlevel = sxpar(header,'extlevel')
+
+ sxdelpar,header,['XTENSION','EXTNAME','EXTVER','EXTLEVEL']
+
+;
+; separate header into main and extension header
+;
+ keywords = strmid(header,0,8)
+ hpos1 = where(keywords eq 'BEGIN MA') & hpos1 = hpos1[0] ;begin main
+ hpos2 = where(keywords eq 'BEGIN EX') & hpos2 = hpos2[0] ;begin ext.
+ hpos3 = where(keywords eq 'END ') & hpos3 = hpos3[0] ;end of header
+
+ if (hpos1 gt 0) && (hpos2 lt hpos1) then begin
+ message,'Invalid header BEGIN EXTENSION HEADER ... out of place'
+ goto,error_exit
+ endif
+
+ if (hpos3 lt 0) then begin
+ print,'FITS_WRITE: END missing from input header and was added'
+ header = [header,'END ']
+ hpos2 = n_elements(header)-1
+ end
+;
+; determine if a extension was supplied and no primary data unit (PDU)
+; was written
+;
+ if (fcb.nextend eq -1) then begin ;no pdu written yet?
+ if (hpos2 gt 0) || (Axtension ne '') || (Aextname ne '') || $
+ (Aextver ne 0) || (Aextlevel ne 0) then begin
+;
+; write null image PDU
+;
+ if (hpos1 gt 0) && (hpos2 gt (hpos1+1)) then $
+ hmain = [header[hpos1+1:hpos2-1],'END ']
+ fits_write,fcb,0,hmain,/no_abort,message=message
+ if message NE '' then goto,error_exit
+ end
+ end
+;
+; For extensions, do not use PDU portion of the header
+;
+ if (hpos2 gt 0) then header = header[hpos2+1:hpos3]
+;
+; create required keywords for the header
+;
+ h = strarr(20)
+ h[0] = 'END '
+
+ if fcb.nextend eq -1 then begin
+ sxaddpar,h,'SIMPLE','T','image conforms to FITS standard'
+ end else begin
+ if Axtension eq '' then Axtension = 'IMAGE '
+ sxaddpar,h,'XTENSION',Axtension,'extension type'
+ end
+ sxaddpar,h,'BITPIX',bitpix,'bits per data value'
+ sxaddpar,h,'NAXIS',naxis,'number of axes'
+ if naxis gt 0 then for i=1,naxis do $
+ sxaddpar,h,'NAXIS'+strtrim(i,2),axis[i-1]
+ if fcb.nextend eq -1 then begin
+ sxaddpar,h,'EXTEND','T','file may contain extensions'
+ end else begin ;PCOUNT, GCOUNT are mandatory for extensions
+ sxaddpar,h,'PCOUNT',0
+ sxaddpar,h,'GCOUNT',1
+ if (Axtension eq 'BINTABLE') || $
+ (Axtension eq 'TABLE ') then begin
+ tfields = sxpar(header,'TFIELDS') > 0
+ sxaddpar,h,'TFIELDS',tfields
+ endif
+ if Aextname ne '' then sxaddpar,h,'EXTNAME',Aextname
+ if Aextver gt 0 then sxaddpar,h,'EXTVER',Aextver
+ if Aextlevel gt 0 then sxaddpar,h,'EXTLEVEL',Aextlevel
+ endelse
+ if idltype EQ 12 then $
+ sxaddpar,header,'BZERO',32768,'Data is unsigned integer'
+ if idltype EQ 13 then $
+ sxaddpar,header,'BZERO',2147483648,'Data is unsigned long'
+ if idltype GE 12 then sxdelpar,header,'BSCALE'
+ if (idltype EQ 4) || (idltype EQ 5) then $
+ sxdelpar,header,['BSCALE','BZERO']
+;
+; delete special keywords from user supplied header
+;
+ pcount = sxpar(header,'pcount')
+ groups = sxpar(header,'groups')
+ sxdelpar,header,['SIMPLE','BITPIX','NAXIS','NAXIS1','NAXIS2','NAXIS3', $
+ 'NAXIS4','NAXIS5','NAXIS6','NAXIS7','NAXIS8','EXTEND', $
+ 'PCOUNT','GCOUNT','GROUPS','TFIELDS']
+ if groups then if (pcount gt 0) then for i=1,pcount do $
+ sxdelpar,header,['ptype','pscal','pzero']+strtrim(i,2)
+;
+; combine the two headers
+;
+ last = where(strmid(h,0,8) eq 'END ')
+ header = [h[0:last[0]-1],header]
+
+;
+; convert header to bytes and write
+;
+write_header:
+ last = where(strmid(header,0,8) eq 'END ')
+ n = last[0] + 1
+ byte_header = replicate(32b,80,n)
+ for i=0,n-1 do byte_header[0,i] = byte(header[i])
+ writeu,fcb.unit,byte_header
+;
+; pad header to 2880 byte records
+;
+ npad = 2880 - (80L*n mod 2880)
+ if npad eq 2880 then npad = 0
+ if (npad gt 0) then writeu,fcb.unit,replicate(32b,npad)
+ nbytes_header = npad + n*80
+ if keyword_set(no_data) then return
+;
+; process data
+;
+ if naxis gt 0 then begin
+;
+; convert to IEEE
+;
+ unsigned = (idltype EQ 12) || (idltype EQ 13)
+ if idltype EQ 12 then newdata = fix(data - 32768)
+ if idltype EQ 13 then newdata = long(data - 2147483648)
+;
+; write the data
+;
+ nbytes = long64(N_elements(data)) * (abs(bitpix)/8)
+ npad = 2880 - (nbytes mod 2880)
+ if npad eq 2880 then npad = 0
+ if unsigned then writeu,fcb.unit,newdata else writeu,fcb.unit,data
+ if npad gt 0 then begin
+ if Axtension EQ 'TABLE ' then padnum = 32b else padnum = 0b
+ writeu,fcb.unit,replicate(padnum,npad)
+ endif
+ nbytes_data = nbytes + npad
+ end else begin
+ nbytes_data = 0
+ end
+;
+; done, update file control block
+;
+ fcb.nextend = fcb.nextend + 1
+ if fcbtype eq 7 then fits_close,fcb else file_or_fcb = fcb
+ !err = 1
+ return
+;
+; error exit
+;
+ioerror:
+ message = !error_state.msg
+error_exit:
+ if fcbtype eq 7 then free_lun,fcb.unit
+ !err = -1
+ if keyword_set(no_abort) then return
+ message,' ERROR: '+message,/CON
+ retall
+end
diff --git a/Code/script_idl_mv/astrolib/fitsdir.pro b/Code/script_idl_mv/astrolib/fitsdir.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d674003a78df03b83cbfbdf5aafcbd190b555f05
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fitsdir.pro
@@ -0,0 +1,332 @@
+pro fitsdir ,directory, TEXTOUT = textout, Keywords = keywords, $
+ nosize = nosize, alt1_keywords=alt1_keywords, alt2_keywords=alt2_keywords,$
+ alt3_keywords = alt3_keywords, NoTelescope = NoTelescope,exten=exten
+;+
+; NAME:
+; FITSDIR
+; PURPOSE:
+; Display selected FITS keywords from the headers of FITS files.
+; EXPLANATION:
+;
+; The values of either user-specified or default FITS keywords are
+; displayed in either the primary header and/or the first extension header.
+; Unless the /NOSIZE keyword is set, the data size is also displayed.
+; The default keywords are as follows (with keywords in 2nd row used if
+; those in the first row not found, and the 3rd row if neither the keywords
+; in the first or second rows found:)
+;
+; DATE-OBS TELESCOP OBJECT EXPTIME
+; TDATEOBS TELNAME TARGNAME INTEG ;First Alternative
+; DATE OBSERVAT EXPOSURE ;Second Alternative
+; INSTRUME EXPTIM ;Third Alternative
+;
+; FITSDIR will also recognize gzip compressed files (must have a .gz
+; or FTZ extension).
+; CALLING SEQUENCE:
+; FITSDIR , [ directory, TEXTOUT =, EXTEN=, KEYWORDS=, /NOSIZE, /NoTELESCOPE
+; ALT1_KEYWORDS= ,ALT2_KEYWORDS = ,ALT3_KEYWORDS =
+;
+; OPTIONAL INPUT PARAMETERS:
+; DIRECTORY - Scalar string giving file name, disk or directory to be
+; searched. Wildcard file names are allowed. Examples of
+; valid names include 'iraf/*.fits' (Unix) or 'd:\myfiles\f*.fits',
+; (Windows).
+;
+; OPTIONAL KEYWORD INPUT PARAMETER
+; KEYWORDS - FITS keywords to display, as either a vector of strings or as
+; a comma delimited scalar string, e.g.'testname,dewar,filter'
+; If not supplied, then the default keywords are 'DATE-OBS',
+; 'TELESCOP','OBJECT','EXPTIME'
+; ALT1_KEYWORDS - A list (either a vector of strings or a comma delimited
+; strings of alternative keywords to use if the default
+; KEYWORDS cannot be found. By default, 'TDATEOBS', is the
+; alternative to DATE-OBS, 'TELNAME' for 'TELESCOP','TARGNAME'
+; for 'OBJECT', and 'INTEG' for EXPTIME
+; ALT2_KEYWORDS - A list (either a vector of strings or a comma delimited
+; strings of alternative keywords to use if neither KEYWORDS
+; nor ALT1_KEYWORDS can be found.
+; ALT3_KEYWORDS - A list (either a vector of strings or a comma delimited
+; strings of alternative keywords to use if neither KEYWORDS
+; nor ALT1_KEYWORDS nor ALT2_KEYWORDS can be found.
+; /NOSIZE - if set then information about the image size is not displayed
+; TEXTOUT - Controls output device as described in TEXTOPEN procedure
+; textout=1 TERMINAL using /more option
+; textout=2 TERMINAL without /more option
+; textout=3 .prt
+; textout=4 laser.tmp
+; textout=5 user must open file
+; textout=7 Append to existing .prt file
+; textout = filename (default extension of .prt)
+; EXTEN - Specifies an extension number (/EXTEN works for first extension)
+; which is checked for the desired keywords.
+; /NOTELESCOPE - If set, then if the default keywords are used, then the
+; TELESCOPE (or TELNAME, OBSERVAT, INSTRUME) keywords are omitted
+; to give more room for display other keywords. The /NOTELESCOP
+; keyword has no effect if the default keywords are not used.
+; OUTPUT PARAMETERS:
+; None.
+;
+; EXAMPLES:
+; (1) Print info on all'*.fits' files in the current directory using default
+; keywords. Include information from the extension header
+; IDL> fitsdir,/exten
+;
+; (2) Write a driver program to display selected keywords in HST/ACS drizzled
+; (*drz) images
+; pro acsdir
+; keywords = 'date-obs,targname,detector,filter1,filter2,exptime'
+; fitsdir,'*drz.fits',key=keywords,/exten
+; return & end
+;
+; (3) Write info on all *.fits files in the Unix directory /usr2/smith, to a
+; file 'smith.txt' using the default keywords, but don't display the value
+; of the TELESCOPE keyword
+;
+; IDL> fitsdir ,'/usr2/smith/*.fits',t='smith.txt', /NoTel
+;
+; PROCEDURE:
+; FILE_SEARCH() is used to find the specified FITS files. The
+; header of each file is read, and the selected keywords are extracted.
+; The formatting is adjusted so that no value is truncated on display.
+;
+; SYSTEM VARIABLES:
+; TEXTOPEN (called by FITSDIR) will automatically define the following
+; non-standard system variables if they are not previously defined:
+;
+; DEFSYSV,'!TEXTOUT',1
+; DEFSYSV,'!TEXTUNIT',0
+;
+; PROCEDURES USED:
+; FDECOMP, FXMOVE, MRD_HREAD, REMCHAR
+; TEXTOPEN, TEXTCLOSE
+; MODIFICATION HISTORY:
+; Written, W. Landsman, HSTX February, 1993
+; Search alternate keyword names W.Landsman October 1998
+; Avoid integer truncation for NAXISi >32767 W. Landsman July 2000
+; Don't leave open unit W. Landsman July 2000
+; Added EXTEN keyword, work with compressed files, additional alternate
+; keywords W. Landsman December 2000
+; Don't assume floating pt. exposure time W. Landsman September 2001
+; Major rewrite, KEYWORD & ALT*_KEYWORDS keywords, no truncation,
+; /NOSIZE keyword W. Landsman, SSAI August 2002
+; Assume V5.3 or later W. Landsman November 2002
+; Fix case where no keywords supplied W. Landsman January 2003
+; NAXIS* values must be integers W. Landsman SSAI June 2003
+; Trim spaces off of input KEYWORD values W. Landsman March 2004
+; Treat .FTZ extension as gzip compressed W. Landsman September 2004
+; Assume since V5.5, file_search() available W. Landsman Aug 2006
+; Don't assume all images compressed or uncompressed W. L. Apr 2010
+; Use V6.0 notation W.L. Feb 2011
+; Don't let a corrupted file cause an abort W.L. Feb 2014
+;-
+; On_error,2
+
+ compile_opt idl2
+
+ if N_elements(directory) EQ 0 then directory = '*.fits'
+ if N_elements(exten) EQ 0 then exten = 0
+
+ FDECOMP, directory, disk, dir, filename, ext
+ if filename EQ '' then begin
+ directory = disk + dir + '*.fits'
+ filename = '*'
+ ext = 'fits'
+ endif else if !VERSION.OS_FAMILY EQ 'unix' then begin
+ if (strpos(filename,'*') LT 0) && (ext EQ '') then begin
+ directory = disk + dir + filename + '/*.fits'
+ filename = '*'
+ ext = 'fits'
+ endif
+ endif
+
+ if N_elements(keywords) EQ 0 then begin
+ keywords = ['date-obs','telescop','object','exptime']
+ if N_elements(alt1_keywords) EQ 0 then $
+ alt1_keywords = ['tdateobs','telname','targname','integ']
+ if N_elements(alt2_keywords) EQ 0 then $
+ alt2_keywords = ['date','observat','','exposure']
+ if N_elements(alt3_keywords) EQ 0 then $
+ alt3_keywords = ['','instrume','','exptim' ]
+ if keyword_set(NoTelescope) then begin
+ ii = [0,2,3]
+ keywords = keywords[ii] & alt1_keywords = alt1_keywords[ii]
+ alt2_keywords = alt2_keywords[ii] & alt3_keywords = alt3_keywords[ii]
+ endif
+ endif
+ if N_elements(keywords) EQ 1 then $
+ keys = strtrim(strupcase(strsplit(keywords,',',/EXTRACT)),2) else $
+ keys = strupcase(keywords)
+ Nkey = N_elements(keys)
+
+ case N_elements(alt1_keywords) of
+ 0: alt1_set = bytarr(Nkey)
+ 1: alt1_keys = strtrim(strupcase(strsplit(alt1_keywords[0],',',/EXTRACT)),2)
+ else: alt1_keys = strupcase(alt1_keywords)
+ endcase
+ if N_elements(alt1_set) EQ 0 then alt1_set = strlen(strtrim(alt1_keys,2)) GT 0
+
+ case N_elements(alt2_keywords) of
+ 0: alt2_set = bytarr(Nkey)
+ 1: alt2_keys = strtrim(strupcase(strsplit(alt2_keywords,',',/EXTRACT)),2)
+ else: alt2_keys = strupcase(alt2_keywords)
+ endcase
+ if N_elements(alt2_set) EQ 0 then alt2_set = strlen(strtrim(alt2_keys,2)) GT 0
+
+ case N_elements(alt3_keywords) of
+ 0: alt3_set = bytarr(Nkey)
+ 1: alt3_keys = strtrim(strupcase(strsplit(alt3_keywords,',',/EXTRACT)),2)
+ else: alt3_keys = strupcase(alt3_keywords)
+ endcase
+ if N_elements(alt3_set) EQ 0 then alt3_set = strlen(strtrim(alt3_keys,2)) GT 0
+
+ keylen = strlen(keys)
+
+ direct = spec_dir(directory)
+ files = file_search(directory,COUNT = n,/full)
+
+ if n EQ 0 then begin ;Any files found?
+ message,'No files found on '+ direct, /CON
+ return
+ endif
+
+ good = where( strlen(files) GT 0, Ngood)
+ if Ngood EQ 0 then message,'No FITS files found on '+ directory $
+ else files = files[good]
+
+; Set output device according to keyword TEXTOUT or system variable !TEXTOUT
+
+ defsysv,'!TEXTOUT',exists=ex ; Check if !TEXTOUT exists.
+ if ex eq 0 then defsysv,'!TEXTOUT',1 ; If not define it.
+ defsysv,'!TEXTUNIT',exists=ex ; Check if !TEXTOUT exists.
+ if ex eq 0 then defsysv,'!TEXTUNIT',1 ; If not define it.
+ if ~keyword_set( TEXTOUT ) then textout= !TEXTOUT
+
+ dir = 'dummy'
+ num = 0
+
+ get_lun,unit
+
+ fdecomp, files, disk, dir2, fname, qual ;Decompose into disk+filename
+ fname = strtrim(fname,2)
+ keyvalue = strarr(n,nkey)
+ bignaxis = strarr(n)
+ namelen = max(strlen(fname))
+
+ for i = 0,n-1 do begin ;Loop over each FITS file
+ compress = (qual[i] EQ 'gz') || (strupcase(qual[i]) EQ 'FTZ')
+ openr, unit, files[i], error = error, compress = compress
+ if error LT 0 then goto, BADHD
+ mrd_hread, unit, h, status, /silent, ERRMSG = errmsg
+ if status LT 0 then goto, BADHD
+
+ if exten GT 0 then begin
+ close,unit
+ openr, unit, files[i], error = error, compress = compress
+ stat = fxmove(unit, exten, /silent)
+ mrd_hread, unit, h1, extstatus, /silent, ERRMSG = errmsg
+ if extstatus EQ 0 then h = [h1,h]
+ endif
+
+ keyword = strtrim( strmid(h,0,8),2 ) ;First 8 chars is FITS keyword
+ lvalue = strtrim(strmid(h,10,20),2 )
+ value = strtrim( strmid(h,10,68),2 ) ;Chars 10-30 is FITS value
+
+ if ~keyword_set(nosize) then begin
+ l= where(keyword EQ 'NAXIS',Nfound) ;Must have NAXIS keyword
+ if Nfound GT 0 then naxis = long( lvalue[ l[0] ] ) else goto, BADHD
+
+ if naxis EQ 0 then naxisi = '0' else begin
+
+ l = where( keyword EQ 'NAXIS1', Nfound) ;Must have NAXIS1 keyword
+ if Nfound gt 0 then naxis1 = long( lvalue[l[0] ] ) else goto, BADHD
+ naxisi = strtrim( naxis1,2 )
+ endelse
+
+ if NAXIS GE 2 then begin
+ l = where(keyword EQ 'NAXIS2', Nfound) ;Must have NAXIS2 keyword
+ if Nfound gt 0 then naxis2 = long(lvalue[l[0]]) else goto, BADHD
+ naxisi = naxisi + ' ' + strtrim( naxis2, 2 )
+ endif
+
+ if NAXIS GE 3 then begin
+ l = where( keyword EQ 'NAXIS3', Nfound ) ;Must have NAXIS3 keyword
+ if Nfound GT 0 then naxis3 = long( lvalue[l[0]] ) else goto, BADHD
+ naxisi = naxisi + ' ' + strtrim( naxis3, 2 )
+ endif
+ bignaxis[i] = strtrim(naxisi)
+ endif
+
+ for k=0,nkey-1 do begin
+ l = where(keyword EQ keys[k], Nfound)
+ if Nfound EQ 0 then if alt1_set[k] then $
+ l = where(keyword EQ alt1_keys[k], Nfound)
+ if Nfound EQ 0 then if alt2_set[k] then $
+ l = where(keyword EQ alt2_keys[k], Nfound)
+ if Nfound EQ 0 then if alt3_set[k] then $
+ l = where(keyword EQ alt3_keys[k], Nfound)
+ if nfound GT 0 then begin
+ kvalue = value[l[0]]
+ if strpos(kvalue,"'") GE 0 then begin
+ temp = gettok(kvalue,"'")
+ keyvalue[i,k] = strtrim(gettok(kvalue,"'"),2)
+ endif else keyvalue[i,k] = strtrim(gettok(kvalue,'/'),2)
+ endif
+
+ endfor
+
+ BADHD:
+
+ close,unit
+ if status LT 0 then begin
+ message,'Bad File: ' + files[i],/Con
+ if N_elements(errmsg) NE 0 then message,errmsg,/CON
+ endif
+ endfor
+ DONE:
+ free_lun, unit
+ vallen = lonarr(nkey)
+ for k=0,nkey-1 do vallen[k] = max(strlen(keyvalue[*,k]))
+
+
+ textopen, 'fitsdir', TEXTOUT=textout,/STDOUT
+ printf,!TEXTUNIT,' '
+ printf,!TEXTUNIT,'FITS File Directory ' + systime()
+ printf,!TEXTUNIT, direct
+ printf,!TEXTUNIT, ' '
+
+ pheader = ' NAME '
+ if namelen GT 5 then pheader += string(replicate(32b,namelen-5))
+ if ~keyword_set(nosize) then begin
+ pheader += 'SIZE '
+ naxislen = max(strlen(bignaxis))+1
+ if naxislen GT 5 then pheader += string(replicate(32b,naxislen-5))
+ endif
+ for k=0,nkey-1 do begin
+ pheader += keys[k] + ' '
+ if vallen[k] GT keylen[k] then $
+ pheader += string(replicate(32b,vallen[k]-keylen[k]))
+ endfor
+ printf,!TEXTUNIT, pheader
+ printf,!TEXTUNIT, ' '
+ xx = namelen + 2
+ fmt = '(A'
+ if ~keyword_set(nosize) then begin
+ fmt += ',T' + strtrim(xx,2)
+ xx += (naxislen>4) + 1
+ endif
+ fmt += ',A'
+ remchar,keyvalue,"'"
+
+ for k=0,nkey-1 do begin
+
+ fmt += ',T' + strtrim(xx,2) + ',A'
+ xx += (vallen[k]>keylen[k]) +1
+ endfor
+ fmt += ')'
+
+ for i=0,n-1 do printf, f= fmt, $
+ !TEXTUNIT,fname[i],bignaxis[i], keyvalue[i,*]
+
+ textclose,textout=textout
+ return ;Normal return
+ end
diff --git a/Code/script_idl_mv/astrolib/fitsrgb_to_tiff.pro b/Code/script_idl_mv/astrolib/fitsrgb_to_tiff.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e3b711ad49444d4c9d2f3a503a6db84ea2cc2cf8
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fitsrgb_to_tiff.pro
@@ -0,0 +1,143 @@
+ PRO FITSRGB_to_TIFF, path, rgb_files, tiff_name, BY_PIXEL=by_pixel, $
+ PREVIEW=preview, RED=r_mix, GREEN=g_mix, BLUE=b_mix
+;+
+; NAME:
+; FITSRGB_to_TIFF
+; PURPOSE:
+; Combine separate red, green, and blue FITS images into TIFF format
+; EXPLANATION:
+; The output TIFF (class R) file can have colors interleaved either
+; by pixel or image. The colour mix is also adjustable.
+;
+; CALLING SEQUENCE:
+; FITSRGB_to_TIFF, path, rgb_files, tiff_name [,/BY_PIXEL, /PREVIEW,
+; RED= , GREEN =, BLUE =]
+;
+; INPUTS:
+; path = file system directory path to the RGB files required.
+; rgb_files = string array with three components - the red FITS file
+; filename, the blue FITS file filename and the green FITS
+; file filename
+;
+; OUTPUTS:
+; tiff_name = string containing name of tiff file to be produced
+;
+; OPTIONAL OUTPUT:
+; Header = String array containing the header from the FITS file.
+;
+; OPTIONAL INPUT KEYWORDS:
+; BY_PIXEL = This causes TIFF file RGB to be interleaved by pixel
+; rather than the default of by image.
+; PREVIEW = Allows a 24 bit image to be displayed on the screen
+; to check the colour mix.
+; RED = Real number containing the fractional mix of red
+; GREEN = Real number containing the fractional mix of green
+; BLUE = Real number containing the fractional mix of blue
+;
+; EXAMPLE:
+; Read three FITS files, 'red.fits', 'blue.fits' and 'green.fits' from
+; the directory '/data/images/space' and output a TIFF file named
+; 'colour.tiff'
+;
+; IDL> FITSRGB_to_TIFF, '/data/images/space', ['red.fits', $
+; 'blue.fits', 'green.fits'], 'colour.tiff'
+;
+; Read three FITS files, 'red.fits', 'blue.fits' and 'green.fits' from
+; the current directory and output a TIFF file named '/images/out.tiff'
+; In this case, the red image is twice as strong as the green and the
+; blue is a third more intense. A preview on screen is also wanted.
+;
+; IDL> FITSRGB_to_TIFF, '.', ['red.fits', $
+; 'blue.fits', 'green.fits'], '/images/out.tiff', $
+; /PREVIEW, RED=0.5, GREEN=1.0, BLUE=0.666
+;
+;
+; RESTRICTIONS:
+; (1) Limited to the ability of the routine READFITS
+;
+; NOTES:
+; None
+;
+; PROCEDURES USED:
+; Functions: READFITS, CONCAT_DIR
+; Procedures: WRITE_TIFF
+;
+; MODIFICATION HISTORY:
+; 16th January 1995 - Written by Carl Shaw, Queen's University Belfast
+; 27 Jan 1995 - W. Landsman, Add CONCAT_DIR for VMS, Windows compatibility
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use WRITE_TIFF instead of obsolete TIFF_WRITE W. Landsman December 1998
+; Cosmetic changes W. Landsman February 2000
+;-
+;
+; Make sure user has supplied valid parameters
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ print, 'Syntax - FITSRGB_to_TIFF, path, rgb_files, tiff_name'
+ print,' [/BY_PIXEL,/PREVIEW, RED=, GREEN=, BLUE= ]'
+ return
+ ENDIF
+;
+ IF N_ELEMENTS(rgb_files) LT 3 THEN $
+ MESSAGE, 'Three filenames for the colour components have not been supplied'
+;
+ by_pixel = KEYWORD_SET(BY_PIXEL)
+;
+ IF ~KEYWORD_SET(r_mix) THEN r_mix = 1.0
+ IF ~KEYWORD_SET(g_mix) THEN g_mix = 1.0
+ IF ~KEYWORD_SET(b_mix) THEN b_mix = 1.0
+;
+; Now load the colour components
+;
+ fname = CONCAT_DIR( path, rgb_files )
+ red = READFITS( fname[0], /SILENT)
+ green = READFITS( fname[1], /SILENT)
+ blue = READFITS( fname[2], /SILENT)
+;
+; Data now needs to be scaled to the same byte range (0-255) and also
+; scaled according to the RGB mix values supplied by the user
+;
+ red = red[*,*] * r_mix
+ green = green[*,*] * g_mix
+ blue = blue[*,*] * b_mix ;scale intensity by supplied mix
+;
+ maxlim = MAX(red) > MAX(green) > MAX(blue) ;max intensity
+ minlim = MIN(red) < MIN(green) < MIN(blue) ;min intensity
+ red = BYTSCL(red, MIN=minlim, MAX=maxlim)
+ green = BYTSCL(green, MIN=minlim, MAX=maxlim)
+ blue = BYTSCL(blue, MIN=minlim, MAX=maxlim) ;scale colours to same byte range
+;
+; Preview image on window system if required
+;
+ IF keyword_set(PREVIEW) THEN BEGIN
+ window, 0, colors=256
+ wset, 0
+ tv, color_quan(red, green, blue, r, g, b, colors=255)
+ tvlct, r, g, b
+ ENDIF
+;
+; Now write out result as a tiff file
+;
+ IF by_pixel THEN BEGIN
+ ;
+ ; Interleave by pixel
+ ;
+ extent = SIZE(red)
+ xsize = extent[1]
+ ysize = extent[2] ;get image size
+ interarr = FLTARR(3, xsize, ysize, /NOZERO) ;make interleaved array
+ interarr[0, *, *] = red
+ interarr[1, *, *] = green
+ interarr[2, *, *] = blue
+ ;
+ WRITE_TIFF, tiff_name, interarr
+ ;
+ ENDIF ELSE BEGIN
+ ;
+ ; Interleave by image
+ ;
+ WRITE_TIFF, tiff_name, RED=red, BLUE=blue, GREEN=green, PLANARCONFIG=2
+ ;
+ ENDELSE
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/flegendre.pro b/Code/script_idl_mv/astrolib/flegendre.pro
new file mode 100644
index 0000000000000000000000000000000000000000..00fb5baf5ec526084820b317d3f8bbcad430c051
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/flegendre.pro
@@ -0,0 +1,74 @@
+function flegendre,x,m
+;+
+; NAME:
+; FLEGENDRE
+; PURPOSE:
+; Compute the first M terms in a Legendre polynomial expansion.
+; EXPLANATION:
+; Meant to be used as a supplied function to SVDFIT.
+;
+; This procedure became partially obsolete in IDL V5.0 with the
+; introduction of the /LEGENDRE keyword to SVDFIT and the associated
+; SVDLEG function. However, note that, unlike SVDLEG, FLEGENDRE works
+; on vector values of X.
+; CALLING SEQUENCE:
+; result = FLEGENDRE( X, M)
+;
+; INPUTS:
+; X - the value of the independent variable, scalar or vector
+; M - number of term of the Legendre expansion to compute, integer scalar
+;
+; OUTPUTS:
+; result - (N,M) array, where N is the number of elements in X and M
+; is the order. Contains the value of each Legendre term for
+; each value of X
+; EXAMPLE:
+; (1) If x = 2.88 and M = 3 then
+; IDL> print, flegendre(x,3) ==> [1.00, 2.88, 11.9416]
+;
+; This result can be checked by explicitly computing the first 3 Legendre
+; terms, 1.0, x, 0.5*( 3*x^2 -1)
+;
+; (2) Find the coefficients to an M term Legendre polynomial that gives
+; the best least-squares fit to a dataset (x,y)
+; IDL> coeff = SVDFIT( x,y,M,func='flegendre')
+;
+; The coefficients can then be supplied to the function POLYLEG to
+; compute the best YFIT values for any X.
+; METHOD:
+; The recurrence relation for the Legendre polynomials is used to compute
+; each term. Compare with the function FLEG in "Numerical Recipes"
+; by Press et al. (1992), p. 674
+;
+; REVISION HISTORY:
+; Written Wayne Landsman Hughes STX April 1995
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ On_Error,2
+
+ if N_params() LT 2 then begin
+ print,'Syntax - result = FLEGENDRE( x, m)'
+ return,0
+ endif
+
+ if m LT 1 then message, $
+ 'ERROR - Order of Legendre polynomial must be at least 1'
+ N = N_elements(x)
+ size_x = size(x)
+ leg = make_array(n, m, type = size_x[size_x[0]+1] > 4)
+
+ leg[0,0] = replicate( 1., n)
+ if m GE 2 then leg[0,1] = x
+ if m GE 3 then begin
+ twox = 2.*x
+ f2 = x
+ d = 1.
+ for j=2,m-1 do begin
+ f1 = d
+ f2 = f2 + 2.*x
+ d = d+1.
+ leg[0,j] = ( f2*leg[*,j-1] - f1*leg[*,j-2] )/d
+ endfor
+ endif
+ return, leg
+ end
diff --git a/Code/script_idl_mv/astrolib/flux2mag.pro b/Code/script_idl_mv/astrolib/flux2mag.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d21d9cf0aab8d61fc64d28851e75d790bb0299a3
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/flux2mag.pro
@@ -0,0 +1,51 @@
+function flux2mag, flux, zero_pt, ABwave = abwave
+;+
+; NAME:
+; FLUX2MAG
+; PURPOSE:
+; Convert from flux (ergs/s/cm^2/A) to magnitudes.
+; EXPLANATION:
+; Use MAG2FLUX() for the opposite direction.
+;
+; CALLING SEQUENCE:
+; mag = flux2mag( flux, [ zero_pt, ABwave= ] )
+;
+; INPUTS:
+; flux - scalar or vector flux vector, in erg cm-2 s-1 A-1
+;
+; OPTIONAL INPUT:
+; zero_pt - scalar giving the zero point level of the magnitude.
+; If not supplied then zero_pt = 21.1 (Code et al 1976)
+; Ignored if the ABwave keyword is supplied
+;
+; OPTIONAL KEYWORD INPUT:
+; ABwave - wavelength scalar or vector in Angstroms. If supplied, then
+; FLUX2MAG() returns Oke AB magnitudes (Oke & Gunn 1983, ApJ, 266,
+; 713).
+;
+; OUTPUT:
+; mag - magnitude vector. If the ABwave keyword is set then mag
+; is given by the expression
+; ABMAG = -2.5*alog10(f) - 5*alog10(ABwave) - 2.406
+;
+; Otherwise, mag is given by the expression
+; mag = -2.5*alog10(flux) - zero_pt
+; EXAMPLE:
+; Suppose one is given wavelength and flux vectors, w (in Angstroms) and
+; f (in erg cm-2 s-1 A-1). Plot the spectrum in AB magnitudes
+;
+; IDL> plot, w, flux2mag(f,ABwave = w), /nozero
+;
+; REVISION HISTORY:
+; Written J. Hill STX Co. 1988
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added ABwave keyword W. Landsman September 1998
+;-
+
+ if ( N_params() LT 2 ) then zero_pt = 21.10 ;Default zero pt
+
+ if keyword_set(ABwave) then $
+ return, -2.5*alog10(flux) - 5*alog10(ABwave) - 2.406 else $
+ return, -2.5*alog10(flux) - zero_pt
+
+ end
diff --git a/Code/script_idl_mv/astrolib/fm_unred.pro b/Code/script_idl_mv/astrolib/fm_unred.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2bb8de241f6c800f7089f3c62491dc427afcc521
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fm_unred.pro
@@ -0,0 +1,174 @@
+pro fm_unred, wave, flux, ebv, funred, R_V = R_V, gamma = gamma, x0 = x0, $
+ c1 = c1, c2 = c2, c3 = c3, c4 = c4,avglmc=avglmc, lmc2 = lmc2, $
+ ExtCurve=ExtCurve
+;+
+; NAME:
+; FM_UNRED
+; PURPOSE:
+; Deredden a flux vector using the Fitzpatrick (1999) parameterization
+; EXPLANATION:
+; The R-dependent Galactic extinction curve is that of Fitzpatrick & Massa
+; (Fitzpatrick, 1999, PASP, 111, 63; astro-ph/9809387 ).
+; Parameterization is valid from the IR to the far-UV (3.5 microns to 0.1
+; microns). UV extinction curve is extrapolated down to 912 Angstroms.
+;
+; CALLING SEQUENCE:
+; FM_UNRED, wave, flux, ebv, [ funred, R_V = , /LMC2, /AVGLMC, ExtCurve=
+; gamma =, x0=, c1=, c2=, c3=, c4= ]
+; INPUT:
+; WAVE - wavelength vector (Angstroms)
+; FLUX - calibrated flux vector, same number of elements as WAVE
+; If only 3 parameters are supplied, then this vector will
+; updated on output to contain the dereddened flux.
+; EBV - color excess E(B-V), scalar. If a negative EBV is supplied,
+; then fluxes will be reddened rather than dereddened.
+;
+; OUTPUT:
+; FUNRED - unreddened flux vector, same units and number of elements
+; as FLUX
+;
+; OPTIONAL INPUT KEYWORDS
+; R_V - scalar specifying the ratio of total to selective extinction
+; R(V) = A(V) / E(B - V). If not specified, then R = 3.1
+; Extreme values of R(V) range from 2.3 to 5.3
+;
+; /AVGLMC - if set, then the default fit parameters c1,c2,c3,c4,gamma,x0
+; are set to the average values determined for reddening in the
+; general Large Magellanic Cloud (LMC) field by Misselt et al.
+; (1999, ApJ, 515, 128)
+; /LMC2 - if set, then the fit parameters are set to the values determined
+; for the LMC2 field (including 30 Dor) by Misselt et al.
+; Note that neither /AVGLMC or /LMC2 will alter the default value
+; of R_V which is poorly known for the LMC.
+;
+; The following five input keyword parameters allow the user to customize
+; the adopted extinction curve. For example, see Clayton et al. (2003,
+; ApJ, 588, 871) for examples of these parameters in different interstellar
+; environments.
+;
+; x0 - Centroid of 2200 A bump in microns (default = 4.596)
+; gamma - Width of 2200 A bump in microns (default =0.99)
+; c3 - Strength of the 2200 A bump (default = 3.23)
+; c4 - FUV curvature (default = 0.41)
+; c2 - Slope of the linear UV extinction component
+; (default = -0.824 + 4.717/R)
+; c1 - Intercept of the linear UV extinction component
+; (default = 2.030 - 3.007*c2
+;
+; OPTIONAL OUTPUT KEYWORD:
+; ExtCurve - Returns the E(wave-V)/E(B-V) extinction curve, interpolated
+; onto the input wavelength vector
+;
+; EXAMPLE:
+; Determine how a flat spectrum (in wavelength) between 1200 A and 3200 A
+; is altered by a reddening of E(B-V) = 0.1. Assume an "average"
+; reddening for the diffuse interstellar medium (R(V) = 3.1)
+;
+; IDL> w = 1200 + findgen(40)*50 ;Create a wavelength vector
+; IDL> f = w*0 + 1 ;Create a "flat" flux vector
+; IDL> fm_unred, w, f, -0.1, fnew ;Redden (negative E(B-V)) flux vector
+; IDL> plot,w,fnew
+;
+; NOTES:
+; (1) The following comparisons between the FM curve and that of Cardelli,
+; Clayton, & Mathis (1989), (see ccm_unred.pro):
+; (a) - In the UV, the FM and CCM curves are similar for R < 4.0, but
+; diverge for larger R
+; (b) - In the optical region, the FM more closely matches the
+; monochromatic extinction, especially near the R band.
+; (2) Many sightlines with peculiar ultraviolet interstellar extinction
+; can be represented with the FM curve, if the proper value of
+; R(V) is supplied.
+; (3) Use the 4 parameter calling sequence if you wish to save the
+; original flux vector.
+; PROCEDURE CALLS:
+; CSPLINE(), POLY()
+; REVISION HISTORY:
+; Written W. Landsman Raytheon STX October, 1998
+; Based on FMRCurve by E. Fitzpatrick (Villanova)
+; Added /LMC2 and /AVGLMC keywords, W. Landsman August 2000
+; Added ExtCurve keyword, J. Wm. Parker August 2000
+; Assume since V5.4 use COMPLEMENT to WHERE W. Landsman April 2006
+; Fix calculation of EXTCurve A. Sarkisyan/W. Landsman Jan 2014
+;
+;-
+ On_error, 2
+ compile_opt idl2
+
+ if N_params() LT 3 then begin
+ print,'Syntax: FM_UNRED, wave, flux, ebv, funred,[ R_V =, /LMC2, /AVGLMC '
+ print,' gamma =, x0 =, c1 =, c2 = ,c3 = ,c4 =, ExtCurve=]'
+ return
+ endif
+
+ if N_elements(R_V) EQ 0 then R_V = 3.1
+
+ x = 10000./ wave ; Convert to inverse microns
+ curve = x*0.
+
+; Set default values of c1,c2,c3,c4,gamma and x0 parameters
+
+ if keyword_set(LMC2) then begin
+ if N_elements(x0) EQ 0 then x0 = 4.626
+ if N_elements(gamma) EQ 0 then gamma = 1.05
+ if N_elements(c4) EQ 0 then c4 = 0.42
+ if N_elements(c3) EQ 0 then c3 = 1.92
+ if N_elements(c2) EQ 0 then c2 = 1.31
+ if N_elements(c1) EQ 0 then c1 = -2.16
+ endif else if keyword_set(AVGLMC) then begin
+ if N_elements(x0) EQ 0 then x0 = 4.596
+ if N_elements(gamma) EQ 0 then gamma = 0.91
+ if N_elements(c4) EQ 0 then c4 = 0.64
+ if N_elements(c3) EQ 0 then c3 = 2.73
+ if N_elements(c2) EQ 0 then c2 = 1.11
+ if N_elements(c1) EQ 0 then c1 = -1.28
+ endif else begin
+ if N_elements(x0) EQ 0 then x0 = 4.596
+ if N_elements(gamma) EQ 0 then gamma = 0.99
+ if N_elements(c3) EQ 0 then c3 = 3.23
+ if N_elements(c4) EQ 0 then c4 = 0.41
+ if N_elements(c2) EQ 0 then c2 = -0.824 + 4.717/R_V
+ if N_elements(c1) EQ 0 then c1 = 2.030 - 3.007*c2
+ endelse
+
+; Compute UV portion of A(lambda)/E(B-V) curve using FM fitting function and
+; R-dependent coefficients
+
+ xcutuv = 10000.0/2700.0
+ xspluv = 10000.0/[2700.0,2600.0]
+ iuv = where(x ge xcutuv, N_UV, complement = iopir, Ncomp = Nopir)
+ IF (N_UV GT 0) THEN xuv = [xspluv,x[iuv]] ELSE xuv = xspluv
+
+ yuv = c1 + c2*xuv
+ yuv = yuv + c3*xuv^2/((xuv^2-x0^2)^2 +(xuv*gamma)^2)
+ yuv = yuv + c4*(0.5392*((xuv>5.9)-5.9)^2+0.05644*((xuv>5.9)-5.9)^3)
+ yuv = yuv + R_V
+ yspluv = yuv[0:1] ; save spline points
+
+ IF (N_UV GT 0) THEN curve[iuv] = yuv[2:*] ; remove spline points
+
+; Compute optical portion of A(lambda)/E(B-V) curve
+; using cubic spline anchored in UV, optical, and IR
+
+ xsplopir = [0,10000.0/[26500.0,12200.0,6000.0,5470.0,4670.0,4110.0]]
+ ysplir = [0.0,0.26469,0.82925]*R_V/3.1
+ ysplop = [poly(R_V, [-4.22809e-01, 1.00270, 2.13572e-04] ), $
+ poly(R_V, [-5.13540e-02, 1.00216, -7.35778e-05] ), $
+ poly(R_V, [ 7.00127e-01, 1.00184, -3.32598e-05] ), $
+ poly(R_V, [ 1.19456, 1.01707, -5.46959e-03, 7.97809e-04, $
+ -4.45636e-05] ) ]
+
+ ysplopir = [ysplir,ysplop]
+
+ if (Nopir GT 0) then $
+ curve[iopir] = CSPLINE([xsplopir,xspluv],[ysplopir,yspluv],x[iopir])
+
+ ; Now apply extinction correction to input flux vector
+
+ curve = ebv*curve
+ if N_params() EQ 3 then flux = flux * 10.^(0.4*curve) else $
+ funred = flux * 10.^(0.4*curve) ;Derive unreddened flux
+
+ ExtCurve = Curve/ebv - R_V ;Updated Jan 2014
+
+ end
diff --git a/Code/script_idl_mv/astrolib/forprint.pro b/Code/script_idl_mv/astrolib/forprint.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b529e12fa512ebab725b72918c72c651431d0b7a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/forprint.pro
@@ -0,0 +1,240 @@
+pro forprint, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, $
+ v15,v16,v17,v18,TEXTOUT = textout, FORMAT = format, SILENT = SILENT, $
+ STARTLINE = startline, NUMLINE = numline, COMMENT = comment, $
+ SUBSET = subset, NoCOMMENT=Nocomment,STDOUT=stdout, WIDTH=width
+;+
+; NAME:
+; FORPRINT
+; PURPOSE:
+; Print a set of vectors by looping over each index value.
+;
+; EXPLANATION:
+; If W and F are equal length vectors, then the statement
+; IDL> forprint, w, f
+; is equivalent to
+; IDL> for i = 0L, N_elements(w)-1 do print,w[i],f[i]
+;
+; CALLING SEQUENCE:
+; forprint, v1,[ v2, v3, v4,....v18, FORMAT = , TEXTOUT = ,STARTLINE =,
+; SUBSET=, NUMLINE =, /SILENT, COMMENT= ]
+;
+; INPUTS:
+; V1,V2,...V18 - Arbitrary IDL vectors. If the vectors are not of
+; equal length then the number of rows printed will be equal
+; to the length of the smallest vector. Up to 18 vectors
+; can be supplied.
+;
+; OPTIONAL KEYWORD INPUTS:
+;
+; TEXTOUT - Controls print output device, defaults to !TEXTOUT
+;
+; textout=1 TERMINAL using /more option if available
+; textout=2 TERMINAL without /more option
+; textout=3 file 'forprint.prt'
+; textout=4 file 'laser.tmp'
+; textout=5 user must open file
+; textout = filename (default extension of .prt)
+; textout=7 Append to .prt file if it exists
+;
+; COMMENT - String scalar or vector to write to the first line of output
+; file if TEXTOUT > 2. By default, FORPRINT will write a time
+; stamp on the first line. Use /NOCOMMENT if you don't want
+; FORPRINT to write anything in the output file. If COMMENT
+; is a vector then one line will be written for each element.
+; FORMAT - Scalar format string as in the PRINT procedure. The use
+; of outer parenthesis is optional. Ex. - format="(F10.3,I7)"
+; This program will automatically remove a leading "$" from
+; incoming format statements. Ex. - "$(I4)" would become "(I4)".
+; If omitted, then IDL default formats are used.
+; /NOCOMMENT - Set this keyword if you don't want any comment line
+; line written as the first line in a harcopy output file.
+; /SILENT - Normally, with a hardcopy output (TEXTOUT > 2), FORPRINT will
+; print an informational message. If the SILENT keyword
+; is set and non-zero, then this message is suppressed.
+; SUBSET - Index vector specifying elements to print. No error checking
+; is done to make sure the indicies are valid. The statement
+;
+; IDL> forprint,x,y,z,subset=s
+; is equivalent to
+; IDL> for i=0,n-1 do print, x[s[i]], y[s[i]], z[s[i]]
+;
+; STARTLINE - Integer scalar specifying the first line in the arrays
+; to print. Default is STARTLINE = 1, i.e. start at the
+; beginning of the arrays. (If a SUBSET keyword is supplied
+; then STARTLINE refers to first element in the subscript vector.)
+; /STDOUT - If set, the force standard output unit (=-1) if not writing
+; to a file. This allows the FORPRINT output to be captured
+; in a journal file. Only needed for non-GUI terminals
+; WIDTH - Line width for wrapping, passed onto OPENW when using hardcopy.
+;
+; OUTPUTS:
+; None
+; SYSTEM VARIABLES:
+; If keyword TEXTOUT is not used, the default is the nonstandard
+; keyword !TEXTOUT. If you want to use FORPRINT to write more than
+; once to the same file then set TEXTOUT=5, and open and close the
+; file yourself (see documentation of TEXTOPEN for more info).
+;
+; The non-standard system variables !TEXTOUT and !TEXTUNIT are
+; automatically added if not present to start with.
+; EXAMPLE:
+; Suppose W,F, and E are the wavelength, flux, and epsilon vectors for
+; a spectrum. Print these values to a file 'output.dat' in a nice
+; format.
+;
+; IDL> fmt = '(F10.3,1PE12.2,I7)'
+; IDL> forprint, F = fmt, w, f, e, TEXT = 'output.dat'
+; RESTRICTIONS:
+; Uses the EXECUTE() function and so is not compatible with the IDL
+; virtual machine.
+; PROCEDURES CALLED:
+; TEXTOPEN, TEXTCLOSE
+; REVISION HISTORY:
+; Written W. Landsman April, 1989
+; Keywords textout and format added, J. Isensee, July, 1990
+; Made use of parenthesis in FORMAT optional W. Landsman May 1992
+; Added STARTLINE keyword W. Landsman November 1992
+; Set up so can handle 18 input vectors. J. Isensee, HSTX Corp. July 1993
+; Handle string value of TEXTOUT W. Landsman, HSTX September 1993
+; Added NUMLINE keyword W. Landsman, HSTX February 1996
+; Added SILENT keyword W. Landsman, RSTX, April 1998
+; Much faster printing to a file W. Landsman, RITSS, August, 2001
+; Use SIZE(/TNAME) instead of DATATYPE() W. Landsman SSAI October 2001
+; Fix skipping of first line bug introduced Aug 2001 W. Landsman Nov2001
+; Added /NOCOMMENT keyword, the SILENT keyword now controls only
+; the display of informational messages. W. Landsman June 2002
+; Skip PRINTF if IDL in demo mode W. Landsman October 2004
+; Assume since V5.4 use BREAK instead of GOTO W. Landsman April 2006
+; Add SUBSET keyword, warning if different size vectors passed.
+; P.Broos,W.Landsman. Aug 2006
+; Change keyword_set() to N_elements W. Landsman Oct 2006
+; Added /STDOUT keyword W. Landsman Oct 2006
+; Fix error message for undefined variable W. Landsman April 2007
+; Added WIDTH keyword J. Bailin Nov 2010
+; Allow multiple (vector) comment lines W. Landsman April 2011
+; Define !TEXTOUT and !TEXTUNIT if needed. W. Landsman October 2012
+;-
+ On_error,2 ;Return to caller
+ compile_opt idl2
+
+ npar = N_params()
+ if npar EQ 0 then begin
+ print,'Syntax - FORPRINT, v1, [ v2, v3,...v18, FORMAT =, /SILENT, SUBSET='
+ print,' /NoCOMMENT, COMMENT =, STARTLINE = , NUMLINE =, TEXTOUT =, WIDTH =]'
+ return
+ endif
+
+ defsysv,'!TEXTOUT',exists=ex ; Check if !TEXTOUT exists.
+ if ex eq 0 then defsysv,'!TEXTOUT',1 ; If not define it.
+ defsysv,'!TEXTUNIT',exists=ex ; Check if !TEXTUNIT exists.
+ if ex eq 0 then defsysv,'!TEXTUNIT',0 ; If not define it.
+
+
+ if N_elements( STARTLINE ) EQ 0 then startline = 1l else $
+ startline = startline > 1l
+
+ fmt="F" ;format flag
+ npts = N_elements(v1)
+
+ if ( npts EQ 0 ) then message,'ERROR - Parameter 1 is not defined'
+
+; Remove "$" sign from format string and append parentheses if not
+; already present
+
+ if N_elements( format ) EQ 1 then begin
+
+ fmt = "T" ;format present
+ frmt = format
+ if strmid(frmt,0,1) eq '$' then $
+ frmt = strmid(frmt,1,strlen(frmt)-1) ;rem. '$' from format if present
+
+ if strmid(frmt,0,1) NE '(' then frmt = '(' + frmt
+ if strmid( frmt,strlen(frmt)-1,1) NE ')' then frmt += ')'
+
+ endif
+
+ if npar GT 1 then begin ;Get number of elements in smallest array
+
+ for i = 2, npar do begin
+ tst = execute('this_npts = N_elements(v'+strtrim(i,2)+')')
+ if this_npts EQ 0 then $
+ message,'ERROR - Parameter ' + strtrim(i,2) + ' is not defined'
+
+ if ((npts NE this_npts) && ~keyword_set(silent)) then $
+ message,/INF,'Warning, vectors have different lengths.'
+
+ npts = npts < this_npts
+ endfor
+
+ endif
+
+ if keyword_set(NUMLINE) then npts = (startline + numline-1) < npts
+
+ if N_Elements(SUBSET) GT 0 then begin
+ npts = N_elements(subset) < npts
+ index = '[subset[i]]'
+ endif else index = '[i]'
+
+
+ str = 'v1' + index
+ if npar GT 1 then $
+ for i = 2, npar do str = str + ',v' + strtrim(i,2) + index
+
+; Use default output dev.
+ demo = lmgr(/demo)
+ if ~demo then begin
+
+ if ~keyword_set( TEXTOUT ) then textout = !TEXTOUT
+ if size( textout,/TNAME) EQ 'STRING' then text_out = 6 $ ;make numeric
+ else text_out = textout
+
+ textopen,'FORPRINT',TEXTOUT=textout,SILENT=silent,STDOUT=STDOUT, $
+ MORE_SET = more_set, WIDTH=width
+ if ( text_out GT 2 ) && (~keyword_set(NOCOMMENT)) then begin
+ Ncomm = N_elements(comment)
+ if Ncomm GT 0 then $
+ for i=0,ncomm-1 do printf,!TEXTUNIT,comment[i] else $
+ printf,!TEXTUNIT,'FORPRINT: ',systime()
+ endif
+ endif
+
+ if fmt EQ "F" then begin ;Use default formats
+
+ if demo then begin
+ test = execute('for i=startline-1,npts-1 do print,' + str)
+
+ endif else if more_set then begin
+ for i = startline-1, npts-1 do begin
+
+ test = execute('printf,!TEXTUNIT,' + str)
+ if !ERR EQ 1 then BREAK ;Did user press 'Q' key?
+
+ endfor
+ endif else test = $
+ execute('for i=startline-1,npts-1 do printf,!TEXTUNIT,' + str)
+
+ endif else begin ;User specified format
+
+ if demo then begin
+ test = execute('for i=startline-1,npts-1 do print,FORMAT=frmt,' + str)
+
+ endif else if more_set then begin
+
+ for i = startline-1, npts-1 do begin
+
+ test = execute( 'printf, !TEXTUNIT, FORMAT=frmt,' + str )
+ if !ERR EQ 1 then BREAK
+
+ endfor
+
+ endif else test = $
+ execute('for i=startline-1,npts-1 do printf,!TEXTUNIT,FORMAT=frmt,'+str)
+
+
+ endelse
+
+
+ textclose, TEXTOUT = textout ;Close unit opened by TEXTOPEN
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/frebin.pro b/Code/script_idl_mv/astrolib/frebin.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1f2e10eca98ebdc31e0bae5eaf7620c7bf390028
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/frebin.pro
@@ -0,0 +1,217 @@
+function frebin,image,nsout,nlout,total=total
+;+
+; NAME:
+; FREBIN
+;
+; PURPOSE:
+; Shrink or expand the size of an array an arbitrary amount using interpolation
+;
+; EXPLANATION:
+; FREBIN is an alternative to CONGRID or REBIN. Like CONGRID it
+; allows expansion or contraction by an arbitrary amount. ( REBIN requires
+; integral factors of the original image size.) Like REBIN it conserves
+; flux by ensuring that each input pixel is equally represented in the output
+; array.
+;
+; CALLING SEQUENCE:
+; result = FREBIN( image, nsout, nlout, [ /TOTAL] )
+;
+; INPUTS:
+; image - input image, 1-d or 2-d numeric array
+; nsout - number of samples in the output image, numeric scalar
+;
+; OPTIONAL INPUT:
+; nlout - number of lines in the output image, numeric scalar
+; If not supplied, then set equal to 1
+;
+; OPTIONAL KEYWORD INPUTS:
+; /total - if set, the output pixels will be the sum of pixels within
+; the appropriate box of the input image. Otherwise they will
+; be the average. Use of the /TOTAL keyword conserves total counts.
+;
+; OUTPUTS:
+; The resized image is returned as the function result. If the input
+; image is of type DOUBLE or FLOAT then the resized image is of the same
+; type. If the input image is BYTE, INTEGER or LONG then the output
+; image is usually of type FLOAT. The one exception is expansion by
+; integral amount (pixel duplication), when the output image is the same
+; type as the input image.
+;
+; EXAMPLE:
+; Suppose one has an 800 x 800 image array, im, that must be expanded to
+; a size 850 x 900 while conserving the total counts:
+;
+; IDL> im1 = frebin(im,850,900,/total)
+;
+; im1 will be a 850 x 900 array, and total(im1) = total(im)
+; NOTES:
+; If the input image sizes are a multiple of the output image sizes
+; then FREBIN is equivalent to the IDL REBIN function for compression,
+; and simple pixel duplication on expansion.
+;
+; If the number of output pixels are not integers, the output image
+; size will be truncated to an integer. The platescale, however, will
+; reflect the non-integer number of pixels. For example, if you want to
+; bin a 100 x 100 integer image such that each output pixel is 3.1
+; input pixels in each direction use:
+; n = 100/3.1 ; 32.2581
+; image_out = frebin(image,n,n)
+;
+; The output image will be 32 x 32 and a small portion at the trailing
+; edges of the input image will be ignored.
+;
+; PROCEDURE CALLS:
+; None.
+; HISTORY:
+; Adapted from May 1998 STIS version, written D. Lindler, ACC
+; Added /NOZERO, use INTERPOLATE instead of CONGRID, June 98 W. Landsman
+; Fixed for nsout non-integral but a multiple of image size Aug 98 D.Lindler
+; DJL, Oct 20, 1998, Modified to work for floating point image sizes when
+; expanding the image.
+; Improve speed by addressing arrays in memory order W.Landsman Dec/Jan 2001
+;-
+;----------------------------------------------------------------------------
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 1 then begin
+ print,'Syntax = newimage = FREBIN(image, nsout, nlout, [/TOTAL])'
+ return,-1
+ endif
+
+ if n_elements(nlout) eq 0 then nlout=1
+;
+; determine size of input image
+;
+ ns = n_elements(image[*,0])
+ nl = n_elements(image)/ns
+;
+; determine if we can use the standard rebin function
+;
+ dtype = size(image,/TNAME)
+ if dtype EQ 'DOUBLE' then begin
+ sbox = ns/double(nsout)
+ lbox = nl/double(nlout)
+ end else begin
+ sbox = ns/float(nsout)
+ lbox = nl/float(nlout)
+ end
+
+; Contraction by an integral amount
+
+ if (nsout eq long(nsout)) && (nlout eq long(nlout)) then begin
+ if ((ns mod nsout) EQ 0) && ((nl mod nlout) EQ 0) then $
+ if (dtype EQ 'DOUBLE') || (dtype EQ 'FLOAT') then begin
+ if keyword_set(total) then $
+ return,rebin(image,nsout,nlout)*sbox*lbox else $
+ return,rebin(image,nsout,nlout)
+ endif else begin
+ if keyword_set(total) then $
+ return,rebin(float(image),nsout,nlout)*sbox*lbox else $
+ return,rebin(float(image),nsout,nlout)
+ endelse
+
+
+; Expansion by an integral amount
+ if ((nsout mod ns) EQ 0) && ((nlout mod nl) EQ 0) then begin
+ xindex = long(lindgen(nsout)/(nsout/ns))
+ if nl EQ 1 then begin
+ if keyword_set(total) then $
+ return,interpolate(image,xindex)*sbox else $
+ return,interpolate(image,xindex)
+ endif
+ yindex = long(lindgen(nlout)/(nlout/nl))
+ if keyword_set(total) then $
+ return,interpolate(image,xindex,yindex,/grid)*sbox*lbox else $
+ return,interpolate(image,xindex,yindex,/grid)
+ endif
+ endif
+ ns1 = ns-1
+ nl1 = nl-1
+
+; Do 1-d case separately
+
+ if nl EQ 1 then begin
+ if dtype eq 'DOUBLE' then result = dblarr(nsout,/NOZERO) $
+ else result = fltarr(nsout,/NOZERO)
+ for i=0L,nsout-1 do begin
+ rstart = i*sbox ;starting position for each box
+ istart = long(rstart)
+ rstop = rstart + sbox ;ending position for each box
+ istop = long(rstop) ftab_ext,'spec.fit','wavelength,flux',w,f
+; or
+; IDL> ftab_ext,'spec.fit',[1,2],w,f
+;
+; PROCEDURES CALLED:
+; FITS_READ, FITS_CLOSE, FTINFO, FTGET(), TBINFO, TBGET()
+; HISTORY:
+; version 1 W. Landsman August 1997
+; Improve speed processing binary tables W. Landsman March 2000
+; Use new FTINFO calling sequence W. Landsman May 2000
+; Don't call fits_close if fcb supplied W. Landsman May 2001
+; Use STRSPLIT to parse column string W. Landsman July 2002
+; Cleanup pointers in TBINFO structure W. Landsman November 2003
+; Avoid EXECUTE() if V6.1 or later W. Landsamn December 2006
+; Assume since V6.1 W. Landsman June 2009
+; Read up to 30 columns W.L. Aug 2009
+; Setting ROWS = -1 should work as documented, accept up to 50
+; columns W.L. Oct 2013
+;-
+;---------------------------------------------------------------------
+ compile_opt idl2
+ if N_params() LT 3 then begin
+ print,'Syntax - FTAB_EXT, name, columns, v1, [v2,...,v50, ROWS=, EXTEN=]'
+ return
+ endif
+ N_ext = N_params() - 2
+ strng = size(columns,/TNAME) EQ 'STRING' ;Is columns a string?
+
+ if ~keyword_set(exten_no) then exten_no = 1
+ dtype = size(file_or_fcb,/TNAME)
+ if dtype NE 'STRUCT' then fits_open,file_or_fcb,fcb else fcb=file_or_fcb
+ if fcb.nextend EQ 0 then $
+ message,'ERROR - FITS file contains no table extensions'
+ if fcb.nextend LT exten_no then $
+ message,'ERROR - FITS file contains only ' + strtrim(fcb.nextend,2) + $
+ ' extensions'
+
+ if (N_elements(rows) GT 0) && (min(rows) GE 0) then begin
+ minrow = min(rows, max = maxrow)
+ naxis1 = fcb.axis[0,exten_no]
+ first = naxis1*minrow
+ last = naxis1*(maxrow+1)-1
+ xrow = rows - minrow
+ fits_read,fcb,tab,htab,exten_no=exten_no,first=first,last=last,/no_pdu
+ tab = reform(tab,naxis1,maxrow-minrow+1,/overwrite)
+ endif else begin
+ fits_read, fcb, tab, htab, exten_no=exten_no,/no_pdu
+ xrow = -1
+ endelse
+ if dtype NE 'STRUCT' then fits_close,fcb else $
+ file_or_fcb.last_extension = exten_no
+ ext_type = fcb.xtension[exten_no]
+
+ case ext_type of
+ 'A3DTABLE': binary = 1b
+ 'BINTABLE': binary = 1b
+ 'TABLE': binary = 0b
+ else: message,'ERROR - Extension type of ' + $
+ ext_type + 'is not a FITS table format'
+ endcase
+
+ if strng then colnames= strsplit(columns,',',/EXTRACT) else $
+ colnames = columns
+ if binary then tbinfo,htab,tb_str else ftinfo,htab,ft_str
+
+
+ vv = 'v' + strtrim( indgen(n_ext)+1,2)
+ for i = 0, N_ext-1 do begin
+
+ if binary then $
+ (scope_varfetch(vv[i])) = TBGET( tb_str,tab,colnames[i],xrow,nulls) $
+ else $
+ (scope_varfetch(vv[i])) = FTGET( ft_str,tab,colnames[i],xrow,nulls)
+ endfor
+ if binary then begin
+ ptr_free, tb_str.tscal
+ ptr_free, tb_str.tzero
+ endif
+ return
+ end
+
+
diff --git a/Code/script_idl_mv/astrolib/ftab_help.pro b/Code/script_idl_mv/astrolib/ftab_help.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a2b3d1fecf1eb5337115fd50e422ded0e8b721d3
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftab_help.pro
@@ -0,0 +1,103 @@
+pro ftab_help,file_or_fcb,EXTEN_NO = exten_no, TEXTOUT = textout
+;+
+; NAME:
+; FTAB_HELP
+; PURPOSE:
+; Describe the columns of a FITS binary or ASCII table extension(s).
+;
+; CALLING SEQUENCE:
+; FTAB_HELP, filename, [ EXTEN_No = , TEXTOUT= ]
+; or
+; FTAB_HELP, fcb, [EXTEN_No=, TEXTOUT= ]
+;
+; INPUTS:
+; filename - scalar string giving name of the FITS file.
+; fcb - FITS control block returned by a previous call to FITS_OPEN
+;
+; OPTIONAL KEYWORD INPUTS:
+; EXTEN_NO - integer scalar or vector specifying which FITS extensions
+; to display. Default is to display all FITS extension.
+; TEXTOUT - scalar number (0-7) or string (file name) determining
+; output device (see TEXTOPEN). Default is TEXTOUT=1, output
+; to the user's terminal
+;
+; EXAMPLE:
+; Describe the columns in the second and fourth extensions of a FITS
+; file spec.fits and write the results to a file 'spec24.lis'
+;
+; IDL> ftab_help,'spec.fits',exten=[2,4],t='spec24.lis'
+;
+; SYSTEM VARIABLES:
+; Uses the non-standard system variables !TEXTOUT and !TEXTUNIT
+; which must be defined (e.g. with ASTROLIB) before compilation
+; NOTES:
+; The behavior of FTAB_HELP was changed in August 2005 to display
+; all extensions by default, rather than just the first extension
+; PROCEDURES USED:
+; FITS_READ, FITS_CLOSE, FITS_OPEN, FTHELP, TBHELP, TEXTOPEN, TEXTCLOSE
+; HISTORY:
+; version 1 W. Landsman August 1997
+; Corrected documentation W. Landsman September 1997
+; Don't call fits_close if fcb supplied W. Landsman May 2001
+; Default now is to display all extensions, EXTEN keyword can now
+; be a vector W. Landsman Aug 2005
+;-
+;----------------------------------------------------------------------
+ compile_opt idl2
+ if N_params() LT 1 then begin
+ print,'Syntax - FTAB_HELP, fcb_or_filename, [EXTEN_NO=, TEXTOUT= ]'
+ return
+ endif
+
+ sz = size(file_or_fcb)
+ if sz[sz[0]+1] NE 8 then fits_open,file_or_fcb,fcb else fcb=file_or_fcb
+ if fcb.nextend EQ 0 then begin
+ message,'File contains no Table extensions',/INF
+ if sz[sz[0]+1] NE 8 then fits_close,fcb else $
+ file_or_fcb.last_extension = exten_no
+ return
+ endif
+ if N_elements(exten_no) EQ 0 then exten_no = indgen(fcb.nextend)+1
+
+ nprint = N_elements(exten_no)
+ textopen,'ftab_help',textout=textout
+ printf,!TEXTUNIT,' '
+printf,!TEXTUNIT, 'FITS file: ' + fcb.filename
+ printf,!TEXTUNIT,' '
+
+ for i=0, nprint-1 do begin
+
+ fits_read,fcb, dummy, htab, /header_only,/no_pdu, exten_no=exten_no[i]
+ ext_type = fcb.xtension[exten_no[i]]
+
+ image = 0b
+ case ext_type of
+ 'A3DTABLE': binary = 1b
+ 'BINTABLE': binary = 1b
+ 'TABLE': binary = 0b
+ 'IMAGE': image = 1b
+ else: message,'ERROR - Extension type of ' + $
+ ext_type + ' is not a recognized FITS extension'
+ endcase
+
+ enum = exten_no[i]
+ printf,!TEXTUNIT, 'Extension No: ' + strtrim(enum,2)
+
+ if image then begin
+ dimen = sxpar(htab,'NAXIS*')
+ printf, !TEXTUNIT,'FITS Image Extension: Size ' + $
+ strjoin(strtrim(dimen,2),' by ')
+ endif else begin
+
+
+ if binary then tbhelp, htab, TEXTOUT = 5 $
+ else fthelp, htab, TEXTOUT = 5
+ printf,!TEXTUNIT,' '
+ endelse
+ endfor
+ if sz[sz[0]+1] NE 8 then fits_close,fcb else $
+ file_or_fcb.last_extension = enum
+
+ textclose, textout=textout
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftab_print.pro b/Code/script_idl_mv/astrolib/ftab_print.pro
new file mode 100644
index 0000000000000000000000000000000000000000..63bb8f97a6224e81a00b77d162a492ea4889afc3
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftab_print.pro
@@ -0,0 +1,107 @@
+pro ftab_print,filename,columns,rows, TEXTOUT = textout, FMT = fmt, $
+ EXTEN_NO = exten_no, num_header_lines=num_header_lines, $
+ nval_per_line=nval_per_line
+;+
+; NAME:
+; FTAB_PRINT
+; PURPOSE:
+; Print the contents of a FITS (binary or ASCII) table extension.
+; EXPLANATION:
+; User can specify which rows or columns to print
+;
+; CALLING SEQUENCE:
+; FTAB_PRINT, filename, columns, rows,
+; [ TEXTOUT=, FMT=, EXTEN_NO= NUM_HEADER_LINES ]
+;
+; INPUTS:
+; filename - scalar string giving name of a FITS file containing a
+; binary or ASCII table
+; columns - string giving column names, or vector giving
+; column numbers (beginning with 1). If a string
+; supplied then column names should be separated by comma's.
+; if not supplied, then all columns are printed.
+; If set to '*' then all columns are printed in table format
+; (1 row per line, binary tables only).
+; rows - (optional) vector of row numbers to print (beginning with 0).
+; If not supplied or set to scalar, -1, then all rows
+; are printed.
+; OPTIONAL KEYWORD INPUT:
+; EXTEN_NO - Extension number to read. If not set, then the first
+; extension is printed (EXTEN_NO=1)
+; FMT = Format string for print display (binary tables only). If not
+; supplied, then any formats in the TDISP keyword fields will be
+; used, otherwise IDL default formats. For ASCII tables, the
+; format used is always as stored in the FITS table.
+; NUM_HEADER_LINES - Number of lines to display the column headers (default
+; = 1). By setting NUM_HEADER_LINES to an integer larger than 1,
+; one can avoid truncation of the headers. In addition, setting
+; NUM_HEADER_LINES will display commented lines indicating
+; a FORMAT for reading the data, and a suggested call to
+; readfmt.pro. Works for binary tables only
+; NVAL_PER_LINE - The maximum number of values displayed from a
+; multivalued column when printing in table format. Default = 6
+; TEXTOUT - scalar number (0-7) or string (file name) determining
+; output device (see TEXTOPEN). Default is TEXTOUT=1, output
+; to the user's terminal
+; EXAMPLE:
+; (1) Print all rows of the first 5 columns of the first extension of the
+; file 'wfpc.fits'
+; IDL> ftab_print,'vizier.fits',indgen(5)+1
+;
+; (2) Print all columns of the first row to a file 'vizier.dat' in
+; 'table' format
+; IDL> ftab_print,'vizier.fits',t='vizier.dat','*',0
+; SYSTEM VARIABLES:
+; Uses the non-standard system variables !TEXTOUT and !TEXTUNIT
+; which must be defined (e.g. with ASTROLIB) prior to compilation.
+; PROCEDURES USED:
+; FITS_CLOSE, FITS_OPEN, FITS_READ, FTPRINT, TBPRINT
+; HISTORY:
+; version 1 W. Landsman August 1997
+; Check whether data exists W. Landsman Feb 2007
+; Check whether extension exists W. Landsman Mar 2010
+; Added NUM_HEADER_LINES, NVAL_PER_LINE keywords for binary tables
+; W. Landsman Apr 2010
+;-
+;----------------------------------------------------------------------
+ On_error,2
+ compile_opt idl2
+ if N_params() LT 1 then begin
+ print,'Syntax - ftab_print, filename, columns, rows,'
+ print,' [EXTEN_NO=, FMT= , TEXTOUT= ]'
+ return
+ endif
+
+ if not keyword_set(exten_no) then exten_no = 1
+
+ fits_open,filename,fcb
+ if fcb.nextend LT exten_no then begin
+ message,/CON, $
+ 'ERROR - Extension ' + strtrim(exten_no,2) + ' not present in FITS file'
+ return
+ endif
+
+ if fcb.axis[1,exten_no] EQ 0 then begin
+ message,/CON, $
+ 'ERROR - Extension ' + strtrim(exten_no,2) + ' contains no data'
+ return
+ endif
+ fits_read,fcb,tab,htab,exten_no=exten_no
+ fits_close,fcb
+
+ ext_type = fcb.xtension[exten_no]
+
+ case ext_type of
+ 'A3DTABLE': binary = 1b
+ 'BINTABLE': binary = 1b
+ 'TABLE': binary = 0b
+ else: message,'ERROR - Extension type of ' + $
+ ext_type + ' is not a FITS table format'
+ endcase
+
+ if binary then tbprint,htab,tab,columns,rows, TEXTOUT = textout,fmt=fmt, $
+ num_header_lines=num_header_lines, $
+ nval_per_line=nval_per_line $
+ else ftprint,htab,tab,columns,rows, TEXTOUT = textout
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftaddcol.pro b/Code/script_idl_mv/astrolib/ftaddcol.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a53d23a5eca036707924e046361c0be8951f71e7
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftaddcol.pro
@@ -0,0 +1,150 @@
+pro ftaddcol,h,tab,name,idltype,tform,tunit,tscal,tzero,tnull
+;+
+; NAME:
+; FTADDCOL
+; PURPOSE:
+; Routine to add a field to a FITS ASCII table
+;
+; CALLING SEQUENCE:
+; ftaddcol, h, tab, name, idltype, [ tform, tunit, tscal, tzero, tnull ]
+;
+; INPUTS:
+; h - FITS table header. It will be updated as appropriate
+; tab - FITS table array. Number of columns will be increased if
+; neccessary.
+; name - field name, scalar string
+; idltype - idl data type (as returned by SIZE function) for field,
+; For string data (type=7) use minus the string length.
+;
+; OPTIONAL INPUTS:
+; tform - format specification 'qww.dd' where q = A, I, E, or D
+; tunit - string giving physical units for the column.
+; tscal - scale factor
+; tzero - zero point for field
+; tnull - null value for field
+;
+; Use '' as the value of tform,tunit,tscal,tzero,tnull if you want
+; the default or no specification of them in the table header.
+;
+; OUTPUTS:
+; h,tab - updated to allow new column of data
+;
+; PROCEDURES USED:
+; FTINFO, FTSIZE, GETTOK(), SXADDPAR
+; HISTORY:
+; version 1 D. Lindler July, 1987
+; Converted to IDL V5.0 W. Landsman September 1997
+; Updated call to new FTINFO W. Landsman April 2000
+;-
+ On_error,2
+ if N_params() LT 2 then begin
+ print,'Syntax - FTADDCOL, h, tab, name, idltype, '
+ print,' [ tform, tunit, tscal, tzero, tnull ]'
+ return
+ endif
+
+; get table size
+
+ ftsize,h,tab,ncols,nrows,tfields,allcols,allrows
+
+; check to see if column name is a string
+
+ s = size(name)
+ if (s[0] NE 0) or (s[1] NE 7) then $
+ message,'Column name must be a string'
+
+; check to see if column already exists
+
+ ftinfo,h,ft_str, Count = count
+ if Count GT 0 then begin
+ g = where(strtrim(ft_str.ttype,2) EQ strupcase(name), Ng)
+ if Ng GT 0 then message,'ERROR - Column '+name+' already exists'
+ endif
+
+; set non specified inputs to ''
+
+ npar = N_params()
+ if npar lt 5 then tform = ''
+ if npar lt 6 then tunit = ''
+ if npar lt 7 then tscal = ''
+ if npar lt 8 then tzero = ''
+ if npar lt 9 then tnull = ''
+
+; create default format if not supplied
+
+ if tform eq '' then begin
+ case idltype of
+ 1: tform = 'I4' ;byte
+ 2: tform = 'I6' ;integer*2
+ 4: tform = 'E15.8' ;real*4
+ 3: tform = 'I11' ;longword
+ 5: tform = 'D23.8' ;real*8
+ else: begin
+ if idltype LT 0 then begin ;string
+ tform = 'A'+strtrim(fix(abs(idltype)),2)
+ idltype = 7
+ end else message,'Invalid idltype specified'
+ end
+ end; case
+ end
+
+; get field width from format
+
+ width = fix(gettok(strmid(tform,1,strlen(tform)-1),'.'))
+
+;
+; is present allocated table size large enough?
+;
+; If the new field is not a string, put a zero in the leftmost position
+; of the record so that a "Type conversion error" won't occur.
+;
+ if (width+ncols) GT allcols then begin
+ tab = [ tab, replicate(32B,width,allrows)] ;increase size
+ if (idltype NE 7) then tab[allcols,*] = 48B
+ endif
+
+;
+; update header
+;
+ tfields = tfields+1
+ apos = strtrim(tfields,2)
+ ttype = strupcase(name) ;ttype
+ while strlen(ttype) lt 8 do ttype = ttype+' '
+ sxaddpar,h,'TTYPE'+apos,ttype,'','HISTORY'
+
+;
+ sxaddpar,h,'TBCOL'+apos,ncols+1,'','HISTORY' ;tbcol (WBL 2-88)
+
+;
+ while strlen(tform) lt 8 do tform = tform+' ' ;tform
+ sxaddpar,h,'TFORM'+apos,tform,'','HISTORY'
+
+
+ if tunit NE '' then begin ;tunit
+ while strlen(tunit) lt 8 do tunit = tunit+' '
+ sxaddpar,h,'tunit'+apos,tunit,'','HISTORY'
+ end
+
+ if string(tscal) NE '' then $
+ sxaddpar,h,'tscal'+apos,tscal,'','HISTORY' ;tscal
+
+
+ if string(tzero) NE '' then $
+ sxaddpar,h,'tzero'+apos,tzero,'','HISTORY' ;tzero
+
+ if string(tnull) NE '' then begin ;tnull
+ s = size(tnull) & type = s[s[0]+1]
+ if type NE 1 then stnull = string(tnull,'('+strtrim(tform)+')') $
+ else stnull = tnull
+ while strlen(stnull) LT 8 do stnull = stnull+' '
+ sxaddpar, h, 'TNULL' + apos, stnull, '', 'HISTORY'
+ end
+
+;
+; increase table size in header
+;
+ sxaddpar,h,'TFIELDS',tfields
+ sxaddpar,h,'NAXIS1',ncols+width
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftcreate.pro b/Code/script_idl_mv/astrolib/ftcreate.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5602ed399074680b21dd26d802a959296cb94503
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftcreate.pro
@@ -0,0 +1,55 @@
+pro ftcreate, MAXCOLS,MAXROWS,H,TAB
+;+
+; NAME:
+; FTCREATE
+; PURPOSE:
+; Create a new (blank) FITS ASCII table and header with specified size.
+;
+; CALLING SEQUENCE:
+; ftcreate, maxcols, maxrows, h, tab
+;
+; INPUTS:
+; maxcols - number of character columns allocated, integer scalar
+; maxrows - maximum number of rows allocated, integer scalar
+;
+; OUTPUTS:
+; h - minimal FITS Table extension header, string array
+; OPTIONAL OUTPUT:
+; tab - empty table, byte array
+; HISTORY:
+; version 1 D. Lindler July. 87
+; Converted to IDL V5.0 W. Landsman September 1997
+; Make table creation optional, allow 1 row table, add comments to
+; required FITS keywords W. Landsman October 2001
+;-
+;----------------------------------------------------------------------
+ On_error,2
+
+ if n_params() lt 3 then begin
+ print,'Syntax - FTCREATE, maxcols, maxrows, h, [tab]'
+ return
+ endif
+
+; Create blank table if tab output variable supplied
+
+ if N_params() GE 4 then begin
+ tab = replicate(32B, maxcols, maxrows)
+ if maxrows EQ 1 then tab = reform(tab,maxcols,1)
+ endif
+;
+; Create header (destroy any previous contents) and add required ASCII table
+; keywords
+;
+ h = strarr(9) + string(' ',format='(a80)')
+ h[0] = 'END' + string(replicate(32b,77))
+ sxaddpar, h, 'XTENSION', 'TABLE ',' ASCII table extension'
+ sxaddpar, h, 'BITPIX', 8,' 8 bit bytes'
+ sxaddpar, h, 'NAXIS', 2,' 2-dimensional ASCII table'
+ sxaddpar, h, 'NAXIS1', 0,' Width of table in bytes'
+ sxaddpar, h, 'NAXIS2', 0,' Number of rows in table'
+ sxaddpar, h, 'PCOUNT', 0,' Size of special data area'
+ sxaddpar, h, 'GCOUNT', 1,' one data group (required keyword)
+ sxaddpar, h, 'TFIELDS', 0,' Number of fields in each row'
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftdelcol.pro b/Code/script_idl_mv/astrolib/ftdelcol.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8c9fa9148c01a784f4f5eaf550d39f813d4c7273
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftdelcol.pro
@@ -0,0 +1,114 @@
+pro ftdelcol,h,tab,name
+;+
+; NAME:
+; FTDELCOL
+; PURPOSE:
+; Delete a column of data from a FITS table
+;
+; CALLING SEQUENCE:
+; ftdelcol, h, tab, name
+;
+; INPUTS-OUPUTS
+; h,tab - FITS table header and data array. H and TAB will
+; be updated with the specified column deleted
+;
+; INPUTS:
+; name - Either (1) a string giving the name of the column to delete
+; or (2) a scalar giving the column number to delete (starting with 1)
+; Only 1 column can be deleted at a time
+;
+; EXAMPLE:
+; Suppose it has been determined that the F7.2 format used for a field
+; FLUX in a FITS table is insufficient. The old column must first be
+; deleted before a new column can be written with a new format.
+;
+; flux = FTGET(h,tab,'FLUX') ;Save the existing values
+; FTDELCOL,h,tab,'FLUX' ;Delete the existing column
+; FTADDCOL,h,tab,'FLUX',8,'F9.2' ;Create a new column with larger format
+; FTPUT,h,tab,'FLUX',0,flux ;Put back the original values
+;
+; REVISION HISTORY:
+; Written W. Landsman STX Co. August, 1988
+; Adapted for IDL Version 2, J. Isensee, July, 1990
+; Updated call to new FTINFO W. Landsman May 2000
+; Allow specification of column number in addition to field name
+; M. Nolan/W. Landsman Sep 2015
+;-
+; On_error,2
+
+ if N_params() LT 3 then begin
+ print,'Syntax - FTDELCOL, h, tab, name'
+ return
+ endif
+
+ ftsize,h,tab,ncol,nrows,tfields,allcols,allrows
+
+; Make sure column exists
+
+ ftinfo, h, ft_str ;Get starting column and width (in bytes)
+ sz = size(name)
+ if ((sz[0] ne 0) || (sz[1] EQ 0)) then $
+ message,'Invalid field specification, it must be a scalar'
+
+ if sz[1] EQ 7 then begin ;If a string, get the field number
+ ttype = strupcase( strtrim(ft_str.ttype,2))
+ field = where(ttype EQ strupcase(strtrim(name,2)), Npos) + 1
+ if Npos EQ 0 then message, $
+ 'Specified field ' + strupcase(strtrim(name,2)) + ' not in FITS table'
+ endif else begin ;Column number supplied
+ field = long(name)
+ if (field LT 1 || field GT n_elements(ft_str.ttype)) then message, $
+ 'Column number must be between 1 and ' + strtrim(n_elements(ft_str.ttype),2)
+ endelse
+
+
+; Eliminate relevant columns from TAB
+
+ field = field[0]
+ tbcol = ft_str.tbcol[field-1]-1 ;Convert to IDL indexing
+ width = ft_str.width[field-1]
+ case 1 of
+ tbcol eq 0: tab = tab[width:*,*] ;First column
+ tbcol eq ncol-width: tab = tab[0:tbcol-1,*] ;Last column
+ else: tab = [tab[0:tbcol-1,*],tab[tbcol+width:*,*]] ;All other columns
+ endcase
+
+; Parse the header. Remove specified keyword from header. Lower
+; the index of subsequent keywords. Update the TBCOL*** index of
+; subsequent keywords
+
+ nh = N_elements(h)
+ hnew = strarr(nh)
+ j = 0
+ key = strupcase(strmid(h,0,5))
+ for i= 0,nh-1 do begin ;Loop over each element in header
+ if (key[i] eq 'TTYPE') || (key[i] eq 'TFORM') || (key[i] eq 'TUNIT') || $
+ (key[i] eq 'TNULL') || (key[i] eq 'TBCOL') then begin
+ row = h[i]
+ ifield = fix(strtrim(strmid(row,5,3)))
+ if ifield GT field then begin ;Subsequent field?
+ if ifield le 10 then fmt = "(I1,' ')" else fmt ='(I2)'
+ strput,row,string(ifield-1,format=fmt),5
+ if key[i] eq 'TBCOL' then begin
+ value = fix(strtrim(strmid(row,10,20)))-width
+ v = string(value)
+ s = strlen(v)
+ strput,row,v,30-s ;Right justify
+ endif
+ endif
+ if ifield ne field then hnew[j] = row else j--
+
+ endif else hnew[j] = h[i]
+
+ j++
+ endfor
+
+ sxaddpar,hnew,'TFIELDS',tfields-1 ;Reduce number of fields by 1
+ sxaddpar,hnew,'NAXIS1',ncol-width ;Reduce num. of columns by WIDTH
+
+ h = hnew[0:j-1]
+ message,'Field '+ strtrim(strupcase(name),2) + $
+ ' has been deleted from the FITS table',/INF
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftdelrow.pro b/Code/script_idl_mv/astrolib/ftdelrow.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5e64b7e475b0ea608f1dae09620a50ae65138e11
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftdelrow.pro
@@ -0,0 +1,74 @@
+pro ftdelrow,h,tab,rows
+;+
+; NAME:
+; FTDELROW
+; PURPOSE:
+; Delete a row of data from a FITS table
+;
+; CALLING SEQUENCE:
+; ftdelrow, h, tab, rows
+;
+; INPUTS-OUPUTS
+; h,tab - FITS table header and data array. H and TAB will
+; be updated on output with the specified row(s) deleted.
+; rows - scalar or vector, specifying the row numbers to delete
+; This vector will be sorted and duplicates removed by FTDELROW
+;
+; EXAMPLE:
+; Compress a table to include only non-negative flux values
+;
+; flux = FTGET(h,tab,'FLUX') ;Obtain original flux vector
+; bad = where(flux lt 0) ;Find negative fluxes
+; FTDELROW,h,tab,bad ;Delete rows with negative fluxes
+;
+; PROCEDURE:
+; Specified rows are deleted from the data array, TAB. The NAXIS2
+; keyword in the header is updated.
+;
+; PROCEDURES USED:
+; sxaddpar
+;
+; REVISION HISTORY:
+; Written W. Landsman STX Co. August, 1988
+; Checked for IDL Version 2, J. Isensee, July, 1990
+; Converted to IDL V5.0 W. Landsman September 1997
+; Assume since V5.4, use BREAK instead of GOTO W. Landsman April 2006
+;
+;-
+ On_error,2
+
+ if N_params() LT 3 then begin
+ print,'Syntax - ftdelrow,h,tab,rows'
+ return
+ endif
+
+ nrows = sxpar(h,'NAXIS2') ;Original number of rows
+ if (max(rows) GE nrows) or (min(rows) LT 0) then $
+ message,'Specified rows must be between 0 and ' + strtrim(nrows-1,2)
+
+ ndel = N_elements(rows)
+ if ndel GT 1 then begin
+ rows = rows[rem_dup(rows)] ;Sort and remove duplicate values
+ ndel = N_elements(rows)
+ endif
+
+ j = 0L
+ i = rows[0]
+ for k = long(rows[0]),nrows-1 do begin
+ if k EQ rows[j] then begin
+ j = j+1
+ if j EQ ndel then BREAK
+ endif else begin
+ tab[0,i] = tab[*,k]
+ i = i+1
+ endelse
+
+ endfor
+ k = k-1
+
+ if k NE nrows-1 then tab[0,i] = tab[*,i+j:nrows-1]
+ tab = tab[*,0:nrows-ndel-1]
+ sxaddpar,h,'NAXIS2',nrows-ndel ;Reduce number of rows
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftget.pro b/Code/script_idl_mv/astrolib/ftget.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a5f6885fb1f49fbc9aa643ff035855b41186184e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftget.pro
@@ -0,0 +1,146 @@
+function ftget,hdr_or_ftstr,tab,field,rows,nulls
+;+
+; NAME:
+; FTGET
+; PURPOSE:
+; Function to return value(s) from specified column in a FITS ASCII table
+;
+; CALLING SEQUENCE
+; values = FTGET( h, tab, field, [ rows, nulls ] )
+; or
+; values = FTGET( ft_str, tab, field. [rows, nulls]
+; INPUTS:
+; h - FITS ASCII extension header (e.g. as returned by FITS_READ)
+; or
+; ft_str - FITS table structure extracted from FITS header by FTINFO
+; Use of the IDL structure will improve processing speed
+; tab - FITS ASCII table array (e.g. as returned by FITS_READ)
+; field - field name or number
+;
+; OPTIONAL INPUTS:
+; rows - scalar or vector giving row number(s)
+; Row numbers start at 0. If not supplied or set to
+; -1 then values for all rows are returned
+;
+; OUTPUTS:
+; the values for the row are returned as the function value.
+; Null values are set to 0 or blanks for strings.
+;
+; OPTIONAL OUTPUT:
+; nulls - null value flag of same length as the returned data.
+; It is set to 1 at null value positions and 0 elsewhere.
+; If supplied then the optional input, rows, must also
+; be supplied.
+;
+; EXAMPLE:
+; Read the columns labeled 'WAVELENGTH' and 'FLUX' from the second
+; (ASCII table) extension of a FITS file 'spectra.fit'
+;
+; IDL> fits_read,'spectra.fit',tab,htab,exten=2 ;Read 2nd extension
+; IDL> w = ftget( htab, tab,'wavelength') ;Wavelength vector
+; IDL> f = ftget( htab, tab,'flux') ;Flux vector
+;
+; Slightly more efficient would be to first call FTINFO
+; IDL> ftinfo, htab, ft_str ;Extract structure
+; IDL> w = ftget(ft_str, tab,'wavelength') ;Wavelength vector
+; IDL> f = ftget(ft_str, tab,'flux') ;Flux vector
+;
+; NOTES:
+; (1) Use the higher-level procedure FTAB_EXT to extract vectors
+; directly from the FITS file.
+; (2) Use FTAB_HELP or FTHELP to determine the columns in a particular
+; ASCII table.
+; HISTORY:
+; coded by D. Lindler July, 1987
+; Always check for null values W. Landsman August 1990
+; More informative error message W. Landsman Feb. 1996
+; Converted to IDL V5.0 W. Landsman September 1997
+; Allow structure rather than FITS header W. Landsman May 2000
+; No case sensitivity in TTYPE name W. Landsman February 2002
+;-
+;------------------------------------------------------------------
+; On_error,2
+
+ sz = size(tab)
+ nrows = sz(2)
+
+; get characteristics of specified field
+
+ size_hdr = size(hdr_or_ftstr)
+ case size_hdr[size_hdr[0]+1] of
+ 7: ftinfo,hdr_or_ftstr,ft_str
+ 8: ft_str = hdr_or_ftstr
+ else: message,'ERROR - Invalid FITS header or structure supplied'
+ endcase
+
+ sz = size(field)
+ if ((sz[0] ne 0) or (sz[1] EQ 0)) then $
+ message,'Invalid field specification, it must be a scalar'
+
+ if sz[1] EQ 7 then begin
+ field = strupcase(strtrim(field,2))
+ ttype = strupcase( strtrim(ft_str.ttype,2) )
+ ipos = where(ttype EQ field, Npos)
+ if Npos EQ 0 then message, $
+ 'Specified field ' + strupcase(strtrim(field,2)) + ' not in table'
+ endif else ipos = field -1
+ ipos = ipos[0]
+
+ tbcol = ft_str.tbcol[ipos]-1 ;IDL starts at zero not one
+ width = ft_str.width[ipos]
+ tnull = ft_str.tnull[ipos]
+ idltype = ft_str.idltype[ipos]
+
+; if rows not supplied then return all rows
+
+ if N_params() LT 4 then rows = -1
+
+; determine if scalar supplied
+
+ row = rows
+ s = size(row) & ndim = s[0]
+ if ndim EQ 0 then begin ;scalar?
+ if row LT 0 then begin ; -1 get all rows
+ ndim = 1
+ row = lindgen(nrows)
+ end else begin
+ row = lonarr(1) + row
+ end
+ end
+
+; check for valid row numbers
+
+ if (min(row) lt 0) or (max(row) gt (nrows-1)) then $
+ message,'ERROR - Row numbers must be between 0 and ' + $
+ strtrim((nrows-1),2)
+
+; get column
+
+ if ndim EQ 0 then begin ;scalar?
+ dd = string(tab[tbcol:tbcol+width-1,row[0]])
+ data = strarr(1)
+ data[0] = dd
+ end else begin ;vector
+ data = string(tab[tbcol:tbcol+width-1,*])
+ data = data[row]
+ end
+
+; check for null values
+ n = N_elements(data)
+ d = make_array(size=[1,n,idltype,n])
+
+ if strlen(tnull) GT 0 then begin
+ len = strlen(data[0]) ;field size
+ while strlen(tnull) LT len do tnull = tnull + ' ' ;pad with blanks
+ if strlen(tnull) GT len then tnull = strmid(tnull,0,len)
+ nulls = data EQ tnull
+ valid = where(nulls EQ 0b, nvalid)
+
+; convert data to the correct type
+
+ if nvalid GT 0 then d[valid] = data[valid]
+
+ endif else d[0] = strtrim(data,2)
+
+ return,d
+ end
diff --git a/Code/script_idl_mv/astrolib/fthelp.pro b/Code/script_idl_mv/astrolib/fthelp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..63eb46f35d82a76ff14a995d45dfdd537245b608
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fthelp.pro
@@ -0,0 +1,96 @@
+pro fthelp,h,TEXTOUT=textout
+;+
+; NAME:
+; FTHELP
+; PURPOSE:
+; Routine to print a description of a FITS ASCII table extension
+;
+; CALLING SEQUENCE:
+; FTHELP, H, [ TEXTOUT = ]
+;
+; INPUTS:
+; H - FITS header for ASCII table extension, string array
+;
+; OPTIONAL INPUT KEYWORD
+; TEXTOUT - scalar number (0-7) or string (file name) determining
+; output device (see TEXTOPEN). Default is TEXTOUT=1, output
+; to the user's terminal
+;
+; NOTES:
+; FTHELP checks that the keyword XTENSION equals 'TABLE' in the FITS
+; header.
+;
+; SYSTEM VARIABLES:
+; Uses the non-standard system variables !TEXTOUT and !TEXTUNIT
+; which must be defined (e.g. with ASTROLIB) prior to compilation.
+; PROCEDURES USED:
+; REMCHAR, SXPAR(), TEXTOPEN, TEXTCLOSE, ZPARCHECK
+;
+; HISTORY:
+; version 1 W. Landsman Jan. 1988
+; Add TEXTOUT option, cleaner format W. Landsman September 1991
+; TTYPE value can be longer than 8 chars, W. Landsman August 1995
+; Remove calls to !ERR, some vectorization W. Landsman February 2000
+; Slightly more compact display W. Landsman August 2005
+;-
+ compile_opt idl2
+ On_error,2 ;Return to caller
+
+ if N_params() EQ 0 then begin
+ print,'Syntax - FTHELP, hdr, [ TEXTOUT = ]'
+ return
+ endif
+
+ zparcheck,'FTHELP',h,1,7,1,'Table Header' ;Make sure a string array
+
+ n = sxpar( h, 'TFIELDS' , Count = N_TFields)
+ if N_TFields EQ 0 then message, $
+ 'ERROR - FITS Header does not include required TFIELDS keyword'
+ if strtrim(sxpar(h,'XTENSION'),2) ne 'TABLE' then $
+ message,'WARNING - Header is not for a FITS Table',/INF
+
+ if not keyword_set(TEXTOUT) then textout = 1
+ textopen,'fthelp',TEXTOUT=textout
+
+ naxis = sxpar( h, 'NAXIS*')
+ printf,!TEXTUNIT,'FITS ASCII Table: ' +$
+ 'Size ',strtrim(naxis[0],2),' by ',strtrim(naxis[1],2)
+
+ extname = sxpar(h,'EXTNAME', Count=N_ext)
+ if N_ext GT 0 then printf,!TEXTUNIT, 'Extension Name: ',sxpar(h,'EXTNAME')
+ extver = sxpar(h, 'EXTVER', Count = N_extver)
+ if N_extver GT 0 then printf,!TEXTUNIT,'Version: ',extver
+ printf,!TEXTUNIT,' '
+ printf,!TEXTUNIT, $
+ 'Field Name Unit Format Column'
+
+ tbcol = intarr(n)
+ tform = strarr(n) & tunit = tform & ttype =tform
+ name = strmid(h,0,5)
+ number = strtrim(strmid(h,5,3),2)
+ value = strtrim(strmid(h,11,20),2)
+
+ for i = 1, N_elements(h)-1 do begin
+ case name[i] of
+ 'TTYPE': ttype[fix(number[i]-1)] = value[i]
+ 'TFORM': tform[fix(number[i]-1)] = value[i]
+ 'TUNIT': tunit[fix(number[i]-1)] = value[i]
+ 'TBCOL': tbcol[fix(number[i]-1)] = fix(value[i])
+ 'END ': goto, DONE
+ ELSE :
+ end
+
+ endfor
+
+DONE: ;Done reading FITS header
+
+ ttype = strtrim(ttype,2) & remchar,ttype,"'"
+ remchar,tunit,"'"
+ remchar,tform,"'"
+ for i = 0,n-1 do printf,!TEXTUNIT,i+1,ttype[i],tunit[i],tform[i],tbcol[i], $
+ f='(I5,T9,A,T30,A,T47,A,T55,I8)'
+
+ textclose,TEXTOUT=textout
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/fthmod.pro b/Code/script_idl_mv/astrolib/fthmod.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2e1e8d38a86f83f87397c698dcbf3a62d7dd5d7f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fthmod.pro
@@ -0,0 +1,63 @@
+pro fthmod,h,field,parameter,value
+;+
+; NAME:
+; FTHMOD
+; PURPOSE:
+; Procedure to modify header information for a specified field
+; in a FITS table.
+;
+; CALLING SEQUENCE:
+; fthmod, h, field, parameter, value
+;
+; INPUT:
+; h - FITS header for the table
+; field - field name or number
+; parameter - string name of the parameter to modify. Choices
+; include:
+; TTYPE - field name
+; TUNIT - physical units for field (eg. 'ANGSTROMS')
+; TNULL - null value (string) for field, (eg. '***')
+; TFORM - format specification for the field
+; TSCAL - scale factor
+; TZERO - zero offset
+; User should be aware that the validity of the change is
+; not checked. Unless you really know what you are doing,
+; this routine should only be used to change field names,
+; units, or another user specified parameter.
+; value - new value for the parameter. Refer to the FITS table
+; standards documentation for valid values.
+;
+; EXAMPLE:
+; Change the units for a field name "FLUX" to "Janskys" in a FITS table
+; header,h
+;
+; IDL> FTHMOD, h, 'FLUX', 'TUNIT','Janskys'
+; METHOD:
+; The header keyword is modified
+; with the new value.
+; HISTORY:
+; version 1, D. Lindler July 1987
+; Converted to IDL V5.0 W. Landsman September 1997
+; Major rewrite to use new FTINFO call W. Landsman May 2000
+;-
+;-----------------------------------------------------------------------
+on_error,2
+
+ ftinfo,h,ft_str
+ sz = size(field)
+ if ((sz[0] ne 0) or (sz[1] EQ 0)) then $
+ message,'Invalid field specification, it must be a scalar'
+
+ if sz[1] EQ 7 then begin
+ field = strupcase(strtrim(field,2))
+ ttype = strtrim(ft_str.ttype,2)
+ ipos = where(ttype EQ field, Npos)
+ if Npos EQ 0 then message, $
+ 'Specified field ' + strupcase(strtrim(field,2)) + ' not in table'
+ endif else ipos = field -1
+
+;
+ par = parameter+strtrim(ipos[0]+1,2)
+ sxaddpar,h,par,value
+return
+end
diff --git a/Code/script_idl_mv/astrolib/ftinfo.pro b/Code/script_idl_mv/astrolib/ftinfo.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c5230fd8583d4cd89e4fbd8f3f54a8657802683f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftinfo.pro
@@ -0,0 +1,116 @@
+pro ftinfo, h, ft_str, Count = tfields
+;+
+; NAME:
+; FTINFO
+; PURPOSE:
+; Return an informational structure from a FITS ASCII table header.
+; CALLING SEQUENCE:
+; ftinfo,h,ft_str, [Count = ]
+;
+; INPUTS:
+; h - FITS ASCII table header, string array
+;
+; OUTPUTS:
+; ft_str - IDL structure with extracted info from the FITS ASCII table
+; header. Tags include
+; .tbcol - starting column position in bytes
+; .width - width of the field in bytes
+; .idltype - idltype of field.
+; 7 - string, 4- real*4, 3-integer, 5-real*8
+; .tunit - string unit numbers
+; .tscal - scale factor
+; .tzero - zero point for field
+; .tnull - null value for the field
+; .tform - format for the field
+; .ttype - field name
+;
+; OPTIONAL OUTPUT KEYWORD:
+; Count - Integer scalar giving number of fields in the table
+; PROCEDURES USED:
+; GETTOK(), SXPAR()
+; NOTES:
+; This procedure underwent a major revision in May 2000, and **THE
+; NEW CALLING SEQUENCE IS INCOMPATIBLE WITH THE OLD ONE **
+; HISTORY:
+; D. Lindler July, 1987
+; Converted to IDL V5.0 W. Landsman September 1997
+; Major rewrite, return structure W. Landsman April 2000
+;-
+;----------------------------------------------------------------------------
+; On_error,2
+;
+ if N_params() LT 2 then begin
+ print,'Syntax - FTINFO, header, ft_str'
+ return
+ endif
+
+; get number of fields
+
+ tfields = sxpar( h, 'TFIELDS' , Count = N_TFields)
+ if N_TFields EQ 0 then $
+ message,'Invalid FITS header. keyword TFIELDS is missing'
+
+ if tfields EQ 0 then return
+ tbcol = intarr(tfields)
+ tform = replicate(' ',tfields)
+
+; get info for specified field
+
+ ttype = sxpar(h,'ttype*',Count=N_ttype) ;field name
+ if N_ttype EQ 0 then ttype = strarr(tfields)
+
+ tbcol[0] = sxpar(h,'tbcol*', Count = N_tbcol) ;starting column position
+ if N_tbcol NE tfields then message,/CON, $
+ 'Warning - Invalid FITS table header -- TBCOL not present for all fields'
+;
+ tform[0] = strtrim(sxpar(h,'tform*', Count = N_tform),2) ; column format
+ if N_tform NE tfields then message,/CON, $
+ 'Warning - Invalid FITS table header -- TFORM not present for all fields'
+ ; ; physical units
+ tunit = strarr(Tfields)
+ temp = sxpar(h, 'TUNIT*', Count = N_tunit)
+ if N_tunit GT 0 then tunit[0] = temp
+
+ tscal = fltarr(Tfields)
+ temp = sxpar(h, 'TSCAL*', Count = N_tscal) ; data scale factor
+ if N_tscal GT 0 then tscal[0] = temp
+
+ tzero = fltarr(tfields)
+ temp = sxpar(h,'TZERO*', Count = N_tzero) ; zero point for field
+ if N_tzero GT 0 then tzero[0] = temp
+
+ tnull = strarr(Tfields)
+ temp = sxpar(h,'TNULL*', Count = N_tnull) ;null data value
+ if N_tnull GT 0 then tnull[0] = temp
+;
+; determine idl data type from format
+;
+ type = strmid(tform,0,1)
+ idltype = intarr(tfields)
+ for i=0,tfields-1 do begin
+ case strupcase(type[i]) of
+ 'A' : idltype[i] = 7
+ 'I' : idltype[i] = 3
+ 'E' : idltype[i] = 4
+ 'F' : idltype[i] = 4
+ 'D' : idltype[i] = 5
+ else: message,'Invalid format specification for keyword ' + $
+ 'TFORM' + strtrim(i+1,2)
+ endcase
+ endfor
+;
+; get field width in characters
+;
+ decpos = strpos(tform,'.')
+ decimal = decpos GT 0
+ len = strlen(tform)
+ width = intarr(tfields)
+ for i=0, tfields-1 do begin
+ if decimal[i] then width[i] = fix(strmid(tform[i],1,decpos[i]-1)) else $
+ width[i] = fix(strmid(tform[i],1,len[i]-1))
+ endfor
+ ft_str = {TBCOL:tbcol,WIDTH:width,IDLTYPE:idltype,TUNIT:tunit, TSCAL:tscal, $
+ TZERO:tzero, TNULL:tnull, TFORM:tform, TTYPE:ttype}
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftkeeprow.pro b/Code/script_idl_mv/astrolib/ftkeeprow.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f02c4b16bb55430429e72e573bda70da69214b6b
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftkeeprow.pro
@@ -0,0 +1,41 @@
+pro ftkeeprow,h,tab,subs
+;+
+; NAME:
+; FTKEEPROW
+; PURPOSE:
+; Subscripts (and reorders) a FITS table. A companion piece to FTDELROW.
+;
+; CALLING SEQUENCE:
+; ftkeeprow, h, tab, subs
+;
+; INPUT PARAMETERS:
+; h = FITS table header array
+; tab = FITS table data array
+; subs = subscript array of FITS table rows. Works like any other IDL
+; subscript array (0 based, of course).
+;
+; OUTPUT PARAMETERS:
+; h and tab are modified
+;
+; MODIFICATION HISTORY:
+; Written by R. S. Hill, ST Sys. Corp., 2 May 1991.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+ On_error,2 ;Return to caller
+
+ if N_params() LT 3 then begin
+ print,'Syntax - ftkeeprow, h, tab, subs'
+ return
+ endif
+
+ insize = sxpar(h,'NAXIS2')
+ tab = tab[*,subs]
+ outsize = N_elements(subs)
+ sxaddpar, h, 'NAXIS2', outsize
+ tag = 'FTKEEPROW '+systime(0)+': '
+ sxaddhist, tag + 'table subscripted', h
+ sxaddhist, tag + strtrim(string(insize),2) + ' rows in, ' + $
+ strtrim(string(outsize),2) + ' rows out',h
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftprint.pro b/Code/script_idl_mv/astrolib/ftprint.pro
new file mode 100644
index 0000000000000000000000000000000000000000..71278e0b099da479c08ab8854a5f8b7ebd576728
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftprint.pro
@@ -0,0 +1,170 @@
+pro ftprint,h,tab,columns,rows,textout=textout
+;+
+; NAME:
+; FTPRINT
+; PURPOSE:
+; Procedure to print specified columns and rows of a FITS table
+;
+; CALLING SEQUENCE:
+; FTPRINT, h, tab, columns, [ rows, TEXTOUT = ]
+;
+; INPUTS:
+; h - Fits header for table, string array
+; tab - table array
+; columns - string giving column names, or vector giving
+; column numbers (beginning with 1). If string
+; supplied then column names should be separated by comma's.
+; rows - (optional) vector of row numbers to print. If
+; not supplied or set to scalar, -1, then all rows
+; are printed.
+;
+; OUTPUTS:
+; None
+;
+; OPTIONAL INPUT KEYWORDS:
+; TEXTOUT controls the output device; see the procedure TEXTOPEN
+;
+; SYSTEM VARIABLES:
+; Uses nonstandard system variables !TEXTOUT and !TEXTOPEN
+; These will be defined (using ASTROLIB) if not already present.
+; Set !TEXTOUT = 3 to direct output to a disk file. The system
+; variable is overriden by the value of the keyword TEXTOUT
+;
+; EXAMPLES:
+;
+; ftprint,h,tab,'STAR ID,RA,DEC' ;print id,ra,dec for all stars
+; ftprint,h,tab,[2,3,4],indgen(100) ;print columns 2-4 for
+; ;first 100 stars
+; ftprint,h,tab,text="stars.dat" ;Convert entire FITS table to
+; ;an ASCII file named STARS.DAT
+;
+; PROCEDURES USED:
+; FTSIZE, FTINFO, TEXTOPEN, TEXTCLOSE
+;
+; RESTRICTIONS:
+; (1) Program does not check whether output length exceeds output
+; device capacity (e.g. 80 or 132).
+; (2) Column heading may be truncated to fit in space defined by
+; the FORMAT specified for the column
+; (3) Program does not check for null values
+;
+; HISTORY:
+; version 1 D. Lindler Feb. 1987
+; Accept undefined values of rows, columns W. Landsman August 1997
+; New FTINFO calling sequence W. Landsman May 2000
+; Parse scalar string with STRSPLIT W. Landsman July 2002
+; Fix format display of row number W. Landsman March 2003
+; Fix format display of row number again W. Landsman May 2003
+;-
+; On_error,2
+ compile_opt idl2
+;
+; set defaulted parameters
+;
+ if N_params() LT 2 then begin
+ print,'Syntax - FTPRINT, h, tab, [ columns, rows, TEXTOUT= ]'
+ return
+ endif
+
+ defsysv,'!textout',exists = i
+ if i EQ 0 then astrolib
+
+ if N_elements(columns) EQ 0 then columns = -1
+ if N_elements(rows) EQ 0 then rows= -1
+ if not keyword_set(TEXTOUT) then textout = !TEXTOUT
+
+; make sure rows is a vector
+
+ n = N_elements(rows)
+ if n EQ 1 then r = [rows] else r = long(rows)
+ ftsize,h,tab,ncols,nrows,tfields,allcols,allrows, ERRMSG = errmsg ;table size
+ if ERRMSG NE '' then message,errmsg
+ if r[0] EQ -1 then r = lindgen(nrows) ;default
+
+ Nr = N_elements(r)
+ good = where( (r GE 0) and (r LT nrows), Ngood)
+ if Ngood NE Nr then begin
+ if Ngood EQ 0 then message,'ERROR - No valid row numbers supplied'
+ r = r[good]
+ endif
+;
+; extract column info
+;
+ title1 = ''
+ title2 = ''
+ FTINFO,h,ft_str
+
+;
+; if columns is a string, change it to string array
+;
+ if size(columns,/TNAME) EQ 'STRING' then begin
+ colnames = strsplit(columns,',',/EXTRACT)
+ numcol = N_elements(colnames)
+ colnames = strupcase(strtrim(colnames,2))
+ ttype = strtrim(ft_str.ttype,2)
+ colnum = intarr(numcol)
+ for i = 0,numcol-1 do begin
+ icol = where(ttype EQ colnames[i], Nfound)
+ if Nfound EQ 0 then message, $
+ 'ERROR - Field ' + colnames[i] + ' not found in FITS ASCII table'
+ colnum[i] = icol[0]
+ endfor
+ end else begin ;user supplied vector
+ colnum = fix(columns) -1 ;make sure it is integer
+ numcol = N_elements(colnum) ;number of elements
+ if numcol EQ 1 then begin
+ if colnum[0] LT 0 then begin
+ colnum = indgen(tfields) & numcol = tfields
+ endif & endif
+ end
+
+ flen = ft_str.width[colnum]
+ colpos = ft_str.tbcol[colnum]
+ ttype = strtrim( ft_str.ttype[colnum],2)
+ tunit = strtrim( ft_str.tunit[colnum],2)
+;
+; create header lines
+;
+ for i=0,numcol-1 do begin
+ name = strn(ttype[i],padtype=2,len=flen[i] )
+ unit = strn(tunit[i],padtype=2,len=flen[i] )
+ title1 = title1 + ' ' + name
+ title2 = title2 + ' ' + unit
+ endfor
+;
+; open output file
+;
+ textopen,'FTPRINT',TEXTOUT=textout, MORE_SET = more_set
+
+ ifmt = fix(alog10(max(r)+1)) > 3
+ title1 = strn('ROW',padtype=2,len = ifmt) + title1
+ title2 = string(replicate(32b,ifmt+1)) + title2
+ ifmt = strtrim(ifmt,2)
+;
+; loop on rows
+;
+ printf,!TEXTUNIT,title1
+ printf,!TEXTUNIT,title2
+ printf,!TEXTUNIT,' '
+
+ for i = 0, Nr-1 do begin
+;
+; loop on columns
+;
+ line = string(r[i],format='(i' + ifmt + ')') ;print line
+ for j = 0,numcol-1 do begin
+ cpos=colpos[j]-1 ;column number
+ val = string(tab[cpos:cpos+flen[j]-1,r[i]])
+ line = line+' '+ val
+ endfor
+ printf,!TEXTUNIT,line
+ if more_set then if (!ERR EQ 1) then goto, DONE
+ endfor
+;
+; done
+;
+DONE:
+ textclose,textout=textout
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftput.pro b/Code/script_idl_mv/astrolib/ftput.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cee3f6c5e4a724051e18415ca6b396be322908a2
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftput.pro
@@ -0,0 +1,174 @@
+pro ftput,h,tab,field,row,values,nulls
+;+
+; NAME:
+; FTPUT
+; PURPOSE:
+; Procedure to add or update a field in an FITS ASCII table
+; CALLING SEQUENCE:
+; FTPUT, htab, tab, field, row, values, [ nulls ]
+;
+; INPUTS:
+; htab - FITS ASCII table header string array
+; tab - FITS ASCII table array (e.g. as read by READFITS)
+; field - string field name or integer field number
+; row - either a non-negative integer scalar giving starting row to
+; update, or a non-negative integer vector specifying rows to
+; update. FTPUT will append a new row to a table if the value
+; of 'row' exceeds the number of rows in the tab array
+; values - value(s) to add or update. If row is a vector
+; then values must contain the same number of elements.
+;
+; OPTIONAL INPUT:
+; nulls - null value flag of same length as values.
+; It should be set to 1 at null value positions
+; and 0 elsewhere.
+;
+; OUTPUTS:
+; htab,tab will be updated as specified.
+;
+; EXAMPLE:
+; One has a NAME and RA and Dec vectors for 500 stars with formats A6,
+; F9.5 and F9.5 respectively. Write this information to an ASCII table
+; named 'star.fits'.
+;
+; IDL> FTCREATE,24,500,h,tab ;Create table header and (empty) data
+; IDL> FTADDCOL,h,tab,'RA',8,'F9.5','DEGREES' ;Explicity define the
+; IDL> FTADDCOL,h,tab,'DEC',8,'F9.5','DEGREES' ;RA and Dec columns
+; IDL> FTPUT,h,tab,'RA',0,ra ;Insert RA vector into table
+; IDL> FTPUT,h,tab,'DEC',0,dec ;Insert DEC vector into table
+; IDL> FTPUT, h,tab, 'NAME',0,name ;Insert NAME vector with default
+; IDL> WRITEFITS,'stars.fits',tab,h ;Write to a file
+;
+; Note that (1) explicit formatting has been supplied for the (numeric)
+; RA and Dec vectors, but was not needed for the NAME vector, (2) A width
+; of 24 was supplied in FTCREATE based on the expected formats (6+9+9),
+; though the FT* will adjust this value as necessary, and (3) WRITEFITS
+; will create a minimal primary header
+; NOTES:
+; (1) If the specified field is not already in the table, then FTPUT will
+; create a new column for that field using default formatting. However,
+; FTADDCOL should be called prior to FTPUT for explicit formatting.
+;
+; PROCEDURES CALLED
+; FTADDCOL, FTINFO, FTSIZE, SXADDPAR, SXPAR()
+; HISTORY:
+; version 1 D. Lindler July, 1987
+; Allow E format W. Landsman March 1992
+; Write in F format if E format will overflow April 1994
+; Update documentation W. Landsman January 1996
+; Allow 1 element vector W. Landsman March 1996
+; Adjust string length to maximum of input string array June 1997
+; Work for more than 32767 elements August 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+; Updated call to the new FTINFO W. Landsman May 2000
+; Fix case where header does not have any columns yet W.Landsman Sep 2002
+; Assume since V5.2, omit fstring() call W. Landsman April 2006
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 5 then begin
+ print,'Syntax - FTPUT, htab, tab, field, row, values, [nulls]'
+ return
+ endif
+
+ nrow = N_elements(row) ;Number of elements in row vector
+
+ nullflag = N_elements(nulls) GT 0 ;Null values supplied?
+
+ ftsize,h,tab,ncols,nrows,tfields,allcols,allrows ; Get size of table
+
+; Make values a vector if scalar supplied
+
+ s = size(values) & ndim = s[0] & type = s[ndim+1]
+
+ if ndim gt 1 then $
+ message,'Input values must be scalar or 1-D array'
+
+ sz_row = size(row)
+ scalar = sz_row[0] EQ 0
+
+ v = values
+ if nullflag then nullvals = nulls
+
+; Get info on field specified
+
+ ftinfo,h,ft_str, Count = tfields
+ if tfields EQ 0 then ipos = -1 else begin
+ if size(field,/TNAME) EQ 'STRING' then begin
+ field = strupcase(strtrim(field,2))
+ ttype = strtrim(ft_str.ttype,2)
+ ipos = where(ttype EQ field, Npos)
+ endif else ipos = field -1
+ endelse
+
+ if ipos[0] EQ -1 then begin ;Does it exist?
+
+; Add new column if it doesn't exist
+
+ if type EQ 7 then type = (-max(strlen(v)))
+ ftaddcol, h, tab, field, type
+ ftinfo,h,ft_str
+ ftsize,h,tab,ncols,nrows,tfields,allcols,allrows
+ ipos = tfields-1
+ endif
+
+ ipos = ipos[0]
+ tbcol = ft_str.tbcol[ipos]-1 ;IDL starts at zero not one.
+
+; Convert input vector to string array
+
+ n = N_elements(v)
+ data = string(replicate(32b, ft_str.width[ipos], n ) )
+ if nrow GT 1 then if (nrow NE n) then $
+ message,'Number of specified rows must equal number of values'
+
+ fmt = strupcase(strtrim(ft_str.tform[ipos],2))
+ fmt1 = strmid(fmt,0,1)
+ if (fmt1 EQ 'D') or (fmt1 EQ 'E') then begin ;Need at least 6 chars for E fmt
+ point = strpos(fmt,'.')
+ wid = fix(strmid(fmt,1,point-1))
+ decimal = fix(strmid(fmt,point+1,1000))
+ if wid-decimal LT 6 then fmt = 'F' + strmid(fmt,1,1000)
+ endif
+ fmt = '(' + fmt + ')'
+ data = string(v, FORMAT = fmt)
+
+; insert null values
+
+ if nullflag GT 5 then begin
+ bad = where(nullvals, Nbad)
+ if Nbad GT 0 then for i = 0L, Nbad-1 do data[bad[i]] = tnull
+ end
+
+;
+; Do we need to increase the number of rows in the table?
+;
+if scalar then maxrow = row+n else maxrow = max(row) + 1
+if maxrow GT allrows then begin ;expand table size
+
+ ;
+ ; Create a replacement table with the required number of rows.
+ ;
+ newtab = replicate(32b,allcols,maxrow)
+ newtab[0,0] = tab
+
+ ;
+ ; Move the new table into the old table.
+ ;
+ tab = newtab
+
+end
+ if maxrow GT nrows then sxaddpar,h,'naxis2',maxrow
+
+;
+; Now insert into table.
+;
+ if scalar then tab[tbcol,row] = byte(data) $
+ else for i = 0L,N_elements(row)-1 do tab[tbcol,row[i]] = byte(data[i])
+
+;
+; Return to calling routine.
+;
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftsize.pro b/Code/script_idl_mv/astrolib/ftsize.pro
new file mode 100644
index 0000000000000000000000000000000000000000..81c633c1adedcee40a1e8d829091be8f8a9e6b8c
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftsize.pro
@@ -0,0 +1,73 @@
+pro ftsize,h,tab,ncols,nrows,tfields,ncols_all,nrows_all, ERRMSG = ERRMSG
+;+
+; NAME:
+; FTSIZE
+; PURPOSE:
+; Procedure to return the size of a FITS ASCII table.
+;
+; CALLING SEQUENCE:
+; ftsize,h,tab,ncols,rows,tfields,ncols_all,nrows_all, [ERRMSG = ]
+;
+; INPUTS:
+; h - FITS ASCII table header, string array
+; tab - FITS table array, 2-d byte array
+;
+; OUTPUTS:
+; ncols - number of characters per row in table
+; nrows - number of rows in table
+; tfields - number of fields per row
+; ncols_all - number of characters/row allocated (size of tab)
+; nrows_all - number of rows allocated
+;
+; OPTIONAL OUTPUT KEYWORD:
+; ERRMSG = If this keyword is present, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned.
+; HISTORY
+; D. Lindler July, 1987
+; Fix for 1-row table, W. Landsman HSTX, June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added ERRMSG keyword W. Landsman May 2000
+;
+;-
+;------------------------------------------------------------------------
+ On_error,2
+
+; check for valid header type
+
+ s=size(h) & ndim=s[0] & type=s[ndim+1]
+ save_err = arg_present(errmsg)
+ errmsg = ''
+
+ if (ndim ne 1) or (type ne 7) then begin
+ errmsg = 'Invalid FITS header, it must be a string array'
+ if not save_err then message,'ERROR - ' + errmsg
+ endif
+
+; check for valid table array
+
+ s = size(tab) & ndim = s[0] & vtype = s[ndim+1]
+ if (vtype ne 1) then begin ;Mod June 1994, for degenerate dim.
+ errmsg = 'Invalid table array, it must be a 2-D byte array'
+ if not save_err then message,'ERROR - ' + errmsg
+ endif
+
+ ncols_all = s[1] ;allocated characters per row
+ nrows_all = s[2] ;allocated rows
+
+; Get number of fields
+
+ tfields = sxpar(h,'TFIELDS', Count = N)
+ if N LT 0 then begin
+ errmsg = 'Invalid FITS ASCII table header, TFIELDS keyword missing'
+ if not save_err then message,'ERROR - ' + errmsg
+ endif
+
+; Get number of columns and rows
+
+ ncols = sxpar(h, 'NAXIS1')
+ nrows = sxpar(h, 'NAXIS2')
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/ftsort.pro b/Code/script_idl_mv/astrolib/ftsort.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0e3c86b528ecb732cadc75413c27d3698f00f56a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/ftsort.pro
@@ -0,0 +1,97 @@
+pro ftsort,h,tab,hnew,tabnew,field, reverse = revers
+;+
+; NAME:
+; FTSORT
+; PURPOSE:
+; Sort a FITS ASCII table according to a specified field
+;
+; CALLING SEQUENCE:
+; FTSORT,h,tab,[field, REVERSE = ] ;Sort original table header and array
+; or
+; FTSORT,h,tab,hnew,tabnew,[field, REVERSE =] ;Create new sorted header
+;
+; INPUTS:
+; H - FITS header (string array)
+; TAB - FITS table (byte array) associated with H. If less than 4
+; parameters are supplied, then H and TAB will be updated to
+; contain the sorted table
+;
+; OPTIONAL INPUTS:
+; FIELD - Field name(s) or number(s) used to sort the entire table.
+; If FIELD is a vector then the first element is used for the
+; primary sort, the second element is used for the secondary
+; sort, and so forth. (A secondary sort only takes effect when
+; values in the primary sort field are equal.) Character fields
+; are sorted using the ASCII collating sequence. If omitted,
+; the user will be prompted for the field name.
+;
+; OPTIONAL OUTPUTS:
+; HNEW,TABNEW - Header and table containing the sorted tables
+;
+; EXAMPLE:
+; Sort a FITS ASCII table by the 'DECLINATION' field in descending order
+; Assume that the table header htab, and array, tab, have already been
+; read (e.g. with READFITS or FITS_READ):
+
+; IDL> FTSORT, htab, tab,'DECLINATION',/REVERSE
+; OPTIONAL INPUT KEYWORD:
+; REVERSE - If set then the table is sorted in reverse order (maximum
+; to minimum. If FIELD is a vector, then REVERSE can also be
+; a vector. For example, REVERSE = [1,0] indicates that the
+; primary sort should be in descending order, and the secondary
+; sort should be in ascending order.
+;
+; EXAMPLE:
+; SIDE EFFECTS:
+; A HISTORY record is added to the table header.
+; REVISION HISTORY:
+; Written W. Landsman June, 1988
+; Converted to IDL V5.0 W. Landsman September 1997
+; New FTINFO calling sequence, added REVERSE keyword, allow secondary sorts
+; W. Landsman May 2000
+;-
+ On_error,2
+ npar = N_params()
+ if npar lt 2 then begin
+ print,'Syntax: ftsort, h, tab, [ field ]'
+ print,' OR: ftsort,h,tab,hnew,tabnew,[field]'
+ return
+ endif
+
+ if npar eq 3 then field = hnew
+
+ nf = N_elements(field)
+ nr = N_elements(revers)
+ if nr EQ 0 then revers = bytarr(nf) else $
+ if nr LT nf then revers = [revers,bytarr(nf-nr)]
+
+ ftinfo,h,ft_str
+ key = ftget(ft_str,tab, field[nf-1])
+ index = sort(key)
+ if revers[nf-1] then index = reverse(index)
+ tabnew = tab[*,index]
+
+
+ if nf GT 1 then begin
+ for i= nf-2,0 do begin
+ key = ftget(ft_str,tabnew,field[i])
+ index = bsort(key,reverse=revers[i])
+ tabnew = tabnew[*,index]
+ endfor
+ endif
+
+ str = strtrim(field[0],2)
+ if nf GT 1 then begin
+ for i = 1,nf-1 do str = str + ',' + strtrim( field[i],2)
+ str = 'Keywords: ' + str
+ endif else str = 'Keyword: ' + str
+ if npar ge 4 then begin
+ hnew = h
+ sxaddhist,'FTSORT: '+ systime() +' Sort ' + str,hnew
+ endif else begin
+ tab = tabnew
+ sxaddhist,'FTSORT: '+ systime() +' Sort ' + str,h
+ endelse
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/fxaddpar.pro b/Code/script_idl_mv/astrolib/fxaddpar.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3f40df496b9d3341dfe69ade420eb4973d244954
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxaddpar.pro
@@ -0,0 +1,718 @@
+;+
+; NAME:
+; FXADDPAR
+; Purpose :
+; Add or modify a parameter in a FITS header array.
+; Explanation :
+; This version of FXADDPAR will write string values longer than 68
+; characters using the FITS continuation convention described at
+; http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html
+; Use :
+; FXADDPAR, HEADER, NAME, VALUE, COMMENT
+; Inputs :
+; HEADER = String array containing FITS header. The maximum string
+; length must be equal to 80. If not defined, then FXADDPAR
+; will create an empty FITS header array.
+;
+; NAME = Name of parameter. If NAME is already in the header the
+; value and possibly comment fields are modified. Otherwise a
+; new record is added to the header. If NAME is equal to
+; either "COMMENT" or "HISTORY" then the value will be added to
+; the record without replacement. In this case the comment
+; parameter is ignored.
+;
+; VALUE = Value for parameter. The value expression must be of the
+; correct type, e.g. integer, floating or string.
+; String values of 'T' or 'F' are considered logical
+; values unless the /NOLOGICAL keyword is set. If the value is
+; a string and is "long" (more than 69 characters), then it
+; may be continued over more than one line using the OGIP
+; CONTINUE standard.
+;
+; Opt. Inputs :
+; COMMENT = String field. The '/' is added by this routine. Added
+; starting in position 31. If not supplied, or set equal to ''
+; (the null string), then any previous comment field in the
+; header for that keyword is retained (when found).
+; Outputs :
+; HEADER = Updated header array.
+; Opt. Outputs:
+; None.
+; Keywords :
+; BEFORE = Keyword string name. The parameter will be placed before the
+; location of this keyword. For example, if BEFORE='HISTORY'
+; then the parameter will be placed before the first history
+; location. This applies only when adding a new keyword;
+; keywords already in the header are kept in the same position.
+;
+; AFTER = Same as BEFORE, but the parameter will be placed after the
+; location of this keyword. This keyword takes precedence over
+; BEFORE.
+;
+; FORMAT = Specifies FORTRAN-like format for parameter, e.g. "F7.3". A
+; scalar string should be used. For complex numbers the format
+; should be defined so that it can be applied separately to the
+; real and imaginary parts. If not supplied, then the IDL
+; default formatting is used, except that double precision is
+; given a format of G19.12.
+;
+; /NOCONTINUE = By default, FXADDPAR will break strings longer than 68
+; characters into multiple lines using the continuation
+; convention. If this keyword is set, then the line will
+; instead be truncated to 68 characters. This was the default
+; behaviour of FXADDPAR prior to December 1999.
+;
+; /NOLOGICAL = If set, then the values 'T' and 'F' are not interpreted as
+; logical values, and are simply added without interpretation.
+;
+; /NULL = If set, then keywords with values which are undefined, or
+; which have non-finite values (such as NaN, Not-a-Number) are
+; stored in the header without a value, such as
+;
+; MYKEYWD = /My comment
+;
+; MISSING = A value which signals that data with this value should be
+; considered missing. For example, the statement
+;
+; FXADDPAR, HEADER, 'MYKEYWD', -999, MISSING=-999
+;
+; would result in the valueless line described above for the
+; /NULL keyword. Setting MISSING to a value implies /NULL.
+; Cannot be used with string or complex values.
+;
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL, e.g.
+;
+; ERRMSG = ''
+; FXADDPAR, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; DETABIFY(), FXPAR(), FXPARPOS()
+; Common :
+; None.
+; Restrictions:
+; Warning -- Parameters and names are not checked against valid FITS
+; parameter names, values and types.
+;
+; The required FITS keywords SIMPLE (or XTENSION), BITPIX, NAXIS, NAXIS1,
+; NAXIS2, etc., must be entered in order. The actual values of these
+; keywords are not checked for legality and consistency, however.
+;
+; Side effects:
+; All HISTORY records are inserted in order at the end of the header.
+;
+; All COMMENT records are also inserted in order at the end of the
+; header, but before the HISTORY records. The BEFORE and AFTER keywords
+; can override this.
+;
+; All records with no keyword (blank) are inserted in order at the end of
+; the header, but before the COMMENT and HISTORY records. The BEFORE and
+; AFTER keywords can override this.
+;
+; All other records are inserted before any of the HISTORY, COMMENT, or
+; "blank" records. The BEFORE and AFTER keywords can override this.
+;
+; String values longer than 68 characters will be split into multiple
+; lines using the OGIP CONTINUE convention, unless the /NOCONTINUE keyword
+; is set. For a description of the CONTINUE convention see
+; http://fits.gsfc.nasa.gov/registry/continue_keyword.html
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992, from SXADDPAR by D. Lindler and J. Isensee.
+; Differences include:
+;
+; * LOCATION parameter replaced with keywords BEFORE and AFTER.
+; * Support for COMMENT and "blank" FITS keywords.
+; * Better support for standard FITS formatting of string and
+; complex values.
+; * Built-in knowledge of the proper position of required
+; keywords in FITS (although not necessarily SDAS/Geis) primary
+; headers, and in TABLE and BINTABLE extension headers.
+;
+; William Thompson, May 1992, fixed bug when extending length of header,
+; and new record is COMMENT, HISTORY, or blank.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 5 September 1997
+; Fixed bug replacing strings that contain "/" character--it
+; interpreted the following characters as a comment.
+; Version 3, Craig Markwardt, GSFC, December 1997
+; Allow long values to extend over multiple lines
+; Version 4, D. Lindler, March 2000, modified to use capital E instead
+; of a lower case e for exponential format.
+; Version 4.1 W. Landsman April 2000, make user-supplied format uppercase
+; Version 4.2 W. Landsman July 2002, positioning of EXTEND keyword
+; Version 5, 23-April-2007, William Thompson, GSFC
+; Version 6, 02-Aug-2007, WTT, bug fix for OGIP long lines
+; Version 6.1, 10-Feb-2009, W. Landsman, increase default format precision
+; Version 6.2 30-Sep-2009, W. Landsman, added /NOLOGICAL keyword
+; Version 7, 13-Aug-2015, William Thompson, allow null values
+; Add keywords /NULL, MISSING. Catch non-finite values (e.g. NaN)
+; Version 7.1, 22-Sep-2015, W. Thompson, No slash if null & no comment
+; Version :
+; Version 7.1, 22-Sep-2015
+;-
+;
+
+; This is a utility routine, which splits a parameter into several
+; continuation bits.
+PRO FXADDPAR_CONTPAR, VALUE, CONTINUED
+
+ APOST = "'"
+ BLANK = STRING(REPLICATE(32B,80)) ;BLANK line
+
+ ;; The value may not need to be CONTINUEd. If it does, then split
+ ;; out the first value now. The first value does not have a
+ ;; CONTINUE keyword, because it will be grafted onto the proper
+ ;; keyword in the calling routine.
+
+ IF (STRLEN(VALUE) GT 68) THEN BEGIN
+ CONTINUED = [ STRMID(VALUE, 0, 67)+'&' ]
+ VALUE = STRMID(VALUE, 67, STRLEN(VALUE)-67)
+ ENDIF ELSE BEGIN
+ CONTINUED = [ VALUE ]
+ RETURN
+ ENDELSE
+
+ ;; Split out the remaining values.
+ WHILE( STRLEN(VALUE) GT 0 ) DO BEGIN
+ H = BLANK
+
+ ;; Add CONTINUE keyword
+ STRPUT, H, 'CONTINUE '+APOST
+ ;; Add the next split
+ IF(STRLEN(VALUE) GT 68) THEN BEGIN
+ STRPUT, H, STRMID(VALUE, 0, 67)+'&'+APOST, 11
+ VALUE = STRMID(VALUE, 67, STRLEN(VALUE)-67)
+ ENDIF ELSE BEGIN
+ STRPUT, H, VALUE+APOST, 11
+ VALUE = ''
+ ENDELSE
+
+ CONTINUED = [ CONTINUED, H ]
+ ENDWHILE
+
+ RETURN
+END
+
+; Utility routine to add a warning to the file. The calling routine
+; must ensure that the header is in a consistent state before calling
+; FXADDPAR_CONTWARN because the header will be subsequently modified
+; by calls to FXADDPAR.
+PRO FXADDPAR_CONTWARN, HEADER, NAME
+
+; By OGIP convention, the keyword LONGSTRN is added to the header as
+; well. It should appear before the first occurrence of a long
+; string encoded with the CONTINUE convention.
+
+ CONTKEY = FXPAR(HEADER, 'LONGSTRN', COUNT = N_LONGSTRN)
+
+; Calling FXADDPAR here is okay since the state of the header is
+; clean now.
+ IF N_LONGSTRN GT 0 THEN $
+ RETURN
+
+ FXADDPAR, HEADER, 'LONGSTRN', 'OGIP 1.0', $
+ ' The OGIP long string convention may be used.', $
+ BEFORE=NAME
+
+ FXADDPAR, HEADER, 'COMMENT', $
+ ' This FITS file may contain long string keyword values that are', $
+ BEFORE=NAME
+
+ FXADDPAR, HEADER, 'COMMENT', $
+ " continued over multiple keywords. This convention uses the '&'", $
+ BEFORE=NAME
+
+ FXADDPAR, HEADER, 'COMMENT', $
+ ' character at the end of a string which is then continued', $
+ BEFORE=NAME
+
+ FXADDPAR, HEADER, 'COMMENT', $
+ " on subsequent keywords whose name = 'CONTINUE'.", $
+ BEFORE=NAME
+
+ RETURN
+END
+
+
+PRO FXADDPAR, HEADER, NAME, VALUE, COMMENT, BEFORE=BEFORE, $
+ AFTER=AFTER, FORMAT=FORMAT, NOCONTINUE = NOCONTINUE, $
+ ERRMSG=ERRMSG, NOLOGICAL=NOLOGICAL, MISSING=MISSING, NULL=NULL
+
+ ON_ERROR,2 ;Return to caller
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXADDPAR, HEADER, NAME, VALUE [, COMMENT ]'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Define a blank line and the END line
+;
+ ENDLINE = 'END' + STRING(REPLICATE(32B,77)) ;END line
+ BLANK = STRING(REPLICATE(32B,80)) ;BLANK line
+;
+; If no comment was passed, then use a null string.
+;
+ IF N_PARAMS() LT 4 THEN COMMENT = ''
+;
+; Check the HEADER array.
+;
+ N = N_ELEMENTS(HEADER) ;# of lines in FITS header
+ IF N EQ 0 THEN BEGIN ;header defined?
+ HEADER=STRARR(36) ;no, make it.
+ HEADER[0]=ENDLINE
+ N=36
+ ENDIF ELSE BEGIN
+ S = SIZE(HEADER) ;check for string type
+ IF (S[0] NE 1) OR (S[2] NE 7) THEN BEGIN
+ MESSAGE = 'FITS Header (first parameter) must be a ' + $
+ 'string array'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ ENDELSE
+;
+; Make sure NAME is 8 characters long
+;
+ NN = STRING(REPLICATE(32B,8)) ;8 char name
+ STRPUT,NN,STRUPCASE(NAME) ;Insert name
+;
+; Check VALUE.
+;
+ S = SIZE(VALUE) ;get type of value parameter
+ STYPE = S[S[0]+1]
+ SAVE_AS_NULL = 0
+ IF S[0] NE 0 THEN BEGIN
+ MESSAGE = 'Keyword Value (third parameter) must be scalar'
+ GOTO, HANDLE_ERROR
+ END ELSE IF STYPE EQ 0 THEN BEGIN
+ IF (N_ELEMENTS(MISSING) EQ 1) OR KEYWORD_SET(NULL) THEN $
+ SAVE_AS_NULL = 1 ELSE BEGIN
+ MESSAGE = 'Keyword Value (third parameter) is not defined'
+ GOTO, HANDLE_ERROR
+ ENDELSE
+ END ELSE IF STYPE EQ 8 THEN BEGIN
+ MESSAGE = 'Keyword Value (third parameter) cannot be structure'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Check to see if the parameter should be saved as a null value.
+;
+ IF (STYPE NE 6) AND (STYPE NE 7) AND (STYPE NE 9) THEN BEGIN
+ IF N_ELEMENTS(MISSING) EQ 1 THEN $
+ IF VALUE EQ MISSING THEN SAVE_AS_NULL = 1
+ IF NOT SAVE_AS_NULL THEN IF NOT FINITE(VALUE) THEN BEGIN
+ IF ((N_ELEMENTS(MISSING) EQ 1) OR KEYWORD_SET(NULL)) THEN $
+ SAVE_AS_NULL = 1 ELSE BEGIN
+ MESSAGE = 'Keyword Value (third parameter) is not finite'
+ GOTO, HANDLE_ERROR
+ ENDELSE
+ ENDIF
+ ENDIF
+;
+; Extract first 8 characters of each line of header, and locate END line
+;
+ KEYWRD = STRMID(HEADER,0,8) ;Header keywords
+ IEND = WHERE(KEYWRD EQ 'END ',NFOUND)
+;
+; If no END, then add it. Either put it after the last non-null string, or
+; append it to the end.
+;
+ IF NFOUND EQ 0 THEN BEGIN
+ II = WHERE(STRTRIM(HEADER) NE '',NFOUND)
+ II = MAX(II) + 1
+ IF (NFOUND EQ 0) OR (II EQ N_ELEMENTS(HEADER)) THEN $
+ HEADER = [HEADER,ENDLINE] ELSE HEADER[II] = ENDLINE
+ KEYWRD = STRMID(HEADER,0,8)
+ IEND = WHERE(KEYWRD EQ 'END ',NFOUND)
+ ENDIF
+;
+ IEND = IEND[0] > 0 ;Make scalar
+;
+; History, comment and "blank" records are treated differently from the
+; others. They are simply added to the header array whether there are any
+; already there or not.
+;
+ IF (NN EQ 'COMMENT ') OR (NN EQ 'HISTORY ') OR $
+ (NN EQ ' ') THEN BEGIN
+;
+; If the header array needs to grow, then expand it in increments of 36 lines.
+;
+ IF IEND GE (N-1) THEN BEGIN
+ HEADER = [HEADER,REPLICATE(BLANK,36)]
+ N = N_ELEMENTS(HEADER)
+ ENDIF
+;
+; Format the record.
+;
+ NEWLINE = BLANK
+ STRPUT,NEWLINE,NN+STRING(VALUE),0
+;
+; If a history record, then append to the record just before the end.
+;
+ IF NN EQ 'HISTORY ' THEN BEGIN
+ HEADER[IEND] = NEWLINE ;add history rec.
+ HEADER[IEND+1]=ENDLINE ;move end up
+;
+; The comment record is placed immediately after the last previous comment
+; record, or immediately before the first history record, unless overridden by
+; either the BEFORE or AFTER keywords.
+;
+ END ELSE IF NN EQ 'COMMENT ' THEN BEGIN
+ I = FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE=BEFORE)
+ IF I EQ IEND THEN I = $
+ FXPARPOS(KEYWRD,IEND,AFTER='COMMENT',$
+ BEFORE='HISTORY')
+ HEADER[I+1] = HEADER[I:N-2] ;move rest up
+ HEADER[I] = NEWLINE ;insert comment
+;
+; The "blank" record is placed immediately after the last previous "blank"
+; record, or immediately before the first comment or history record, unless
+; overridden by either the BEFORE or AFTER keywords.
+;
+ END ELSE BEGIN
+ I = FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE=BEFORE)
+ IF I EQ IEND THEN I = $
+ FXPARPOS(KEYWRD,IEND,AFTER='',BEFORE='COMMENT')<$
+ FXPARPOS(KEYWRD,IEND,AFTER='',BEFORE='HISTORY')
+ HEADER[I+1] = HEADER[I:N-2] ;move rest up
+ HEADER[I] = NEWLINE ;insert "blank"
+ ENDELSE
+ RETURN
+ ENDIF ;history/comment/blank
+;
+; Find location to insert keyword. If the keyword is already in the header,
+; then simply replace it. If no new comment is passed, then retain the old
+; one.
+;
+ IPOS = WHERE(KEYWRD EQ NN,NFOUND)
+ IF NFOUND GT 0 THEN BEGIN
+ I = IPOS[0]
+ IF COMMENT EQ '' THEN BEGIN
+ SLASH = STRPOS(HEADER[I],'/')
+ QUOTE = STRPOS(HEADER[I],"'")
+ IF (QUOTE GT 0) AND (QUOTE LT SLASH) THEN BEGIN
+ QUOTE = STRPOS(HEADER[I],"'",QUOTE+1)
+ IF QUOTE LT 0 THEN SLASH = -1 ELSE $
+ SLASH = STRPOS(HEADER[I],'/',QUOTE+1)
+ ENDIF
+ IF SLASH NE -1 THEN $
+ COMMENT = STRMID(HEADER[I],SLASH+1,80) ELSE $
+ COMMENT = STRING(REPLICATE(32B,80))
+ ENDIF
+ GOTO, REPLACE
+ ENDIF
+;
+; Start of section dealing with the positioning of required FITS keywords. If
+; the keyword is SIMPLE, then it must be at the beginning.
+;
+ IF NN EQ 'SIMPLE ' THEN BEGIN
+ I = 0
+ GOTO, INSERT
+ ENDIF
+;
+; In conforming extensions, if the keyword is XTENSION, then it must be at the
+; beginning.
+;
+ IF NN EQ 'XTENSION' THEN BEGIN
+ I = 0
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is BITPIX, then it must follow the either SIMPLE or XTENSION
+; keyword.
+;
+ IF NN EQ 'BITPIX ' THEN BEGIN
+ IF (KEYWRD[0] NE 'SIMPLE ') AND $
+ (KEYWRD[0] NE 'XTENSION') THEN BEGIN
+ MESSAGE = 'Header must start with either SIMPLE or XTENSION'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 1
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is NAXIS, then it must follow the BITPIX keyword.
+;
+ IF NN EQ 'NAXIS ' THEN BEGIN
+ IF KEYWRD[1] NE 'BITPIX ' THEN BEGIN
+ MESSAGE = 'Required BITPIX keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 2
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is NAXIS1, then it must follow the NAXIS keyword.
+;
+ IF NN EQ 'NAXIS1 ' THEN BEGIN
+ IF KEYWRD[2] NE 'NAXIS ' THEN BEGIN
+ MESSAGE = 'Required NAXIS keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 3
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is NAXIS, then it must follow the NAXIS keyword.
+;
+ IF STRMID(NN,0,5) EQ 'NAXIS' THEN BEGIN
+ NUM_AXIS = FIX(STRMID(NN,5,3))
+ PREV = STRING(REPLICATE(32B,8)) ;Format NAXIS
+ STRPUT,PREV,'NAXIS',0 ;Insert NAXIS
+ STRPUT,PREV,STRTRIM(NUM_AXIS-1,2),5 ;Insert
+ IF KEYWRD[NUM_AXIS+1] NE PREV THEN BEGIN
+ MESSAGE = 'Required '+PREV+' keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = NUM_AXIS + 2
+ GOTO, INSERT
+ ENDIF
+
+;
+; If the keyword is EXTEND, then it must follow the last NAXIS* keyword.
+;
+
+ IF NN EQ 'EXTEND ' THEN BEGIN
+ IF KEYWRD[2] NE 'NAXIS ' THEN BEGIN
+ MESSAGE = 'Required NAXIS keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ FOR I = 3, N-2 DO $
+ IF STRMID(KEYWRD[I],0,5) NE 'NAXIS' THEN GOTO, INSERT
+
+ ENDIF
+
+;
+; If the first keyword is XTENSION, and has the value of either 'TABLE' or
+; 'BINTABLE', then there are some additional required keywords.
+;
+ IF KEYWRD[0] EQ 'XTENSION' THEN BEGIN
+ XTEN = FXPAR(HEADER,'XTENSION')
+ IF (XTEN EQ 'TABLE ') OR (XTEN EQ 'BINTABLE') THEN BEGIN
+;
+; If the keyword is PCOUNT, then it must follow the NAXIS2 keyword.
+;
+ IF NN EQ 'PCOUNT ' THEN BEGIN
+ IF KEYWRD[4] NE 'NAXIS2 ' THEN BEGIN
+ MESSAGE = 'Required NAXIS2 keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 5
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is GCOUNT, then it must follow the PCOUNT keyword.
+;
+ IF NN EQ 'GCOUNT ' THEN BEGIN
+ IF KEYWRD[5] NE 'PCOUNT ' THEN BEGIN
+ MESSAGE = 'Required PCOUNT keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 6
+ GOTO, INSERT
+ ENDIF
+;
+; If the keyword is TFIELDS, then it must follow the GCOUNT keyword.
+;
+ IF NN EQ 'TFIELDS ' THEN BEGIN
+ IF KEYWRD[6] NE 'GCOUNT ' THEN BEGIN
+ MESSAGE = 'Required GCOUNT keyword not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ I = 7
+ GOTO, INSERT
+ ENDIF
+ ENDIF
+ ENDIF
+;
+; At this point the location has not been determined, so a new line is added
+; at the end of the FITS header, but before any blank, COMMENT, or HISTORY
+; keywords, unless overridden by the BEFORE or AFTER keywords.
+;
+ I = FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE=BEFORE)
+ IF I EQ IEND THEN I = $
+ FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE='') < $
+ FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE='COMMENT') < $
+ FXPARPOS(KEYWRD,IEND,AFTER=AFTER,BEFORE='HISTORY')
+;
+; A new line needs to be added. First check to see if the length of the
+; header array needs to be extended. Then insert a blank record at the proper
+; place.
+;
+INSERT:
+ IF IEND EQ (N-1) THEN BEGIN
+ HEADER = [HEADER,REPLICATE(BLANK,36)]
+ N = N_ELEMENTS(HEADER)
+ ENDIF
+ HEADER[I+1] = HEADER[I:N-2]
+ HEADER[I] = BLANK
+ IEND = IEND + 1 ; CM 24 Sep 1997
+;
+; Now put value into keyword at line I.
+;
+REPLACE:
+ H=BLANK ;80 blanks
+ STRPUT,H,NN+'= ' ;insert name and =.
+ APOST = "'" ;quote (apostrophe) character
+ TYPE = SIZE(VALUE) ;get type of value parameter
+;
+; Store the value depending on the data type. If a character string, first
+; check to see if it is one of the logical values "T" (true) or "F" (false).
+;
+
+ IF TYPE[1] EQ 7 THEN BEGIN ;which type?
+ UPVAL = STRUPCASE(VALUE) ;force upper case.
+ IF ~KEYWORD_SET(NOLOGICAL) $
+ && ((UPVAL EQ 'T') OR (UPVAL EQ 'F')) THEN BEGIN
+ STRPUT,H,UPVAL,29 ;insert logical value.
+;
+; Otherwise, remove any tabs, and check for any apostrophes in the string.
+;
+ END ELSE BEGIN
+ VAL = DETABIFY(VALUE)
+ NEXT_CHAR = 0
+ REPEAT BEGIN
+ AP = STRPOS(VAL,"'",NEXT_CHAR)
+ IF AP GE 66 THEN BEGIN
+ VAL = STRMID(VAL,0,66)
+ END ELSE IF AP GE 0 THEN BEGIN
+ VAL = STRMID(VAL,0,AP+1) + APOST + $
+ STRMID(VAL,AP+1,80)
+ NEXT_CHAR = AP + 2
+ ENDIF
+ ENDREP UNTIL AP LT 0
+
+;
+; If a long string, then add the comment as soon as possible.
+;
+; CM 24 Sep 1997
+; Separate parameter if it needs to be CONTINUEd.
+;
+ IF NOT KEYWORD_SET(NOCONTINUE) THEN $
+ FXADDPAR_CONTPAR, VAL, CVAL ELSE $
+ CVAL = STRMID(VAL,0,68)
+ K = I + 1
+ ;; See how many CONTINUE lines there already are
+ WHILE K LT IEND DO BEGIN
+ IF STRMID(HEADER[K],0,8) NE 'CONTINUE' THEN $
+ GOTO, DONE_CHECK_CONT
+ K = K + 1
+ ENDWHILE
+
+ DONE_CHECK_CONT:
+ NOLDCONT = K - I - 1
+ NNEWCONT = N_ELEMENTS(CVAL) - 1
+
+ ;; Insert new lines if needed
+ IF NNEWCONT GT NOLDCONT THEN BEGIN
+ INS = NNEWCONT - NOLDCONT
+ WHILE IEND+INS GE N DO BEGIN
+ HEADER = [HEADER, REPLICATE(BLANK,36)]
+ N = N_ELEMENTS(HEADER)
+ ENDWHILE
+ ENDIF
+
+ ;; Shift the old lines properly
+ IF NNEWCONT NE NOLDCONT THEN $
+ HEADER[I+NNEWCONT+1] = HEADER[I+NOLDCONT+1:IEND]
+ IEND = IEND + NNEWCONT - NOLDCONT
+
+ ;; Blank out any lines at the end if needed
+ IF NNEWCONT LT NOLDCONT THEN BEGIN
+ DEL = NOLDCONT - NNEWCONT
+ HEADER[IEND+1:IEND+DEL] = REPLICATE('', DEL)
+ ENDIF
+
+ IF STRLEN(CVAL[0]) GT 18 THEN BEGIN
+ STRPUT,H,APOST+STRMID(CVAL[0],0,68)+APOST+ $
+ ' /'+COMMENT,10
+ HEADER[I]=H
+
+; There might be a continuation of this string. CVAL would contain
+; more than one element if that is so.
+
+ ;; Add new continuation lines
+ IF N_ELEMENTS(CVAL) GT 1 THEN BEGIN
+ HEADER[I+1] = CVAL[1:*]
+
+ ;; Header state is now clean, so add
+ ;; warning to header
+
+ FXADDPAR_CONTWARN, HEADER, NAME
+ ENDIF
+ DONE_CONT:
+ RETURN
+;
+; If a short string, then pad out to at least eight characters.
+;
+ END ELSE BEGIN
+ STRPUT,H,APOST+CVAL[0],10
+ STRPUT,H,APOST,11+(STRLEN(CVAL[0])>8)
+ ENDELSE
+
+ ENDELSE
+;
+; If complex, then format the real and imaginary parts, and add the comment
+; beginning in column 51.
+;
+ END ELSE IF (TYPE[1] EQ 6) OR (TYPE[1] EQ 9) THEN BEGIN
+ IF TYPE[1] EQ 6 THEN VR = FLOAT(VALUE) ELSE VR = DOUBLE(VALUE)
+ VI = IMAGINARY(VALUE)
+ IF N_ELEMENTS(FORMAT) EQ 1 THEN BEGIN ;use format keyword
+ VR = STRING(VR, '('+STRUPCASE(FORMAT)+')')
+ VI = STRING(VI, '('+STRUPCASE(FORMAT)+')')
+ END ELSE BEGIN
+ VR = STRTRIM(VR, 2)
+ VI = STRTRIM(VI, 2)
+ ENDELSE
+ SR = STRLEN(VR) & STRPUT,H,VR,(30-SR)>10
+ SI = STRLEN(VI) & STRPUT,H,VI,(50-SI)>30
+ STRPUT,H,' /'+COMMENT,50
+ HEADER[I] = H
+ RETURN
+;
+; If not complex or a string, then format according to either the FORMAT
+; keyword, or the default for that datatype.
+;
+ END ELSE BEGIN
+ IF NOT SAVE_AS_NULL THEN BEGIN
+ IF (N_ELEMENTS(FORMAT) EQ 1) THEN $ ;use format keyword
+ V = STRING(VALUE,'('+STRUPCASE(FORMAT)+')' ) ELSE BEGIN
+ IF TYPE[1] EQ 5 THEN $
+ V = STRING(VALUE,FORMAT='(G19.12)') ELSE $
+ V = STRTRIM(strupcase(VALUE),2) ;default format
+ ENDELSE
+ S = STRLEN(V) ;right justify
+ STRPUT,H,V,(30-S)>10 ;insert
+ ENDIF
+ ENDELSE
+;
+; Add the comment, and store the completed line in the header. Don't
+; add the slash if the value is null and there is no comment.
+;
+ IF (NOT SAVE_AS_NULL) OR (STRLEN(STRTRIM(COMMENT)) GT 0) THEN BEGIN
+ STRPUT,H,' /',30 ;add ' /'
+ STRPUT,H,COMMENT,32 ;add comment
+ ENDIF
+ HEADER[I]=H ;save line
+;
+ ERRMSG = ''
+ RETURN
+;
+; Error handling point.
+;
+HANDLE_ERROR:
+ IF ARG_PRESENT(ERRMSG) THEN ERRMSG = 'FXADDPAR: ' + MESSAGE $
+ ELSE MESSAGE, MESSAGE
+ RETURN
+ END
+
diff --git a/Code/script_idl_mv/astrolib/fxbaddcol.pro b/Code/script_idl_mv/astrolib/fxbaddcol.pro
new file mode 100644
index 0000000000000000000000000000000000000000..fc09694dd7d9025bc0584acc6959e4d8940bfa99
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbaddcol.pro
@@ -0,0 +1,382 @@
+ PRO FXBADDCOL,INDEX,HEADER,ARRAY,TTYPE,COMMENT,TUNIT=TUNIT, $
+ TSCAL=TSCAL,TZERO=TZERO,TNULL=TNULL,TDISP=TDISP, $
+ TDMIN=TDMIN,TDMAX=TDMAX,TDESC=TDESC,TROTA=TROTA, $
+ TRPIX=TRPIX,TRVAL=TRVAL,TDELT=TDELT,TCUNI=TCUNI, $
+ NO_TDIM=NO_TDIM,VARIABLE=VARIABLE,DCOMPLEX=DCOMPLEX, $
+ BIT=BIT,LOGICAL=LOGICAL,ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBADDCOL
+; PURPOSE :
+; Adds a column to a binary table extension.
+; EXPLANATION :
+; Modify a basic FITS binary table extension (BINTABLE) header array to
+; define a column.
+; USE :
+; FXBADDCOL, INDEX, HEADER, ARRAY [, TTYPE [, COMMENT ]]
+; INPUTS :
+; HEADER = String array containing FITS extension header.
+; ARRAY = IDL variable used to determine the data size and type
+; associated with the column. If the column is defined as
+; containing variable length arrays, then ARRAY must be of the
+; maximum size to be stored in the column.
+; Opt. Inputs :
+; TTYPE = Column label.
+; COMMENT = Comment for TTYPE
+; Outputs :
+; INDEX = Index (1-999) of the created column.
+; HEADER = The header is modified to reflect the added column.
+; Opt. Outputs:
+; None.
+; Keywords :
+; VARIABLE= If set, then the column is defined to contain pointers to
+; variable length arrays in the heap area.
+; DCOMPLEX= If set, and ARRAY is complex, with the first dimension being
+; two (real and imaginary parts), then the column is defined as
+; double-precision complex (type "M"). This keyword is
+; only needed prior to IDL Version 4.0, when the double
+; double complex datatype was unavailable in IDL
+; BIT = If passed, and ARRAY is of type byte, then the column is
+; defined as containing bit mask arrays (type "X"), with the
+; value of BIT being equal to the number of mask bits.
+; LOGICAL = If set, and array is of type byte, then the column is defined
+; as containing logical arrays (type "L").
+; NO_TDIM = If set, then the TDIMn keyword is not written out to the
+; header. No TDIMn keywords are written for columns containing
+; variable length arrays.
+; TUNIT = If passed, then corresponding keyword is added to header.
+; TSCAL = Same.
+; TZERO = Same.
+; TNULL = Same.
+; TDISP = Same.
+; TDMIN = Same.
+; TDMAX = Same.
+; TDESC = Same.
+; TCUNI = Same.
+; TROTA = Same.
+; TRPIX = Same.
+; TRVAL = Same.
+; TDELT = Same.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBADDCOL, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXADDPAR, FXPAR
+; Common :
+; None.
+; Restrictions:
+; Warning: No checking is done of any of the parameters defining the
+; values of optional FITS keywords.
+;
+; FXBHMAKE must first be called to initialize the header.
+;
+; If ARRAY is of type character, then it must be of the maximum length
+; expected for this column. If a character string array, then the
+; largest string in the array is used to determine the maximum length.
+;
+; The DCOMPLEX keyword is ignored if ARRAY is not double-precision.
+; ARRAY must also have a first dimension of two representing the real and
+; imaginary parts.
+;
+; The BIT and LOGICAL keywords are ignored if ARRAY is not of type byte.
+; BIT takes precedence over LOGICAL.
+;
+; Side effects:
+; If the data array is multidimensional, then a TDIM keyword is added to
+; the header, unless either NO_TDIM or VARIABLE is set.
+;
+; No TDIMn keywords are written out for bit arrays (format 'X'), since
+; the dimensions would refer to bits, not bytes.
+;
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992.
+; W. Thompson, Feb 1992, changed from function to procedure.
+; W. Thompson, Feb 1992, modified to support variable length arrays.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, William Thompson, GSFC, 30 December 1994
+; Added keyword TCUNI.
+; Version 5, Wayne Landsman, GSFC, 12 Aug 1997
+; Recognize double complex IDL datatype
+; Version 6, Wayne Landsman, GSFC. C. Yamauchi (ISAS) 23 Feb 2006
+; Support 64bit integers
+; Version 7, C. Markwardt, GSFC, Allow unsigned integers, which
+; have special TSCAL/TZERO values. Feb 2009
+; Version 8, P.Broos (PSU), Wayne Landsman (GSFC) Mar 2010
+; Do *not* force TTYPE* keyword to uppercase
+; Version :
+; Version 8, Mar 2010
+;-
+;
+ ON_ERROR,2
+;
+; Check the number of parameters first.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXBADDCOL, INDEX, HEADER, ARRAY ' + $
+ '[, TTYPE [, COMMENT]]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get the next column number.
+;
+ INDEX = FXPAR(HEADER,'TFIELDS') + 1
+;
+; Determine the data type and size of the data array. Use this to
+; calculate the parameters needed for the binary table.
+;
+ S = SIZE(ARRAY) ;obtain size of array.
+ TYPE = S[S[0]+1] ;type of data.
+ N_ELEM = N_ELEMENTS(ARRAY) ;Number of elements
+;
+ CASE TYPE OF
+ 0: BEGIN
+ MESSAGE = 'Data parameter is not defined'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+;
+; If the array is of type byte, then check to see if either the BIT or LOGICAL
+; keywords were passed.
+;
+ 1: BEGIN
+ IF N_ELEMENTS(BIT) EQ 1 THEN BEGIN
+ N_BYTES = LONG((BIT+7)/8)
+ IF N_BYTES NE N_ELEM THEN BEGIN
+ MESSAGE = 'Number of bits does ' + $
+ 'not match array size.'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ N_ELEM = BIT
+ TFORM = "X"
+ TF_COMMENT = 'Bit array'
+ END ELSE IF KEYWORD_SET(LOGICAL) THEN BEGIN
+ N_BYTES = N_ELEM
+ TFORM = "L"
+ TF_COMMENT = 'Logical array'
+ END ELSE BEGIN
+ N_BYTES = N_ELEM
+ TFORM = "B"
+ TF_COMMENT = 'Integer*1 (byte)'
+ ENDELSE
+ END
+;
+; If complex, then check to see if the DCOMPLEX keyword was set, and if the
+; first dimension is two.
+;
+ 5: BEGIN
+ IF KEYWORD_SET(DCOMPLEX) THEN BEGIN
+ IF S[1] NE 2 THEN BEGIN
+ MESSAGE = 'The first dimension ' + $
+ 'of ARRAY must be two'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ N_BYTES = 8*N_ELEM
+ N_ELEM = N_ELEM / 2
+ TFORM = "M"
+ TF_COMMENT = 'Complex*16 (double-' + $
+ 'precision complex)'
+ S = [S[0]-1,S[2:*]]
+ END ELSE BEGIN
+ N_BYTES = 8*N_ELEM
+ TFORM = "D"
+ TF_COMMENT = 'Real*8 (double precision)'
+ ENDELSE
+ END
+;
+; Note that character string arrays are considered to have an extra first
+; dimension, namely the (maximum) number of characters.
+;
+ 7: BEGIN
+ STR_LEN = MAX(STRLEN(ARRAY))
+ N_BYTES = STR_LEN*N_ELEM
+ N_ELEM = N_BYTES
+ TFORM = "A"
+ TF_COMMENT = 'Character string'
+ S = [S[0]+1, STR_LEN, S[1:*]] ;Add extra dimension
+ END
+;
+; All other types are straightforward.
+;
+ 2: BEGIN
+ N_BYTES = 2*N_ELEM
+ TFORM = "I"
+ TF_COMMENT = 'Integer*2 (short integer)'
+ END
+ 3: BEGIN
+ N_BYTES = 4*N_ELEM
+ TFORM = "J"
+ TF_COMMENT = 'Integer*4 (long integer)'
+ END
+ 4: BEGIN
+ N_BYTES = 4*N_ELEM
+ TFORM = "E"
+ TF_COMMENT = 'Real*4 (floating point)'
+ END
+ 6: BEGIN
+ N_BYTES = 8*N_ELEM
+ TFORM = "C"
+ TF_COMMENT = 'Complex*8 (complex)'
+ END
+ 8: BEGIN
+ MESSAGE = "Can't write structures to FITS files"
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ 9: BEGIN
+ N_BYTES = 16*N_ELEM
+ TFORM = "M"
+ TF_COMMENT = 'Complex*16 (double-' + $
+ 'precision complex)'
+ END
+
+ 12: BEGIN
+ ;; Unsigned 16-bit integers are stored as signed
+ ;; integers with a TZERO offset.
+ N_BYTES = 2*N_ELEM
+ TFORM = "I"
+ TF_COMMENT = 'Unsigned Integer*2 (short integer)'
+ IF N_ELEMENTS(TSCAL) EQ 0 THEN TSCAL = 1
+ IF N_ELEMENTS(TZERO) EQ 0 THEN TZERO = 32768
+ IF TSCAL[0] NE 1 OR TZERO[0] NE 32768 THEN BEGIN
+ MESSAGE = 'For 2-byte unsigned type, TSCAL/TZERO must be 1/32768'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ END
+
+ 13: BEGIN
+ ;; Unsigned 32-bit integers are stored as signed
+ ;; integers with a TZERO offset.
+ N_BYTES = 4*N_ELEM
+ TFORM = "J"
+ TF_COMMENT = 'Unsigned Integer*4 (long integer)'
+ IF N_ELEMENTS(TSCAL) EQ 0 THEN TSCAL = 1
+ IF N_ELEMENTS(TZERO) EQ 0 THEN TZERO = 2147483648D
+ IF TSCAL[0] NE 1 OR TZERO[0] NE 2147483648D THEN BEGIN
+ MESSAGE = 'For 4-byte unsigned type, TSCAL/TZERO must be 1/2147483648'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ END
+
+ 14: BEGIN
+ N_BYTES = 8*N_ELEM
+ TFORM = "K"
+ TF_COMMENT = 'Integer*8 (long long ' + $
+ 'integer)'
+ END
+
+
+
+ ENDCASE
+;
+; If the column is to contain variable length data, then the number of bytes
+; is 8, and TFORM has "1P" in the front, and "()" in the back.
+;
+ IF KEYWORD_SET(VARIABLE) THEN BEGIN
+ N_BYTES = 8
+ TFORM = '1P' + TFORM + '(' + STRTRIM(N_ELEM,2) + ')'
+ TF_COMMENT = TF_COMMENT + ', variable length'
+;
+; Otherwise, TFORM has "" in the front.
+;
+ END ELSE TFORM = STRTRIM(N_ELEM,2) + TFORM
+;
+; Update the mandatory keywords in the header.
+;
+ NAXIS1 = FXPAR(HEADER,'NAXIS1')
+ FXADDPAR,HEADER,'NAXIS1',NAXIS1+N_BYTES
+ FXADDPAR,HEADER,'TFIELDS',INDEX
+;
+; Add the keyword defining this column.
+;
+ COL = STRTRIM(INDEX,2) ;ASCII form of column index
+ FXADDPAR, HEADER, 'TFORM'+COL, TFORM, TF_COMMENT
+;
+; If the TTYPE parameter has been passed, then add this keyword to the header.
+;
+ IF N_PARAMS() GE 4 THEN BEGIN
+ If N_PARAMS() EQ 4 THEN COMMENT="Label for column "+COL
+ FXADDPAR,HEADER,'TTYPE'+COL,TTYPE,COMMENT
+ ENDIF
+;
+; If the number of dimensions of the data array are greater than one, then add
+; the TDIM keyword. Don't add this keyword if either the NO_TDIM, VARIABLE or
+; BIT keyword is set.
+;
+ IF (S[0] GT 1) AND NOT (KEYWORD_SET(NO_TDIM) OR KEYWORD_SET(BIT) OR $
+ KEYWORD_SET(VARIABLE)) THEN BEGIN
+ TDIM = "(" + STRTRIM(S[1],2)
+ FOR I = 2,S[0] DO TDIM = TDIM + "," + STRTRIM(S[I],2)
+ TDIM = TDIM + ')'
+ FXADDPAR,HEADER,'TDIM'+COL,TDIM, $
+ 'Array dimensions for column '+COL
+ ENDIF
+;
+; If the various keywords were passed, then add them to the header.
+;
+ IF N_ELEMENTS(TUNIT) EQ 1 THEN FXADDPAR,HEADER,'TUNIT'+COL,TUNIT, $
+ 'Units of column '+COL
+ IF N_ELEMENTS(TSCAL) EQ 1 THEN FXADDPAR,HEADER,'TSCAL'+COL,TSCAL, $
+ 'Scale parameter for column '+COL
+ IF N_ELEMENTS(TZERO) EQ 1 THEN FXADDPAR,HEADER,'TZERO'+COL,TZERO, $
+ 'Zero offset for column '+COL
+ IF N_ELEMENTS(TNULL) EQ 1 THEN FXADDPAR,HEADER,'TNULL'+COL,TNULL, $
+ 'Null value for column '+COL
+ IF N_ELEMENTS(TDISP) EQ 1 THEN FXADDPAR,HEADER,'TDISP'+COL,TDISP, $
+ 'Display format for column '+COL
+;
+ IF N_ELEMENTS(TDMIN) EQ 1 THEN FXADDPAR,HEADER,'TDMIN'+COL,TDMIN, $
+ 'Minimum value in column '+COL
+ IF N_ELEMENTS(TDMAX) EQ 1 THEN FXADDPAR,HEADER,'TDMAX'+COL,TDMAX, $
+ 'Maximum value in column '+COL
+ IF N_ELEMENTS(TDESC) EQ 1 THEN FXADDPAR,HEADER,'TDESC'+COL,TDESC, $
+ 'Axis labels for column '+COL
+ IF N_ELEMENTS(TCUNI) EQ 1 THEN FXADDPAR,HEADER,'TCUNI'+COL,TCUNI, $
+ 'Axis units for column '+COL
+ IF N_ELEMENTS(TROTA) EQ 1 THEN FXADDPAR,HEADER,'TROTA'+COL,TROTA, $
+ 'Rotation angles for column '+COL
+ IF N_ELEMENTS(TRPIX) EQ 1 THEN FXADDPAR,HEADER,'TRPIX'+COL,TRPIX, $
+ 'Reference pixel for column '+COL
+ IF N_ELEMENTS(TRVAL) EQ 1 THEN FXADDPAR,HEADER,'TRVAL'+COL,TRVAL, $
+ 'Reference position for column '+COL
+ IF N_ELEMENTS(TDELT) EQ 1 THEN FXADDPAR,HEADER,'TDELT'+COL,TDELT, $
+ 'Axis increments for column '+COL
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbclose.pro b/Code/script_idl_mv/astrolib/fxbclose.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2c6987c084234265d3521f985ed5e2086e709fe0
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbclose.pro
@@ -0,0 +1,101 @@
+ PRO FXBCLOSE, UNIT, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBCLOSE
+; Purpose :
+; Close a FITS binary table extension opened for read.
+; Explanation :
+; Closes a FITS binary table extension that had been opened for read by
+; FXBOPEN.
+; Use :
+; FXBCLOSE, UNIT
+; Inputs :
+; UNIT = Logical unit number of the file.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBCLOSE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; None.
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The file must have been opened with FXBOPEN.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Feb. 1992.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version :
+; Version 3, 23 June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN BEGIN
+ MESSAGE = 'Syntax: FXBCLOSE, UNIT'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Find the index of the file.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Make sure the file was opened for read access.
+;
+ IF STATE[ILUN] NE 1 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened for read access'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Close the file, and mark it as closed.
+;
+ FREE_LUN,UNIT
+ STATE[ILUN] = 0
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbcolnum.pro b/Code/script_idl_mv/astrolib/fxbcolnum.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c456cb563bd419c11d4598c98b4c40b3fa175cb9
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbcolnum.pro
@@ -0,0 +1,124 @@
+ FUNCTION FXBCOLNUM, UNIT, COL, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBCOLNUM()
+; Purpose :
+; Returns a binary table column number.
+; Explanation :
+; Given a column specified either by number or name, this routine will
+; return the appropriate column number.
+; Use :
+; Result = FXBCOLNUM( UNIT, COL )
+; Inputs :
+; UNIT = Logical unit number corresponding to the file containing the
+; binary table.
+; COL = Column in the binary table, given either as a character
+; string containing a column label (TTYPE), or as a numerical
+; column index starting from column one.
+; Opt. Inputs :
+; None.
+; Outputs :
+; The result of the function is the number of the column specified, or
+; zero if no column is found (when passed by name).
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; Result = FXBCOLNUM( ERRMSG=ERRMSG, ... )
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; None.
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The binary table file must have been opened with FXBOPEN.
+;
+; If COL is passed as a number, rather than as a name, then it must be
+; consistent with the number of columns in the table.
+;
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; None.
+; Written :
+; William Thompson, GSFC, 2 July 1993.
+; Modified :
+; Version 1, William Thompson, GSFC, 2 July 1993.
+; Version 2, William Thompson, GSFC, 29 October 1993.
+; Added error message for not finding column by name.
+; Version 3, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version :
+; Version 4, 23 June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN BEGIN
+ MESSAGE = 'Syntax: Result = FXBCOLNUM( UNIT, COL )'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Find the logical unit number in the FXBINTABLE common block.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If COL is of type string, then search for a column with that label.
+;
+ SC = SIZE(COL)
+ IF SC[SC[0]+1] EQ 7 THEN BEGIN
+ SCOL = STRUPCASE(STRTRIM(COL,2))
+ ICOL = WHERE(TTYPE[*,ILUN] EQ SCOL, NCOL)
+ ICOL = ICOL[0]
+ IF ICOL LT 0 THEN BEGIN
+ MESSAGE = 'Column "' + SCOL + '" not found'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Otherwise, a numerical column was passed. Check its value.
+;
+ END ELSE ICOL = LONG(COL) - 1
+ IF (ICOL LT 0) OR (ICOL GE TFIELDS[ILUN]) THEN BEGIN
+ MESSAGE= 'COL must be between 1 and ' + $
+ STRTRIM(TFIELDS[ILUN],2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Return ICOL as a number between 1 and N.
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN, ICOL + 1
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbcreate.pro b/Code/script_idl_mv/astrolib/fxbcreate.pro
new file mode 100644
index 0000000000000000000000000000000000000000..45a2fa9dbb8ba5e817f26707a41cbfa880dac4a4
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbcreate.pro
@@ -0,0 +1,190 @@
+ PRO FXBCREATE, UNIT, FILENAME, HEADER, EXTENSION, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBCREATE
+; Purpose :
+; Open a new binary table at the end of a FITS file.
+; Explanation :
+; Write a binary table extension header to the end of a disk FITS file,
+; and leave it open to receive the data.
+;
+; The FITS file is opened, and the pointer is positioned just after the
+; last 2880 byte record. Then the binary header is appended. Calls to
+; FXBWRITE will append the binary data to this file, and then FXBFINISH
+; will close the file.
+;
+; Use :
+; FXBCREATE, UNIT, FILENAME, HEADER
+; Inputs :
+; FILENAME = Name of FITS file to be opened.
+; HEADER = String array containing the FITS binary table extension
+; header.
+; Opt. Inputs :
+; None.
+; Outputs :
+; UNIT = Logical unit number of the opened file.
+; EXTENSION= Extension number of newly created extension.
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBCREATE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXADDPAR, FXBFINDLUN, FXBPARSE, FXFINDEND
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The primary FITS data unit must already be written to a file. The
+; binary table extension header must already be defined (FXBHMAKE), and
+; must match the data that will be written to the file.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Jan 1992, based on WRITEFITS by J. Woffard and W. Landsman.
+; W. Thompson, Feb 1992, changed from function to procedure.
+; W. Thompson, Feb 1992, removed all references to temporary files.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 July 1993.
+; Fixed bug with variable length arrays.
+; Version 3, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 5, Antony Bird, Southampton, 25 June 1997
+; Modified to allow very long tables
+; Version :
+; Version 5, 25 June 1997
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added EXTENSION parameter, C. Markwardt 1999 Jul 15
+; More efficient zeroing of file, C. Markwardt, 26 Feb 2001
+; Recompute header size if updating THEAP keyword B. Roukema April 2010
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXBCREATE, UNIT, FILENAME, HEADER'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get a logical unit number, open the file, and find the end.
+;
+ GET_LUN,UNIT
+ OPENU, UNIT, FILENAME, /BLOCK
+ FXFINDEND, UNIT, EXTENSION
+;
+; Store the UNIT number in the common block, and leave space for the other
+; parameters. Initialize the common block if need be. ILUN is an index into
+; the arrays.
+;
+ ILUN = FXBFINDLUN(UNIT)
+;
+; Store the current position as the start of the header. Mark the file as
+; open for write.
+;
+ POINT_LUN,-UNIT,POINTER
+ MHEADER[ILUN] = POINTER
+ STATE[ILUN] = 2
+;
+; Determine if an END line occurs, and add one if necessary
+;
+CHECK_END:
+ ENDLINE = WHERE(STRMID(HEADER,0,8) EQ 'END ', NEND)
+ ENDLINE = ENDLINE[0]
+ IF NEND EQ 0 THEN BEGIN
+ MESSAGE,/INF,'WARNING - An END statement has been appended ' +$
+ 'to the FITS header'
+ HEADER = [HEADER, 'END' + STRING(REPLICATE(32B,77))]
+ ENDLINE = N_ELEMENTS(HEADER) - 1
+ ENDIF
+ NMAX = ENDLINE + 1 ;Number of 80 byte records
+ NHEAD = FIX((NMAX+35)/36) ;Number of 2880 byte records
+;
+; Convert the header to byte and force into 80 character lines.
+;
+WRITE_HEADER:
+ BHDR = REPLICATE(32B, 80, 36*NHEAD)
+ FOR N = 0,ENDLINE DO BHDR[0,N] = BYTE( STRMID(HEADER[N],0,80) )
+ WRITEU, UNIT, BHDR
+;
+; Get the rest of the information, and store it in the common block.
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ FXBPARSE,ILUN,HEADER,ERRMSG=ERRMSG
+ IF ERRMSG NE '' THEN RETURN
+ END ELSE FXBPARSE,ILUN,HEADER
+;
+; Check the size of the heap offset. If the heap offset is smaller than the
+; table, then reset it to the size of the table.
+;
+ DDHEAP = HEAP[ILUN] - NAXIS1[ILUN]*NAXIS2[ILUN]
+ IF DDHEAP LT 0 THEN BEGIN
+ MESSAGE,'Heap offset smaller than table size--resetting', $
+ /CONTINUE
+ HEAP[ILUN] = NAXIS1[ILUN]*NAXIS2[ILUN]
+ FXADDPAR,HEADER,'THEAP',HEAP[ILUN]
+ POINT_LUN, UNIT, MHEADER[ILUN]
+
+; Have we changed position of the END keyword?
+ GOTO, CHECK_END
+ ENDIF
+;
+; Fill out the file to size it properly.
+;
+ ;; This segment is now optimized to write out more than one
+ ;; row at a time, which is crucial for tables with many small
+ ;; rows. The code heuristically chooses a buffer size which
+ ;; is 1% of the file, but no bigger than 512k, and always a
+ ;; multiple of the row size.
+
+
+ BUFSIZE = LONG(NAXIS1[ILUN]*NAXIS2[ILUN]/100) > NAXIS1[ILUN] < 524288L
+ BUFSIZE = (FLOOR(BUFSIZE/NAXIS1[ILUN])>1) * NAXIS1[ILUN]
+ BUFFER = BYTARR(BUFSIZE)
+ TOTBYTES = NAXIS1[ILUN]*NAXIS2[ILUN]
+
+ ;; TOTBYTES keeps count of bytes left to write
+ WHILE TOTBYTES GT 0 DO BEGIN
+ ;; Case of final rows which might not be EQ BUFSIZE
+ IF TOTBYTES LT BUFSIZE THEN BUFFER = BYTARR(TOTBYTES)
+ WRITEU,UNIT,BUFFER
+ TOTBYTES = TOTBYTES - BUFSIZE
+ ENDWHILE
+;
+; If there's any extra space before the start of the heap, then write that out
+; as well.
+;
+ IF DDHEAP GT 0 THEN BEGIN
+ BUFFER = BYTARR(DDHEAP)
+ WRITEU,UNIT,BUFFER
+ ENDIF
+;
+; Initialize DHEAP, and return.
+;
+ DHEAP[ILUN] = 0
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
+
diff --git a/Code/script_idl_mv/astrolib/fxbdimen.pro b/Code/script_idl_mv/astrolib/fxbdimen.pro
new file mode 100644
index 0000000000000000000000000000000000000000..16bc619a69aca3710c9bbee55e46713a05fd7307
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbdimen.pro
@@ -0,0 +1,127 @@
+ FUNCTION FXBDIMEN, UNIT, COL, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBDIMEN()
+;
+; PURPOSE:
+; Returns the dimensions for a column in a FITS binary table.
+;
+; Explanation : This procedure returns the dimensions associated with a column
+; in a binary table opened for read with the command FXBOPEN.
+;
+; Use : Result = FXBDIMEN(UNIT,COL)
+;
+; Inputs : UNIT = Logical unit number returned by FXBOPEN routine.
+; Must be a scalar integer.
+;
+; COL = Column in the binary table to read data from, either
+; as a character string containing a column label
+; (TTYPE), or as a numerical column index starting from
+; column one.
+;
+; Opt. Inputs : None.
+;
+; Outputs : The result of the function is an array containing the
+; dimensions for the specified column in the FITS binary table
+; that UNIT points to.
+;
+; Opt. Outputs: None.
+;
+; Keywords : ERRMSG = If defined and passed, then any error messages will
+; be returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no
+; errors are encountered, then a null string is
+; returned. In order to use this feature, ERRMSG must
+; be defined first, e.g.
+;
+; ERRMSG = ''
+; Result = FXBDIMEN( ERRMSG=ERRMSG, ... )
+; IF ERRMSG NE '' THEN ...
+;
+; Calls : FXBCOLNUM, FXBFINDLUN
+;
+; Common : Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+;
+; Restrictions: None.
+;
+; Side effects: The dimensions will be returned whether or not the table is
+; still open or not.
+;
+; If UNIT does not point to a binary table, then 0 is returned.
+;
+; If UNIT is an undefined variable, then 0 is returned.
+;
+; Category : Data Handling, I/O, FITS, Generic.
+;
+; Prev. Hist. : None.
+;
+; Written : William Thompson, GSFC, 4 March 1994.
+;
+; Modified : Version 1, William Thompson, GSFC, 4 March 1994.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+;
+; Version : Version 3, 23 June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN BEGIN
+ MESSAGE = 'Syntax: Result = FXBDIMEN(UNIT,COL)'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If UNIT is undefined, then return zero.
+;
+ IF N_ELEMENTS(UNIT) EQ 0 THEN RETURN, 0
+;
+; Check the validity of UNIT.
+;
+ IF N_ELEMENTS(UNIT) GT 1 THEN BEGIN
+ MESSAGE = 'UNIT must be a scalar'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ SZ = SIZE(UNIT)
+ IF SZ[SZ[0]+1] GT 3 THEN BEGIN
+ MESSAGE = 'UNIT must be an integer'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Find the column number for the requested column.
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ICOL = FXBCOLNUM(UNIT,COL,ERRMSG=ERRMSG)
+ IF MESSAGE NE '' THEN RETURN, 0
+ END ELSE ICOL = FXBCOLNUM(UNIT,COL)
+ IF ICOL EQ 0 THEN BEGIN
+ MESSAGE = 'No such column'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN, 0
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get the dimensions associated with UNIT and COL.
+;
+ ILUN = FXBFINDLUN(UNIT)
+ DIMS = N_DIMS[*,ICOL-1,ILUN]
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN, DIMS[1:DIMS[0]]
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbfind.pro b/Code/script_idl_mv/astrolib/fxbfind.pro
new file mode 100644
index 0000000000000000000000000000000000000000..530835de7f71580bd41ebdec9e43d4847079be1d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbfind.pro
@@ -0,0 +1,158 @@
+ PRO FXBFIND,P1,KEYWORD,COLUMNS,VALUES,N_FOUND,DEFAULT, $
+ COMMENTS=COMMENTS
+;+
+; NAME:
+; FXBFIND
+; Purpose :
+; Find column keywords in a FITS binary table header.
+; Explanation :
+; Finds the value of a column keyword for all the columns in the binary
+; table for which it is set. For example,
+;
+; FXBFIND, UNIT, 'TTYPE', COLUMNS, VALUES, N_FOUND
+;
+; Would find all instances of the keywords TTYPE1, TTYPE2, etc. The
+; array COLUMNS would contain the column numbers for which a TTYPEn
+; keyword was found, and VALUES would contain the values. N_FOUND would
+; contain the total number of instances found.
+;
+; Use :
+; FXBFIND, [UNIT or HEADER], KEYWORD, COLUMNS, VALUES, N_FOUND
+; [, DEFAULT ]
+; Inputs :
+; Either UNIT or HEADER must be passed.
+;
+; UNIT = Logical unit number of file opened by FXBOPEN.
+; HEADER = FITS binary table header.
+; KEYWORD = Prefix to a series of FITS binary table column keywords. The
+; keywords to be searched for are formed by combining this
+; prefix with the numbers 1 through the value of TFIELDS in the
+; header.
+; Opt. Inputs :
+; DEFAULT = Default value to use for any column keywords that aren't
+; found. If passed, then COLUMNS and VALUES will contain
+; entries for every column. Otherwise, COLUMNS and VALUES only
+; contain entries for columns where values were found.
+; Outputs :
+; COLUMNS = Array containing the column numbers for which values of the
+; requested keyword series were found.
+; VALUES = Array containing the found values.
+; N_FOUND = Number of values found. The value of this parameter is
+; unaffected by whether or not DEFAULT is passed.
+; Opt. Outputs:
+; None.
+; Output Keywords :
+; COMMENTS = Comments associated with each keyword, if any
+; Calls :
+; FXBFINDLUN, FXPAR
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; If UNIT is passed, then the file must have been opened with FXBOPEN.
+; If HEADER is passed, then it must be a legal FITS binary table header.
+;
+; The type of DEFAULT must be consistent with the values of the requested
+; keywords, i.e. both most be either of string or numerical type.
+;
+; The KEYWORD prefix must not have more than five characters to leave
+; room for the three digits allowed for the column numbers.
+;
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb. 1992.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Vectorized implementation improves performance, CM 18 Nov 1999
+; Added COMMENTS keyword CM Nov 2003
+; Remove use of obsolete !ERR system variable W. Landsman April 2010
+; Fix error introduced April 2010 W. Landsman
+; Version :
+; Version 3, April 2010.
+;-
+;
+@fxbintable
+ ON_ERROR,2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 5 THEN MESSAGE, $
+ 'Syntax: FXBFIND,[UNIT/HEADER],KEYWORD,COLUMNS,VALUES,' + $
+ 'N_FOUND [,DEFAULT]'
+;
+; Get the header.
+;
+ IF N_ELEMENTS(P1) EQ 1 THEN BEGIN
+ ILUN = FXBFINDLUN(P1)
+ HEADER = HEAD[*,ILUN]
+ END ELSE HEADER = P1
+;
+; Get the value of TFIELDS from HEADER.
+;
+ TFIELDS0 = FXPAR(HEADER,'TFIELDS')
+ IF TFIELDS0 EQ 0 THEN MESSAGE,'No columns found in HEADER'
+
+;
+; Extract the keyword values all in one pass
+;
+ KEYVALUES = FXPAR(HEADER, STRTRIM(KEYWORD,2)+'*', $
+ COMMENT=COMMENT_STRS, DATATYPE=DEFAULT, COUNT=NKEY)
+ N_FOUND = 0L
+
+;
+; INDEX is used as an array index to fill in the final output
+;
+ IF NKEY GT 0 THEN BEGIN
+ N_FOUND = N_ELEMENTS(KEYVALUES)
+ INDEX = LINDGEN(N_FOUND)
+ ENDIF
+
+
+;
+; INDEX is used as an array index to fill in the final output
+;
+ IF N_FOUND GT 0 THEN INDEX = LINDGEN(N_FOUND)
+
+;
+; If a default was given, then we are a little more careful to
+; reproduce the correct number of values.
+;
+ IF N_ELEMENTS(DEFAULT) GT 0 THEN BEGIN
+ ;; If no values were found we need to fill KEYVALUES with
+ ;; *something*.
+ IF N_FOUND LE 0 THEN KEYVALUES = DEFAULT
+ COLUMNS = LINDGEN(TFIELDS0) + 1
+
+ ;; Make an array with the number of columns in the table
+ SZ_VALUE = SIZE(KEYVALUES[0])
+ VALUES = MAKE_ARRAY(TFIELDS0, TYPE=SZ_VALUE[1], VALUE=DEFAULT)
+ COMMENTS = STRARR(TFIELDS0)
+
+ ;; Fill the columns which had this keyword
+ IF N_FOUND GT 0 THEN BEGIN
+ VALUES[INDEX] = KEYVALUES
+ COMMENTS[INDEX] = COMMENT_STRS
+ ENDIF
+
+ ENDIF ELSE BEGIN
+
+;
+; If no default was given, we can simply return the values returned
+; by FXPAR.
+;
+ IF N_FOUND GT 0 THEN BEGIN
+ COLUMNS = INDEX + 1
+ VALUES = KEYVALUES
+ COMMENTS = COMMENT_STRS
+ ENDIF
+
+ ENDELSE
+ RETURN
+
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbfindlun.pro b/Code/script_idl_mv/astrolib/fxbfindlun.pro
new file mode 100644
index 0000000000000000000000000000000000000000..78b3bb8b8d33ba14f3904b3be3f70cb7a55144f9
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbfindlun.pro
@@ -0,0 +1,120 @@
+ FUNCTION FXBFINDLUN, UNIT
+;+
+; NAME:
+; FXBFINDLUN()
+; Purpose :
+; Find logical unit number UNIT in FXBINTABLE common block.
+; Explanation :
+; Finds the proper index to use for getting information about the logical
+; unit number UNIT in the arrays stored in the FXBINTABLE common block.
+; Called from FXBCREATE and FXBOPEN.
+; Use :
+; Result = FXBFINDLUN( UNIT )
+; Inputs :
+; UNIT = Logical unit number.
+; Opt. Inputs :
+; None.
+; Outputs :
+; The result of the function is an index into the FXBINTABLE common
+; block.
+; Opt. Outputs:
+; None.
+; Keywords :
+; None.
+; Calls :
+; None.
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; None.
+; Side effects:
+; If UNIT is not found in the common block, then it is added to the
+; common block.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb. 1992.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 July 1993.
+; Added DHEAP variable to fix bug with variable length arrays.
+; Version 3, Michael Schubnell, University of Michigan, 22 May 1996
+; Change N_DIMS from short to long integer.
+; Version :
+; Version 3, 22 May 1996
+; Make NAXIS1, NAXIS2, HEAP, DHEAP, BYTOFF 64-bit integers to deal with large files,
+; E. Hivon Mar 2008
+; Also make NHEADER a 64 bit integer W. Landsman May 2016
+;
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE, $
+ 'Syntax: ILUN = FXBFINDLUN( UNIT )'
+;
+; If the common block hasn't been initialized yet, then initialize it.
+;
+ IF N_ELEMENTS(LUN) EQ 0 THEN BEGIN
+ LUN = UNIT
+ STATE = 0
+ HEAD = ''
+ MHEADER = 0L
+ NHEADER = 0LL
+ NAXIS1 = 0LL
+ NAXIS2 = 0LL
+ TFIELDS = 0L
+ HEAP = 0LL
+ DHEAP = 0LL
+ BYTOFF = 0LL
+ TTYPE = ''
+ FORMAT = ''
+ IDLTYPE = 0
+ N_ELEM = 0L
+ TSCAL = 1.
+ TZERO = 0.
+ MAXVAL = 0L
+ N_DIMS = LONARR(9,2)
+ ILUN = 0
+;
+; Otherwise, find the logical unit number in the common block. If not found,
+; then add it.
+;
+ END ELSE BEGIN
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ LUN = [LUN,UNIT]
+ STATE = [STATE, 0]
+ BOOST_ARRAY,HEAD,''
+ MHEADER = [MHEADER,0]
+ NHEADER = [NHEADER,0]
+ NAXIS1 = [NAXIS1, 0]
+ NAXIS2 = [NAXIS2, 0]
+ TFIELDS = [TFIELDS,0]
+ HEAP = [HEAP, 0]
+ DHEAP = [DHEAP, 0]
+ BOOST_ARRAY,BYTOFF,0
+ BOOST_ARRAY,TTYPE,''
+ BOOST_ARRAY,FORMAT,''
+ BOOST_ARRAY,IDLTYPE,0
+ BOOST_ARRAY,N_ELEM,0
+ BOOST_ARRAY,TSCAL,1.
+ BOOST_ARRAY,TZERO,0.
+ BOOST_ARRAY,MAXVAL,0
+ BOOST_ARRAY,N_DIMS,LONARR(9,2)
+ ILUN = N_ELEMENTS(LUN)-1
+ ENDIF
+ ENDELSE
+;
+; Return the index into the common block arrays.
+;
+ RETURN,ILUN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbfinish.pro b/Code/script_idl_mv/astrolib/fxbfinish.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e5c9b39ff102b54ec5659e6ec65730ca80b58a16
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbfinish.pro
@@ -0,0 +1,129 @@
+ PRO FXBFINISH, UNIT, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBFINISH
+; Purpose :
+; Close a FITS binary table extension file opened for write.
+; Explanation :
+; Closes a FITS binary table extension file that had been opened for
+; write by FXBCREATE.
+; Use :
+; FXBFINISH, UNIT
+; Inputs :
+; UNIT = Logical unit number of the file.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBFINISH, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; None.
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The file must have been opened with FXBCREATE, and written with
+; FXBWRITE.
+; Side effects:
+; Any bytes needed to pad the file out to an integral multiple of 2880
+; bytes are written out to the file. Then, the file is closed.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Jan 1992.
+; W. Thompson, Feb 1992, modified to support variable length arrays.
+; W. Thompson, Feb 1992, removed all references to temporary files.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 July 1993.
+; Fixed bug with variable length arrays.
+; Version 3, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version :
+; Version 4, 23 June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN BEGIN
+ MESSAGE = 'Syntax: FXBFINISH, UNIT'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Find the index of the file.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Make sure the file was opened for write access.
+;
+ IF STATE[ILUN] NE 2 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened for write access'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Calculate how many bytes are needed to pad out the file.
+;
+ OFFSET = NHEADER[ILUN] + HEAP[ILUN] + DHEAP[ILUN]
+ NPAD = OFFSET MOD 2880
+ IF NPAD NE 0 THEN BEGIN
+ NPAD = 2880 - NPAD
+ POINT_LUN,UNIT,OFFSET
+ WRITEU,UNIT,BYTARR(NPAD)
+ ENDIF
+;
+; If variable sized arrays were written out to the file, then the PCOUNT value
+; must be updated. It is taken for granted that PCOUNT is the sixth keyword
+; down, and the value is inserted right justified to column 30.
+;
+ PCOUNT = HEAP[ILUN] + DHEAP[ILUN] - NAXIS1[ILUN]*NAXIS2[ILUN]
+ IF PCOUNT GT 0 THEN BEGIN
+ PCOUNT = STRTRIM(PCOUNT,2)
+ POINT_LUN,UNIT,MHEADER[ILUN] + 430 - STRLEN(PCOUNT)
+ WRITEU,UNIT,PCOUNT
+ ENDIF
+;
+; Close the file, mark it as closed, and return.
+;
+ FREE_LUN,UNIT
+ STATE[ILUN] = 0
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbgrow.pro b/Code/script_idl_mv/astrolib/fxbgrow.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6285bce4061ea256dd190e4adc5393021eea41e9
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbgrow.pro
@@ -0,0 +1,245 @@
+ PRO FXBGROW, UNIT, HEADER, NROWS, ERRMSG=ERRMSG, NOZERO=NOZERO, $
+ BUFFERSIZE=BUFFERSIZE0
+;+
+; NAME:
+; FXBGROW
+; PURPOSE :
+; Increase the number of rows in a binary table.
+; EXPLANATION :
+; Call FXBGROW to increase the size of an already-existing FITS
+; binary table. The number of rows increases to NROWS; however
+; the table cannot shrink by this operation. This procedure is
+; useful when a table with an unknown number of rows must be
+; created. The caller would then call FXBCREATE to construct a
+; table of some base size, and follow with calls to FXBGROW to
+; lengthen the table as needed. The extension being enlarged
+; need not be the last extension in the file. If subsequent
+; extensions exist in the file, they will be shifted properly.
+;
+; CALLING SEQUENCE :
+; FXBGROW, UNIT, HEADER, NROWS[, ERRMSG= , NOZERO= , BUFFERSIZE= ]
+;
+; INPUT PARAMETERS :
+; UNIT = Logical unit number of an already-opened file.
+; HEADER = String array containing the FITS binary table extension
+; header. The header is modified in place.
+; NROWS = New number of rows, always more than the previous
+; number.
+;
+; OPTIONAL INPUT KEYWORDS:
+; NOZERO = when set, FXBGROW will not zero-pad the new data if
+; it doesn't have to.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBGROW, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+; BUFFERSIZE = Size in bytes for intermediate data transfers
+; (default 32768)
+;
+; Calls :
+; FXADDPAR, FXHREAD, BLKSHIFT
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The file must be open with write permission.
+;
+; The binary table extension in question must already by written
+; to the file (using FXBCREATE).
+;
+; A table can never shrink via this operation.
+;
+; SIDE EFFECTS:
+; The FITS file will grow in size, and heap areas are
+; preserved by moving them to the end of the file.
+;
+; The header is modified to reflect the new number of rows.
+; CATEGORY :
+; Data Handling, I/O, FITS, Generic.
+; Initially written, C. Markwardt, GSFC, Nov 1998
+; Added ability to enlarge arbitrary extensions and tables with
+; variable sized rows, not just the last extension in a file,
+; CM, April 2000
+; Fix bug in the zeroing of the output file, C. Markwardt, April 2005
+;
+;-
+;
+@fxbintable
+ ON_ERROR, 0
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXBGROW, UNIT, HEADER, NROWS'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Find the index of the file.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Don't shrink the file.
+;
+ IF NAXIS2[ILUN] GE NROWS THEN GOTO, FINISH
+;
+; Make sure the file was opened for write access.
+;
+ IF STATE[ILUN] NE 2 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened for write access'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Compute number of bytes and buffer size
+;
+
+ NBYTES = (NROWS-NAXIS2[ILUN])*NAXIS1[ILUN]
+ IF N_ELEMENTS(BUFFERSIZE0) EQ 0 THEN BUFFERSIZE0 = 32768L
+ BUFFERSIZE = LONG(BUFFERSIZE0[0])
+ BUFFERSIZE = FLOOR(BUFFERSIZE/NAXIS1[ILUN])*NAXIS1[ILUN]
+ IF BUFFERSIZE LE 0 THEN BUFFERSIZE = NAXIS1[ILUN]
+
+;
+; First, shift the following extensions by block multiples
+;
+ ;; Current beginning of next extension
+ N_EXT = NHEADER[ILUN] + HEAP[ILUN] + DHEAP[ILUN]
+ ;; New beginning of next extension, after shifting
+ N_EXT1 = N_EXT + NBYTES
+ ;; Round to nearest block size
+ IF N_EXT MOD 2880 NE 0 THEN N_EXT = N_EXT + 2880 - (N_EXT MOD 2880)
+ IF N_EXT1 MOD 2880 NE 0 THEN N_EXT1 = N_EXT1 + 2880 - (N_EXT1 MOD 2880)
+ NBYTES1 = N_EXT1 - N_EXT
+
+ ERRMSG1 = ''
+ IF NBYTES1 GT 0 THEN BEGIN
+ BLKSHIFT, UNIT, N_EXT, NBYTES1, ERRMSG=ERRMSG1, $
+ NOZERO=KEYWORD_SET(NOZERO), BUFFERSIZE=BUFFERSIZE
+ IF ERRMSG1 NE '' THEN GOTO, RETMESSAGE
+ ENDIF
+;
+; Next, shift the data between the end of the table and the next
+; extension, if any.
+;
+ ;; End of table data (but before variable-sized heap data)
+ ETAB = NHEADER[ILUN] + NAXIS1[ILUN]*NAXIS2[ILUN]
+ IF N_EXT GT ETAB THEN BEGIN
+ BLKSHIFT, UNIT, [ETAB, N_EXT1-NBYTES-1L], NBYTES, ERRMSG=ERRMSG1, $
+ NOZERO=KEYWORD_SET(NOZERO), BUFFERSIZE=BUFFERSIZE
+ ENDIF
+
+ RETMESSAGE:
+ IF ERRMSG1 NE '' THEN BEGIN
+ MESSAGE = ERRMSG1
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+
+;
+; Zero-fill if necessary (if the original table had no trailing
+; extensions)
+;
+
+ FS = FSTAT(UNIT)
+
+ IF FS.SIZE LT N_EXT1 AND NOT KEYWORD_SET(NOZERO) THEN BEGIN
+ POINT_LUN, UNIT, ETAB
+ NLEFT = N_EXT1 - ETAB
+ NBUFF = BUFFERSIZE < NLEFT
+ BB = BYTARR(NBUFF)
+
+ WHILE NLEFT GT 0 DO BEGIN
+ WRITEU, UNIT, BB
+ NLEFT = NLEFT - N_ELEMENTS(BB)
+ IF (NLEFT LT NBUFF) AND (NLEFT GT 0) THEN BB = BB[0:NLEFT-1]
+ ENDWHILE
+ ENDIF
+
+;
+; Update the internal state.
+;
+ HEAP[ILUN] = HEAP[ILUN] + NBYTES
+ NAXIS2[ILUN] = NROWS
+
+;
+; Modify passed copy of header
+;
+ IF N_ELEMENTS(HEADER) GT 0 THEN BEGIN
+ FXADDPAR, HEADER, 'NAXIS2', LONG(NROWS), 'Number of rows (grown)'
+ THEAP = FXPAR(HEADER, 'THEAP', COUNT=COUNT)
+ IF COUNT GT 0 THEN BEGIN
+ THEAP = THEAP + NBYTES
+ FXADDPAR, HEADER, 'THEAP', THEAP, 'Offset of heap'
+ ENDIF
+ ENDIF
+
+
+;
+; Modify internal copy of HEADER
+;
+ XHEADER = HEAD[*,ILUN]
+ FXADDPAR, XHEADER, 'NAXIS2', LONG(NROWS), 'Number of rows (grown)'
+ THEAP = FXPAR(XHEADER, 'THEAP', COUNT=COUNT)
+ IF COUNT GT 0 THEN BEGIN
+ THEAP = THEAP + NBYTES
+ FXADDPAR, XHEADER, 'THEAP', THEAP, 'Offset of heap'
+ ENDIF
+ HEAD[*,ILUN] = XHEADER
+
+;
+; Modify disk copy of HEADER
+;
+ POINT_LUN, UNIT, MHEADER[ILUN]
+ FXHREAD, UNIT, DHEADER, STATUS
+ IF STATUS NE 0 THEN BEGIN
+ MESSAGE = 'Could not load header from file'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ FXADDPAR, DHEADER, 'NAXIS2', LONG(NROWS), 'Number of rows (grown)'
+ THEAP = FXPAR(DHEADER, 'THEAP', COUNT=COUNT)
+ IF COUNT GT 0 THEN BEGIN
+ THEAP = THEAP + NBYTES
+ FXADDPAR, DHEADER, 'THEAP', THEAP, 'Offset of heap'
+ ENDIF
+ ;; Don't worry about the header increasing in size, since
+ ;; every binary table has to have NAXIS2 already.
+ SLEN = STRLEN(DHEADER[0])
+ FULL = STRING(REPLICATE(32B, 80))
+ ;; Pad with spaces
+ IF SLEN LT 80 THEN DHEADER[0] = DHEADER[0] + STRMID(FULL,0,80-SLEN)
+ BHDR = BYTE(DHEADER)
+ BHDR = BHDR[0:79,*]
+ POINT_LUN, UNIT, MHEADER[ILUN]
+ WRITEU, UNIT, BHDR
+
+FINISH:
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbheader.pro b/Code/script_idl_mv/astrolib/fxbheader.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6e37e19abfd31c10e43b0c26a7267e7113dbf557
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbheader.pro
@@ -0,0 +1,81 @@
+ FUNCTION FXBHEADER, UNIT
+;+
+; NAME:
+; FXBHEADER()
+;
+; PURPOSE:
+; Returns the header of an open FITS binary table.
+;
+; EXPLANATION:
+; This procedure returns the FITS extension header of a FITS
+; binary table opened for read with the command FXBOPEN.
+;
+; Use : Result = FXBHEADER(UNIT)
+;
+; Inputs : UNIT = Logical unit number returned by FXBOPEN routine.
+; Must be a scalar integer.
+;
+; Opt. Inputs : None.
+;
+; Outputs : The result of the function is a string array containing the
+; header for the FITS binary table that UNIT points to.
+;
+; Opt. Outputs: None.
+;
+; Keywords : None.
+;
+; Calls : FXBFINDLUN
+;
+; Common : Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+;
+; Restrictions: None.
+;
+; Side effects: The string array returned always has as many elements as the
+; largest header read by FXBOPEN. Any extra elements beyond the
+; true header are blank or null strings.
+;
+; The header will be returned whether or not the table is still
+; open or not.
+;
+; If UNIT does not point to a binary table, then a string array
+; of nulls is returned.
+;
+; If UNIT is an undefined variable, then the null string is
+; returned.
+;
+; Category : Data Handling, I/O, FITS, Generic.
+;
+; Prev. Hist. : None.
+;
+; Written : William Thompson, GSFC, 1 July 1993.
+;
+; Modified : Version 1, William Thompson, GSFC, 1 July 1993.
+;
+; Version : Version 1, 1 July 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE,'Syntax: Result = FXBHEADER(UNIT)'
+;
+; If UNIT is undefined, then return the null string.
+;
+ IF N_ELEMENTS(UNIT) EQ 0 THEN RETURN, ''
+;
+; Check the validity of UNIT.
+;
+ IF N_ELEMENTS(UNIT) GT 1 THEN MESSAGE,'UNIT must be a scalar'
+ SZ = SIZE(UNIT)
+ IF SZ[SZ[0]+1] GT 3 THEN MESSAGE,'UNIT must be an integer'
+;
+; Get the state associated with UNIT.
+;
+ ILUN = FXBFINDLUN(UNIT)
+ RETURN, HEAD[*,ILUN]
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbhelp.pro b/Code/script_idl_mv/astrolib/fxbhelp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2a7c19977ab1e592ca3c284deebe5579dcca7d88
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbhelp.pro
@@ -0,0 +1,128 @@
+ PRO FXBHELP,UNIT
+;+
+; NAME:
+; FXBHELP
+; Purpose :
+; Prints short description of columns in a FITS binary table.
+; Explanation :
+; Prints a short description of the columns in a FITS binary table to the
+; terminal screen.
+; Use :
+; FXBHELP, UNIT
+; Inputs :
+; UNIT = Logical unit number of file opened by FXBOPEN.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; None.
+; Calls :
+; FXBFIND, FXBFINDLUN, FXPAR
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The file must have been opened with FXBOPEN.
+; Side effects:
+; Certain fields may be truncated in the display.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb. 1992, from TBHELP by W. Landsman.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 12 May 1993.
+; Modified to not write to a logical unit number assigned to the
+; terminal. This makes it compatible with IDL for Windows.
+; Version 3, Wayne Landsman GSFC April 2010
+; Remove use of obsolete !ERR system variable
+; Version :
+; Version 3, April 2010.
+;-
+;
+@fxbintable
+ ON_ERROR,2
+ COMPILE_OPT IDL2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 1 THEN MESSAGE,'Syntax: FXBHELP, UNIT'
+;
+; Get the header.
+;
+ ILUN = FXBFINDLUN(UNIT)
+ HEADER = HEAD[*,ILUN]
+;
+; Get the extension name.
+;
+ EXTNAME = FXPAR(HEADER,'EXTNAME', COUNT=N_EXTNAME)
+ IF N_EXTNAME LE 0 THEN EXTNAME = ''
+;
+; Print the labels.
+;
+ PRINT,' '
+ PRINT,'FITS Binary Table: ' + EXTNAME
+ PRINT,'Table contains ' + STRTRIM(TFIELDS[ILUN],2) + $
+ ' columns, by ' + STRTRIM(NAXIS2[ILUN],2) + ' rows'
+ PRINT,' '
+ T_FORMAT = 26 ;Starting column for Format/Size
+ T_UNITS = 46 ;Starting column for Units
+ T_NULL = 58 ;Starting column for Null
+ PRINT,FORMAT="('Col',2X,'Name',T" + STRTRIM(T_FORMAT,2) + $
+ ",'Type Size',T" + STRTRIM(T_UNITS,2) + ",'Units',T" + $
+ STRTRIM(T_NULL,2) + ",6X,'Null')"
+ PRINT,' '
+;
+; Get the values of the information to be printed.
+;
+ FXBFIND,HEADER,'TDIM', COL,TDIM0, N_FOUND,''
+ FXBFIND,HEADER,'TUNIT',COL,TUNIT0,N_FOUND,''
+;
+ FXBFIND,HEADER,'TNULL',COL,TNULL0,N_FOUND
+ SNULL = STRARR(TFIELDS[ILUN])
+ IF N_FOUND GT 0 THEN FOR I = 0,N_ELEMENTS(COL)-1 DO $
+ SNULL[COL[I]-1] = STRTRIM(TNULL0[I],2)
+;
+; Print the column information.
+;
+ FOR ICOL = 0,TFIELDS[ILUN]-1 DO BEGIN
+ CASE FORMAT[ICOL,ILUN] OF
+ 'L': TYPE0 = 'Log'
+ 'A': TYPE0 = 'Asc'
+ 'B': TYPE0 = 'Byt'
+ 'I': TYPE0 = 'Int'
+ 'J': TYPE0 = 'Lng'
+ 'E': TYPE0 = 'Flt'
+ 'D': TYPE0 = 'Dbl'
+ 'C': TYPE0 = 'Cmp'
+ 'M': TYPE0 = 'DbC'
+ 'X': TYPE0 = 'Bit'
+ ENDCASE
+ IF MAXVAL[ICOL,ILUN] GT 0 THEN BEGIN
+ ELEM = MAXVAL[ICOL,ILUN]
+ IF FORMAT[ICOL,ILUN] EQ 'M' THEN ELEM = ELEM/2
+ ELEM = "< " + STRTRIM(ELEM,2)
+ END ELSE IF TDIM0[ICOL] NE '' THEN BEGIN
+ ELEM = TDIM0[ICOL]
+ END ELSE BEGIN
+ ELEM = N_ELEM[ICOL,ILUN]
+ IF FORMAT[ICOL,ILUN] EQ 'M' THEN ELEM = ELEM/2
+ ELEM = STRTRIM(ELEM,2)
+ ENDELSE
+ PRINT,ICOL+1,TTYPE[ICOL,ILUN],TYPE0,ELEM, $
+ TUNIT0[ICOL],SNULL[ICOL], FORMAT='(I3,2X,A,T' + $
+ STRTRIM(T_FORMAT-2,2) + ',2X,A3,2X,A,T' + $
+ STRTRIM(T_UNITS-2,2) + ',2X,A,T' + $
+ STRTRIM(T_NULL-2,2) + ',2X,A10)'
+ ENDFOR
+ PRINT,' '
+;
+ RETURN
+ END
+
diff --git a/Code/script_idl_mv/astrolib/fxbhmake.pro b/Code/script_idl_mv/astrolib/fxbhmake.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7d9ff316702841923e037fde7c95714e4df11bfa
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbhmake.pro
@@ -0,0 +1,150 @@
+ PRO FXBHMAKE,HEADER,NROWS,EXTNAME,COMMENT,DATE=DATE, $
+ INITIALIZE=INITIALIZE,EXTVER=EXTVER,EXTLEVEL=EXTLEVEL, $
+ ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBHMAKE
+; Purpose :
+; Create basic FITS binary table extension (BINTABLE) header.
+; Explanation :
+; Creates a basic header array with all the required keywords, but with
+; none of the table columns defined. This defines a basic structure
+; which can then be added to or modified by other routines.
+; Use :
+; FXBHMAKE, HEADER, NROWS [, EXTNAME [, COMMENT ]]
+; Inputs :
+; NROWS = Number of rows in the binary table.
+; Opt. Inputs :
+; EXTNAME = If passed, then the EXTNAME record is added with this value.
+; COMMENT = Comment to go along with EXTNAME.
+; Outputs :
+; HEADER = String array containing FITS extension header.
+; Opt. Outputs:
+; None.
+; Keywords :
+; INITIALIZE = If set, then the header is completely initialized, and any
+; previous entries are lost.
+; DATE = If set, then the DATE keyword is added to the header.
+; EXTVER = Extension version number (integer).
+; EXTLEVEL = Extension level number (integer).
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBHMAKE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; GET_DATE, FXADDPAR, FXHCLEAN
+; Common :
+; None.
+; Restrictions:
+; Warning: No checking is done of any of the parameters.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992.
+; William Thompson, Sep 1992, added EXTVER and EXTLEVEL keywords.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version :
+; Version 3, 23 June 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR,2
+;
+; Check the number of parameters first.
+;
+ IF N_PARAMS() LT 2 THEN BEGIN
+ MESSAGE = 'Calling sequence: FXBHMAKE, HEADER, NROWS ' + $
+ '[, EXTNAME [, COMMENT ]]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If requested, then initialize the header.
+;
+ IF KEYWORD_SET(INITIALIZE) THEN BEGIN
+ HEADER = STRARR(36)
+ HEADER[0] = 'END' + STRING(REPLICATE(32B,77))
+;
+; Else, if undefined, then initialize the header.
+;
+ END ELSE IF N_ELEMENTS(HEADER) EQ 0 THEN BEGIN
+ HEADER = STRARR(36)
+ HEADER[0] = 'END' + STRING(REPLICATE(32B,77))
+;
+; Otherwise, make sure that HEADER is a string array, and remove any keywords
+; that describe the format of the file.
+;
+ END ELSE BEGIN
+ SZ = SIZE(HEADER)
+ IF (SZ[0] NE 1) OR (SZ[2] NE 7) THEN BEGIN
+ MESSAGE = 'HEADER must be a (one-dimensional) ' + $
+ 'string array'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ FXHCLEAN,HEADER,ERRMSG=ERRMSG
+ IF ERRMSG EQ '' THEN RETURN
+ END ELSE FXHCLEAN,HEADER
+ ENDELSE
+;
+; Add the required keywords. Start out with a completely blank table, with no
+; columns.
+;
+ FXADDPAR,HEADER,'XTENSION','BINTABLE','Written by IDL: '+ SYSTIME()
+ FXADDPAR,HEADER,'BITPIX',8
+ FXADDPAR,HEADER,'NAXIS',2,'Binary table'
+ FXADDPAR,HEADER,'NAXIS1',0,'Number of bytes per row'
+ FXADDPAR,HEADER,'NAXIS2',LONG(NROWS),'Number of rows'
+ FXADDPAR,HEADER,'PCOUNT',0,'Random parameter count'
+ FXADDPAR,HEADER,'GCOUNT',1,'Group count'
+ FXADDPAR,HEADER,'TFIELDS',0,'Number of columns'
+;
+; If requested, add the EXTNAME keyword to the header.
+;
+ IF N_PARAMS() GE 3 THEN BEGIN
+ IF N_PARAMS() EQ 3 THEN COMMENT = 'Extension name'
+ FXADDPAR,HEADER,'EXTNAME',EXTNAME,COMMENT
+ ENDIF
+;
+; If requested, add the EXTVER keyword to the header.
+;
+ IF N_ELEMENTS(EXTVER) EQ 1 THEN $
+ FXADDPAR,HEADER,'EXTVER',LONG(EXTVER),'Extension version'
+;
+; If requested, add the EXTLEVEL keyword to the header.
+;
+ IF N_ELEMENTS(EXTLEVEL) EQ 1 THEN $
+ FXADDPAR,HEADER,'EXTLEVEL',LONG(EXTLEVEL),'Extension level'
+;
+; If requested, add the DATE keyword to the header, containing the current
+; date.
+;
+ IF KEYWORD_SET(DATE) THEN BEGIN
+ GET_DATE,DTE ;Get current date as CCYY-MM-DD
+ FXADDPAR,HEADER,'DATE',DTE,'Creation date'
+ ENDIF
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbintable.pro b/Code/script_idl_mv/astrolib/fxbintable.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f4791a2d5da790b1c483cd08651790e6f0582e13
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbintable.pro
@@ -0,0 +1,71 @@
+;+
+; NAME:
+; FXBINTABLE
+; Purpose :
+; Common block FXBINTABLE used by "FXB" routines.
+; Explanation :
+; This is not an IDL routine as such, but contains the definition of the
+; common block FXBINTABLE for inclusion into other routines. By defining
+; the common block in one place, the problem of conflicting definitions
+; is avoided.
+;
+; This file is included into routines that need this common block with
+; the single line (left justified)
+;
+; @fxbintable
+;
+; FXBINTABLE contains the following arrays:
+;
+; LUN = An array of logical unit numbers of currently (or
+; previously) opened binary table files.
+; STATE = Array containing the state of the FITS files
+; associated with the logical unit numbers, where
+; 0=closed, 1=open for read, and 2=open for write.
+; HEAD = FITS binary table headers.
+; MHEADER = Array containing the positions of the first data byte
+; of the header for each file referenced by array LUN.
+; NHEADER = Array containing the positions of the first data byte
+; after the header for each file referenced by array
+; LUN.
+; NAXIS1 = Values of NAXIS1 from the binary table headers.
+; NAXIS2 = Values of NAXIS2 from the binary table headers.
+; TFIELDS = Values of TFIELDS from the binary table headers.
+; HEAP = The start of the first byte of the heap area
+; for variable length arrays.
+; DHEAP = The start of the first byte of the next variable
+; length array, if writing.
+; BYTOFF = Byte offset from the beginning of the row for each
+; column in the binary table headers.
+; TTYPE = Values of TTYPE for each column in the binary table
+; headers.
+; FORMAT = Character code formats of the various columns.
+; IDLTYPE = IDL type code for each column in the binary table
+; headers.
+; N_ELEM = Number of elements for each column in the binary
+; table headers.
+; TSCAL = Scale factors for the individual columns.
+; TZERO = Zero offsets for the individual columns.
+; MAXVAL = For variable length arrays, contains the maximum
+; number of elements for each column in the binary
+; table headers.
+; N_DIMS = Number of dimensions, and array of dimensions for
+; each column of type string in the binary table
+; headers.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb 1992.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 July 1993.
+; Added DHEAP variable to fix bug with variable length arrays.
+; Version :
+; Version 2, 21 July 1993.
+;-
+;
+ COMMON FXBINTABLE,LUN,STATE,HEAD,MHEADER,NHEADER,NAXIS1,NAXIS2, $
+ TFIELDS,HEAP,DHEAP,BYTOFF,TTYPE,FORMAT,IDLTYPE,N_ELEM,TSCAL, $
+ TZERO,MAXVAL,N_DIMS
diff --git a/Code/script_idl_mv/astrolib/fxbisopen.pro b/Code/script_idl_mv/astrolib/fxbisopen.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ae5fca17b2eed8a05d4e6d0bfdbbbf4d9a613266
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbisopen.pro
@@ -0,0 +1,77 @@
+ FUNCTION FXBISOPEN,UNIT
+;+
+; NAME:
+; FXBISOPEN()
+;
+; PURPOSE:
+; Returns true if UNIT points to an open FITS binary table.
+;
+; Explanation : This procedure checks to see if the logical unit number given
+; by the variable UNIT corresponds to a FITS binary table opened
+; for read with the command FXBOPEN, and which has not yet been
+; closed with FXBCLOSE.
+;
+; Use : Result = FXBISOPEN(UNIT)
+;
+; If FXBISOPEN(UNIT) THEN ...
+;
+; Inputs : UNIT = Logical unit number returned by FXBOPEN routine.
+; Must be a scalar integer.
+;
+; Opt. Inputs : None.
+;
+; Outputs : The result of the function is either True (1) or False (0),
+; depending on whether UNIT points to an open binary table or
+; not.
+;
+; Opt. Outputs: None.
+;
+; Keywords : None.
+;
+; Calls : FXBFINDLUN
+;
+; Common : Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+;
+; Restrictions: None.
+;
+; Side effects: If UNIT is an undefined variable, then False (0) is returned.
+;
+; If UNIT points to a FITS binary table file that is opened for
+; write, then False (0) is returned.
+;
+; Category : Data Handling, I/O, FITS, Generic.
+;
+; Prev. Hist. : None.
+;
+; Written : William Thompson, GSFC, 1 July 1993.
+;
+; Modified : Version 1, William Thompson, GSFC, 1 July 1993.
+;
+; Version : Version 1, 1 July 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE,'Syntax: Result = FXBISOPEN(UNIT)'
+;
+; If UNIT is undefined, then return False.
+;
+ IF N_ELEMENTS(UNIT) EQ 0 THEN RETURN, 0
+;
+; Check the validity of UNIT.
+;
+ IF N_ELEMENTS(UNIT) GT 1 THEN MESSAGE,'UNIT must be a scalar'
+ SZ = SIZE(UNIT)
+ IF SZ[SZ[0]+1] GT 3 THEN MESSAGE,'UNIT must be an integer'
+;
+; Get the state associated with UNIT.
+;
+ ILUN = FXBFINDLUN(UNIT)
+ RETURN, STATE[ILUN] EQ 1
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbopen.pro b/Code/script_idl_mv/astrolib/fxbopen.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f3273776d82cafe9239614e5594c8dda4599816d
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbopen.pro
@@ -0,0 +1,350 @@
+ PRO FXBOPEN, UNIT, FILENAME0, EXTENSION, HEADER, NO_TDIM=NO_TDIM, $
+ ERRMSG=ERRMSG, ACCESS=ACCESS, REOPEN=REOPEN
+;+
+; NAME:
+; FXBOPEN
+; Purpose :
+; Open binary table extension in a disk FITS file for reading or updating
+; Explanation :
+; Opens a binary table extension in a disk FITS file for reading. The
+; columns are then read using FXBREAD, and the file is closed when done
+; with FXBCLOSE.
+; Use :
+; FXBOPEN, UNIT, FILENAME, EXTENSION [, HEADER ]
+; Inputs :
+; FILENAME = Name of FITS file to be opened. Optional
+; extension *number* may be specified, in either of
+; the following formats (using the FTOOLS
+; convention): FILENAME[EXT] or FILENAME+EXT, where
+; EXT is 1 or higher. Such an extension
+; specification takes priority over EXTENSION.
+;
+; EXTENSION = Either the number of the FITS extension, starting with the
+; first extension after the primary data unit being one; or a
+; character string containing the value of EXTNAME to search
+; for.
+; Opt. Inputs :
+; None.
+; Outputs :
+; UNIT = Logical unit number of the opened file.
+; Opt. Outputs:
+; HEADER = String array containing the FITS binary table extension
+; header.
+; Keywords :
+; NO_TDIM = If set, then any TDIMn keywords found in the header are
+; ignored.
+;
+; ACCESS = A scalar string describing access privileges as
+; one of READ ('R') or UPDATE ('RW').
+; DEFAULT: 'R'
+;
+; REOPEN = If set, UNIT must be an already-opened file unit.
+; FXBOPEN will treat the file as a FITS file.
+;
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBOPEN, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXBFINDLUN, FXBPARSE, FXHREAD, FXPAR
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The file must be a valid FITS file.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Feb 1992, based on READFITS by J. Woffard and W. Landsman.
+; W. Thompson, Feb 1992, changed from function to procedure.
+; W. Thompson, June 1992, fixed up error handling.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 27 May 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 21 June 1994
+; Extended ERRMSG to call to FXBPARSE
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, 23 June 1994
+;
+; Added ACCESS, REOPEN keywords, and FXFILTER package, CM 1999 Feb 03
+; Added FILENAME[EXT] and FILENAME+EXT extension parsing, CM 1999 Jun 28
+; Some general tidying, CM 1999 Nov 18
+; Allow for possible 64bit integer number of bytes W. Landsman Nov 2007
+; Make Ndata a 64bit integer to deal with larger files, E. Hivon, Mar 2008
+;
+;
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXBOPEN, UNIT, FILENAME, EXTENSION ' + $
+ '[, HEADER ]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Check the type of the EXTENSION parameter.
+;
+ IF N_ELEMENTS(EXTENSION) NE 1 THEN BEGIN
+ MESSAGE = 'EXTENSION must be a scalar'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ SZ = SIZE(EXTENSION)
+ ETYPE = SZ[SZ[0]+1]
+ IF ETYPE EQ 8 THEN BEGIN
+ MESSAGE = 'EXTENSION must not be a structure'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If EXTENSION is of type string, then search for the proper extension by
+; name. Otherwise, search by number.
+;
+ IF ETYPE EQ 7 THEN BEGIN
+ S_EXTENSION = STRTRIM(STRUPCASE(EXTENSION),2)
+ END ELSE BEGIN
+ I_EXTENSION = FIX(EXTENSION)
+ IF I_EXTENSION LT 1 THEN BEGIN
+ MESSAGE = 'EXTENSION must be greater than zero'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDELSE
+;
+; Check access parameter
+ IF N_ELEMENTS(ACCESS) EQ 0 THEN ACCESS='R'
+ SZ = SIZE(ACCESS)
+ IF SZ[SZ[0]+1] NE 7 THEN GOTO, ACCERR
+ IF STRUPCASE(ACCESS) NE 'R' AND STRUPCASE(ACCESS) NE 'RW' THEN BEGIN
+ ACCERR:
+ MESSAGE = "ACCESS must be either 'R' or 'RW'"
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Establish the read/write state
+;
+ ST = 1 ; Read only
+ IF STRUPCASE(ACCESS) EQ 'RW' THEN ST = 2 ; Read/write
+
+;
+; Get a logical unit number, and open the file.
+;
+ FILENAME = FILENAME0
+ IF NOT KEYWORD_SET(REOPEN) THEN BEGIN
+
+ ;; Check for extension name at the end of a filename
+ LEN = STRLEN(FILENAME0)
+ NEWEXT = 0L
+ BFILENAME = BYTE(FILENAME)
+ B0 = (BYTE('0'))(0) & B9 = (BYTE('9'))(0)
+ I = LEN-1
+ BB = BFILENAME[I]
+
+ ;; First case: FILENAME[5]
+ IF LEN GE 4 AND STRING(BB) EQ ']' THEN BEGIN ;; Count backwards
+ I = I - 1
+ IF BFILENAME[I] GE B0 AND BFILENAME[I] LE B9 THEN BEGIN
+ WHILE I GT 0 AND $
+ BFILENAME[I] GE B0 AND BFILENAME[I] LT B9 DO I = I - 1
+ IF I GT 0 AND STRING(BFILENAME[I]) EQ '[' THEN BEGIN
+ NEWEXT = LONG(STRMID(FILENAME,I+1,10))
+ FLEN = I
+ ENDIF
+ ENDIF
+ ENDIF
+
+ ;; Second case: FILENAME+5
+ IF LEN GE 3 AND BB GE B0 AND BB LE B9 THEN BEGIN ;; Count backwards
+ WHILE I GT 0 AND $
+ BFILENAME[I] GE B0 AND BFILENAME[I] LT B9 DO I = I - 1
+ IF I GT 0 AND STRING(BFILENAME[I]) EQ '+' THEN BEGIN
+ NEWEXT = LONG(STRMID(FILENAME,I+1,10))
+ FLEN = I
+ ENDIF
+ ENDIF
+ IF NEWEXT GT 0 THEN BEGIN
+ FILENAME = STRMID(FILENAME, 0, FLEN)
+ I_EXTENSION = NEWEXT
+ ETYPE = 1
+ ENDIF
+
+ ;; Open the file
+ IF ST EQ 1 THEN $
+ OPENR, UNIT, FILENAME, /BLOCK, /GET_LUN, ERROR=ERROR $
+ ELSE $
+ OPENU, UNIT, FILENAME, /BLOCK, /GET_LUN, ERROR=ERROR
+ IF ERROR NE 0 THEN GOTO, NO_SUCH_FILE
+ ENDIF
+
+;
+; Reopen the file if requested. Essentially this means seeking to
+; the start, after some error checking.
+;
+ IF KEYWORD_SET(REOPEN) THEN BEGIN
+ SZ = SIZE(UNIT)
+ IF N_ELEMENTS(UNIT) NE 1 OR SZ[SZ[0]+1] EQ 8 THEN BEGIN
+ MESSAGE = 'UNIT must be a scalar numeric type'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Error checking on file unit
+;
+ UNIT = UNIT[0]
+ FS = FSTAT(UNIT)
+ IF (FS.OPEN NE 1) OR (FS.READ NE 1) $
+ OR (ST EQ 2 AND FS.WRITE NE 1) THEN BEGIN
+ MESSAGE = 'UNIT '+strtrim(unit,2)+' must be open for reading'
+ IF ST EQ 2 THEN MESSAGE = MESSAGE + '/writing'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ ;; Seek to the start of the file
+ POINT_LUN, UNIT, 0L
+ ENDIF
+
+
+;
+; Store the UNIT number in the common block, and leave space for the other
+; parameters. Initialize the common block if need be. ILUN is an index into
+; the arrays.
+;
+ ILUN = FXBFINDLUN(UNIT)
+;
+; Mark the file as open for read or write.
+;
+ STATE[ILUN] = ST
+;
+; Read the primary header.
+;
+ FXHREAD,UNIT,HEADER,STATUS
+ IF STATUS NE 0 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Unable to read primary FITS header'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ I_EXT = 0
+;
+; Make sure that the file does contain extensions.
+;
+ START = 0L
+ IF NOT FXPAR(HEADER,'EXTEND', START=START) THEN BEGIN
+ FREE_LUN, UNIT
+ MESSAGE = 'File ' + FILENAME + ' does not contain extensions'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get the number of bytes taken up by the data.
+;
+NEXT_EXT:
+ BITPIX = FXPAR(HEADER,'BITPIX', START=START)
+ NAXIS = FXPAR(HEADER,'NAXIS', START=START)
+ GCOUNT = FXPAR(HEADER,'GCOUNT', START=START)
+ IF GCOUNT EQ 0 THEN GCOUNT = 1
+ PCOUNT = FXPAR(HEADER,'PCOUNT', START=START)
+ IF NAXIS GT 0 THEN BEGIN
+ DIMS = FXPAR(HEADER,'NAXIS*') ;Read dimensions
+ NDATA = long64(DIMS[0])
+ IF NAXIS GT 1 THEN FOR I=2,NAXIS DO NDATA = NDATA*DIMS[I-1]
+ ENDIF ELSE NDATA = 0
+ NBYTES = LONG64(ABS(BITPIX) / 8) * GCOUNT * (PCOUNT + NDATA)
+;
+; Read the next extension header in the file.
+;
+ NREC = (NBYTES + 2879) / 2880
+ POINT_LUN, -UNIT, POINTLUN ;Current position
+ MHEAD0 = POINTLUN + NREC*2880L
+ POINT_LUN, UNIT, MHEAD0 ;Next FITS extension
+ FXHREAD,UNIT,HEADER,STATUS
+ IF STATUS NE 0 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Requested extension not found'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ I_EXT = I_EXT + 1
+;
+; Check to see if the current extension is the one desired.
+;
+ START = 0L
+ IF ETYPE EQ 7 THEN BEGIN
+ EXTNAME = STRTRIM(STRUPCASE(FXPAR(HEADER,'EXTNAME', $
+ START=START)),2)
+ IF EXTNAME EQ S_EXTENSION THEN GOTO, DONE
+ END ELSE IF I_EXT EQ I_EXTENSION THEN GOTO, DONE
+ GOTO, NEXT_EXT
+;
+; Check to see if the extension type is BINTABLE or A3DTABLE.
+;
+DONE:
+ XTENSION = STRTRIM(STRUPCASE(FXPAR(HEADER,'XTENSION', START=START)),2)
+ IF (XTENSION NE 'BINTABLE') AND (XTENSION NE 'A3DTABLE') THEN BEGIN
+ IF ETYPE EQ 7 THEN EXT = S_EXTENSION ELSE EXT = I_EXTENSION
+ FREE_LUN,UNIT
+ MESSAGE = 'Extension ' + STRTRIM(EXT,2) + $
+ ' is not a binary table'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get the rest of the information, and store it in the common block.
+;
+ MHEADER[ILUN] = MHEAD0
+ FXBPARSE,ILUN,HEADER,NO_TDIM=NO_TDIM,ERRMSG=ERRMSG
+ RETURN
+;
+; Error point for not being able to open the file
+;
+NO_SUCH_FILE:
+ MESSAGE = 'Unable to open file ' + STRTRIM(FILENAME,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbparse.pro b/Code/script_idl_mv/astrolib/fxbparse.pro
new file mode 100644
index 0000000000000000000000000000000000000000..92601d50869682818292953193234b52641163df
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbparse.pro
@@ -0,0 +1,162 @@
+ PRO FXBPARSE, ILUN, HEADER, NO_TDIM=NO_TDIM, ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBPARSE
+; Purpose :
+; Parse the binary table extension header.
+; Explanation :
+; Parses the binary table extension header, and store the information
+; about the format of the binary table in the FXBINTABLE common
+; block--called from FXBCREATE and FXBOPEN.
+; Use :
+; FXBPARSE, ILUN, UNIT, HEADER
+; Inputs :
+; ILUN = Index into the arrays in the FXBINTABLE common block.
+; HEADER = FITS binary table extension header.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; NO_TDIM = If set, then any TDIMn keywords found in the header are
+; ignored.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBPARSE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXBFIND, FXBTDIM, FXBTFORM, FXPAR
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; None.
+; Side effects:
+; Any TDIMn keywords found for bit arrays (format 'X') are ignored, since
+; the dimensions would refer to bits, not bytes.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb. 1992.
+; William Thompson, Jan. 1993, modified for renamed FXBTFORM and FXBTDIM.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, Michael Schubnell, University of Michigan, 22 May 1996
+; Change N_DIMS from short to long integer.
+; Version 5, W. Landsman, GSFC, 12 Aug 1997
+; Use double complex datatype, if needed
+; Version 6, W. Landsman GSFC 30 Aug 1997
+; Optimized FXPAR; call FXBFIND for speed, CM 1999 Nov 18
+; Modify DHEAP(ILUN) when opening table now, CM 2000 Feb 22
+; Default the TZERO/TSCAL tables to double instead of single
+; precision floating point, CM 2003 Nov 23
+; Make NAXIS1 and NAXIS2 64-bit integers to deal with large files,
+; E. Hivon Mar 2008
+; Remove use of Obsolete !ERR system variable
+; Version
+; Version 8 April 2010
+;-
+;
+@fxbintable
+ ON_ERROR,2
+ COMPILE_OPT IDL2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN BEGIN
+ MESSAGE = 'Syntax: FXBPARSE, ILUN, HEADER'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Gather the necessary information, and store it in the common block.
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ FXBTFORM,HEADER,BYTOFF0,IDLTYPE0,FORMAT0,N_ELEM0,MAXVAL0, $
+ ERRMSG=ERRMSG
+ IF ERRMSG NE '' THEN RETURN
+ END ELSE FXBTFORM,HEADER,BYTOFF0,IDLTYPE0,FORMAT0,N_ELEM0,MAXVAL0
+;
+ FXBFIND,HEADER,'TTYPE',COLUMNS,TTYPE0,N_FOUND,''
+ FXBFIND,HEADER,'TSCAL',COLUMNS,TSCAL0,N_FOUND,1D
+ FXBFIND,HEADER,'TZERO',COLUMNS,TZERO0,N_FOUND,0D
+ POINT_LUN,-LUN[ILUN],NHEAD0
+;
+; Get the information from the required keywords.
+;
+ STORE_ARRAY,HEAD,HEADER,ILUN
+ NHEADER[ILUN] = NHEAD0
+ START = 0L
+ NAXIS1[ILUN] = long64(FXPAR(HEADER,'NAXIS1', START=START))
+ NAXIS2[ILUN] = long64(FXPAR(HEADER,'NAXIS2', START=START))
+ TFIELDS[ILUN] = FXPAR(HEADER,'TFIELDS', START=START)
+ PCOUNT = FXPAR(HEADER,'PCOUNT', START=START)
+;
+; If THEAP is not present, then set it equal to the size of the table.
+;
+ THEAP = FXPAR(HEADER,'THEAP', START=START, COUNT=N_THEAP)
+ IF N_THEAP LE 0 THEN THEAP = NAXIS1[ILUN]*NAXIS2[ILUN]
+ HEAP[ILUN] = THEAP
+;
+; Modify DHEAP
+;
+ DDHEAP = PCOUNT - (THEAP - NAXIS1[ILUN]*NAXIS2[ILUN])
+ IF DDHEAP GT 0 THEN DHEAP[ILUN] = DDHEAP ELSE DHEAP[ILUN] = 0
+;
+; Store the information about the columns.
+;
+ STORE_ARRAY,BYTOFF,BYTOFF0,ILUN
+ STORE_ARRAY,TTYPE,STRUPCASE(STRTRIM(TTYPE0,2)),ILUN
+ STORE_ARRAY,IDLTYPE,IDLTYPE0,ILUN
+ STORE_ARRAY,FORMAT,FORMAT0,ILUN
+ STORE_ARRAY,N_ELEM,N_ELEM0,ILUN
+ STORE_ARRAY,TSCAL,TSCAL0,ILUN
+ STORE_ARRAY,TZERO,TZERO0,ILUN
+ STORE_ARRAY,MAXVAL,MAXVAL0,ILUN
+ STORE_ARRAY,N_DIMS,LONARR(9,N_ELEMENTS(N_ELEM0)),ILUN
+;
+; If not a variable length array, then get the dimensions associated with each
+; column from the TDIMn keywords. If not found, then assume to be the number
+; of elements.
+;
+ FXBFIND,HEADER,'TDIM',COLUMNS,TDIMS,N_FOUND,''
+ FOR ICOL = 0,TFIELDS[ILUN]-1 DO IF MAXVAL[ICOL,ILUN] EQ 0 THEN BEGIN
+ TDIM = TDIMS[ICOL]
+ TDIM_USED = (TDIM NE '') AND (NOT KEYWORD_SET(NO_TDIM))
+ IF TDIM_USED THEN DIMS = FIX(FXBTDIM(TDIM)) $
+ ELSE DIMS = N_ELEM[ICOL,ILUN]
+ DIMS = [N_ELEMENTS(DIMS),DIMS]
+;
+; If the datatype is a bit array, then no dimensions are applied to the data.
+;
+ IF FORMAT[ICOL,ILUN] EQ 'X' THEN DIMS = [1,N_ELEM[ICOL,ILUN]]
+ N_DIMS[0,ICOL,ILUN] = DIMS
+;
+; For those columns which are character strings, then the number of
+; characters, N_CHAR, is the first dimension, and the number of elements is
+; actually N_ELEM/N_CHAR.
+;
+ IF IDLTYPE[ICOL,ILUN] EQ 7 THEN $
+ N_ELEM[ICOL,ILUN] = N_ELEM[ICOL,ILUN] / DIMS[1]
+ ENDIF
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbread.pro b/Code/script_idl_mv/astrolib/fxbread.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a482f0e7a4953133d1836db7224a22eb9bc129fa
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbread.pro
@@ -0,0 +1,388 @@
+ PRO FXBREAD, UNIT, DATA, COL, ROW, NOSCALE=NOSCALE, VIRTUAL=VIR, $
+ DIMENSIONS=DIMS0, NANVALUE=NANVALUE, ERRMSG=ERRMSG, $
+ NOIEEE=NOIEEE
+;+
+; NAME:
+; FXBREAD
+; Purpose :
+; Read a data array from a disk FITS binary table file.
+; Explanation :
+; Each call to FXBREAD will read the data from one column and one row
+; from the FITS data file, which should already have been opened by
+; FXBOPEN. One needs to call this routine for every column and every row
+; in the binary table. FXBCLOSE will then close the FITS data file.
+; Use :
+; FXBREAD, UNIT, DATA, COL [, ROW ]
+; Inputs :
+; UNIT = Logical unit number corresponding to the file containing the
+; binary table.
+; COL = Column in the binary table to read data from, either as a
+; character string containing a column label (TTYPE), or as a
+; numerical column index starting from column one.
+; Opt. Inputs :
+; ROW = Either row number in the binary table to read data from,
+; starting from row one, or a two element array containing a
+; range of row numbers to read. If not passed, then the entire
+; column is read in.
+;
+; Row must be passed for variable length arrays.
+;
+; Outputs :
+; DATA = IDL data array to be read from the file.
+; Opt. Outputs:
+; None.
+; Keywords :
+; NOSCALE = If set, then the output data will not be scaled using the
+; optional TSCAL and TZERO keywords in the FITS header.
+; Default is to scale.
+; NOIEEE = If set, then the output data is not byte-swapped to
+; machine order. NOIEEE implies NOSCALE.
+; Default is to perform the byte-swap.
+; VIRTUAL = If set, and COL is passed as a name rather than a number,
+; then if the program can't find a column with that name, it
+; will then look for a keyword with that name in the header.
+; Such a keyword would then act as a "virtual column", with the
+; same value for every row.
+; DIMENSIONS = Vector array containing the dimensions to be used to read
+; in the data. Bypasses any dimensioning information stored in
+; the header. Ignored for bit arrays. If the data type is
+; double-precision complex, then an extra dimension of 2 is
+; prepended to the dimensions passed by the user.
+; NANVALUE= Value signalling data dropout. All points corresponding to
+; IEEE NaN (not-a-number) are converted to this number.
+; Ignored unless DATA is of type float, double-precision or
+; complex.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBREAD, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXPAR, WHERE_NEGZERO, WHERENAN
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The binary table file must have been opened with FXBOPEN.
+;
+; The data must be consistent with the column definition in the binary
+; table header.
+;
+; The row number must be consistent with the number of rows stored in the
+; binary table header.
+;
+; The number of elements implied by the dimensions keyword must not
+; exceed the number of elements stored in the file.
+;
+; Side effects:
+; If the DIMENSIONS keyword is used, then the number of data points read
+; in may be less than the number of points stored in the table.
+;
+; If there are no elements to read in (the number of elements is zero),
+; then the program sets !ERR to -1, and DATA is unmodified.
+;
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Jan 1992.
+; W. Thompson, Feb 1992, modified to support variable length arrays.
+; W. Thompson, Jun 1992, modified way that row ranges are read in. No
+; longer works reiteratively.
+; W. Thompson, Jun 1992, fixed bug where NANVALUE would be modified by
+; TSCAL and TZERO keywords.
+; W. Thompson, Jun 1992, fixed bug when reading character strings.
+; Treats dimensions better when reading multiple
+; rows.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 30 June 1993.
+; Added overwrite keyword to REFORM call to speed up.
+; Version 3, William Thompson, GSFC, 21 July 1993.
+; Fixed bug with variable length arrays.
+; Version 4, William Thompson, GSFC, 29 October 1993.
+; Added error message for not finding column by name.
+; Version 5, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 6, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 7, William Thompson, GSFC, 29 December 1994
+; Fixed bug where single element dimensions were lost.
+; Version 8, William Thompson, GSFC, 20 March 1995
+; Fixed bug introduced in version 7.
+; Version 9, Wayne Landsman, GSFC, 3 July 1996
+; Fixed bug involving use of virtual keyword.
+; Version 10, William Thompson, GSFC, 31-Jan-1997
+; Added call to WHERE_NEGZERO.
+; Version 11, Wayne Landsman, GSFC, 12 Aug, 1997
+; Use IDL dcomplex datatype if needed
+; Version 12, Wayne Landmsan, GSFC, 20 Feb, 1998
+; Remove call to WHERE_NEGZERO (now part of IEEE_TO_HOST)
+; Version 13, 18 Nov 1999, CM, Add NOIEEE keyword
+; Version 14, 21 Aug 2000, William Thompson, GSFC
+; Catch I/O errors
+; Version 15, W. Landsman GSFC 10 Dec 2009
+; Fix Dimension keyword, remove IEEE_TO_HOST
+; Version 16, William Thompson, 18-May-2016, change POINTER to ULONG
+; Version :
+; Version 16, 18-May-2016
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+ ON_IOERROR, HANDLE_IO_ERROR
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = 'Syntax: FXBREAD, UNIT, DATA, COL [, ROW ]'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Find the logical unit number in the FXBINTABLE common block.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + ' not opened properly'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; If COL is of type string, then search for a column with that label.
+;
+ SC = SIZE(COL)
+ VIRTUAL = 0
+ IF SC[SC[0]+1] EQ 7 THEN BEGIN
+ SCOL = STRUPCASE(STRTRIM(COL,2))
+ ICOL = WHERE(TTYPE[*,ILUN] EQ SCOL, NCOL)
+ ICOL = ICOL[0]
+ IF (ICOL LT 0) AND (NOT KEYWORD_SET(VIR)) THEN BEGIN
+ MESSAGE = 'Column "' + SCOL + '" not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; If the column was not found, and VIRTUAL was set, then search for a keyword
+; by that name.
+;
+ IF NCOL EQ 0 THEN BEGIN
+ IF KEYWORD_SET(VIR) THEN BEGIN
+ HEADER = HEAD[*,ILUN]
+ VALUE = FXPAR(HEADER,SCOL,COUNT=CC)
+ IF CC GT 0 THEN BEGIN
+ DATA = VALUE
+ VIRTUAL = 1
+ GOTO, CHECK_ROW
+ ENDIF
+ ENDIF
+ MESSAGE = 'Column "' + SCOL + '" not found'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Otherwise, a numerical column was passed. Check its value.
+;
+ END ELSE ICOL = LONG(COL) - 1
+ IF (ICOL LT 0) OR (ICOL GE TFIELDS[ILUN]) THEN BEGIN
+ MESSAGE = 'COL must be between 1 and ' + $
+ STRTRIM(TFIELDS[ILUN],2)
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; If there are no elements in the array, then set !ERR to -1.
+;
+ IF N_ELEM[ICOL,ILUN] EQ 0 THEN BEGIN
+ MESSAGE,'Number of elements to read in is zero',/INFORMATIONAL
+ !ERR = -1
+ RETURN
+ ENDIF
+;
+; If ROW was not passed, then set it equal to the entire range. Otherwise,
+; extract the range.
+;
+CHECK_ROW:
+ IF N_PARAMS() EQ 3 THEN ROW = [1,NAXIS2[ILUN]]
+ CASE N_ELEMENTS(ROW) OF
+ 1: ROW2 = LONG(ROW[0])
+ 2: ROW2 = LONG(ROW[1])
+ ELSE: BEGIN
+ MESSAGE = 'ROW must have one or two elements'
+ GOTO, HANDLE_ERROR
+ END
+ ENDCASE
+ ROW1 = LONG(ROW[0])
+;
+; If ROW represents a range, then make sure that the row range is legal, and
+; that reading row ranges is allowed (i.e., the column is not variable length.
+;
+ IF ROW1 NE ROW2 THEN BEGIN
+ MAXROW = NAXIS2[ILUN]
+ IF (ROW1 LT 1) OR (ROW1 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[0] must be between 1 and ' + $
+ STRTRIM(MAXROW,2)
+ GOTO, HANDLE_ERROR
+ END ELSE IF (ROW2 LT ROW1) OR (ROW2 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[1] must be between ' + $
+ STRTRIM(ROW1,2) + ' and ' + STRTRIM(MAXROW,2)
+ GOTO, HANDLE_ERROR
+ END ELSE IF NOT VIRTUAL THEN IF MAXVAL[ICOL,ILUN] GT 0 THEN $
+ BEGIN
+ MESSAGE = 'Row ranges not allowed for ' + $
+ 'variable-length columns'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Otherwise, if ROW is a single number, then just make sure it's valid.
+;
+ END ELSE BEGIN
+ IF (ROW1 LT 1) OR (ROW1 GT NAXIS2[ILUN]) THEN BEGIN
+ MESSAGE = 'ROW must be between 1 and ' + $
+ STRTRIM(NAXIS2[ILUN],2)
+ GOTO, HANDLE_ERROR
+ ENDIF
+ ENDELSE
+;
+; If a virtual column, then simply return the value. If necessary, then
+; replicate the value the correct number of times.
+;
+ IF VIRTUAL THEN BEGIN
+ IF ROW1 EQ ROW2 THEN DATA = VALUE ELSE $
+ DATA = REPLICATE(VALUE,ROW2-ROW1+1)
+ RETURN
+ ENDIF
+;
+; Find the position of the first byte of the data array in the file.
+;
+ OFFSET = NHEADER[ILUN] + NAXIS1[ILUN]*(ROW1-1) + BYTOFF[ICOL,ILUN]
+ POINT_LUN,UNIT,OFFSET
+;
+; If a variable length array, then read in the number of elements, and the
+; pointer to the variable length array. Change the pointing.
+;
+ IF MAXVAL[ICOL,ILUN] GT 0 THEN BEGIN
+ POINTER = ULONARR(2)
+ READU,UNIT,POINTER
+ BYTEORDER, POINTER, /NTOHL
+ DIMS = POINTER[0]
+ POINT_LUN,UNIT,NHEADER[ILUN] + HEAP[ILUN] + POINTER[1]
+;
+; If there are no elements in the array, then set !ERR to -1.
+;
+ IF DIMS EQ 0 THEN BEGIN
+ MESSAGE,'Number of elements to read in is zero', $
+ /INFORMATIONAL
+ !ERR = -1
+ RETURN
+ ENDIF
+;
+; If the datatype is a bit array, then the array is treated as a byte array
+; with 1/8 the number of elements.
+;
+ IF FORMAT[ICOL,ILUN] EQ 'X' THEN DIMS = LONG((DIMS+7)/8)
+;
+; If fixed length, then get the dimensions of the output array.
+;
+ END ELSE BEGIN
+ DIMS = N_DIMS[*,ICOL,ILUN]
+ DIMS = DIMS[1:DIMS[0]]
+ ENDELSE
+;
+; If the DIMENSIONS keyword has been passed, then use that instead of the
+; dimensions already determined.
+;
+ IF (N_ELEMENTS(DIMS0) GT 0) AND (FORMAT[ICOL,ILUN] NE 'X') $
+ THEN BEGIN
+ IF PRODUCT(DIMS0) GT PRODUCT(DIMS) THEN BEGIN
+ MESSAGE = 'Requested dimensions exceeds the ' + $
+ 'number of elements'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ DIMS = DIMS0
+ ENDIF
+;
+; Read in the data. If a character string array, then read in a byte array.
+;
+ DATATYPE = IDLTYPE[ICOL,ILUN]
+ IF DATATYPE EQ 7 THEN DATATYPE = 1
+;
+; If only reading in a single row, then the pointer should already be set.
+; Otherwise, the pointer needs to be set for each row.
+;
+ IF ROW1 EQ ROW2 THEN BEGIN
+ DATA = MAKE_ARRAY(TYPE=DATATYPE,DIMENSION=DIMS)
+ DATA = REFORM(DATA,DIMS,/OVERWRITE)
+ READU,UNIT,DATA
+ END ELSE BEGIN
+ DIMS2 = [DIMS, ROW2-ROW1+1]
+ DATA = MAKE_ARRAY(TYPE=DATATYPE, DIMENSION=DIMS2)
+ DATA = REFORM(DATA, DIMS2, /OVERWRITE)
+ TEMPDATA = MAKE_ARRAY(TYPE=DATATYPE, DIMENSION=DIMS)
+ TEMPDATA = REFORM(TEMPDATA, DIMS, /OVERWRITE)
+ NTEMP = N_ELEMENTS(TEMPDATA)
+ FOR IROW = ROW1,ROW2 DO BEGIN
+ OFFSET = NHEADER[ILUN] + BYTOFF[ICOL,ILUN]
+ POINT_LUN,UNIT,OFFSET + NAXIS1[ILUN]*(IROW-1)
+ READU,UNIT,TEMPDATA
+ DATA[(IROW-ROW1)*NTEMP] = TEMPDATA[*]
+ ENDFOR
+ ENDELSE
+;
+; If a character string array, then convert to type string.
+;
+ IF IDLTYPE[ICOL,ILUN] EQ 7 THEN BEGIN
+ DATA = STRING(DATA)
+ COUNT = 0
+;
+; Otherwise, if necessary, then convert the data to the native format of the
+; host machine. Also, if NANVALUE is passed, then keep track of any IEEE NaN
+; values.
+;
+ END ELSE IF IDLTYPE[ICOL,ILUN] NE 1 THEN BEGIN
+ IF (N_ELEMENTS(NANVALUE) EQ 1) AND (IDLTYPE[ICOL,ILUN] GE 4) $
+ AND (IDLTYPE[ICOL,ILUN] LE 6) THEN $
+ W = WHERENAN(DATA,COUNT) ELSE COUNT = 0
+ IF NOT KEYWORD_SET(NOIEEE) THEN $
+ SWAP_ENDIAN_INPLACE,DATA,/SWAP_IF_LITTLE
+ END ELSE COUNT = 0
+;
+; If DIMS is simply the number 1, then convert DATA either to a scalar or to a
+; simple vector, depending on how many rows were read in.
+;
+ IF (N_ELEMENTS(DIMS) EQ 1) AND (DIMS[0] EQ 1) THEN BEGIN
+ IF N_ELEMENTS(DATA) EQ 1 THEN DATA = DATA[0] ELSE $
+ DATA = REFORM(DATA,ROW2-ROW1+1,/OVERWRITE)
+ ENDIF
+;
+; If the parameters TZERO and TSCAL are non-trivial, then adjust the array by
+; these values.
+;
+ IF NOT KEYWORD_SET(NOSCALE) AND NOT KEYWORD_SET(NOIEEE) THEN BEGIN
+ BZERO = TZERO[ICOL,ILUN]
+ BSCALE = TSCAL[ICOL,ILUN]
+ IF (BSCALE NE 0) AND (BSCALE NE 1) THEN DATA *= BSCALE
+ IF BZERO NE 0 THEN DATA += BZERO
+ ENDIF
+;
+; Store NANVALUE everywhere where the data corresponded to IEE NaN.
+;
+ IF COUNT GT 0 THEN DATA[W] = NANVALUE
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+;
+; I/O error handling point.
+;
+HANDLE_IO_ERROR:
+ MESSAGE = 'I/O error reading file'
+;
+; Error handling point.
+;
+HANDLE_ERROR:
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = MESSAGE ELSE MESSAGE, MESSAGE
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbreadm.pro b/Code/script_idl_mv/astrolib/fxbreadm.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cf70a8dacf1c94a43c8acf686cee9059b01cb111
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbreadm.pro
@@ -0,0 +1,905 @@
+;+
+; NAME:
+; FXBREADM
+; PURPOSE:
+; Read multiple columns/rows from a disk FITS binary table file.
+; EXPLANATION :
+; A call to FXBREADM will read data from multiple rows and
+; multiple columns in a single procedure call. Up to forty-nine
+; columns may be read in a single pass; the number of rows is
+; limited essentially by available memory. The file should have
+; already been opened with FXBOPEN. FXBREADM optimizes reading
+; multiple columns by first reading a large chunk of data from
+; the FITS file directly, and then slicing the data into columns
+; within memory. FXBREADM can read variable-length arrays (see
+; below).
+;
+; The number of columns is limited to 49 if data are passed by
+; positional argument. However, this limitation can be overcome
+; by having FXBREADM return the data in an array of pointers.
+; The user should set the PASS_METHOD keyword to 'POINTER', and an
+; array of pointers to the data will be returned in the POINTERS keyword.
+; The user is responsible for freeing the pointers; however,
+; FXBREADM will reuse any pointers passed into the procedure, and
+; hence any pointed-to data will be destroyed.
+;
+; FXBREADM can also read variable-length columns from FITS
+; binary tables. Since such data is not of a fixed size, it is
+; returned as a structure. The structure has the following
+; elements:
+;
+; VARICOL: ;; Flag: variable length column (= 1)
+; N_ELEMENTS: ;; Total number of elements returned
+; TYPE: ;; IDL data type code (integer)
+; N_ROWS: ;; Number of rows read from table (integer)
+; INDICES: ;; Indices of each row's data (integer array)
+; DATA: ;; Raw data elements (variable type array)
+;
+; In order to gain access to the Ith row's data, one should
+; examine DATA(INDICES(I):INDICES(I+1)-1), which is similar in
+; construct to the REVERSE_INDICES keyword of the HISTOGRAM
+; function.
+;
+; CALLING SEQUENCE:
+; FXBREADM, UNIT, COL, DATA1, [ DATA2, ... DATA48, ROW=, BUFFERSIZE = ]
+; /NOIEEE, /NOSCALE, /VIRTUAL, NANVALUE=, PASS_METHOD = POINTERS=,
+; ERRMSG = , WARNMSG = , STATUS = , /DEFAULT_FLOAT]
+;
+; INPUT PARAMETERS :
+; UNIT = Logical unit number corresponding to the file containing the
+; binary table.
+; COL = An array of columns in the binary table to read data
+; from, either as character strings containing column
+; labels (TTYPE), or as numerical column indices
+; starting from column one.
+; Outputs :
+; DATA1, DATA2...DATA48 = A named variable to accept the data values, one
+; for each column. The columns are stored in order of the
+; list in COL. If the read operation fails for a
+; particular column, then the corresponding output Dn
+; variable is not altered. See the STATUS keyword.
+; Ignored if PASS_METHOD is 'POINTER'.
+;
+; OPTIONAL INPUT KEYWORDS:
+; ROW = Either row number in the binary table to read data from,
+; starting from row one, or a two element array containing a
+; range of row numbers to read. If not passed, then the entire
+; column is read in.
+; /DEFAULT_FLOAT = If set, then scaling with TSCAL/TZERO is done with
+; floating point rather than double precision.
+; /NOIEEE = If set, then then IEEE floating point data will not
+; be converted to the host floating point format (and
+; this by definition implies NOSCALE). The user is
+; responsible for their own floating point conversion.
+; /NOSCALE = If set, then the output data will not be scaled using the
+; optional TSCAL and TZERO keywords in the FITS header.
+; Default is to scale.
+; VIRTUAL = If set, and COL is passed as a name rather than a number,
+; then if the program can't find a column with that name, it
+; will then look for a keyword with that name in the header.
+; Such a keyword would then act as a "virtual column", with the
+; same value for every row.
+; DIMENSIONS = FXBREADM ignores this keyword. It is here for
+; compatibility only.
+; NANVALUE= Value signalling data dropout. All points corresponding to
+; IEEE NaN (not-a-number) are converted to this number.
+; Ignored unless DATA is of type float, double-precision or
+; complex.
+; PASS_METHOD = A scalar string indicating method of passing
+; data from FXBREADM. Either 'ARGUMENT' (indicating
+; pass by positional argument), or 'POINTER' (indicating
+; passing an array of pointers by the POINTERS
+; keyword).
+; Default: 'ARGUMENT'
+; POINTERS = If PASS_METHOD is 'POINTER' then an array of IDL
+; pointers is returned in this keyword, one for each
+; requested column. Any pointers passed into FXBREADM will
+; have their pointed-to data destroyed. Ultimately the
+; user is responsible for deallocating pointers.
+; BUFFERSIZE = Raw data are transferred from the file in chunks
+; to conserve memory. This is the size in bytes of
+; each chunk. If a value of zero is given, then all
+; of the data are transferred in one pass. Default is
+; 32768 (32 kB).
+; OPTIONAL OUTPUT KEYWORDS:
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBREAD, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+; WARNMSG = Messages which are considered to be non-fatal
+; "warnings" are returned in this output string.
+; Note that if some but not all columns are
+; unreadable, this is considered to be non-fatal.
+; STATUS = An output array containing the status for each
+; column read, 1 meaning success and 0 meaning failure.
+;
+; Calls :
+; FXPAR(), WHERENAN()
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The binary table file must have been opened with FXBOPEN.
+;
+; The data must be consistent with the column definition in the binary
+; table header.
+;
+; The row number must be consistent with the number of rows stored in the
+; binary table header.
+;
+; Generally speaking, FXBREADM will be faster than iterative
+; calls to FXBREAD when (a) a large number of columns is to be
+; read or (b) the size in bytes of each cell is small, so that
+; the overhead of the FOR loop in FXBREAD becomes significant.
+;
+; SIDE EFFECTS:
+; If there are no elements to read in (the number of elements is zero),
+; then the program sets !ERR to -1, and DATA is unmodified.
+;
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; C. Markwardt, based in concept on FXBREAD version 12 from
+; IDLASTRO, but with significant and
+; major changes to accommodate the
+; multiple row/column technique. Mostly
+; the parameter checking and general data
+; flow remain.
+; C. Markwardt, updated to read variable length arrays, and to
+; pass columns by handle or pointer.
+; 20 Jun 2001
+; C. Markwardt, try to conserve memory when creating the arrays
+; 13 Oct 2001
+; Handle case of GE 50 columns, C. Markwardt, 18 Apr 2002
+; Handle case where TSCAL/TZERO changes type of column,
+; C. Markwardt, 23 Feb 2003
+; Fix bug in handling of FOUND and numeric columns,
+; C. Markwardt 12 May 2003
+; Removed pre-V5.0 HANDLE options W. Landsman July 2004
+; Fix bug when HANDLE options were removed, July 2004
+; Handle special cases of TSCAL/TZERO which emulate unsigned
+; integers, Oct 2003
+; Add DEFAULT_FLOAT keyword to select float values instead of double
+; for TSCAL'ed, June 2004
+; Read 64bit integer columns, E. Hivon, Mar 2008
+; Add support for columns with TNULLn keywords, C. Markwardt, Apr 2010
+; Add support for files larger than 2 GB, C. Markwardt, 2012-04-17
+; Use V6 notation, remove IEEE_TO_HOST W. Landsman Mar 2014
+;
+;-
+;
+
+
+;; This is a utility routine which converts the data from raw bytes to
+;; IDL variables.
+PRO FXBREADM_CONV, BB, DD, CTYPE, PERROW, NROWS, $
+ NOIEEE=NOIEEE, NOSCALE=NOSCALE, VARICOL=VARICOL, $
+ NANVALUE=NANVALUE, TZERO=TZERO, TSCAL=TSCAL, $
+ TNULL_VALUE=TNULL, TNULL_FLAG=TNULLQ, $
+ DEFAULT_FLOAT=DF
+
+ COMMON FXBREADM_CONV_COMMON, DTYPENAMES
+ IF N_ELEMENTS(DTYPENAMES) EQ 0 THEN $
+ DTYPENAMES = [ '__BAD', 'BYTE', 'FIX', 'LONG', $
+ 'FLOAT', 'DOUBLE', 'COMPLEX', 'STRING', $
+ '__BAD', 'DCOMPLEX', '__BAD', '__BAD', '__BAD', '__BAD', 'LONG64' ]
+
+ TYPENAME = DTYPENAMES[CTYPE]
+
+ IF CTYPE EQ 7 THEN BEGIN
+ DD = STRING(TEMPORARY(BB))
+ ENDIF ELSE BEGIN
+ DD = CALL_FUNCTION(TYPENAME, TEMPORARY(BB), 0, PERROW*NROWS)
+ ENDELSE
+ IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD]
+ DD = REFORM(DD, PERROW, NROWS, /OVERWRITE)
+
+ ;; Now perform any type-specific conversions, etc.
+ COUNT = 0L
+ CASE 1 OF
+ ;; Integer types
+ (CTYPE EQ 2 || CTYPE EQ 3 || ctype eq 14): BEGIN
+ IF ~KEYWORD_SET(NOIEEE) || KEYWORD_SET(VARICOL) THEN $
+ SWAP_ENDIAN_INPLACE, DD, /SWAP_IF_LITTLE
+ ;; Check for TNULL values
+ ;; We will convert to NAN values later (or if the user
+ ;; requested a different value we will use that)
+ IF KEYWORD_SET(TNULLQ) THEN BEGIN
+ W = WHERE(DD EQ TNULL,COUNT)
+ IF N_ELEMENTS(NANVALUE) EQ 0 THEN NANVALUE = !VALUES.D_NAN
+ ENDIF
+ END
+
+ ;; Floating and complex types
+ (CTYPE GE 4 || CTYPE LE 6 || CTYPE EQ 9): BEGIN
+ IF ~KEYWORD_SET(NOIEEE) THEN BEGIN
+ IF N_ELEMENTS(NANVALUE) GT 0 THEN W=WHERENAN(DD,COUNT)
+ SWAP_ENDIAN_INPLACE, DD, /SWAP_IF_LITTLE
+ ENDIF
+ END
+
+ ;; String types (CTYPE EQ 7) have already been converted
+ ;; in the above CALL_FUNCTION. No further conversion
+ ;; is necessary here.
+ ENDCASE
+
+;
+; If the parameters TZERO and TSCAL are non-trivial, then adjust the array by
+; these values.
+;
+ IF ((~KEYWORD_SET(NOIEEE) && ~KEYWORD_SET(NOSCALE)) && $
+ (~KEYWORD_SET(VARICOL)) && $
+ (N_ELEMENTS(TZERO) EQ 1 && N_ELEMENTS(TSCAL) EQ 1)) THEN BEGIN
+
+ IF KEYWORD_SET(DF) THEN BEGIN
+ ;; Default to float
+ TSCAL = FLOAT(TSCAL)
+ TZERO = FLOAT(TZERO)
+ ENDIF
+
+ IF CTYPE EQ 2 AND TSCAL[0] EQ 1 AND TZERO[0] EQ 32768 THEN BEGIN
+ ;; SPECIAL CASE: Unsigned 16-bit integer
+ DD = UINT(DD) - UINT(32768)
+ ENDIF ELSE IF CTYPE EQ 3 AND TSCAL[0] EQ 1 AND $
+ TZERO[0] EQ 2147483648D THEN BEGIN
+ ;; SPECIAL CASE: Unsigned 32-bit integer
+ DD = ULONG(DD) - ULONG(2147483648)
+ ENDIF ELSE BEGIN
+ IF (TSCAL[0] NE 0) && (TSCAL[0] NE 1) THEN DD = TSCAL[0]*DD
+ IF TZERO[0] NE 0 THEN DD = DD + TZERO[0]
+ ENDELSE
+ ENDIF
+
+;
+; Store NANVALUE everywhere where the data corresponded to IEEE NaN.
+;
+ IF COUNT GT 0 && N_ELEMENTS(NANVALUE) GT 0 THEN DD[W] = NANVALUE
+
+END
+
+PRO FXBREADM, UNIT, COL, $
+ D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, $
+ D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, $
+ D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, $
+ D30, D31, D32, D33, D34, D35, D36, D37, D38, D39, $
+ D40, D41, D42, D43, D44, D45, D46, D47, $
+ ROW=ROW, VIRTUAL=VIR, DIMENSIONS=DIM, $
+ NOSCALE=NOSCALE, NOIEEE=NOIEEE, DEFAULT_FLOAT=DEFAULT_FLOAT, $
+ PASS_METHOD=PASS_METHOD, POINTERS=POINTERS, $
+ NANVALUE=NANVALUE, BUFFERSIZE=BUFFERSIZE, $
+ ERRMSG=ERRMSG, WARNMSG=WARNMSG, STATUS=OUTSTATUS
+
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 2 THEN BEGIN
+ MESSAGE = 'Syntax: FXBREADM, UNIT, COL, D0, D1, ... [, ROW= ]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_ELEMENTS(BUFFERSIZE) EQ 0 THEN BUFFERSIZE = 32768L
+
+;
+; COL may be one of several descriptors:
+; * a list of column numbers, beginning with 1
+; * a list of column names
+;
+ MYCOL = [ COL ] ; Make sure it is an array
+
+ SC = SIZE(MYCOL)
+ NUMCOLS = N_ELEMENTS(MYCOL)
+ OUTSTATUS = LONARR(NUMCOLS)
+ COLNAMES = 'D'+STRTRIM(LINDGEN(NUMCOLS),2)
+
+;
+; Determine whether the data is to be extracted as pointers or arguments
+;
+ IF N_ELEMENTS(PASS_METHOD) EQ 0 THEN PASS_METHOD = 'ARGUMENT'
+ PASS = STRUPCASE(STRTRIM(PASS_METHOD[0],2))
+ IF PASS NE 'ARGUMENT' AND PASS NE 'POINTER' THEN BEGIN
+ MESSAGE = 'ERROR: PASS_METHOD must be ARGUMENT or POINTER'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ NP = N_ELEMENTS(POINTERS)
+ IF PASS EQ 'POINTER' THEN BEGIN
+ IF NP EQ 0 THEN POINTERS = PTRARR(NUMCOLS, /ALLOCATE_HEAP)
+ NP = N_ELEMENTS(POINTERS)
+ SZ = SIZE(POINTERS)
+ IF SZ[SZ[0]+1] NE 10 THEN BEGIN
+ MESSAGE = 'ERROR: POINTERS must be an array of pointers'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Expand the pointer array if necessary
+;
+ IF NP LT NUMCOLS THEN $
+ POINTERS = [POINTERS[*], PTRARR(NUMCOLS-NP, /ALLOCATE_HEAP)]
+ NP = N_ELEMENTS(POINTERS)
+
+;
+; Make sure there are no null pointers, which cannot be assigned to.
+;
+ WH = WHERE(PTR_VALID(POINTERS) EQ 0, CT)
+ IF CT GT 0 THEN POINTERS[WH] = PTRARR(CT, /ALLOCATE_HEAP)
+
+ ENDIF
+
+
+;
+; Find the logical unit number in the FXBINTABLE common block.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Check the number of columns. It should be fewer than 49
+;
+ IF PASS EQ 'ARGUMENT' THEN BEGIN
+ IF NUMCOLS GT 49 THEN BEGIN
+ MESSAGE = 'Maximum of 49 columns exceeded'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_PARAMS()-2 LT NUMCOLS AND N_ELEMENTS(ERRMSG) EQ 0 THEN BEGIN
+ MESSAGE, 'WARNING: number of data parameters less than columns', $
+ /INFO
+ ENDIF
+ ENDIF
+
+ ICOL = LONARR(NUMCOLS)
+ VIRTUAL = BYTARR(NUMCOLS)
+ VIRTYPE = LONARR(NUMCOLS)
+ FOUND = BYTARR(NUMCOLS)
+ VARICOL = BYTARR(NUMCOLS)
+ NOTFOUND = ''
+ NNOTFOUND = 0L
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = ''
+
+;
+; If COL is of type string, then search for a column with that label.
+;
+ IF SC[SC[0]+1] EQ 7 THEN BEGIN
+ MYCOL = STRUPCASE(STRTRIM(MYCOL,2))
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ XCOL = WHERE(TTYPE[*,ILUN] EQ MYCOL[I], NCOL)
+ ICOL[I] = XCOL[0]
+;
+; If the column was not found, and VIRTUAL was set, then search for a keyword
+; by that name.
+;
+ IF NCOL GT 0 THEN FOUND[I] = 1
+ IF NOT FOUND[I] AND KEYWORD_SET(VIR) THEN BEGIN
+ HEADER = HEAD[*,ILUN]
+ VALUE = FXPAR(HEADER,MYCOL[I], Count = N_VALUE)
+ IF N_VALUE GE 0 THEN BEGIN
+ RESULT = EXECUTE(COLNAMES[I]+' = VALUE')
+ SV = SIZE(VALUE)
+ VIRTYPE[I] = SV[SV[0]+1]
+ VIRTUAL[I] = 1
+ FOUND[I] = 1
+ ENDIF
+ ENDIF ELSE IF ~FOUND[I] THEN BEGIN
+ IF NOTFOUND EQ '' THEN NOTFOUND = MYCOL[I] $
+ ELSE NOTFOUND = NOTFOUND +', ' + MYCOL[I]
+ NNOTFOUND++
+ ENDIF
+
+ ENDFOR
+
+ IF NNOTFOUND EQ NUMCOLS THEN BEGIN
+ MESSAGE = 'ERROR: None of the requested columns were found'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF ELSE IF NNOTFOUND GT 0 THEN BEGIN
+ MESSAGE = 'WARNING: Columns ' + NOTFOUND + ' were not found'
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = MESSAGE $
+ ELSE MESSAGE, MESSAGE, /INFO
+ ENDIF
+
+;
+; Otherwise, a numerical column was passed. Check its value.
+;
+ ENDIF ELSE BEGIN
+ ICOL[*] = LONG(MYCOL) - 1
+ FOUND[*] = 1
+ ENDELSE
+
+; Step through each column index
+ MESSAGE = ''
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ IF ~FOUND[I] THEN GOTO, LOOP_END_COLCHECK
+ IF VIRTUAL[I] THEN GOTO, LOOP_END_COLCHECK
+
+ IF (ICOL[I] LT 0) OR (ICOL[I] GE TFIELDS[ILUN]) THEN BEGIN
+ MESSAGE = MESSAGE + '; COL "'+STRTRIM(MYCOL[I],2)+$
+ '" must be between 1 and ' + $
+ STRTRIM(TFIELDS[ILUN],2)
+ FOUND[I] = 0
+ ENDIF
+;
+; If there are no elements in the array, then set !ERR to -1.
+;
+ IF FOUND[I] AND N_ELEM[ICOL[I],ILUN] EQ 0 THEN BEGIN
+ FOUND[I] = 0
+ MESSAGE = MESSAGE + '; Number of elements to read in "'+$
+ STRTRIM(MYCOL[I],2)+'" is zero'
+; !ERR = -1
+; RETURN
+ ENDIF
+
+;
+; Flag variable-length columns
+;
+ IF MAXVAL[ICOL[I],ILUN] GT 0 THEN BEGIN
+ FOUND[I] = 1
+ VARICOL[I] = 1
+ ENDIF
+
+ LOOP_END_COLCHECK:
+
+ ENDFOR
+
+;
+; Check to be sure that there are columns to be read
+;
+ W = WHERE(FOUND EQ 1, COUNT)
+ WV = WHERE(FOUND EQ 1 OR VARICOL EQ 1, WVCOUNT)
+ IF WVCOUNT EQ 0 THEN BEGIN
+ STRPUT, MESSAGE, ':', 0
+ MESSAGE = 'ERROR: No requested columns could be read'+MESSAGE
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF ELSE IF MESSAGE NE '' THEN BEGIN
+ STRPUT, MESSAGE, ':', 0
+ MESSAGE = 'WARNING: Some columns could not be read'+MESSAGE
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = MESSAGE $
+ ELSE MESSAGE, MESSAGE, /INFO
+ ENDIF
+
+;
+; If ROW was not passed, then set it equal to the entire range. Otherwise,
+; extract the range.
+;
+ IF N_ELEMENTS(ROW) EQ 0 THEN ROW = [1LL, NAXIS2[ILUN]]
+ CASE N_ELEMENTS(ROW) OF
+ 1: ROW2 = LONG64(ROW[0])
+ 2: ROW2 = LONG64(ROW[1])
+ ELSE: BEGIN
+ MESSAGE = 'ROW must have one or two elements'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ ENDCASE
+ ROW1 = LONG64(ROW[0])
+;
+; If ROW represents a range, then make sure that the row range is legal, and
+; that reading row ranges is allowed (i.e., the column is not variable length.
+;
+ IF ROW1 NE ROW2 THEN BEGIN
+ MAXROW = NAXIS2[ILUN]
+ IF (ROW1 LT 1) OR (ROW1 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[0] must be between 1 and ' + $
+ STRTRIM(MAXROW,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF (ROW2 LT ROW1) OR (ROW2 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[1] must be between ' + $
+ STRTRIM(ROW1,2) + ' and ' + STRTRIM(MAXROW,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Otherwise, if ROW is a single number, then just make sure it's valid.
+;
+ END ELSE BEGIN
+ IF (ROW1 LT 1) OR (ROW1 GT NAXIS2[ILUN]) THEN BEGIN
+ MESSAGE = 'ROW must be between 1 and ' + $
+ STRTRIM(NAXIS2[ILUN],2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDELSE
+
+;
+; Compose information about the output
+;
+ HEADER = HEAD[*,ILUN]
+ COLNDIM = LONARR(NUMCOLS)
+ COLDIM = LONARR(NUMCOLS, 20) ;; Maximum of 20 dimensions in output
+ COLTYPE = LONARR(NUMCOLS)
+ BOFF1 = LONARR(NUMCOLS)
+ BOFF2 = LONARR(NUMCOLS)
+ TNULL_FLG = INTARR(NUMCOLS) ;; 1 if TNULLn column is present
+ TNULL_VAL = DBLARR(NUMCOLS) ;; value of TNULLn column if present
+ NROWS = ROW2-ROW1+1
+ FOR I = 0L, NUMCOLS-1 DO BEGIN
+
+ IF ~FOUND[I] THEN GOTO, LOOP_END_DIMS
+ ;; Data type of the input.
+ IF VIRTUAL[I] THEN BEGIN
+ ; Virtual column: read from keyword itself
+ COLTYPE[I] = VIRTYPE[I]
+ GOTO, LOOP_END_DIMS
+ ENDIF ELSE IF VARICOL[I] THEN BEGIN
+ ; Variable length column: 2-element long
+ COLTYPE[I] = 3
+ DIMS = [1L, 2L]
+ ENDIF ELSE BEGIN
+ COLTYPE[I] = IDLTYPE[ICOL[I],ILUN]
+ DIMS = N_DIMS[*,ICOL[I],ILUN]
+ ENDELSE
+
+ NDIMS = DIMS[0]
+ DIMS = DIMS[1:NDIMS]
+
+ IF NDIMS EQ 1 AND DIMS[0] EQ 1 THEN BEGIN
+
+ ;; Case of only one output element, try to return a
+ ;; scalar. Otherwise, it is a vector equal to the
+ ;; number of rows to be read
+
+ COLNDIM[I] = 1L
+ COLDIM[I,0] = NROWS
+ ENDIF ELSE BEGIN
+
+ COLNDIM[I] = NDIMS
+ COLDIM[I,0:(NDIMS-1)] = DIMS
+ IF NROWS GT 1 THEN BEGIN
+ COLDIM[I,NDIMS] = NROWS
+ COLNDIM[I]++
+ ENDIF
+
+ ENDELSE
+
+ ;; For strings, the number of characters is the first
+ ;; dimension. This information is useless to us now,
+ ;; since the STRING() type cast which will appear below
+ ;; handles the array conversion automatically.
+ IF COLTYPE[I] EQ 7 THEN BEGIN
+ IF COLNDIM[I] GT 1 THEN BEGIN
+ COLDIM[I,0:COLNDIM[I]-2] = COLDIM[I,1:COLNDIM[I]-1]
+ COLDIM[I,COLNDIM[I]-1] = 0
+ COLNDIM[I] = COLNDIM[I] - 1
+ ENDIF ELSE BEGIN ;; Case of a single row
+ COLNDIM[I] = 1L
+ COLDIM[I,0] = NROWS
+ ENDELSE
+ ENDIF
+
+ ;; Byte offsets
+ BOFF1[I] = BYTOFF[ICOL[I],ILUN]
+ IF ICOL[I] EQ TFIELDS[ILUN]-1 THEN $
+ BOFF2[I] = NAXIS1[ILUN]-1 $
+ ELSE $
+ BOFF2[I] = BYTOFF[ICOL[I]+1,ILUN]-1
+
+ ;; TNULLn keywords for integer type columns
+ IF (COLTYPE[I] GE 1 AND COLTYPE[I] LE 3) OR $
+ (COLTYPE[I] GE 12 AND COLTYPE[I] LE 15) THEN BEGIN
+ TNULLn = 'TNULL'+STRTRIM(ICOL[I]+1,2)
+ VALUE = FXPAR(HEADER,TNULLn, Count = N_VALUE)
+ IF N_VALUE GT 0 THEN BEGIN
+ TNULL_FLG[I] = 1
+ TNULL_VAL[I] = VALUE
+ ENDIF
+ ENDIF
+
+ LOOP_END_DIMS:
+
+ ENDFOR
+
+;
+; Construct any virtual columns first
+;
+ WC = WHERE(FOUND EQ 1 AND VIRTUAL EQ 1, WCCOUNT)
+ FOR I = 0L, WCCOUNT-1 DO BEGIN
+ ;; If it's virtual, then the value only needs to be
+ ;; replicated
+ EXTCMD = COLNAMES[WC[I]]+'= REPLICATE(D'+COLNAMES[WC[I]]+',NROWS)'
+ ;; Run the command that selects the data
+ RESULT = EXECUTE(EXTCMD)
+ IF RESULT EQ 0 THEN BEGIN
+ MESSAGE = 'ERROR: Could not extract data (column '+$
+ STRTRIM(MYCOL[WC[I]],2)+')'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ ENDIF ELSE MESSAGE, MESSAGE
+ ENDIF
+ OUTSTATUS[I] = 1
+ ENDFOR
+
+
+; Skip to processing variable-length columns if all other columns are virtual
+ WC = WHERE(FOUND EQ 1 AND VIRTUAL EQ 0, WCCOUNT)
+ IF WCCOUNT EQ 0 THEN GOTO, PROC_CLEANUP
+
+; Create NANVALUES, the template to use when a NAN is found
+ IF N_ELEMENTS(NANVALUE) GE NUMCOLS THEN BEGIN
+ NANVALUES = NANVALUE[0:NUMCOLS-1]
+ ENDIF ELSE IF N_ELEMENTS(NANVALUE) GT 0 THEN BEGIN
+ NANVALUES = REPLICATE(NANVALUE[0], NUMCOLS)
+ NANVALUES[0] = NANVALUE
+ I = N_ELEMENTS(NANVALUE)
+ IF I LT NUMCOLS THEN $
+ NANVALUES[I:*] = NANVALUE[0]
+ ENDIF
+
+;
+; Find the position of the first byte of the data array in the file.
+;
+ OFFSET0 = NHEADER[ILUN] + NAXIS1[ILUN]*(ROW1-1LL)
+ POS = 0LL
+ NROWS0 = NROWS
+ J = 0LL
+ FIRST = 1
+ ;; Here, we constrain the buffer to be at least 16 rows long.
+ ;; If we fill up 32 kB with fewer than 16 rows, then there
+ ;; must be a lot of (big) columns in this table. It's
+ ;; probably a candidate for using FXBREAD instead.
+ BUFFROWS = LONG((BUFFERSIZE/NAXIS1[ILUN]) > 16L)
+ IF BUFFERSIZE LE 0 THEN BUFFROWS = NROWS0
+
+;
+; Loop through the data in chunks
+;
+ WHILE NROWS GT 0 DO BEGIN
+ J++
+ NR = NROWS < BUFFROWS
+ OFFSET1 = NAXIS1[ILUN]*POS
+
+;
+; Proceed by reading a byte array from the input data file
+; FXBREADM reads all columns from the specified rows, and
+; sorts out the details of which bytes belong to which columns
+; in the next FOR loop.
+;
+ BB = BYTARR(NAXIS1[ILUN], NR)
+ POINT_LUN, UNIT, OFFSET0+OFFSET1
+ READU, UNIT, BB
+; FXGSEEK, UNIT, OFFSET0+OFFSET1
+; FXGREAD, UNIT, BB
+
+;
+; Now select out the desired columns
+;
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+
+ ;; Extract the proper rows and columns
+ IF ~FOUND[I] THEN GOTO, LOOP_END_STORE
+ IF VIRTUAL[I] THEN GOTO, LOOP_END_STORE
+
+ ;; Extract the data from the byte array and convert it
+ ;; The inner CALL_FUNCTION is to one of the coercion
+ ;; functions, such as FIX(), DOUBLE(), STRING(), etc.,
+ ;; which is called with an offset to force a conversion
+ ;; from bytes to the data type.
+ ;; The outer CALL_FUNCTION is to REFORM(), which makes
+ ;; sure that the data structure is correct.
+ ;;
+ DIMS = COLDIM[I,0:COLNDIM[I]-1]
+ PERROW = ROUND(PRODUCT(DIMS)/NROWS0)
+
+ IF N_ELEMENTS(NANVALUES) GT 0 THEN $
+ EXTRA={NANVALUE: NANVALUES[I]}
+
+ FXBREADM_CONV, BB[BOFF1[I]:BOFF2[I], *], DD, COLTYPE[I], PERROW, NR,$
+ NOIEEE=KEYWORD_SET(NOIEEE), NOSCALE=KEYWORD_SET(NOSCALE), $
+ TZERO=TZERO[ICOL[I], ILUN], TSCAL=TSCAL[ICOL[I], ILUN], $
+ VARICOL=VARICOL[I], DEFAULT_FLOAT=DEFAULT_FLOAT, $
+ TNULL_VALUE=TNULL_VAL[I], TNULL_FLAG=TNULL_FLG[I], $
+ _EXTRA=EXTRA
+
+ ;; Initialize the output variable on the first chunk
+ IF FIRST THEN BEGIN
+ SZ = SIZE(DD)
+ ;; NOTE: type could have changed if TSCAL/TZERO were used
+ COLTYPEI = SZ(SZ[0]+1)
+ RESULT = EXECUTE(COLNAMES[I]+' = 0')
+ RESULT = EXECUTE(COLNAMES[I]+' = '+$
+ 'MAKE_ARRAY(PERROW, NROWS0, TYPE=COLTYPEI)')
+ RESULT = EXECUTE(COLNAMES[I]+' = '+$
+ 'REFORM('+COLNAMES[I]+', PERROW, NROWS0,/OVERWRITE)')
+ ENDIF
+
+ ;; Finally, store this in the output variable
+ RESULT = EXECUTE(COLNAMES[I]+'[0,POS] = DD')
+ DD = 0
+ IF RESULT EQ 0 THEN BEGIN
+ MESSAGE = 'ERROR: Could not compose output data '+COLNAMES[I]
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ ENDIF ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ OUTSTATUS[I] = 1
+
+ LOOP_END_STORE:
+ ENDFOR
+
+ FIRST = 0
+ NROWS = NROWS - NR
+ POS = POS + NR
+ ENDWHILE
+
+;
+; Read the variable-length columns from the heap. Adjacent data are
+; coalesced into one read operation. Note: this technique is thus
+; optimal for extensions with only one variable-length column. If
+; there are more than one then coalescence will not occur.
+;
+
+ ;; Width of the various data types in bytes
+ WIDARR = [0L, 1L, 2L, 4L, 4L, 8L, 8L, 1L, 0L,16L, 0L]
+ WV = WHERE(OUTSTATUS EQ 1 AND VARICOL EQ 1, WVCOUNT)
+ FOR J = 0, WVCOUNT-1 DO BEGIN
+ I = WV[J]
+ RESULT = EXECUTE('PDATA = '+COLNAMES[I])
+ NVALS = PDATA[0,*] ;; Number of values in each row
+ NTOT = ROUND(TOTAL(NVALS)) ;; Total number of values
+ IF NTOT EQ 0 THEN BEGIN
+ DD = {N_ELEMENTS: 0L, N_ROWS: NROWS0, $
+ INDICES: LON64ARR(NROWS0+1), DATA: 0L}
+ GOTO, FILL_VARICOL
+ ENDIF
+
+ ;; Compute the width in bytes of the data value
+ TYPE = IDLTYPE[ICOL[I], ILUN]
+ WID = LONG64(WIDARR[TYPE < 10])
+ IF WID EQ 0 THEN BEGIN
+ OUTSTATUS[I] = 0
+ MESSAGE = 'ERROR: Column '+COLNAMES[I]+' has unknown data type'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ ;; Coalesce the data pointers
+ BOFF1 = LONG64(PDATA[1,*])
+ BOFF2 = BOFF1 + NVALS*WID
+ WH = WHERE(BOFF1[1:*] NE BOFF2, CT)
+ IF CT GT 0 THEN BI = [-1LL, WH, N_ELEMENTS(BOFF1)-1] $
+ ELSE BI = [-1LL, N_ELEMENTS(BOFF1)-1]
+ CT = CT + 1
+
+ ;; Create the output array
+ BC = BOFF2[BI[1:*]] - BOFF1[BI[0:CT-1]+1] ;; Byte count
+ NB = ROUND(TOTAL(BC)) ;; Total # bytes
+ BB = BYTARR(NB) ;; Byte array
+
+ ;; Initialize the counter variables used in the read-loop
+ CC = 0LL & CC1 = 0LL & K = 0LL
+ BUFFROWS = ROUND(BUFFERSIZE/WID) > 128L
+ BASE = LONG64(NHEADER[ILUN]+HEAP[ILUN])
+
+ ;; Read data from file
+ WHILE CC LT NB DO BEGIN
+ NB1 = (BC[K]-CC1) < BUFFROWS
+ BB1 = BYTARR(NB1)
+
+ POINT_LUN, UNIT, BASE+BOFF1[BI[K]+1]+CC1
+ READU, UNIT, BB1
+; FXGSEEK, UNIT, BASE+BOFF1[BI[K]+1]+CC1
+; FXGREAD, UNIT, BB1
+ BB[CC] = TEMPORARY(BB1)
+
+ CC = CC + NB1
+ CC1 = CC1 + NB1
+ IF CC1 EQ BC[K] THEN BEGIN
+ K = K + 1
+ CC1 = 0L
+ ENDIF
+ ENDWHILE
+
+ ;; Convert the data
+ IF N_ELEMENTS(NANVALUES) GT 0 THEN $
+ EXTRA={NANVALUE: NANVALUES[I]}
+
+ FXBREADM_CONV, BB, DD, TYPE, NTOT, 1L, $
+ NOIEEE=KEYWORD_SET(NOIEEE), NOSCALE=KEYWORD_SET(NOSCALE), $
+ TZERO=TZERO[ICOL[I], ILUN], TSCAL=TSCAL[ICOL[I], ILUN], $
+ DEFAULT_FLOAT=DEFAULT_FLOAT, _EXTRA=EXTRA
+
+ ;; Ensure the correct dimensions, now that we know them
+ COLNDIM[I] = 1
+ COLDIM[I,0] = NTOT
+
+ ;; Construct the indices; unfortunately we need to make an
+ ;; accumulant with a FOR loop
+ INDICES = LON64ARR(NROWS0+1)
+ FOR K = 1LL, NROWS0 DO $
+ INDICES[K] = INDICES[K-1] + NVALS[K-1]
+
+ ;; Construct a structure with additional data
+ DD = {N_ELEMENTS: NTOT, N_ROWS: NROWS0, TYPE: TYPE, $
+ INDICES: INDICES, DATA: TEMPORARY(DD)}
+
+ FILL_VARICOL:
+ RESULT = EXECUTE(COLNAMES[I] +' = TEMPORARY(DD)')
+ ENDFOR
+
+;
+; Compose the output columns, which might need reforming
+;
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ IF OUTSTATUS[I] NE 1 THEN GOTO, LOOP_END_FINAL
+
+ ;; Extract the dimensions and name of the column data
+ DIMS = COLDIM[I,0:COLNDIM[I]-1]
+ NEL = PRODUCT(DIMS)
+ CNAME = COLNAMES[I]
+ IF VARICOL[I] THEN CNAME = CNAME + '.DATA'
+
+ ;; Compose the reforming part
+ IF NEL EQ 1 THEN $
+ CMD = CNAME+'[0]' $
+ ELSE $
+ CMD = 'REFORM(TEMPORARY('+CNAME+'),DIMS,/OVERWRITE)'
+
+ ;; Variable-length columns return extra information
+ IF VARICOL[I] THEN BEGIN
+ CMD = ('{VARICOL: 1,'+$
+ ' N_ELEMENTS: '+COLNAMES[I]+'.N_ELEMENTS, '+$
+ ' TYPE: '+COLNAMES[I]+'.TYPE, '+$
+ ' N_ROWS: '+COLNAMES[I]+'.N_ROWS, '+$
+ ' INDICES: '+COLNAMES[I]+'.INDICES, '+$
+ ' DATA: '+CMD+'}')
+ ENDIF
+
+ ;; Assign to pointer, or re-assign to column
+ IF PASS EQ 'ARGUMENT' THEN $
+ CMD = COLNAMES[I]+' = ' + CMD $
+ ELSE IF PASS EQ 'POINTER' THEN $
+ CMD = '*(POINTERS[I]) = ' + CMD
+
+ RESULT = EXECUTE(CMD)
+ LOOP_END_FINAL:
+ ENDFOR
+
+ PROC_CLEANUP:
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbstate.pro b/Code/script_idl_mv/astrolib/fxbstate.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b2de4693f0d8e483e2a8cf1dd99dd70d15963efd
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbstate.pro
@@ -0,0 +1,74 @@
+ FUNCTION FXBSTATE, UNIT
+;+
+; NAME:
+; FXBSTATE()
+;
+; PURPOSE:
+; Returns the state of a FITS binary table.
+;
+; Explanation : This procedure returns the state of a FITS binary table that
+; was either opened for read with the command FXBOPEN, or for
+; write with the command FXBCREATE.
+;
+; Use : Result = FXBSTATE(UNIT)
+;
+; Inputs : UNIT = Logical unit number returned by FXBOPEN routine.
+; Must be a scalar integer.
+;
+; Opt. Inputs : None.
+;
+; Outputs : The result of the function is the state of the FITS binary
+; table that UNIT points to. This can be one of three values:
+;
+; 0 = Closed
+; 1 = Open for read
+; 2 = Open for write
+;
+; Opt. Outputs: None.
+;
+; Keywords : None.
+;
+; Calls : FXBFINDLUN
+;
+; Common : Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+;
+; Restrictions: None.
+;
+; Side effects: If UNIT is an undefined variable, then 0 (closed) is returned.
+;
+; Category : Data Handling, I/O, FITS, Generic.
+;
+; Prev. Hist. : None.
+;
+; Written : William Thompson, GSFC, 1 July 1993.
+;
+; Modified : Version 1, William Thompson, GSFC, 1 July 1993.
+;
+; Version : Version 1, 1 July 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 1 THEN MESSAGE,'Syntax: Result = FXBSTATE(UNIT)'
+;
+; If UNIT is undefined, then return False.
+;
+ IF N_ELEMENTS(UNIT) EQ 0 THEN RETURN, 0
+;
+; Check the validity of UNIT.
+;
+ IF N_ELEMENTS(UNIT) GT 1 THEN MESSAGE,'UNIT must be a scalar'
+ SZ = SIZE(UNIT)
+ IF SZ[SZ[0]+1] GT 3 THEN MESSAGE,'UNIT must be an integer'
+;
+; Get the state associated with UNIT.
+;
+ ILUN = FXBFINDLUN(UNIT)
+ RETURN, STATE[ILUN]
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbtdim.pro b/Code/script_idl_mv/astrolib/fxbtdim.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3c116e75ce2dab9ea38258fa67ccfde8e63d8b07
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbtdim.pro
@@ -0,0 +1,90 @@
+ FUNCTION FXBTDIM, TDIM_KEYWORD
+;+
+; NAME:
+; FXBTDIM()
+; Purpose :
+; Parse TDIM-like kwywords.
+; Explanation :
+; Parses the value of a TDIM-like keyword (e.g. TDIMnnn, TDESC, etc.) to
+; return the separate elements contained within.
+; Use :
+; Result = FXBTDIM( TDIM_KEYWORD )
+; Inputs :
+; TDIM_KEYWORD = The value of a TDIM-like keyword. Must be a
+; character string of the form "(value1,value2,...)".
+; If the parentheses characters are missing, then the
+; string is simply returned as is, without any further
+; processing.
+; Opt. Inputs :
+; None.
+; Outputs :
+; The result of the function is a character string array containing the
+; values contained within the keyword parameter. If a numerical result
+; is desired, then simply call, e.g.
+;
+; Result = FIX( FXBTDIM( TDIM_KEYWORD ))
+;
+; Opt. Outputs:
+; None.
+; Keywords :
+; None.
+; Calls :
+; GETTOK
+; Common :
+; None.
+; Restrictions:
+; The input parameter must have the proper format. The separate values
+; must not contain the comma character. TDIM_KEYWORD must not be an
+; array.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan. 1992.
+; William Thompson, Jan. 1993, renamed to be compatible with DOS
+; limitations.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version :
+; Version 1, 12 April 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR,2
+;
+; Make sure TDIM_KEYWORD is not an array.
+;
+ IF N_ELEMENTS(TDIM_KEYWORD) NE 1 THEN MESSAGE, $
+ 'TDIM_KEYWORD must be a scalar'
+;
+; Remove any leading or trailing blanks from the keyword.
+;
+ TDIM = STRTRIM(TDIM_KEYWORD,2)
+;
+; The first and last characters should be "(" and ")". If they are not, then
+; simply return the string as is.
+;
+ FIRST = STRMID(TDIM,0,1)
+ LAST = STRMID(TDIM,STRLEN(TDIM)-1,1)
+ IF (FIRST NE "(") OR (LAST NE ")") THEN RETURN,TDIM
+;
+; Otherwise, remove the parentheses characters.
+;
+ TDIM = STRMID(TDIM,1,STRLEN(TDIM)-2)
+;
+; Get the first value.
+;
+ VALUE = GETTOK(TDIM,',')
+;
+; Get all the rest of the values.
+;
+ WHILE TDIM NE '' DO VALUE = [VALUE,GETTOK(TDIM,',')]
+;
+; Return the (string) array of values.
+;
+ RETURN,VALUE
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbtform.pro b/Code/script_idl_mv/astrolib/fxbtform.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c0e05d537c79ed136b6823c50786f8fedb2ca315
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbtform.pro
@@ -0,0 +1,212 @@
+ PRO FXBTFORM,HEADER,TBCOL,IDLTYPE,FORMAT,NUMVAL,MAXVAL,ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBTFORM
+; PURPOSE :
+; Returns information about FITS binary table columns.
+; EXPLANATION :
+; Procedure to return information about the format of the various columns
+; in a FITS binary table.
+; Use :
+; FXBTFORM,HEADER,TBCOL,IDLTYPE,FORMAT,NUMVAL,MAXVAL
+; Inputs :
+; HEADER = Fits binary table header.
+; Opt. Inputs :
+; None.
+; Outputs :
+; TBCOL = Array of starting column positions in bytes.
+; IDLTYPE = IDL data types of columns.
+; FORMAT = Character code defining the data types of the columns.
+; NUMVAL = Number of elements of the data arrays in the columns.
+; MAXVAL = Maximum number of elements for columns containing variable
+; length arrays, or zero otherwise.
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBTFORM, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXPAR
+; Common :
+; None.
+; Restrictions:
+; None.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Feb. 1992, from TBINFO by D. Lindler.
+; W. Thompson, Jan. 1993, renamed to be compatible with DOS limitations.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, William Thompson, GSFC, 9 April 1997
+; Modified so that variable length arrays can be read, even if
+; the maximum array size is not in the header.
+; Version 5 Wayne Landsman, GSFC, August 1997
+; Recognize double complex array type if since IDL version 4.0
+; Version 6 Optimized FXPAR call, CM 1999 Nov 18
+; Version 7: Wayne Landsman, GSFC Feb 2006
+; Added support for 64bit integer K format
+; Version:
+; Version 8: Wayne Landsman GSFC Apr 2010
+; Remove use of obsolete !ERR variable
+;-
+;
+ ON_ERROR,2
+ COMPILE_OPT IDL2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 1 THEN BEGIN
+ MESSAGE = 'Syntax: FXBTFORM,HEADER,TBCOL,IDLTYPE,FORMAT,' + $
+ 'NUMVAL,MAXVAL'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Get the number of fields.
+;
+ TFIELDS = FXPAR(HEADER,'TFIELDS', START=0L, COUNT=N_TFIELDS)
+ IF N_TFIELDS LE 0 THEN BEGIN
+ MESSAGE = 'Invalid FITS header -- keyword TFIELDS is missing'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF TFIELDS EQ 0 THEN BEGIN
+ MESSAGE = 'FIT binary table has no columns'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Initialize the arrays.
+;
+ WIDTH = INTARR(TFIELDS)
+ IDLTYPE = INTARR(TFIELDS)
+ TBCOL = LONARR(TFIELDS)
+ FORMAT = STRARR(TFIELDS)
+ NUMVAL = LONARR(TFIELDS)
+ MAXVAL = LONARR(TFIELDS)
+;
+; Get the column formats.
+;
+ TFORM = FXPAR(HEADER,'TFORM*', COUNT=N_TFORM)
+ IF N_TFORM LE 0 THEN BEGIN
+ MESSAGE = 'Invalid FITS table header -- keyword TFORM ' + $
+ 'not present'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ TFORM = STRUPCASE(STRTRIM(TFORM,2))
+;
+; Parse the values of the TFORM keywords.
+;
+ LEN = STRLEN(TFORM)
+ FOR I = 0,N_ELEMENTS(TFORM)-1 DO BEGIN
+;
+; Step through each character in the format, until a non-numerical character
+; is encountered.
+;
+ ICHAR = 0
+NEXT_CHAR:
+ IF ICHAR GE LEN[I] THEN BEGIN
+ MESSAGE = 'Invalid format specification for ' + $
+ 'keyword TFORM ' + STRTRIM(I+1)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ CHAR = STRUPCASE(STRMID(TFORM[I],ICHAR,1))
+ IF ((CHAR GE '0') AND (CHAR LE '9')) THEN BEGIN
+ ICHAR = ICHAR + 1
+ GOTO, NEXT_CHAR
+ ENDIF
+;
+; Get the number of elements.
+;
+ IF ICHAR EQ 0 THEN NUMVAL[I] = 1 ELSE $
+ NUMVAL[I] = LONG(STRMID(TFORM[I],0,ICHAR))
+;
+; If the character is "P" then the next character is the actual data type,
+; followed by the maximum number of elements surrounded by quotes.
+;
+ IF CHAR EQ "P" THEN BEGIN
+ CHAR = STRUPCASE(STRMID(TFORM[I],ICHAR+1,1))
+ MAXVAL[I] = LONG(STRMID(TFORM[I],ICHAR+3, $
+ LEN[I]-ICHAR-4))
+ IF MAXVAL[I] EQ 0 THEN MAXVAL[I] = 1
+ ENDIF
+;
+; Get the IDL data type, and the size of an element.
+;
+ FORMAT[I] = CHAR
+ CASE CHAR OF
+ 'L': BEGIN & IDLTYPE[I] = 1 & WIDTH[I] = 1 & END
+ 'A': BEGIN & IDLTYPE[I] = 7 & WIDTH[I] = 1 & END
+ 'B': BEGIN & IDLTYPE[I] = 1 & WIDTH[I] = 1 & END
+ 'I': BEGIN & IDLTYPE[I] = 2 & WIDTH[I] = 2 & END
+ 'J': BEGIN & IDLTYPE[I] = 3 & WIDTH[I] = 4 & END
+ 'E': BEGIN & IDLTYPE[I] = 4 & WIDTH[I] = 4 & END
+ 'D': BEGIN & IDLTYPE[I] = 5 & WIDTH[I] = 8 & END
+ 'C': BEGIN & IDLTYPE[I] = 6 & WIDTH[I] = 8 & END
+ 'M': BEGIN & IDLTYPE[I] = 9 & WIDTH[I] =16 & END
+ 'K': BEGIN & IDLTYPE[I] =14 & WIDTH[I] = 8 & END
+;
+;
+; Treat bit arrays as byte arrays with 1/8 the number of elements.
+;
+ 'X': BEGIN
+ IDLTYPE[I] = 1
+ WIDTH[I] = 1
+ IF MAXVAL[I] GT 0 THEN BEGIN
+ MAXVAL[I] = LONG((MAXVAL[I]+7)/8)
+ END ELSE BEGIN
+ NUMVAL[I] = LONG((NUMVAL[I]+7)/8)
+ ENDELSE
+ END
+
+ ELSE: BEGIN
+ MESSAGE = 'Invalid format specification ' + $
+ 'for keyword TFORM' + STRTRIM(I+1,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ ENDCASE
+;
+; Variable length array pointers always take up eight bytes.
+;
+ IF MAXVAL[I] GT 0 THEN WIDTH[I] = 8
+;
+; Calculate the starting byte for each column.
+;
+ IF I GE 1 THEN TBCOL[I] = TBCOL[I-1] + WIDTH[I-1]*NUMVAL[I-1]
+ ENDFOR
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbwrite.pro b/Code/script_idl_mv/astrolib/fxbwrite.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0c0f4539703345765db9c0930d2b9bd82344e66e
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbwrite.pro
@@ -0,0 +1,282 @@
+ PRO FXBWRITE, UNIT, DATA, COL, ROW, BIT=BIT, NANVALUE=NANVALUE, $
+ ERRMSG=ERRMSG
+;+
+; NAME:
+; FXBWRITE
+; Purpose :
+; Write a binary data array to a disk FITS binary table file.
+; Explanation :
+; Each call to FXBWRITE will write to the data file, which should already
+; have been created and opened by FXBCREATE. One needs to call this
+; routine for every column and every row in the binary table. FXBFINISH
+; will then close the file.
+; Use :
+; FXBWRITE, UNIT, DATA, COL, ROW
+; Inputs :
+; UNIT = Logical unit number corresponding to the file containing the
+; binary table.
+; DATA = IDL data array to be written to the file.
+; COL = Column in the binary table to place data in, starting from
+; column one.
+; ROW = Row in the binary table to place data in, starting from row
+; one.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; BIT = Number of bits in bit mask arrays (type "X"). Only used if
+; the column is of variable size.
+; NANVALUE= Value signalling data dropout. All points corresponding to
+; this value are set to be IEEE NaN (not-a-number). Ignored
+; unless DATA is of type float, double-precision or complex.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBWRITE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; None.
+; Common :
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; Restrictions:
+; The binary table file must have been opened with FXBCREATE.
+;
+; The data must be consistent with the column definition in the binary
+; table header.
+;
+; The row number must be consistent with the number of rows stored in the
+; binary table header.
+;
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Jan 1992, based on WRITEFITS by J. Woffard and W. Landsman.
+; W. Thompson, Feb 1992, modified to support variable length arrays.
+; W. Thompson, Feb 1992, removed all references to temporary files.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 July 1993.
+; Fixed bug with variable length arrays.
+; Version 3, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 5, Wayne Landsman, GSFC, 12 Aug 1997
+; Recognize IDL double complex data type
+; Version 6, Converted to IDL V5.0 W. Landsman September 1997
+; Version 7, William Thompson, 18-May-2016, change POINTER to ULONG
+; Version :
+; Version 7, 18-May-2016
+;-
+;
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 4 THEN BEGIN
+ MESSAGE = 'Syntax: FXBWRITE, UNIT, DATA, COL, ROW'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Find the logical unit number in the FXBINTABLE common block.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE,'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Check the row and column parameters against the header.
+;
+ IF (COL LT 1) OR (COL GT TFIELDS[ILUN]) THEN BEGIN
+ MESSAGE = 'COL must be between 1 and ' + $
+ STRTRIM(TFIELDS[ILUN],2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF (ROW LT 1) OR (ROW GT NAXIS2[ILUN]) THEN BEGIN
+ MESSAGE = 'ROW must be between 1 and ' + $
+ STRTRIM(NAXIS2[ILUN],2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Calculate the row and column parameters using IDL zero-based indexing.
+;
+ IROW = LONG(ROW) - 1
+ ICOL = LONG(COL) - 1
+;
+; Check the type of the data against that defined for this column.
+;
+ SZ = SIZE(DATA)
+ TYPE = SZ[SZ[0]+1]
+ IF TYPE NE IDLTYPE[ICOL,ILUN] THEN BEGIN
+ CASE IDLTYPE[ICOL,ILUN] OF
+ 1: STYPE = 'byte'
+ 2: STYPE = 'short integer'
+ 3: STYPE = 'long integer'
+ 4: STYPE = 'floating point'
+ 5: STYPE = 'double precision'
+ 6: STYPE = 'complex'
+ 7: STYPE = 'string'
+ 9: STYPE = 'double complex'
+ ENDCASE
+ MESSAGE = 'Data type should be ' + STYPE
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Check the number of elements, depending on whether or not the column
+; contains variable length arrays.
+;
+ IF MAXVAL[ICOL,ILUN] GT 0 THEN BEGIN
+ IF N_ELEMENTS(DATA) GT MAXVAL[ICOL,ILUN] THEN BEGIN
+ MESSAGE = 'Data array should have no more than ' + $
+ STRTRIM(N_ELEM[ICOL,ILUN],2) + ' elements'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ END ELSE BEGIN
+ IF N_ELEMENTS(DATA) NE N_ELEM[ICOL,ILUN] THEN BEGIN
+ MESSAGE = 'Data array should have ' + $
+ STRTRIM(N_ELEM[ICOL,ILUN],2) + ' elements'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDELSE
+;
+; Find the position of the first byte of the data array in the file.
+;
+ OFFSET = NHEADER[ILUN] + NAXIS1[ILUN]*IROW + BYTOFF[ICOL,ILUN]
+ POINT_LUN,UNIT,OFFSET
+;
+; If a variable length array, then test to see if the array is of type
+; double-precision complex (M) or bit (X).
+;
+ IF MAXVAL[ICOL,ILUN] GT 0 THEN BEGIN
+ N_ELEM0 = N_ELEMENTS(DATA)
+ IF FORMAT[ICOL,ILUN] EQ "X" THEN BEGIN
+ IF N_ELEMENTS(BIT) EQ 0 THEN BEGIN
+ MESSAGE = 'Number of bits not defined'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF N_ELEMENTS(BIT) NE 1 THEN BEGIN
+ MESSAGE = 'Number of bits must be a scalar'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF LONG((BIT+7)/8) NE N_ELEM0 THEN BEGIN
+ MESSAGE = 'Number of bits does not match ' + $
+ 'array size'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ N_ELEM0 = BIT
+ ENDIF
+;
+; Write out the number of elements, and the pointer to the variable length
+; array.
+;
+ POINTER = ULONARR(2)
+ POINTER[0] = N_ELEM0
+ POINTER[1] = DHEAP[ILUN]
+ SWAP_ENDIAN_INPLACE,POINTER,/SWAP_IF_LITTLE
+ WRITEU,UNIT,POINTER
+ POINT_LUN,UNIT,NHEADER[ILUN] + HEAP[ILUN] + DHEAP[ILUN]
+;
+; Update the HEAP pointer.
+;
+ CASE TYPE OF
+ 1: DDHEAP = N_ELEMENTS(DATA) ;Byte
+ 2: DDHEAP = N_ELEMENTS(DATA) * 2 ;Short integer
+ 3: DDHEAP = N_ELEMENTS(DATA) * 4 ;Long integer
+ 4: DDHEAP = N_ELEMENTS(DATA) * 4 ;Float
+ 5: DDHEAP = N_ELEMENTS(DATA) * 8 ;Double
+ 6: DDHEAP = N_ELEMENTS(DATA) * 8 ;Complex
+ 7: DDHEAP = N_ELEMENTS(DATA) ;String
+ 9: DDHEAP = N_ELEMENTS(DATA) * 16 ;Dble Complex
+ ENDCASE
+ DHEAP[ILUN] = DHEAP[ILUN] + DDHEAP
+ ENDIF
+;
+; If a byte array, then simply write out the data.
+;
+ IF TYPE EQ 1 THEN BEGIN
+ WRITEU,UNIT,DATA
+;
+; Otherwise, if a character string array, then write out the character strings
+; with the correct width, truncating or padding with blanks as necessary.
+; However, if a variable length string array, then simply write it out.
+;
+ END ELSE IF TYPE EQ 7 THEN BEGIN
+ IF MAXVAL[ICOL,ILUN] GT 0 THEN BEGIN
+ WRITEU,UNIT,DATA
+ END ELSE BEGIN
+ N_CHAR = N_DIMS[1,ICOL,ILUN]
+ NEWDATA = REPLICATE(32B,N_CHAR,N_ELEMENTS(DATA))
+ FOR I=0,N_ELEMENTS(DATA)-1 DO $
+ NEWDATA[0,I] = BYTE(STRMID(DATA[I],0,N_CHAR))
+ WRITEU,UNIT,NEWDATA
+ ENDELSE
+;
+; Otherwise, if necessary, then byte-swap the data before writing it out.
+; Also, replace any values corresponding data dropout with IEEE NaN.
+;
+ END ELSE BEGIN
+ IF (N_ELEMENTS(NANVALUE) EQ 1) AND (TYPE GE 4) AND $
+ ((TYPE LE 6) OR (TYPE EQ 9)) THEN BEGIN
+ W = WHERE(DATA EQ NANVALUE, COUNT)
+ CASE TYPE OF
+ 4: NAN = FLOAT( REPLICATE('FF'XB,4),0,1)
+ 5: NAN = DOUBLE( REPLICATE('FF'XB,8),0,1)
+ 6: NAN = COMPLEX(REPLICATE('FF'XB,8),0,1)
+ 9: NAN = DCOMPLEX(REPLICATE('FF'XB,16),0,1)
+ ENDCASE
+ END ELSE COUNT = 0
+;
+ NEWDATA = DATA
+ SWAP_ENDIAN_INPLACE, NEWDATA, /SWAP_IF_LITTLE
+ IF COUNT GT 0 THEN NEWDATA[W] = NAN
+ WRITEU,UNIT,NEWDATA
+ ENDELSE
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxbwritm.pro b/Code/script_idl_mv/astrolib/fxbwritm.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a07f508a14237eee7e3a9a2d00d69cf962f44389
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxbwritm.pro
@@ -0,0 +1,713 @@
+ PRO FXBWRITM, UNIT, COL, $
+ D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, $
+ D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, $
+ D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, $
+ D30, D31, D32, D33, D34, D35, D36, D37, D38, D39, $
+ D40, D41, D42, D43, D44, D45, D46, D47, D48, D49, $
+ NOIEEE=NOIEEE, NOSCALE=NOSCALE, $
+ POINTERS=POINTERS, PASS_METHOD=PASS_METHOD, $
+ ROW=ROW, NANVALUE=NANVALUE, BUFFERSIZE=BUFFERSIZE, $
+ ERRMSG=ERRMSG, WARNMSG=WARNMSG, STATUS=OUTSTATUS
+;+
+; NAME:
+; FXBWRITM
+; PURPOSE:
+; Write multiple columns/rows to a disk FITS binary table file.
+; EXPLANATION :
+; A call to FXBWRITM will write multiple rows and multiple
+; columns to a binary table in a single procedure call. Up to
+; fifty columns may be read in a single pass. The file should
+; have already been opened with FXBOPEN (with write access) or
+; FXBCREATE. FXBWRITM optimizes writing multiple columns by
+; first writing a large chunk of data to the FITS file all at
+; once. FXBWRITM cannot write variable-length arrays; use
+; FXBWRITE instead.
+;
+; The number of columns is limited to 50 if data are passed by
+; positional argument. However, this limitation can be overcome
+; by passing pointers to FXBWRITM. The user should set the PASS_METHOD
+; keyword to 'POINTER' as appropriate, and an array of pointers to
+; the data in the POINTERS keyword. The user is responsible for freeing
+; the pointers.
+;
+; CALLING SEQUENCE:
+; FXBWRITM, UNIT, COL, D0, D1, D2, ..., [ ROW= , PASS_METHOD, NANVALUE=
+; POINTERS=, BUFFERSIZE= ]
+;
+; INPUT PARAMETERS:
+; UNIT = Logical unit number corresponding to the file containing the
+; binary table.
+; D0,..D49= An IDL data array to be written to the file, one for
+; each column. These parameters will be igonred if data
+; is passed through the POINTERS keyword.
+; COL = Column in the binary table to place data in. May be either
+; a list of column numbers where the first column is one, or
+; a string list of column names.
+
+; OPTIONAL INPUT KEYWORDS:
+; ROW = Either row number in the binary table to write data to,
+; starting from row one, or a two element array containing a
+; range of row numbers to write. If not passed, then
+; the entire column is written.
+; NANVALUE= Value signalling data dropout. All points corresponding to
+; this value are set to be IEEE NaN (not-a-number). Ignored
+; unless DATA is of type float, double-precision or complex.
+; NOSCALE = If set, then TSCAL/TZERO values are ignored, and data is
+; written exactly as supplied.
+; PASS_METHOD = A scalar string indicating method of passing
+; data to FXBWRITM. One of 'ARGUMENT' (indicating
+; pass by positional argument), or'POINTER' (indicating
+; passing an array of pointers by the POINTERS
+; keyword).
+; Default: 'ARGUMENT'
+; POINTERS = If PASS_METHOD is 'POINTER' then the user must pass
+; an array of IDL pointers to this keyword, one for
+; each column. Ultimately the user is responsible for
+; deallocating pointers.
+; BUFFERSIZE = Data are transferred in chunks to conserve
+; memory. This is the size in bytes of each chunk.
+; If a value of zero is given, then all of the data
+; are transferred in one pass. Default is 32768 (32
+; kB).
+; OPTIONAL OUTPUT KEYWORDS:
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXBWRITE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+; WARNMSG = Messages which are considered to be non-fatal
+; "warnings" are returned in this output string.
+; STATUS = An output array containing the status for each
+; read, 1 meaning success and 0 meaning failure.
+;
+; PROCEDURE CALLS:
+; None.
+; EXAMPLE:
+; Write a binary table 'sample.fits' giving 43 X,Y positions and a
+; 21 x 21 PSF at each position:
+;
+; (1) First, create sample values
+; x = findgen(43) & y = findgen(43)+1 & psf = randomn(seed,21,21,43)
+;
+; (2) Create primary header, write it to disk, and make extension header
+; fxhmake,header,/initialize,/extend,/date
+; fxwrite,'sample.fits',header
+; fxbhmake,header,43,'TESTEXT','Test binary table extension'
+;
+; (3) Fill extension header with desired column names
+; fxbaddcol,1,header,x[0],'X' ;Use first element in each array
+; fxbaddcol,2,header,y[0],'Y' ;to determine column properties
+; fxbaddcol,3,header,psf[*,*,0],'PSF'
+;
+; (4) Write extension header to FITS file
+; fxbcreate,unit,'sample.fits',header
+;
+; (5) Use FXBWRITM to write all data to the extension in a single call
+; fxbwritm,unit,['X','Y','PSF'], x, y, psf
+; fxbfinish,unit ;Close the file
+;
+; COMMON BLOCKS:
+; Uses common block FXBINTABLE--see "fxbintable.pro" for more
+; information.
+; RESTRICTIONS:
+; The binary table file must have been opened with FXBCREATE or
+; FXBOPEN (with write access).
+;
+; The data must be consistent with the column definition in the binary
+; table header.
+;
+; The row number must be consistent with the number of rows stored in the
+; binary table header.
+;
+; A PASS_METHOD of POINTER does not use the EXECUTE() statement and can be
+; used with the IDL Virtual Machine. However, the EXECUTE() statement is
+; used when the PASS_METHOD is by arguments.
+; CATEGORY:
+; Data Handling, I/O, FITS, Generic.
+; PREVIOUS HISTORY:
+; C. Markwardt, based on FXBWRITE and FXBREADM (ver 1), Jan 1999
+; WRITTEN:
+; Craig Markwardt, GSFC, January 1999.
+; MODIFIED:
+; Version 1, Craig Markwardt, GSFC 18 January 1999.
+; Documented this routine, 18 January 1999.
+; C. Markwardt, added ability to pass by handle or pointer.
+; Some bug fixes, 20 July 2001
+; W. Landsman/B.Schulz Allow more than 50 arguments when using pointers
+; W. Landsman Remove pre-V5.0 HANDLE options July 2004
+; W. Landsman Remove EXECUTE() call with POINTERS May 2005
+; C. Markwardt Allow the output table to have TSCAL/TZERO
+; keyword values; if that is the case, then the passed values
+; will be quantized to match those scale factors before being
+; written. Sep 2007
+; E. Hivon: write 64bit integer and double precision columns, Mar 2008
+; C. Markwardt Allow unsigned integers, which have special
+; TSCAL/TZERO values. Feb 2009
+; C. Markwardt Add support for files larger than 2 GB, 2012-04-17
+;
+;-
+;
+ compile_opt idl2
+@fxbintable
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 2 THEN BEGIN
+ MESSAGE = 'Syntax: FXBWRITM, UNIT, COL, DATA1, DATA2, ' $
+ +' ..., ROW=, POINTERS=, PASS_METHOD=, NANVALUE=, BUFFERSIZE='
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_ELEMENTS(BUFFERSIZE) EQ 0 THEN BUFFERSIZE = 32768L
+
+;
+; COL may be one of several descriptors:
+; * a list of column numbers, beginning with 1
+; * a list of column names
+;
+ MYCOL = [ COL ] ; Make sure it is an array
+
+ SC = SIZE(MYCOL)
+ NUMCOLS = N_ELEMENTS(MYCOL)
+ OUTSTATUS = LONARR(NUMCOLS)
+ COLNAMES = 'D'+STRTRIM(LINDGEN(50),2)
+
+;
+; Determine whether the data has been passed as arguments or pointers
+;
+ IF N_ELEMENTS(PASS_METHOD) EQ 0 THEN PASS_METHOD = 'ARGUMENT'
+ PASS = STRUPCASE(STRTRIM(PASS_METHOD[0],2))
+ IF PASS NE 'ARGUMENT' AND PASS NE 'POINTER' THEN BEGIN
+ MESSAGE = 'ERROR: PASS_METHOD must be ARGUMENT or POINTER'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ NP = N_ELEMENTS(POINTERS)
+ IF PASS NE 'ARGUMENT' AND NP LT NUMCOLS THEN BEGIN
+ MESSAGE = 'ERROR: POINTERS array contains too few elements'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ IF PASS EQ 'POINTER' THEN BEGIN
+ SZ = SIZE(POINTERS)
+ IF SZ[SZ[0]+1] NE 10 THEN BEGIN
+ MESSAGE = 'ERROR: POINTERS must be an array of pointers'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ WH = WHERE(PTR_VALID(POINTERS[0:NUMCOLS-1]) EQ 0, CT)
+ IF CT GT 0 THEN BEGIN
+ MESSAGE = 'ERROR: POINTERS contains invalid pointers'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+ ENDIF
+
+
+;
+; Find the logical unit number in the FXBINTABLE common block.
+;
+ ILUN = WHERE(LUN EQ UNIT,NLUN)
+ ILUN = ILUN[0]
+ IF NLUN EQ 0 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened properly'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Make sure the file was opened for write access.
+;
+ IF STATE[ILUN] NE 2 THEN BEGIN
+ MESSAGE = 'Unit ' + STRTRIM(UNIT,2) + $
+ ' not opened for write access'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+;
+; Check the number of columns. It should be fewer than 50
+;
+ IF (NUMCOLS GT 50) AND (PASS EQ 'ARGUMENT') THEN BEGIN
+ MESSAGE = 'Maximum of 50 columns exceeded'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+; Commented out because too much data is not a problem
+; IF NUMCOLS LT N_PARAMS()-2 THEN BEGIN
+; MESSAGE = 'ERROR: too few data parameters passed'
+; IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+; ERRMSG = MESSAGE
+; RETURN
+; END ELSE MESSAGE, MESSAGE
+; ENDIF
+
+ ICOL = LONARR(NUMCOLS)
+ FOUND = BYTARR(NUMCOLS)
+ NOTFOUND = ''
+ NNOTFOUND = 0L
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = ''
+
+;
+; If COL is of type string, then search for a column with that label.
+;
+ IF SC[SC[0]+1] EQ 7 THEN BEGIN
+ MYCOL = STRUPCASE(STRTRIM(MYCOL,2))
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ XCOL = WHERE(TTYPE[*,ILUN] EQ MYCOL[I], NCOL)
+ ICOL[I] = XCOL[0]
+ IF NCOL GT 0 THEN FOUND[I] = 1
+ IF NOT FOUND[I] THEN BEGIN
+ IF NOTFOUND EQ '' THEN NOTFOUND = MYCOL[I] $
+ ELSE NOTFOUND = NOTFOUND +', ' + MYCOL[I]
+ NNOTFOUND = NNOTFOUND + 1
+ ENDIF
+ ENDFOR
+
+ IF NNOTFOUND EQ NUMCOLS THEN BEGIN
+ MESSAGE = 'ERROR: None of the requested columns were found'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF ELSE IF NNOTFOUND GT 0 THEN BEGIN
+ MESSAGE = 'WARNING: Columns ' + NOTFOUND + ' were not found'
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = MESSAGE $
+ ELSE MESSAGE, MESSAGE, /INFO
+ ENDIF
+;
+; Otherwise, a numerical column was passed. Check its value.
+;
+ ENDIF ELSE BEGIN
+ ICOL[*] = LONG(MYCOL) - 1
+ FOUND[ICOL] = 1
+ ENDELSE
+
+
+;
+; Step through each column index, and check for validity
+;
+ MESSAGE = ''
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ IF NOT FOUND[I] THEN GOTO, LOOP_END_COLCHECK
+
+ IF (ICOL[I] LT 0) OR (ICOL[I] GE TFIELDS[ILUN]) THEN BEGIN
+ MESSAGE = 'COL "'+STRTRIM(MYCOL[I],2)+$
+ '" must be between 1 and ' + $
+ STRTRIM(TFIELDS[ILUN],2)
+ FOUND[I] = 0
+ ENDIF
+;
+; If there are no elements in the array, then set !ERR to -1.
+;
+ IF FOUND[I] AND N_ELEM[ICOL[I],ILUN] EQ 0 THEN BEGIN
+ FOUND[I] = 0
+ MESSAGE = MESSAGE + '; Number of elements to write in "'+$
+ STRTRIM(MYCOL[I],2)+'" should be zero'
+ ENDIF
+
+;
+; Do not permit variable-length columns
+;
+ IF MAXVAL[ICOL[I],ILUN] GT 0 THEN BEGIN
+ MESSAGE = MESSAGE + 'FXBWRITM cannot write ' + $
+ 'variable-length column "'+STRTRIM(MYCOL[I],2)+'"'
+ FOUND[I] = 0
+ ENDIF
+
+ LOOP_END_COLCHECK:
+
+ ENDFOR
+;
+; If ROW was not passed, then set it equal to the entire range. Otherwise,
+; extract the range.
+;
+ IF N_ELEMENTS(ROW) EQ 0 THEN BEGIN
+ ROW = [1LL, NAXIS2[ILUN]]
+ ENDIF
+ CASE N_ELEMENTS(ROW) OF
+ 1: ROW2 = LONG64(ROW[0])
+ 2: ROW2 = LONG64(ROW[1])
+ ELSE: BEGIN
+ MESSAGE = 'ROW must have one or two elements'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ ENDCASE
+ ROW1 = LONG64(ROW[0])
+
+;
+; If ROW represents a range, then make sure that the row range is legal, and
+; that reading row ranges is allowed (i.e., the column is not variable length.
+;
+ IF ROW1 NE ROW2 THEN BEGIN
+ MAXROW = NAXIS2[ILUN]
+ IF (ROW1 LT 1) OR (ROW1 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[0] must be between 1 and ' + $
+ STRTRIM(MAXROW,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF (ROW2 LT ROW1) OR (ROW2 GT MAXROW) THEN BEGIN
+ MESSAGE = 'ROW[1] must be between ' + $
+ STRTRIM(ROW1,2) + ' and ' + STRTRIM(MAXROW,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Otherwise, if ROW is a single number, then just make sure it's valid.
+;
+ END ELSE BEGIN
+ IF (ROW1 LT 1) OR (ROW1 GT NAXIS2[ILUN]) THEN BEGIN
+ MESSAGE = 'ROW must be between 1 and ' + $
+ STRTRIM(NAXIS2[ILUN],2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDELSE
+
+;
+; Check the type of the data against that defined for this column.
+;
+ COLNDIM = LONARR(NUMCOLS)
+ COLDIM = LONARR(NUMCOLS, 8) ;; Maximum of 8 dimensions in output
+ COLTYPE = LONARR(NUMCOLS)
+ BOFF1 = LONARR(NUMCOLS)
+ BOFF2 = LONARR(NUMCOLS)
+ NOUTPUT = LONARR(NUMCOLS)
+ NROWS = ROW2-ROW1+1
+ MESSAGE = ''
+ DTYPENAMES = [ 'BAD TYPE', 'BYTE', 'FIX', 'LONG', $
+ 'FLOAT', 'DOUBLE', 'COMPLEX', 'STRING', $
+ 'BAD TYPE', 'DCOMPLEX', $
+ 'BAD TYPE', 'BAD TYPE', 'BAD TYPE', 'BAD TYPE', 'LONG64' ]
+ FOR I = 0L, NUMCOLS-1 DO BEGIN
+
+ IF NOT FOUND[I] THEN GOTO, LOOP_END_DIMS
+ ;; Data type of the input.
+ COLTYPE[I] = IDLTYPE[ICOL[I],ILUN]
+
+ SZ = 0
+ IF PASS EQ 'ARGUMENT' THEN BEGIN
+ RESULT = EXECUTE('SZ = SIZE('+COLNAMES[I]+')')
+ IF RESULT EQ 0 THEN BEGIN
+ MESSAGE = MESSAGE + '; Could not extract type info (column '+$
+ STRTRIM(MYCOL[I],2)+')'
+ FOUND[I] = 0
+ ENDIF
+ ENDIF ELSE SZ = SIZE(*(POINTERS[I]))
+
+ TSCAL1 = TSCAL[ICOL[I],ILUN]
+ TZERO1 = TZERO[ICOL[I],ILUN]
+
+ TYPE = SZ[SZ[0]+1]
+ TYPE_BAD = TYPE NE COLTYPE[I]
+ ;; Handle case of scaled data being stored in an
+ ;; integer column
+ IF NOT KEYWORD_SET(NOSCALE) AND $
+ (TSCAL1 NE 0) AND (TSCAL1 NE 1) AND $
+ (TYPE EQ 4 OR TYPE EQ 5) AND $
+ (COLTYPE[I] EQ 2 OR COLTYPE[I] EQ 3 OR COLTYPE[I] EQ 14) THEN $
+ TYPE_BAD = 0
+
+ ;; Unsigned types are OK
+ IF TSCAL1 EQ 1 AND $
+ ((COLTYPE[I] EQ 2 AND TZERO1 EQ 32768) OR $
+ (COLTYPE[I] EQ 3 AND TZERO1 EQ 2147483648D)) AND $
+ (TYPE EQ 1 OR TYPE EQ 2 OR TYPE EQ 3 OR $
+ TYPE EQ 12 OR TYPE EQ 13 OR TYPE EQ 14) THEN BEGIN
+ TYPE_BAD = 0
+ ENDIF
+
+ IF TYPE_BAD THEN BEGIN
+ CASE COLTYPE[I] OF
+ 1: STYPE = 'byte'
+ 2: STYPE = 'short integer'
+ 3: STYPE = 'long integer'
+ 4: STYPE = 'floating point'
+ 5: STYPE = 'double precision'
+ 6: STYPE = 'complex'
+ 7: STYPE = 'string'
+ 9: STYPE = 'double complex'
+ 12: STYPE = 'unsigned integer'
+ 13: STYPE = 'unsigned long integer'
+ 14: STYPE = 'long64 integer'
+ ENDCASE
+ FOUND[I] = 0
+ MESSAGE = '; Data type (column '+STRTRIM(MYCOL[I],2)+$
+ ') should be ' + STYPE
+ ENDIF
+
+ DIMS = N_DIMS[*,ICOL[I],ILUN]
+ NDIMS = DIMS[0]
+ DIMS = DIMS[1:NDIMS]
+
+ IF NDIMS EQ 1 AND DIMS[0] EQ 1 THEN BEGIN
+
+ ;; Case of only one output element, try to return a
+ ;; scalar. Otherwise, it is a vector equal to the
+ ;; number of rows to be read
+
+ COLNDIM[I] = 1L
+ COLDIM[I,0] = NROWS
+ ENDIF ELSE BEGIN
+
+ COLNDIM[I] = NDIMS
+ COLDIM[I,0:(NDIMS-1)] = DIMS
+ IF NROWS GT 1 THEN BEGIN
+ COLDIM[I,NDIMS] = NROWS
+ COLNDIM[I] = COLNDIM[I]+1
+ ENDIF
+
+ ENDELSE
+
+;
+; Check the number of elements in the input
+;
+ NOUTP = ROUND(PRODUCT(COLDIM[I,0:COLNDIM[I]-1]))
+ IF SZ[SZ[0]+1] EQ 7 THEN BEGIN
+ NOUTP = NOUTP / COLDIM[I,0]
+ IF NOUTP NE SZ[SZ[0]+2] THEN GOTO, ERR_NELEM
+ NOUTPUT[I] = NOUTP
+ ENDIF ELSE IF SZ[SZ[0]+2] NE NOUTP THEN BEGIN
+ ERR_NELEM:
+ MESSAGE = MESSAGE+'; Data array (column '+STRTRIM(MYCOL[I],2)+$
+ ') should have ' + STRTRIM(LONG(NOUTP),2) + ' elements'
+ FOUND[I] = 0
+ ENDIF ELSE NOUTPUT[I] = NOUTP
+
+ ;; Byte offsets
+ BOFF1[I] = BYTOFF[ICOL[I],ILUN]
+ IF ICOL[I] EQ TFIELDS[ILUN]-1 THEN BOFF2[I] = NAXIS1[ILUN]-1 $
+ ELSE BOFF2[I] = BYTOFF[ICOL[I]+1,ILUN]-1
+
+ LOOP_END_DIMS:
+
+ ENDFOR
+
+;
+; Check to be sure that there are columns to be written
+;
+ W = WHERE(FOUND EQ 1, COUNT)
+ IF COUNT EQ 0 THEN BEGIN
+ STRPUT, MESSAGE, ':', 0
+ MESSAGE = 'ERROR: No requested columns could be written'+MESSAGE
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF ELSE IF MESSAGE NE '' THEN BEGIN
+ STRPUT, MESSAGE, ':', 0
+ MESSAGE = 'WARNING: Some columns could not be written'+MESSAGE
+ IF N_ELEMENTS(WARNMSG) NE 0 THEN WARNMSG = MESSAGE $
+ ELSE MESSAGE, MESSAGE, /INFO
+ ENDIF
+
+ ;; I construct a list of unique column names here. Why?
+ ;; Because if *all* the columns are named, then there is no
+ ;; need to read the data from disk first. Since columns can
+ ;; be given more than once in MYCOL, we need to uniq-ify it.
+ CC = MYCOL[UNIQ(MYCOL, SORT(MYCOL))]
+ NC = N_ELEMENTS(CC)
+
+;
+; Find the position of the first byte of the data array in the file.
+;
+ OFFSET0 = NHEADER[ILUN] + NAXIS1[ILUN]*(ROW1-1LL)
+
+ POS = 0LL
+ NROWS0 = NROWS
+ J = 0LL
+ ;; Here, we constrain the buffer to be at least 16 rows long.
+ ;; If we fill up 32 kB with fewer than 16 rows, then there
+ ;; must be a lot of (big) columns in this table. It's
+ ;; probably a candidate for using FXBREAD instead.
+ BUFFROWS = LONG((BUFFERSIZE/NAXIS1[ILUN]) > 16L)
+ IF BUFFERSIZE LE 0 THEN BUFFROWS = NROWS0
+
+;
+; Loop through the data in chunks
+;
+ WHILE NROWS GT 0 DO BEGIN
+ J = J + 1
+ NR = NROWS < BUFFROWS
+ OFFSET1 = NAXIS1[ILUN]*POS
+;
+; Proceed by reading a byte array from the input data file
+; FXBREADM reads all columns from the specified rows, and
+; sorts out the details of which bytes belong to which columns
+; in the next FOR loop.
+;
+ BB = BYTARR(NAXIS1[ILUN], NR)
+; If *all* columns are being filled, then there is no reason to
+; read from the file
+
+ IF NC LT TFIELDS[ILUN] THEN BEGIN
+ POINT_LUN,UNIT,OFFSET0+OFFSET1
+ READU, UNIT, BB
+ ENDIF
+
+;
+; Now select out the desired columns to write
+;
+ FOR I = 0, NUMCOLS-1 DO BEGIN
+ IF NOT FOUND[I] THEN GOTO, LOOP_END_WRITE
+
+ ;; Copy data into DD
+ IF PASS EQ 'ARGUMENT' THEN BEGIN
+ RESULT = EXECUTE('DD = '+COLNAMES[I])
+ IF RESULT EQ 0 THEN GOTO, LOOP_END_WRITE
+ ENDIF ELSE DD = *(POINTERS[I])
+
+; ENDIF
+ IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD]
+ DD = REFORM(DD, NOUTPUT[I]/NROWS0, NROWS0, /OVERWRITE)
+ IF POS GT 0 OR NR LT NROWS0 THEN $
+ DD = DD[*,POS:(POS+NR-1)]
+
+ ;; Now any conversions to FITS format must be done
+ COUNT = 0L
+ CT = COLTYPE[I]
+
+ ;; Perform data scaling, if scaling values are available
+ IF NOT KEYWORD_SET(NOSCALE) THEN BEGIN
+ TSCAL1 = TSCAL[ICOL[I],ILUN]
+ TZERO1 = TZERO[ICOL[I],ILUN]
+ IF TSCAL1 EQ 0 THEN TSCAL1 = 1
+ ;; Handle special unsigned cases
+ IF TZERO1 EQ 32768 AND TSCAL1 EQ 1 AND CT EQ 2 THEN $
+ ;; Unsigned integer
+ DD = UINT(DD) - UINT(TZERO1) $
+ ELSE IF TZERO1 EQ 2147483648D AND TSCAL1 EQ 1 AND CT EQ 3 THEN $
+ ;; Unsigned long integer
+ DD = ULONG(DD) - ULONG(TZERO1) $
+ ELSE IF TZERO1 NE 0 THEN DD = DD - TZERO1
+ IF TSCAL1 NE 1 THEN DD = DD / TSCAL1
+ ENDIF
+ SZ = SIZE(DD)
+ TP = SZ[SZ[0]+1]
+
+ CASE 1 OF
+ ;; Integer types
+ (CT EQ 1): BEGIN
+ ;; Type-cast may be needed if we used TSCAL/TZERO
+ IF TP NE 1 THEN DD = BYTE(DD)
+ END
+ (CT EQ 2): BEGIN
+ ;; Type-cast may be needed if we used TSCAL/TZERO
+ IF TP NE 2 THEN DD = FIX(DD)
+ IF NOT KEYWORD_SET(NOIEEE) THEN $
+ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE
+ END
+ (CT EQ 3): BEGIN
+ ;; Type-cast may be needed if we used TSCAL/TZERO
+ IF TP NE 3 THEN DD = LONG(DD)
+ IF NOT KEYWORD_SET(NOIEEE) THEN $
+ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE
+
+ END
+ (ct eq 14): begin
+ ;; Type-cast may be needed if we used TSCAL/TZERO
+ IF TP NE 14 THEN DD = LONG(DD)
+ IF NOT KEYWORD_SET(NOIEEE) THEN $
+ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE
+ end
+
+ ;; Floating and complex types
+ (CT GE 4 AND CT LE 6 OR CT EQ 9): BEGIN
+ IF NOT KEYWORD_SET(NOIEEE) THEN BEGIN
+ IF N_ELEMENTS(NANVALUE) EQ 1 THEN BEGIN
+ W=WHERE(DD EQ NANVALUE,COUNT)
+ NAN = REPLICATE('FF'XB,16)
+ NAN = CALL_FUNCTION(DTYPENAMES,NAN,0,1)
+ ENDIF
+ SWAP_ENDIAN_INPLACE, DD,/SWAP_IF_LITTLE
+ IF COUNT GT 0 THEN DD[W] = NAN
+ ENDIF
+ END
+
+ ;; String type, needs to be padded with spaces
+ (CT EQ 7): BEGIN
+ N_CHAR = N_DIMS[1,ICOL[I],ILUN]
+ ;; Largest string determines size of array
+ MAXLEN = MAX(STRLEN(DD)) > 1
+ ;; Convert to bytes
+ DD = BYTE(TEMPORARY(DD))
+ IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD]
+ DD = REFORM(DD, MAXLEN, NR, /OVERWRITE)
+
+ ;; Put it into the output array
+ IF MAXLEN GT N_CHAR THEN BEGIN
+ DD = DD[0:(N_CHAR-1),*]
+ ENDIF ELSE BEGIN
+ DB = BYTARR(N_CHAR, NR)
+ DB[0:(MAXLEN-1),*] = TEMPORARY(DD)
+ DD = TEMPORARY(DB)
+ ENDELSE
+
+ ;; Pad any zeroes with spaces
+ WB = WHERE(DD EQ 0b, WCOUNT)
+ IF WCOUNT GT 0 THEN DD[WB] = 32B
+
+ ;; Pretend that it is a byte array
+ CT = 1
+ END
+ ENDCASE
+ IF CT NE 1 THEN $
+ DD = BYTE(TEMPORARY(DD),0,(BOFF2[I]-BOFF1[I]+1),NR)
+ IF N_ELEMENTS(DD) EQ 1 THEN DD = [DD]
+ DD = REFORM(DD, BOFF2[I]-BOFF1[I]+1, NR, /OVERWRITE)
+
+ ;; Now place the data into the byte array
+ BB[BOFF1[I],0] = DD
+
+ OUTSTATUS[I] = 1
+ LOOP_END_WRITE:
+ END
+
+ ;; Finally, write byte array to output file
+ POINT_LUN, UNIT, OFFSET0+OFFSET1
+ BB = REFORM(BB, N_ELEMENTS(BB), /OVERWRITE)
+ WRITEU, UNIT, BB
+
+ NROWS = NROWS - NR
+ POS = POS + NR
+ ENDWHILE
+
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxfindend.pro b/Code/script_idl_mv/astrolib/fxfindend.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b33c1aaa1ed595afbca207f4d48fa7db719c2dc1
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxfindend.pro
@@ -0,0 +1,93 @@
+ PRO FXFINDEND,UNIT, EXTENSION
+;+
+; NAME:
+; FXFINDEND
+; Purpose :
+; Find the end of a FITS file.
+; Explanation :
+; This routine finds the end of the last logical record in a FITS file,
+; which may be different from that of the physical end of the file. Each
+; FITS header is read in and parsed, and the file pointer is moved to
+; where the next FITS extension header would be if there is one, or to
+; the end of the file if not.
+; Use :
+; FXFINDEND, UNIT [, EXTENSION]
+; Inputs :
+; UNIT = Logical unit number for the opened file.
+; Opt. Inputs :
+; None.
+; Outputs :
+; None.
+; Opt. Outputs:
+; EXTENSION = The extension number that a new extension would
+; have if placed at the end of the file.
+; Keywords :
+; None.
+; Calls :
+; FXHREAD, FXPAR
+; Common :
+; None.
+; Restrictions:
+; The file must have been opened for block I/O. There must not be any
+; FITS "special records" at the end of the file.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Feb. 1992.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version :
+; Version 1, 12 April 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+; Added EXTENSION parameter, CM 1999 Nov 18
+; Allow for possible 64bit integer number of bytes W. Landsman Nov 2007
+; make Ndata a long64 to deal with large files. E. Hivon Mar 2008
+;-
+;
+ ON_ERROR,2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() EQ 0 THEN MESSAGE,'Syntax: FXFINDEND, UNIT [,EXTENSION]'
+;
+; Go to the start of the file.
+;
+ POINT_LUN,UNIT,0
+ EXTENSION = 0L
+;
+; Read the next header, and get the number of bytes taken up by the data.
+;
+NEXT_EXT:
+ FXHREAD,UNIT,HEADER,STATUS
+ IF STATUS NE 0 THEN GOTO, DONE
+ BITPIX = FXPAR(HEADER,'BITPIX')
+ NAXIS = FXPAR(HEADER,'NAXIS')
+ GCOUNT = FXPAR(HEADER,'GCOUNT') & IF GCOUNT EQ 0 THEN GCOUNT = 1
+ PCOUNT = FXPAR(HEADER,'PCOUNT')
+ IF NAXIS GT 0 THEN BEGIN
+ DIMS = FXPAR(HEADER,'NAXIS*') ;Read dimensions
+ NDATA = long64(DIMS[0])
+ IF NAXIS GT 1 THEN FOR I=2,NAXIS DO NDATA = NDATA*DIMS[I-1]
+ ENDIF ELSE NDATA = 0
+ NBYTES = LONG64(ABS(BITPIX) / 8) * GCOUNT * (PCOUNT + NDATA)
+;
+; Move to the next extension header in the file.
+;
+ NREC = (NBYTES + 2879) / 2880
+ POINT_LUN, -UNIT, POINTLUN ;Current position
+ POINT_LUN, UNIT, POINTLUN + NREC*2880L ;Next FITS extension
+ EXTENSION = EXTENSION + 1L
+ IF NOT EOF(UNIT) THEN GOTO, NEXT_EXT
+;
+; When done, make sure that the pointer is positioned at the first byte after
+; the last data set.
+;
+DONE:
+ POINT_LUN, UNIT, POINTLUN + NREC*2880L
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxhclean.pro b/Code/script_idl_mv/astrolib/fxhclean.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2b162ed1f026a294b74b43f464e357b056d03ad2
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxhclean.pro
@@ -0,0 +1,110 @@
+ PRO FXHCLEAN,HEADER,ERRMSG=ERRMSG
+;+
+; NAME:
+; FXHCLEAN
+; Purpose :
+; Removes required keywords from FITS header.
+; Explanation :
+; Removes any keywords relevant to array structure from a FITS header,
+; preparatory to recreating it with the proper values.
+; Use :
+; FXHCLEAN, HEADER
+; Inputs :
+; HEADER = FITS header to be cleaned.
+; Opt. Inputs :
+; None.
+; Outputs :
+; HEADER = The cleaned FITS header is returned in place of the input
+; array.
+; Opt. Outputs:
+; None.
+; Keywords :
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXHCLEAN, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; SXDELPAR, FXPAR
+; Common :
+; None.
+; Restrictions:
+; HEADER must be a string array containing a properly formatted FITS
+; header.
+; Side effects:
+; Warning: when cleaning a binary table extension header, not all of the
+; keywords pertaining to columns in the table may be removed.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, William Thompson, GSFC, 30 December 1994
+; Added TCUNIn to list of column keywords to be removed.
+; Version :
+; Version 4, 30 December 1994
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR, 2
+;
+; Check the number of input parameters.
+;
+ IF N_PARAMS() NE 1 THEN BEGIN
+ MESSAGE = 'Syntax: FXHCLEAN, HEADER'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Check the type of HEADER.
+;
+ S = SIZE(HEADER)
+ IF (S[0] NE 1) OR (S[2] NE 7) THEN BEGIN
+ MESSAGE = 'HEADER must be a (one-dimensional) string array'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Start removing the various keywords relative to the structure of the FITS
+; file.
+;
+ SXDELPAR,HEADER,['SIMPLE','EXTEND','XTENSION','BITPIX','PCOUNT', $
+ 'GCOUNT','THEAP']
+;
+; Get the number of axes as stored in the header. Then, remove it, and any
+; NAXISnnn keywords implied by it.
+;
+ NAXIS = FXPAR(HEADER,'NAXIS')
+ SXDELPAR,HEADER,'NAXIS'
+ IF NAXIS GT 0 THEN FOR I=1,NAXIS DO $
+ SXDELPAR,HEADER,'NAXIS'+STRTRIM(I,2)
+;
+; Get the number of columns in a binary table. Remove any column definitions.
+;
+ TFIELDS = FXPAR(HEADER,'TFIELDS')
+ SXDELPAR,HEADER,'TFIELDS'
+ IF TFIELDS GT 0 THEN FOR I=1,TFIELDS DO SXDELPAR,HEADER, $
+ ['TFORM','TTYPE','TDIM','TUNIT','TSCAL','TZERO', $
+ 'TNULL','TDISP','TDMIN','TDMAX','TDESC','TROTA', $
+ 'TRPIX','TRVAL','TDELT','TCUNI'] + STRTRIM(I,2)
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxhmake.pro b/Code/script_idl_mv/astrolib/fxhmake.pro
new file mode 100644
index 0000000000000000000000000000000000000000..598a455ba0b3fa10676383009fdebccf9624d19a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxhmake.pro
@@ -0,0 +1,252 @@
+ PRO FXHMAKE, HEADER, DATA, EXTEND=EXTEND, DATE=DATE, $
+ INITIALIZE=INITIALIZE, ERRMSG=ERRMSG, XTENSION=XTENSION
+;+
+; NAME:
+; FXHMAKE
+; Purpose :
+; Create a basic FITS header array.
+; Explanation :
+; Creates a basic header array with all the required keywords. This
+; defines a basic structure which can then be added to or modified by
+; other routines.
+; Use :
+; FXHMAKE, HEADER [, DATA ]
+; Inputs :
+; None required.
+; Opt. Inputs :
+; DATA = IDL data array to be written to file. It must be in the
+; primary data unit unless the XTENSION keyword is supplied.
+; This array is used to determine the values of the BITPIX and
+; NAXIS, etc. keywords.
+;
+; If not passed, then BITPIX is set to eight, NAXIS is set to
+; zero, and no NAXISnnn keywords are included in this
+; preliminary header.
+; Outputs :
+; HEADER = String array containing FITS header.
+; Opt. Outputs:
+; None.
+; Keywords :
+; INITIALIZE = If set, then the header is completely initialized, and any
+; previous entries are lost.
+; EXTEND = If set, then the keyword EXTEND is inserted into the file,
+; with the value of "T" (true).
+; DATE = If set, then the DATE keyword is added to the header.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXHMAKE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+; XTENSION - If set, then the header is appropriate for an image
+; extension, rather than the primary data unit.
+; Calls :
+; GET_DATE, FXADDPAR, FXHCLEAN
+; Common :
+; None.
+; Restrictions:
+; Groups are not currently supported.
+; Side effects:
+; BITPIX, NAXIS, etc. are defined such that complex arrays are stored as
+; floating point, with an extra first dimension of two elements (real and
+; imaginary parts).
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992, from SXHMAKE by D. Lindler and M. Greason.
+; Differences include:
+;
+; * Use of FITS standard (negative BITPIX) to signal floating
+; point numbers instead of (SDAS/Geis) DATATYPE keyword.
+; * Storage of complex numbers as pairs of real numbers.
+; * Support for EXTEND keyword, and for cases where there is no
+; primary data array.
+; * Insertion of DATE record made optional. Only required FITS
+; keywords are inserted automatically.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 21 June 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, Wayne Landsman, GSFC, 12 August 1997
+; Recognize double complex data type
+; Converted to IDL V5.0 W. Landsman September 1997
+; Version 6, William Thompson, GSFC, 22 September 2004
+; Recognize unsigned integer types.
+; Version 6.1, C. Markwardt, GSFC, 19 Jun 2005
+; Add the XTENSION keyword, which writes an XTENSION
+; keyword instead of SIMPLE.
+; Version :
+; Version 6.1, 19 June 2005
+;-
+;
+ ON_ERROR,2
+;
+; Check the number of parameters first.
+;
+ IF N_PARAMS() LT 1 THEN BEGIN
+ MESSAGE = 'Calling sequence: FXHMAKE, HEADER [, DATA ]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If no data array was passed, then set BITPIX=8 and NAXIS=0. Otherwise,
+; calculate these parameters.
+;
+ IF N_PARAMS() EQ 1 THEN BEGIN
+ BITPIX = 8
+ COMMENT = ''
+ S = 0
+ END ELSE BEGIN
+ S = SIZE(DATA) ;obtain size of array.
+ DTYPE = S[S[0]+1] ;type of data.
+ CASE DTYPE OF
+ 0: BEGIN
+ MESSAGE = 'Data parameter is not defined'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ 1: BEGIN
+ BITPIX = 8
+ COMMENT = 'Integer*1 (byte)'
+ END
+ 2: BEGIN
+ BITPIX = 16
+ COMMENT = 'Integer*2 (short integer)'
+ END
+ 3: BEGIN
+ BITPIX = 32
+ COMMENT = 'Integer*4 (long integer)'
+ END
+ 4: BEGIN
+ BITPIX = -32
+ COMMENT = 'Real*4 (floating point)'
+ END
+ 5: BEGIN
+ BITPIX = -64
+ COMMENT = 'Real*8 (double precision)'
+ END
+ 6: BEGIN ;Complex*8 (complex)
+ BITPIX = -32 ;Store as float
+ S = [S[0]+1, 2, S[1:*]] ;with extra dim
+ COMMENT = 'Real*4 (complex, stored as float)'
+ END
+ 7: BEGIN
+ MESSAGE = "Can't write strings to FITS files"
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ 8: BEGIN
+ MESSAGE = "Can't write structures to FITS files"
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ 9: BEGIN
+ BITPIX = -64 ;Store as double
+ S = [S[0]+1, 2, S[1:*]] ;with extra dim
+ COMMENT = 'Real*8 (dcomplex, stored as double)'
+ END
+;
+; Unsigned data types may require use of BZERO/BSCALE--handled in writer.
+;
+ 12: BEGIN ;Unsigned integer
+ BITPIX = 16
+ COMMENT = 'Integer*2 (short integer)'
+ END
+ 13: BEGIN ;Unsigned long integer
+ BITPIX = 32
+ COMMENT = 'Integer*4 (long integer)'
+ END
+
+ ENDCASE
+ ENDELSE
+;
+; If requested, then initialize the header.
+;
+ IF KEYWORD_SET(INITIALIZE) THEN BEGIN
+ HEADER = STRARR(36)
+ HEADER[0] = 'END' + STRING(REPLICATE(32B,77))
+;
+; Else, if undefined, then initialize the header.
+;
+ END ELSE IF N_ELEMENTS(HEADER) EQ 0 THEN BEGIN
+ HEADER = STRARR(36)
+ HEADER[0] = 'END' + STRING(REPLICATE(32B,77))
+;
+; Otherwise, make sure that HEADER is a string array, and remove any keywords
+; that describe the format of the file.
+;
+ END ELSE BEGIN
+ SZ = SIZE(HEADER)
+ IF (SZ[0] NE 1) OR (SZ[2] NE 7) THEN BEGIN
+ MESSAGE = 'HEADER must be a (one-dimensional) ' + $
+ 'string array'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ FXHCLEAN,HEADER,ERRMSG=ERRMSG
+ IF ERRMSG NE '' THEN RETURN
+ END ELSE FXHCLEAN,HEADER
+ ENDELSE
+;
+; The first keyword must be "SIMPLE". Normally, this has the value "T"
+; (true).
+;
+ IF KEYWORD_SET(XTENSION) THEN BEGIN
+ FXADDPAR,HEADER,'XTENSION','IMAGE','Written by IDL: '+ SYSTIME()
+ ENDIF ELSE BEGIN
+ FXADDPAR,HEADER,'SIMPLE','T','Written by IDL: '+ SYSTIME()
+ ENDELSE
+;
+; The second keyword must be "BITPIX", and the third "NAXIS".
+;
+ FXADDPAR,HEADER,'BITPIX',BITPIX,COMMENT
+ FXADDPAR,HEADER,'NAXIS',S[0] ;# of dimensions
+;
+; If NAXIS is not zero, then add the keywords for the axes. If the data array
+; is complex, then add a comment to the first axis to note that this is
+; actually the real and imaginary parts of the complex number.
+;
+ IF S[0] NE 0 THEN FOR I=1,S[0] DO BEGIN
+ IF (I EQ 1) AND (DTYPE EQ 6) THEN BEGIN
+ FXADDPAR,HEADER,'NAXIS1',S[I], $
+ 'Real and imaginary parts'
+ END ELSE BEGIN
+ FXADDPAR,HEADER,'NAXIS'+STRTRIM(I,2),S[I]
+ ENDELSE
+ ENDFOR
+;
+; If requested, add the EXTEND keyword to the header, and set it to true.
+;
+ IF KEYWORD_SET(EXTEND) THEN $
+ FXADDPAR,HEADER,'EXTEND','T','File contains extensions'
+;
+; If requested, add the DATE keyword to the header, containing the current
+; date.
+;
+ IF KEYWORD_SET(DATE) THEN BEGIN
+ GET_DATE,DTE ;Get current date as CCYY-MM-DD
+ FXADDPAR,HEADER,'DATE',DTE
+ ENDIF
+;
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxhmodify.pro b/Code/script_idl_mv/astrolib/fxhmodify.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8ac0ad27c982cbc70799536e369f0b67ca36b172
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxhmodify.pro
@@ -0,0 +1,277 @@
+PRO FXHMODIFY, FILENAME, NAME, VALUE, COMMENT, BEFORE=BEFORE, $
+ AFTER=AFTER, FORMAT=FORMAT, EXTENSION=EXTENSION, ERRMSG=ERRMSG,$
+ NOGROW=NOGROW
+;+
+; NAME:
+; FXHMODIFY
+; PURPOSE :
+; Modify a FITS header in a file on disk.
+; Explanation :
+; Opens a FITS file, and adds or modifies a parameter in the FITS header.
+; Can be used for either the main header, or for an extension header.
+; The modification is performed directly on the disk file.
+; Use :
+; FXHMODIFY, FILENAME, NAME, VALUE, COMMENT
+; Inputs :
+; FILENAME = String containing the name of the file to be read.
+;
+; NAME = Name of parameter, scalar string If NAME is already in the
+; header the value and possibly comment fields are modified.
+; Otherwise a new record is added to the header. If NAME is
+; equal to either "COMMENT" or "HISTORY" then the value will be
+; added to the record without replacement. In this case the
+; comment parameter is ignored.
+;
+; VALUE = Value for parameter. The value expression must be of the
+; correct type, e.g. integer, floating or string. String
+; values of 'T' or 'F' are considered logical values.
+;
+; Opt. Inputs :
+; COMMENT = String field. The '/' is added by this routine. Added
+; starting in position 31. If not supplied, or set equal to ''
+; (the null string), then any previous comment field in the
+; header for that keyword is retained (when found).
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; EXTENSION = Either the number of the FITS extension, starting with the
+; first extension after the primary data unit being one; or a
+; character string containing the value of EXTNAME to search
+; for. If not passed, then the primary FITS header is
+; modified.
+;
+; BEFORE = Keyword string name. The parameter will be placed before the
+; location of this keyword. For example, if BEFORE='HISTORY'
+; then the parameter will be placed before the first history
+; location. This applies only when adding a new keyword;
+; keywords already in the header are kept in the same position.
+;
+; AFTER = Same as BEFORE, but the parameter will be placed after the
+; location of this keyword. This keyword takes precedence over
+; BEFORE.
+;
+; FORMAT = Specifies FORTRAN-like format for parameter, e.g. "F7.3". A
+; scalar string should be used. For complex numbers the format
+; should be defined so that it can be applied separately to the
+; real and imaginary parts.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXHMODIFY, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; FXHREAD, FXPAR, FXADDPAR, BLKSHIFT
+; Restrictions:
+; This routine can not be used to modify any of the keywords that control
+; the structure of the FITS file, e.g. BITPIX, NAXIS, PCOUNT, etc. Doing
+; so could corrupt the readability of the FITS file.
+; Example:
+; Modify the name 'OBJECT' keyword in the primary FITS header of a FITS
+; file 'spec98.ccd' to contain the value 'test domeflat'
+;
+; IDL> fxhmodify, 'spec98.ccd', 'OBJECT', 'test domeflat'
+;
+; Side effects:
+; If adding a record to the FITS header would increase the
+; number of 2880 byte records stored on disk, then the file is
+; enlarged before modification, unless the NOGROW keyword is passed.
+;
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; None.
+; Written :
+; William Thompson, GSFC, 3 March 1994.
+; Modified :
+; Version 1, William Thompson, GSFC, 3 March 1994.
+; Version 2, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 3.1 Wayne Landsman GSFC 17 March 2006
+; Fix problem in BLKSHIFT call if primary header extended
+; Version 3.2 W. Landsman 14 November 204
+; Allow for need for 64bit number of bytes
+; Version 4, William Thompson, GSFC, 22-Dec-2014
+; Modified test for keyword EXTEND to only issue warning.
+;; Version :
+; Version 4, 22-Dec-2014
+;-
+;
+ COMPILE_OPT IDL2
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 3 THEN BEGIN
+ MESSAGE = $ ;Need at least 3 parameters
+ 'Syntax: FXHMODIFY, FILENAME, NAME, VALUE [, COMMENT ]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If passed, check the type of the EXTENSION parameter.
+;
+ IF N_ELEMENTS(EXTENSION) GT 1 THEN BEGIN
+ MESSAGE = 'EXTENSION must be a scalar'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF N_ELEMENTS(EXTENSION) EQ 1 THEN BEGIN
+ SZ = SIZE(EXTENSION)
+ ETYPE = SZ[SZ[0]+1]
+ IF ETYPE EQ 8 THEN BEGIN
+ MESSAGE = 'EXTENSION must not be a structure'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; If EXTENSION is of type string, then search for the proper extension by
+; name. Otherwise, search by number.
+;
+ IF ETYPE EQ 7 THEN BEGIN
+ S_EXTENSION = STRTRIM(STRUPCASE(EXTENSION),2)
+ END ELSE BEGIN
+ I_EXTENSION = FIX(EXTENSION)
+ IF I_EXTENSION LT 1 THEN BEGIN
+ MESSAGE = 'EXTENSION must be greater than zero'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDELSE
+ ENDIF
+;
+; Get the UNIT number, and open the file.
+;
+ OPENU, UNIT, FILENAME, /BLOCK, /GET_LUN
+;
+; Read in the primary FITS header.
+;
+ FXHREAD,UNIT,HEADER,STATUS
+ IF STATUS NE 0 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Unable to read FITS header'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ MHEAD0 = 0
+ I_EXT = 0
+;
+; If the EXTENSION parameter was passed, then look for the requested
+; extension.
+;
+ IF N_ELEMENTS(EXTENSION) EQ 1 THEN BEGIN
+;
+; Make sure that the file does contain extensions. However, only issue a
+; warning if EXTEND keyword not set.
+;
+ IF ~FXPAR(HEADER,'EXTEND') THEN MESSAGE, /CONTINUE, $
+ 'Keyword EXTEND not set in file ' + FILENAME
+;
+; Get the number of bytes taken up by the data.
+;
+NEXT_EXT:
+ BITPIX = FXPAR(HEADER,'BITPIX')
+ NAXIS = FXPAR(HEADER,'NAXIS')
+ GCOUNT = FXPAR(HEADER,'GCOUNT')
+ IF GCOUNT EQ 0 THEN GCOUNT = 1
+ PCOUNT = FXPAR(HEADER,'PCOUNT')
+ IF NAXIS GT 0 THEN BEGIN
+ DIMS = FXPAR(HEADER,'NAXIS*') ;Read dimensions
+ NDATA = DIMS[0]
+ IF NAXIS GT 1 THEN FOR I=2,NAXIS DO $
+ NDATA = NDATA*DIMS[I-1]
+ ENDIF ELSE NDATA = 0
+ NBYTES = LONG64(ABS(BITPIX) / 8) * GCOUNT * (PCOUNT + NDATA)
+;
+; Read the next extension header in the file.
+;
+ NREC = (NBYTES + 2879) / 2880
+ POINT_LUN, -UNIT, POINTLUN ;Current position
+ MHEAD0 = POINTLUN + NREC*2880L
+ POINT_LUN, UNIT, MHEAD0 ;Next FITS extension
+ FXHREAD,UNIT,HEADER,STATUS
+ POINT_LUN, -UNIT, END_HEADER
+ IF STATUS NE 0 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Requested extension not found'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ I_EXT = I_EXT + 1
+;
+; Check to see if the current extension is the one desired.
+;
+ IF ETYPE EQ 7 THEN BEGIN
+ EXTNAME = STRTRIM(STRUPCASE(FXPAR(HEADER,'EXTNAME')),2)
+ IF EXTNAME EQ S_EXTENSION THEN GOTO, DONE
+ END ELSE IF I_EXT EQ I_EXTENSION THEN GOTO, DONE
+ GOTO, NEXT_EXT
+DONE:
+ ENDIF ELSE POINT_LUN, -UNIT, END_HEADER
+
+;
+; Add or modify the keyword parameter in the header, keeping track of the
+; initial size of the header array.
+;
+ IEND = WHERE(STRMID(HEADER,0,8) EQ 'END ')
+ N_INITIAL = 1 + IEND[0]/36
+ IF N_PARAMS() EQ 4 THEN BEGIN
+ FXADDPAR, HEADER, NAME, VALUE , COMMENT, BEFORE=BEFORE, $
+ AFTER=AFTER, FORMAT=FORMAT
+ END ELSE BEGIN
+ FXADDPAR, HEADER, NAME, VALUE, BEFORE=BEFORE, AFTER=AFTER, $
+ FORMAT=FORMAT
+ ENDELSE
+;
+; If the length of the header has changed, then print an error message.
+;
+ IEND = WHERE(STRMID(HEADER,0,8) EQ 'END ')
+ N_FINAL = 1 + IEND[0]/36
+ IF N_FINAL NE N_INITIAL THEN BEGIN
+ IF KEYWORD_SET(NOGROW) THEN BEGIN
+ MESSAGE, /CONTINUE, 'Adding parameter would increase ' + $
+ 'header length, no action taken.'
+ ENDIF ELSE BEGIN
+ ;; Increase size of the file by inserting multiples of
+ ;; 2880 bytes at the end of the current header. Then
+ ;; resume normal operations.
+ BLKSHIFT, UNIT, END_HEADER, (N_FINAL-N_INITIAL)*36L*80L
+ GOTO, WRITE_HEADER
+ ENDELSE
+;
+; Otherwise, rewind to the beginning of the header, and write the new header
+; over the old header. Convert to byte and force into 80 character lines.
+;
+ ENDIF ELSE BEGIN
+ WRITE_HEADER:
+ BHDR = REPLICATE(32B, 80, 36*N_FINAL)
+ FOR N = 0,IEND[0] DO BHDR[0,N] = BYTE(STRMID(HEADER[N],0,80))
+ POINT_LUN, UNIT, MHEAD0
+ WRITEU, UNIT, BHDR
+ ENDELSE
+;
+; Close the file and return.
+;
+ FREE_LUN, UNIT
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxhread.pro b/Code/script_idl_mv/astrolib/fxhread.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3a4da731b4d18777a7262ac705175a87a88f8398
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxhread.pro
@@ -0,0 +1,119 @@
+ PRO FXHREAD,UNIT,HEADER,STATUS
+;+
+; NAME:
+; FXHREAD
+; Purpose :
+; Reads a FITS header from an opened disk file.
+; Explanation :
+; Reads a FITS header from an opened disk file.
+; Use :
+; FXHREAD, UNIT, HEADER [, STATUS ]
+; Inputs :
+; UNIT = Logical unit number.
+; Opt. Inputs :
+;
+; Outputs :
+; HEADER = String array containing the FITS header.
+; Opt. Outputs:
+; STATUS = Condition code giving the status of the read. Normally, this
+; is zero, but is set to !ERR if an error occurs, or if the
+; first byte of the header is zero (ASCII null).
+; Keywords :
+; None.
+; Calls :
+; None.
+; Common :
+; None.
+; Restrictions:
+; The file must already be positioned at the start of the header. It
+; must be a proper FITS file.
+; Side effects:
+; The file ends by being positioned at the end of the FITS header, unless
+; an error occurs.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Feb 1992, from READFITS by J. Woffard and W. Landsman.
+; W. Thompson, Aug 1992, added test for SIMPLE keyword.
+; Written :
+; William Thompson, GSFC, February 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version :
+; Version 1, 12 April 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+;
+ ON_ERROR,2 ;Return to caller
+ STATUS = 0
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 2 THEN MESSAGE, $
+ 'Calling sequence: FXHREAD, UNIT, HEADER [, STATUS ]'
+;
+; Find out whether one is at the beginning of the file (POSITION=0) or not.
+;
+ POINT_LUN,-UNIT,POSITION
+;
+; Read in the first 2880 byte FITS logical block as a series of 36 card images
+; of 80 bytes each.
+;
+ HDR = BYTARR( 80, 36, /NOZERO )
+ ON_IOERROR, RETURN_STATUS
+ READU, UNIT, HDR
+;
+; If not the primary header, then the first eight bytes should decode to
+; XTENSION. If not, then set status to -1, and return.
+;
+ IF POSITION NE 0 THEN BEGIN
+ FIRST = STRING(HDR[0:7])
+ IF FIRST NE 'XTENSION' THEN BEGIN
+ MESSAGE,'XTENSION keyword not found',/CONTINUE
+ STATUS = -1
+ GOTO, DONE
+ ENDIF
+ ENDIF
+;
+; Interpret the header as a string, and check to see if the END line has been
+; reached.
+;
+ HEADER = STRING( HDR > 32B )
+ ENDLINE = WHERE( STRMID(HEADER,0,8) EQ 'END ', NEND)
+ IF NEND GT 0 THEN HEADER = HEADER[ 0:ENDLINE[0] ]
+;
+; If the primary header (POSITION=0) and the SIMPLE keyword can't be found in
+; the first record, then this can't be a FITS file.
+;
+ IF POSITION EQ 0 THEN BEGIN
+ SIMPLE_LINE = WHERE(STRMID(HEADER,0,8) EQ 'SIMPLE ',N_SIMPLE)
+ IF N_SIMPLE EQ 0 THEN BEGIN
+ MESSAGE,'SIMPLE keyword not found',/CONTINUE
+ STATUS = -1
+ GOTO, DONE
+ ENDIF
+ ENDIF
+;
+; Keep reading until the END line is reached.
+;
+ WHILE NEND EQ 0 DO BEGIN
+ READU, UNIT, HDR
+ HDR1 = STRING( HDR > 32B )
+ ENDLINE = WHERE( STRMID(HDR1,0,8) EQ 'END ', NEND)
+ IF NEND GT 0 THEN HDR1 = HDR1[ 0:ENDLINE[0] ]
+ HEADER = [HEADER, HDR1 ]
+ ENDWHILE
+ GOTO, DONE
+;
+; Error encounter. Store the error code in status.
+;
+RETURN_STATUS:
+ STATUS = !ERR
+;
+; Reset the ON_IOERROR condition.
+;
+DONE:
+ ON_IOERROR,NULL
+ END
diff --git a/Code/script_idl_mv/astrolib/fxmove.pro b/Code/script_idl_mv/astrolib/fxmove.pro
new file mode 100644
index 0000000000000000000000000000000000000000..02b93bf2dec7f1472c28924f431cd3da8f82d627
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxmove.pro
@@ -0,0 +1,137 @@
+FUNCTION FXMOVE, UNIT, EXTEN, SILENT = Silent, EXT_NO = ext_no, ERRMSG=errmsg
+
+;+
+; NAME:
+; FXMOVE
+; PURPOSE:
+; Skip to a specified extension number or name in a FITS file
+;
+; CALLING SEQUENCE:
+; STATUS=FXMOVE(UNIT, EXT, /Silent)
+; STATUS=FXMOVE(UNIT, EXTNAME, /Silent, EXT_NO=, ERRMSG= )
+;
+; INPUT PARAMETERS:
+; UNIT = An open unit descriptor for a FITS data stream.
+; EXTEN = Number of extensions to skip.
+; or
+; Scalar string giving extension name (in the EXTNAME keyword)
+; OPTIONAL INPUT PARAMETER:
+; /SILENT - If set, then any messages about invalid characters in the
+; FITS file are suppressed.
+; OPTIONAL OUTPUT PARAMETER:
+; ERRMSG = If this keyword is present, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned.
+; EXT_NO - Extension number, scalar integer, useful if the user supplied
+; an extension name in the EXTEN parameter
+; RETURNS:
+; 0 if successful.
+; -1 if an error is encountered.
+;
+; COMMON BLOCKS:
+; None.
+; SIDE EFFECTS:
+; Repositions the file pointer.
+; PROCEDURE:
+; Each FITS header is read in and parsed, and the file pointer is moved
+; to where the next FITS extension header until the desired
+; extension is reached.
+; PROCEDURE CALLS:
+; FXPAR(), MRD_HREAD, MRD_SKIP
+; MODIFICATION HISTORY:
+; Extracted from FXPOSIT 8-March-2000 by T. McGlynn
+; Added /SILENT keyword 14-Dec-2000 by W. Landsman
+; Save time by not reading the full header W. Landsman Feb. 2003
+; Allow extension name to be specified, added EXT_NO, ERRMSG keywords
+; W. Landsman December 2006
+; Make search for EXTNAME case-independent W.Landsman March 2007
+; Avoid round-off error for very large extensions N. Piskunov Dec 2007
+; Assume since V6.1 (/INTEGER keyword available to PRODUCT() ) Dec 2007
+; Capture error message from MRD_HREAD (must be used with post-June 2009
+; version of MRD-HREAD) W. Landsman July 2009
+;-
+ On_error, 2
+ compile_opt idl2
+
+ DO_NAME = SIZE( EXTEN,/TNAME) EQ 'STRING'
+ PRINT_ERROR = ~ARG_PRESENT(ERRMSG)
+ ERRMSG = ''
+ IF DO_NAME THEN BEGIN
+ FIRSTBLOCK = 0
+ EXT_NO = 9999
+ ENAME = STRTRIM( STRUPCASE(EXTEN), 2 )
+ ON_IOERROR, ALLOW_PLUN
+ POINT_LUN, -UNIT, DUM
+ ON_IOERROR, NULL
+ ENDIF ELSE BEGIN
+ FIRSTBLOCK = 1
+ EXT_NO = EXTEN
+ ENDELSE
+
+ FOR I = 1, EXT_NO DO BEGIN
+
+;
+; Read the next header, and get the number of bytes taken up by the data.
+;
+
+ IF EOF(UNIT) THEN BEGIN
+ IF DO_NAME THEN ERRMSG = $
+ 'Extension name ' + ename + ' not found in FITS file' ELSE ERRMSG = $
+ 'EOF encountered while moving to specified extension'
+ if PRINT_ERROR then message,errmsg
+ RETURN, -1
+ ENDIF
+
+ ; Can't use FXHREAD to read from pipe, since it uses
+ ; POINT_LUN. So we read this in ourselves using mrd_hread
+
+ MRD_HREAD, UNIT, HEADER, STATUS, SILENT = Silent, $
+ FIRSTBLOCK=FIRSTBLOCK, ERRMSG = ERRMSG
+
+ IF STATUS LT 0 THEN BEGIN
+ IF PRINT_ERROR THEN MESSAGE,ERRMSG ;Typo fix 04/10
+ RETURN, -1
+ ENDIF
+
+ ; Get parameters that determine size of data
+ ; region.
+ IF DO_NAME THEN IF I GT 1 THEN BEGIN
+ EXTNAME = STRTRIM(SXPAR(HEADER,'EXTNAME',COUNT=N_name),2)
+ if N_NAME GT 0 THEN $
+ IF ENAME EQ STRUPCASE(EXTNAME) THEN BEGIN
+ EXT_NO= I-1
+ BLOCK = 1 + ((N_ELEMENTS(HEADER)-1)/36)
+ POINT_LUN, -UNIT, CURR_POSS
+ POINT_LUN, UNIT, CURR_POSS - BLOCK*2880
+ BREAK
+ ENDIF
+ ENDIF
+ BITPIX = FXPAR(HEADER,'BITPIX')
+ NAXIS = FXPAR(HEADER,'NAXIS')
+ GCOUNT = FXPAR(HEADER,'GCOUNT')
+ IF GCOUNT EQ 0 THEN GCOUNT = 1
+ PCOUNT = FXPAR(HEADER,'PCOUNT')
+
+ IF NAXIS GT 0 THEN BEGIN
+ DIMS = FXPAR(HEADER,'NAXIS*') ;Read dimensions
+ NDATA = PRODUCT(DIMS,/INTEGER)
+ ENDIF ELSE NDATA = 0
+
+ NBYTES = LONG64(ABS(BITPIX) / 8) * GCOUNT * (PCOUNT + NDATA)
+;
+; Move to the next extension header in the file.
+;
+ NREC = (NBYTES + 2879) / 2880
+ MRD_SKIP, UNIT, NREC*2880L
+
+ ENDFOR
+
+ RETURN, 0
+ALLOW_PLUN:
+
+ ERRMSG = $
+ 'Extension name cannot be specified unless POINT_LUN access is available'
+ if PRINT_ERROR then message,errmsg
+ RETURN, -1
+END
diff --git a/Code/script_idl_mv/astrolib/fxpar.pro b/Code/script_idl_mv/astrolib/fxpar.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a456b5a107e5e57f08d3857db132648e1920b799
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxpar.pro
@@ -0,0 +1,462 @@
+ FUNCTION FXPAR, HDR, NAME, ABORT, COUNT=MATCHES, COMMENT=COMMENTS, $
+ START=START, PRECHECK=PRECHECK, POSTCHECK=POSTCHECK, $
+ NOCONTINUE = NOCONTINUE, DATATYPE=DATATYPE, $
+ NULL=K_NULL, NAN=NAN, MISSING=MISSING
+;+
+; NAME:
+; FXPAR()
+; PURPOSE:
+; Obtain the value of a parameter in a FITS header.
+; EXPLANATION:
+; The first 8 chacters of each element of HDR are searched for a match to
+; NAME. If the keyword is one of those allowed to take multiple values
+; ("HISTORY", "COMMENT", or " " (blank)), then the value is taken
+; as the next 72 characters. Otherwise, it is assumed that the next
+; character is "=", and the value (and optional comment) is then parsed
+; from the last 71 characters. An error occurs if there is no parameter
+; with the given name.
+;
+; If the value is too long for one line, it may be continued on to the
+; the next input card, using the CONTINUE Long String Keyword convention.
+; For more info, http://fits.gsfc.nasa.gov/registry/continue_keyword.html
+;
+;
+; Complex numbers are recognized as two numbers separated by one or more
+; space characters.
+;
+; If a numeric value has no decimal point (or E or D) it is returned as
+; type LONG. If it contains more than 8 numerals, or contains the
+; character 'D', then it is returned as type DOUBLE. Otherwise it is
+; returned as type FLOAT. If an integer is too large to be stored as
+; type LONG, then it is returned as DOUBLE.
+;
+; If a keyword is in the header and has no value, then the default
+; missing value is returned as explained below. This can be
+; distinguished from the case where the keyword is not found by the fact
+; that COUNT=0 in that case, while existing keywords without a value will
+; be returned with COUNT=1 or more.
+;
+; CALLING SEQUENCE:
+; Result = FXPAR( HDR, NAME [, ABORT, COUNT=, COMMENT=, /NOCONTINUE ] )
+;
+; Result = FXPAR(HEADER,'DATE') ;Finds the value of DATE
+; Result = FXPAR(HEADER,'NAXIS*') ;Returns array dimensions as
+; ;vector
+; REQUIRED INPUTS:
+; HDR = FITS header string array (e.g. as returned by FXREAD). Each
+; element should have a length of 80 characters
+; NAME = String name of the parameter to return. If NAME is of the
+; form 'keyword*' then an array is returned containing values
+; of keywordN where N is an integer. The value of keywordN
+; will be placed in RESULT(N-1). The data type of RESULT will
+; be the type of the first valid match of keywordN
+; found, unless DATATYPE is given.
+; OPTIONAL INPUT:
+; ABORT = String specifying that FXPAR should do a RETALL if a
+; parameter is not found. ABORT should contain a string to be
+; printed if the keyword parameter is not found. If not
+; supplied, FXPAR will return with a negative !err if a keyword
+; is not found.
+; OUTPUT:
+; The returned value of the function is the value(s) associated with the
+; requested keyword in the header array.
+;
+; If the parameter is complex, double precision, floating point, long or
+; string, then the result is of that type. Apostrophes are stripped from
+; strings. If the parameter is logical, 1 is returned for T, and 0 is
+; returned for F.
+;
+; If NAME was of form 'keyword*' then a vector of values are returned.
+;
+; OPTIONAL INPUT KEYWORDS:
+; DATATYPE = A scalar value, indicating the type of vector
+; data. All keywords will be cast to this type.
+; Default: based on first keyword.
+; Example: DATATYPE=0.0D (cast data to double precision)
+; START = A best-guess starting position of the sought-after
+; keyword in the header. If specified, then FXPAR
+; first searches for scalar keywords in the header in
+; the index range bounded by START-PRECHECK and
+; START+POSTCHECK. This can speed up keyword searches
+; in large headers. If the keyword is not found, then
+; FXPAR searches the entire header.
+;
+; If not specified then the entire header is searched.
+; Searches of the form 'keyword*' also search the
+; entire header and ignore START.
+;
+; Upon return START is changed to be the position of
+; the newly found keyword. Thus the best way to
+; search for a series of keywords is to search for
+; them in the order they appear in the header like
+; this:
+;
+; START = 0L
+; P1 = FXPAR('P1', START=START)
+; P2 = FXPAR('P2', START=START)
+;
+; PRECHECK = If START is specified, then PRECHECK is the number
+; of keywords preceding START to be searched.
+; Default: 5
+; POSTCHECK = If START is specified, then POSTCHECK is the number
+; of keywords after START to be searched.
+; Default: 20
+; /NOCONTINUE = If set, then continuation lines will not be read, even
+; if present in the header
+; MISSING = By default, this routine returns 0 when keyword values are
+; not found. This can be overridden by using the MISSING
+; keyword, e.g. MISSING=-1.
+; /NAN = If set, then return Not-a-Number (!values.f_nan) for missing
+; values. Ignored if keyword MISSING is present.
+; /NULL = If set, then return !NULL (undefined) for missing values.
+; Ignored if MISSING of /NAN is present, or if earlier than IDL
+; version 8.0. If multiple values would be returned, then
+; MISSING= or /NAN should be used instead of /NULL, making sure
+; that the datatype is consistent with the non-missing values,
+; e.g. MISSING='' for strings, MISSING=-1 for integers, or
+; MISSING=-1.0 or /NAN for floating point. /NAN should not be
+; used if the datatype would otherwise be integer.
+; OPTIONAL OUTPUT KEYWORD:
+; COUNT = Optional keyword to return a value equal to the number of
+; parameters found by FXPAR.
+; COMMENTS= Array of comments associated with the returned values.
+;
+; PROCEDURE CALLS:
+; GETTOK(), VALID_NUM
+; SIDE EFFECTS:
+;
+; The system variable !err is set to -1 if parameter not found, 0 for a
+; scalar value returned. If a vector is returned it is set to the number
+; of keyword matches found.
+;
+; If a keyword occurs more than once in a header, a warning is given,
+; and the first occurence is used. However, if the keyword is "HISTORY",
+; "COMMENT", or " " (blank), then multiple values are returned.
+;
+; NOTES:
+; The functions SXPAR() and FXPAR() are nearly identical, although
+; FXPAR() has slightly more sophisticated parsing. There is no
+; particular reason for having two nearly identical procedures, but
+; both are too widely used to drop either one.
+;
+; REVISION HISTORY:
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Adapted from SXPAR
+; Version 2, William Thompson, GSFC, 14 October 1994
+; Modified to use VALID_NUM instead of STRNUMBER. Inserted
+; additional call to VALID_NUM to trap cases where character
+; strings did not contain quotation marks.
+; Version 3, William Thompson, GSFC, 22 December 1994
+; Fixed bug with blank keywords, following suggestion by Wayne
+; Landsman.
+; Version 4, Mons Morrison, LMSAL, 9-Jan-98
+; Made non-trailing ' for string tag just be a warning (not
+; a fatal error). It was needed because "sxaddpar" had an
+; error which did not write tags properly for long strings
+; (over 68 characters)
+; Version 5, Wayne Landsman GSFC, 29 May 1998
+; Fixed potential problem with overflow of LONG values
+; Version 6, Craig Markwardt, GSFC, 28 Jan 1998,
+; Added CONTINUE parsing
+; Version 7, Craig Markwardt, GSFC, 18 Nov 1999,
+; Added START, PRE/POSTCHECK keywords for better
+; performance
+; Version 8, Craig Markwardt, GSFC, 08 Oct 2003,
+; Added DATATYPE keyword to cast vector keywords type
+; Version 9, Paul Hick, 22 Oct 2003, Corrected bug (NHEADER-1)
+; Version 10, W. Landsman, GSFC 2 May 2012
+; Keywords of form "name_0" could confuse vector extractions
+; Version 11 W. Landsman, GSFC 24 Apr 2014
+; Don't convert LONG64 numbers to to double precision
+; Version 12, William Thompson, 13-Aug-2014
+; Add keywords MISSING, /NAN, and /NULL
+;-
+;------------------------------------------------------------------------------
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 2 THEN BEGIN
+ PRINT,'Syntax: result = FXPAR( HDR, NAME [, ABORT ])'
+ RETURN, -1
+ ENDIF
+;
+; Determine the default value for missing data.
+;
+ CASE 1 OF
+ N_ELEMENTS(MISSING) EQ 1: MISSING_VALUE = MISSING
+ KEYWORD_SET(NAN): MISSING_VALUE = !VALUES.F_NAN
+ KEYWORD_SET(K_NULL) AND !VERSION.RELEASE GE '8.': $
+ DUMMY = EXECUTE('MISSING_VALUE = !NULL')
+ ELSE: MISSING_VALUE = 0
+ ENDCASE
+ VALUE = MISSING_VALUE
+;
+; Determine the abort condition.
+;
+ IF N_PARAMS() LE 2 THEN BEGIN
+ ABORT_RETURN = 0
+ ABORT = 'FITS Header'
+ END ELSE ABORT_RETURN = 1
+ IF ABORT_RETURN THEN ON_ERROR,1 ELSE ON_ERROR,2
+;
+; Check for valid header. Check header for proper attributes.
+;
+ S = SIZE(HDR)
+ IF ( S[0] NE 1 ) OR ( S[2] NE 7 ) THEN $
+ MESSAGE,'FITS Header (first parameter) must be a string array'
+;
+; Convert the selected keyword NAME to uppercase.
+;
+ NAM = STRTRIM( STRUPCASE(NAME) )
+;
+; Determine if NAME is of form 'keyword*'. If so, then strip off the '*', and
+; set the VECTOR flag. One must consider the possibility that NAM is an empty
+; string.
+;
+ NAMELENGTH1 = (STRLEN(NAM) - 1) > 1
+ IF STRPOS( NAM, '*' ) EQ NAMELENGTH1 THEN BEGIN
+ NAM = STRMID( NAM, 0, NAMELENGTH1)
+ VECTOR = 1 ;Flag for vector output
+ NAME_LENGTH = STRLEN(NAM) ;Length of name
+ NUM_LENGTH = 8 - NAME_LENGTH ;Max length of number portion
+ IF NUM_LENGTH LE 0 THEN MESSAGE, $
+ 'Keyword length must be 8 characters or less'
+;
+; Otherwise, extend NAME with blanks to eight characters.
+;
+ ENDIF ELSE BEGIN
+ WHILE STRLEN(NAM) LT 8 DO NAM = NAM + ' '
+ VECTOR = 0
+ ENDELSE
+;
+; If of the form 'keyword*', then find all instances of 'keyword' followed by
+; a number. Store the positions of the located keywords in NFOUND, and the
+; value of the number field in NUMBER.
+;
+ IF N_ELEMENTS(START) EQ 0 THEN START = -1L
+ START = LONG(START[0])
+ IF NOT VECTOR AND START GE 0 THEN BEGIN
+ IF N_ELEMENTS(PRECHECK) EQ 0 THEN PRECHECK = 5
+ IF N_ELEMENTS(POSTCHECK) EQ 0 THEN POSTCHECK = 20
+ NHEADER = N_ELEMENTS(HDR)
+ MN = (START - PRECHECK) > 0
+ MX = (START + POSTCHECK) < (NHEADER-1) ;Corrected bug
+ KEYWORD = STRMID(HDR[MN:MX], 0, 8)
+ ENDIF ELSE BEGIN
+ RESTART:
+ START = -1L
+ KEYWORD = STRMID( HDR, 0, 8)
+ ENDELSE
+
+ IF VECTOR THEN BEGIN
+ NFOUND = WHERE(STRPOS(KEYWORD,NAM) GE 0, MATCHES)
+ IF ( MATCHES GT 0 ) THEN BEGIN
+ NUMST= STRMID(HDR[NFOUND], NAME_LENGTH, NUM_LENGTH)
+ NUMBER = INTARR(MATCHES)-1
+ FOR I = 0, MATCHES-1 DO $
+ IF VALID_NUM( NUMST[I], NUM) THEN NUMBER[I] = NUM
+ IGOOD = WHERE(NUMBER GE 0, MATCHES)
+ IF MATCHES GT 0 THEN BEGIN
+ NFOUND = NFOUND[IGOOD]
+ NUMBER = NUMBER[IGOOD]
+ G = WHERE(NUMBER GT 0, MATCHES)
+ IF MATCHES GT 0 THEN NUMBER = NUMBER[G]
+ ENDIF
+ ENDIF
+;
+; Otherwise, find all the instances of the requested keyword. If more than
+; one is found, and NAME is not one of the special cases, then print an error
+; message.
+;
+ ENDIF ELSE BEGIN
+ NFOUND = WHERE(KEYWORD EQ NAM, MATCHES)
+ IF MATCHES EQ 0 AND START GE 0 THEN GOTO, RESTART
+ IF START GE 0 THEN NFOUND = NFOUND + MN
+ IF (MATCHES GT 1) AND (NAM NE 'HISTORY ') AND $
+ (NAM NE 'COMMENT ') AND (NAM NE '') THEN $
+ MESSAGE,/INFORMATIONAL, 'WARNING- Keyword ' + $
+ NAM + 'located more than once in ' + ABORT
+ IF (MATCHES GT 0) THEN START = NFOUND[MATCHES-1]
+ ENDELSE
+;
+; Extract the parameter field from the specified header lines. If one of the
+; special cases, then done.
+;
+ IF MATCHES GT 0 THEN BEGIN
+ VALUE = MISSING_VALUE
+ LINE = HDR[NFOUND]
+ SVALUE = STRTRIM( STRMID(LINE,9,71),2)
+ IF (NAM EQ 'HISTORY ') OR (NAM EQ 'COMMENT ') OR $
+ (NAM EQ ' ') THEN BEGIN
+ VALUE = STRTRIM( STRMID(LINE,8,72),2)
+ COMMENTS = STRARR(N_ELEMENTS(VALUE))
+;
+; Otherwise, test to see if the parameter contains a string, signalled by
+; beginning with a single quote character (') (apostrophe).
+;
+ END ELSE FOR I = 0,MATCHES-1 DO BEGIN
+ IF ( STRMID(SVALUE[I],0,1) EQ "'" ) THEN BEGIN
+ TEST = STRMID( SVALUE[I],1,STRLEN( SVALUE[I] )-1)
+ NEXT_CHAR = 0
+ OFF = 0
+ VALUE = ''
+;
+; Find the next apostrophe.
+;
+NEXT_APOST:
+ ENDAP = STRPOS(TEST, "'", NEXT_CHAR)
+ IF ENDAP LT 0 THEN MESSAGE, $
+ 'WARNING: Value of '+NAME+' invalid in '+ABORT+ " (no trailing ')", /info
+ VALUE = VALUE + STRMID( TEST, NEXT_CHAR, ENDAP-NEXT_CHAR )
+;
+; Test to see if the next character is also an apostrophe. If so, then the
+; string isn't completed yet. Apostrophes in the text string are signalled as
+; two apostrophes in a row.
+;
+ IF STRMID( TEST, ENDAP+1, 1) EQ "'" THEN BEGIN
+ VALUE = VALUE + "'"
+ NEXT_CHAR = ENDAP+2
+ GOTO, NEXT_APOST
+ ENDIF
+;
+; Extract the comment, if any.
+;
+ SLASH = STRPOS(TEST, "/", ENDAP)
+ IF SLASH LT 0 THEN COMMENT = '' ELSE $
+ COMMENT = STRMID(TEST, SLASH+1, STRLEN(TEST)-SLASH-1)
+
+;
+; CM 19 Sep 1997
+; This is a string that could be continued on the next line. Check this
+; possibility with the following four criteria: *1) Ends with '&'
+; (2) Next line is CONTINUE (3) LONGSTRN keyword is present (recursive call to
+; FXPAR) 4. /NOCONTINE is not set
+
+ IF NOT KEYWORD_SET(NOCONTINUE) THEN BEGIN
+ OFF = OFF + 1
+ VAL = STRTRIM(VALUE,2)
+
+ IF (STRLEN(VAL) GT 0) AND $
+ (STRMID(VAL, STRLEN(VAL)-1, 1) EQ '&') AND $
+ (STRMID(HDR[NFOUND[I]+OFF],0,8) EQ 'CONTINUE') THEN BEGIN
+ IF (SIZE(FXPAR(HDR, 'LONGSTRN',/NOCONTINUE)))[1] EQ 7 THEN BEGIN
+ VALUE = STRMID(VAL, 0, STRLEN(VAL)-1)
+ TEST = HDR[NFOUND[I]+OFF]
+ TEST = STRMID(TEST, 8, STRLEN(TEST)-8)
+ TEST = STRTRIM(TEST, 2)
+ IF STRMID(TEST, 0, 1) NE "'" THEN MESSAGE, $
+ 'ERROR: Invalidly CONTINUEd string in '+ABORT
+ NEXT_CHAR = 1
+ GOTO, NEXT_APOST
+ ENDIF
+ ENDIF
+ ENDIF
+
+;
+; If not a string, then separate the parameter field from the comment field.
+; If there is no value field, then use the default "missing" value.
+;
+ ENDIF ELSE BEGIN
+ VALUE = MISSING_VALUE
+ TEST = SVALUE[I]
+ IF TEST EQ '' THEN BEGIN
+ COMMENT = ''
+ GOTO, GOT_VALUE
+ ENDIF
+ SLASH = STRPOS(TEST, "/")
+ IF SLASH GE 0 THEN BEGIN
+ COMMENT = STRMID(TEST, SLASH+1, STRLEN(TEST)-SLASH-1)
+ IF SLASH GT 0 THEN TEST = STRMID(TEST, 0, SLASH) ELSE $
+ GOTO, GOT_VALUE
+ END ELSE COMMENT = ''
+;
+; Find the first word in TEST. Is it a logical value ('T' or 'F')?
+;
+ TEST2 = TEST
+ VALUE = GETTOK(TEST2,' ')
+ TEST2 = STRTRIM(TEST2,2)
+ IF ( VALUE EQ 'T' ) THEN BEGIN
+ VALUE = 1
+ END ELSE IF ( VALUE EQ 'F' ) THEN BEGIN
+ VALUE = 0
+ END ELSE BEGIN
+;
+; Test to see if a complex number. It's a complex number if the value and the
+; next word, if any, both are valid numbers.
+;
+ IF STRLEN(TEST2) EQ 0 THEN GOTO, NOT_COMPLEX
+ VALUE2 = GETTOK(TEST2,' ')
+ IF VALID_NUM(VALUE,VAL1) AND VALID_NUM(VALUE2,VAL2) $
+ THEN BEGIN
+ VALUE = COMPLEX(VAL1,VAL2)
+ GOTO, GOT_VALUE
+ ENDIF
+;
+; Not a complex number. Decide if it is a floating point, double precision,
+; or integer number. If an error occurs, then a string value is returned.
+; If the integer is not within the range of a valid long value, then it will
+; be converted to a double.
+;
+NOT_COMPLEX:
+ ON_IOERROR, GOT_VALUE
+ VALUE = TEST
+ IF NOT VALID_NUM(VALUE) THEN GOTO, GOT_VALUE
+ IF (STRPOS(VALUE,'.') GE 0) OR (STRPOS(VALUE,'E') $
+ GE 0) OR (STRPOS(VALUE,'D') GE 0) THEN BEGIN
+ IF ( STRPOS(VALUE,'D') GT 0 ) OR $
+ ( STRLEN(VALUE) GE 8 ) THEN BEGIN
+ VALUE = DOUBLE(VALUE)
+ END ELSE VALUE = FLOAT(VALUE)
+ ENDIF ELSE BEGIN
+ LMAX = 2.0D^31 - 1.0D
+ LMIN = -2.0D^31 ;Typo fixed Feb 2010
+ VALUE = LONG64(VALUE)
+ if (VALUE GE LMIN) and (VALUE LE LMAX) THEN $
+ VALUE = LONG(VALUE)
+ ENDELSE
+
+;
+GOT_VALUE:
+ ON_IOERROR, NULL
+ ENDELSE
+ ENDELSE ; if string
+;
+; Add to vector if required.
+;
+ IF VECTOR THEN BEGIN
+ MAXNUM = MAX(NUMBER)
+ IF ( I EQ 0 ) THEN BEGIN
+ IF N_ELEMENTS(DATATYPE) EQ 0 THEN BEGIN
+ ;; Data type determined from keyword
+ SZ_VALUE = SIZE(VALUE)
+ ENDIF ELSE BEGIN
+ ;; Data type requested by user
+ SZ_VALUE = SIZE(DATATYPE[0])
+ ENDELSE
+ RESULT = MAKE_ARRAY( MAXNUM, TYPE=SZ_VALUE[1])
+ COMMENTS = STRARR(MAXNUM)
+ ENDIF
+ RESULT[ NUMBER[I]-1 ] = VALUE
+ COMMENTS[ NUMBER[I]-1 ] = COMMENT
+ ENDIF ELSE BEGIN
+ COMMENTS = COMMENT
+ ENDELSE
+ ENDFOR
+;
+; Set the value of !ERR for the number of matches for vectors, or simply 0
+; otherwise.
+;
+ IF VECTOR THEN BEGIN
+ !ERR = MATCHES
+ RETURN, RESULT
+ ENDIF ELSE !ERR = 0
+;
+; Error point for keyword not found.
+;
+ ENDIF ELSE BEGIN
+ IF ABORT_RETURN THEN MESSAGE,'Keyword '+NAM+' not found in '+ABORT
+ !ERR = -1
+ ENDELSE
+;
+ RETURN, VALUE
+ END
diff --git a/Code/script_idl_mv/astrolib/fxparpos.pro b/Code/script_idl_mv/astrolib/fxparpos.pro
new file mode 100644
index 0000000000000000000000000000000000000000..eb3b0ec573c1bb260a875caeb681d16a0f82f669
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxparpos.pro
@@ -0,0 +1,85 @@
+ FUNCTION FXPARPOS, KEYWRD, IEND, BEFORE=BEFORE, AFTER=AFTER
+;+
+; NAME:
+; FXPARPOS()
+; Purpose :
+; Finds position to insert record into FITS header.
+; Explanation :
+; Finds the position to insert a record into a FITS header. Called from
+; FXADDPAR.
+; Use :
+; Result = FXPARPOS(KEYWRD, IEND [, BEFORE=BEFORE ] [, AFTER=AFTER ])
+; Inputs :
+; KEYWRD = Array of eight-character keywords in header.
+; IEND = Position of END keyword.
+; Opt. Inputs :
+; None.
+; Outputs :
+; Result of function is position to insert record.
+; Opt. Outputs:
+; None.
+; Keywords :
+; BEFORE = Keyword string name. The parameter will be placed before the
+; location of this keyword. For example, if BEFORE='HISTORY'
+; then the parameter will be placed before the first history
+; location. This applies only when adding a new keyword;
+; keywords already in the header are kept in the same position.
+;
+; AFTER = Same as BEFORE, but the parameter will be placed after the
+; location of this keyword. This keyword takes precedence over
+; BEFORE.
+;
+; If neither BEFORE or AFTER keywords are passed, then IEND is returned.
+;
+; Calls :
+; None.
+; Common :
+; None.
+; Restrictions:
+; KEYWRD and IEND must be consistent with the relevant FITS header.
+; Side effects:
+; None.
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; William Thompson, Jan 1992.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version :
+; Version 1, 12 April 1993.
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+;
+ ON_ERROR,2 ;Return to caller
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() NE 2 THEN MESSAGE, $
+ 'Required parameters are KEYWRD and IEND'
+;
+; If the AFTER keyword has been entered, then find the location.
+;
+ IF N_ELEMENTS(AFTER) EQ 1 THEN BEGIN
+ KEY_AFTER = STRING(REPLICATE(32B,8))
+ STRPUT,KEY_AFTER,STRUPCASE(STRTRIM(AFTER,2)),0
+ ILOC = WHERE(KEYWRD EQ KEY_AFTER,NLOC)
+ IF NLOC GT 0 THEN RETURN, (MAX(ILOC)+1) < IEND
+ ENDIF
+;
+; If AFTER wasn't entered or found, and if the BEFORE keyword has been
+; entered, then find the location.
+;
+ IF N_ELEMENTS(BEFORE) EQ 1 THEN BEGIN
+ KEY_BEFORE = STRING(REPLICATE(32B,8))
+ STRPUT,KEY_BEFORE,STRUPCASE(STRTRIM(BEFORE,2)),0
+ ILOC = WHERE(KEYWRD EQ KEY_BEFORE,NLOC)
+ IF NLOC GT 0 THEN RETURN,ILOC[0]
+ ENDIF
+;
+; Otherwise, simply return IEND.
+;
+ RETURN,IEND
+ END
diff --git a/Code/script_idl_mv/astrolib/fxposit.pro b/Code/script_idl_mv/astrolib/fxposit.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ba2263dab7c59e352c1d190ca14f778f896e6f07
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxposit.pro
@@ -0,0 +1,267 @@
+ FUNCTION FXPOSIT, XFILE, EXT_NO, readonly=readonly, COMPRESS=COMPRESS, $
+ SILENT = Silent, EXTNUM = extnum, ERRMSG= ERRMSG, $
+ LUNIT = lunit, UNIXPIPE= unixpipe, FPACK= fpack, $
+ NO_FPACK = no_fpack,HEADERONLY=headeronly
+;+
+; NAME:
+; FXPOSIT
+; PURPOSE:
+; Return the unit number of a FITS file positioned at specified extension
+; EXPLANATION:
+; The FITS file will be ready to be read at the beginning of the
+; specified extension. Either an extension number or extension name
+; can be specified. Called by headfits.pro, mrdfits.pro
+;
+; Modified in March 2009 to set the /SWAP_IF_LITTLE_ENDIAN keyword
+; when opening a file, and **may not be compatible with earlier versions**
+; CALLING SEQUENCE:
+; unit=FXPOSIT(FILE, EXT_NO_OR_NAME, /READONLY, COMPRESS=program,
+; UNIXPIPE=, ERRMSG= , EXTNUM= , UNIT=, /SILENT
+; /FPACK, /NO_FPACK
+;
+; INPUT PARAMETERS:
+; FILE = FITS file name, scalar string. If an empty string is supplied
+; then the user will be prompted for the file name. The user
+; will also be prompted if a wild card is supplied, and more than
+; one file matches the wildcard.
+; EXT_NO_OR_NAME = Either the extension to be moved to (scalar
+; nonnegative integer) or the name of the extension to read
+; (scalar string)
+;
+; RETURNS:
+; Unit number of file or -1 if an error is detected.
+;
+; OPTIONAL INPUT KEYWORD PARAMETER:
+; COMPRESS - If this keyword is set and non-zero, then then treat
+; the file as compressed. If 1 assume a gzipped file.
+; and use IDLs internal decompression facility. For Unix
+; compressed or bzip2 compressed files spawn off a process to
+; decompress and use its output as the FITS stream. If the
+; keyword is not 1, then use its value as a string giving the
+; command needed for decompression.
+; /FPACK - Signal that the file is compressed with the FPACK software.
+; http://heasarc.gsfc.nasa.gov/fitsio/fpack/ ) By default,
+; (FXPOSIT will assume that if the file name extension ends in
+; .fz that it is fpack compressed.) The FPACK software must
+; be installed on the system
+; /NO_FPACK - The unit will only be used to read the FITS header. In
+; that case FPACK compressed files need not be uncompressed.
+; LUNIT - Integer giving the file unit number. Use this keyword if
+; you want to override the default use of GET_LUN to obtain
+; a unit number.
+; /READONLY - If this keyword is set and non-zero, then OPENR rather
+; than OPENU will be used to open the FITS file. Note that
+; compressed files are always set to /READONLY
+; /SILENT If set, then suppress any messages about invalid characters
+; in the FITS file.
+;
+; OPTIONAL OUTPUT KEYWORDS:
+; EXTNUM - Nonnegative integer give the extension number actually read
+; Useful only if the extension was specified by name.
+; ERRMSG = If this keyword is present, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned.
+; UNIXPIPE - If set to 1, then the FITS file was opened with a UNIX pipe
+; rather than with the OPENR command. This is only required
+; when reading a FPACK, bzip or Unix compressed file. Note
+; that automatic byteswapping cannnot be set for a Unix pipe,
+; since the SWAP_IF_LITTLE_ENDIAN keyword is only available for the
+; OPEN command, and it is the responsibility of the calling
+; routine to perform the byteswapping.
+; SIDE EFFECTS:
+; Opens and returns a file unit.
+; PROCEDURE:
+; Open the appropriate file, or spawn a command and intercept
+; the output.
+; Call FXMOVE to get to the appropriate extension.
+; PROCEDURE CALLS:
+; FXMOVE()
+; MODIFICATION HISTORY:
+; Derived from William Thompson's FXFINDEND routine.
+; Modified by T.McGlynn, 5-October-1994.
+; Modified by T.McGlynn, 25-Feb-1995 to handle compressed
+; files. Pipes cannot be accessed using FXHREAD so
+; MRD_HREAD was written.
+; W. Landsman 23-Apr-1997 Force the /bin/sh shell when uncompressing
+; T. McGlynn 03-June-1999 Use /noshell option to get rid of processes left by spawn.
+; Use findfile to retain ability to use wildcards
+; W. Landsman 03-Aug-1999 Use EXPAND_TILDE under Unix to find file
+; T. McGlynn 04-Apr-2000 Put reading code into FXMOVE,
+; additional support for compression from D.Palmer.
+; W. Landsman/D.Zarro 04-Jul-2000 Added test for !VERSION.OS EQ 'Win32' (WinNT)
+; W. Landsman 12-Dec-2000 Added /SILENT keyword
+; W. Landsman April 2002 Use FILE_SEARCH for V5.5 or later
+; W. Landsman Feb 2004 Assume since V5.3 (OPENR,/COMPRESS available)
+; W. Landsman,W. Thompson, 2-Mar-2004, Add support for BZIP2
+; W. Landsman Don't leave open file if an error occurs
+; W. Landsman Sep 2004 Treat FTZ extension as gzip compressed
+; W. Landsman Feb 2006 Removed leading spaces (prior to V5.5)
+; W. Landsman Nov 2006 Allow specification of extension name
+; Added EXTNUM, ERRMSG keywords
+; W. Landsman/N.Piskunov Dec 2007 Added LUNIT keyword
+; W. Landsman Mar 2009 OPEN with /SWAP_IF_LITTLE_ENDIAN
+; Added UNIXPIPE output keyword
+; N. Rich May 2009 Check if filename is an empty string
+; W. Landsman May 2009 Support FPACK compressed files
+; Added /FPACK, /HEADERONLY keywords
+; W.Landsman July 2009 Deprecated /HEADERONLY add /NO_FPACK
+; W.Landsman July 2011 Check for SIMPLE in first 8 chars
+; Use gunzip to decompress Unix. Z file since compress utility
+; often not installed anymore)
+; W. Landsman October 2012 Add .fz extension if /FPACK set
+; W. Landsman July 2013 More diagnostics if file not found
+;-
+;
+ On_Error,2
+ compile_opt idl2
+;
+; Check the number of parameters.
+;
+ IF N_Params() LT 2 THEN BEGIN
+ PRINT,'SYNTAX: UNIT = FXPOSIT(FILE, EXT_NO, /Readonly,' + $
+ 'ERRMSG= , /SILENT, compress=prog, LUNIT = lunit)'
+ RETURN,-1
+ ENDIF
+ PRINTERR = ~ARG_PRESENT(ERRMSG)
+ ERRMSG = ''
+ UNIXPIPE=0
+; The /headeronly keyword has been replaced with /no_fpack
+ if ~keyword_set(no_fpack) then no_fpack = keyword_set(headeronly)
+ exten = ext_no
+
+ COUNT=0
+ IF XFILE[0] NE '' THEN BEGIN
+ FILE = FILE_SEARCH(XFILE, COUNT=COUNT)
+ IF COUNT GT 1 THEN $
+ FILE = DIALOG_PICKFILE(FILTER=XFILE, /MUST_EXIST, $
+ TITLE = 'Please select a FITS file') $
+ ELSE IF COUNT EQ 0 THEN BEGIN
+ ERRMSG = 'Specified FITS file not found: ' + XFILE[0]
+ IF PRINTERR THEN MESSAGE,ERRMSG,/CON
+ RETURN, -1 ; Don't print anything out, just report an error
+ ENDIF
+ ENDIF ELSE $
+ FILE =DIALOG_PICKFILE(FILTER=['*.fit*;*.fts*;*.img*;*.FIT*'], $
+ TITLE='Please select a FITS file',/MUST_EXIST)
+
+ IF FILE[0] EQ '' THEN BEGIN
+ ERRMSG = 'No FITS file specified '
+ IF PRINTERR THEN MESSAGE,ERRMSG,/CON
+ RETURN, -1 ; Don't print anything out, just report an error
+ ENDIF
+
+ FILE = FILE[0]
+ IF KEYWORD_SET(FPACK) then $
+ if strlowcase(strmid(FILE,2,3,/reverse)) NE '.fz' then $
+ FILE += '.fz'
+
+;
+; Check if logical unit number is specified explicitly.
+;
+ IF KEYWORD_SET(LUNIT) THEN BEGIN
+ UNIT=LUNIT
+ GLUN = 0
+ ENDIF ELSE BEGIN
+ UNIT = -1
+ GLUN = 1
+ ENDELSE
+;
+; Check if this is a compressed file.
+;
+ UCMPRS = ' '
+ IF KEYWORD_SET(compress) THEN BEGIN
+ IF strcompress(string(compress),/remo) eq '1' THEN BEGIN
+ compress = 'gunzip'
+ ENDIF
+ UCMPRS = compress;
+ ENDIF ELSE IF KEYWORD_SET(FPACK) THEN $
+ UCMPRS = 'funpack' $
+ ELSE BEGIN
+
+ LEN = STRLEN(FILE)
+ IF LEN GT 3 THEN $
+ tail = STRLOWCASE(STRMID(file, len-3, 3)) $
+ ELSE tail = ' '
+
+ IF STRMID(tail,1,2) EQ '.z' THEN $
+ UCMPRS = 'gunzip' $
+ ELSE IF (tail EQ '.gz') || (tail EQ 'ftz') THEN $
+ UCMPRS = 'gzip' $
+ ELSE IF tail EQ 'bz2' THEN $
+ UCMPRS = 'bunzip2' $
+ ELSE IF ~KEYWORD_SET(NO_FPACK) THEN $
+ IF tail EQ '.fz' THEN UCMPRS = 'funpack'
+
+ ENDELSE
+
+; Handle compressed files which are always opened for Read only.
+
+ IF UCMPRS EQ 'gzip' THEN BEGIN
+
+ OPENR, UNIT, FILE, /COMPRESS, GET_LUN=glun, ERROR = ERROR, $
+ /SWAP_IF_LITTLE
+ IF ERROR NE 0 THEN BEGIN
+ IF PRINTERR THEN PRINT,!ERROR_STATE.MSG ELSE $
+ ERRMSG = !ERROR_STATE.MSG
+ RETURN,-1
+ ENDIF
+
+ ENDIF ELSE IF UCMPRS NE ' ' THEN BEGIN
+; Handle FPACK compressed file. If an extension name is supplied then
+; first recursively call FXPOSIT to get the extension number. Then open
+; the bidirectional pipe.
+ if UCMPRS EQ 'funpack' then begin
+ if size(exten,/TNAME) EQ 'STRING' THEN BEGIN
+ unit = fxposit( file, ext_no, /no_fpack,extnum=extnum)
+ free_lun,unit
+ exten = extnum
+ endif
+ SPAWN, [UCMPRS,'-S',FILE], UNIT=UNIT, /NOSHELL
+ ENDIF else $
+ SPAWN, [UCMPRS,'-c',FILE], UNIT=UNIT, /NOSHELL
+ UNIXPIPE = 1
+
+ ENDIF ELSE BEGIN
+;
+; Go to the start of the file.
+;
+ IF KEYWORD_SET(READONLY) THEN $
+ OPENR, UNIT, FILE, GET_LUN=glun, ERROR = ERROR, $
+ /SWAP_IF_LITTLE ELSE $
+ OPENU, UNIT, FILE, GET_LUN=glun, ERROR = ERROR, $
+ /SWAP_IF_LITTLE
+
+ IF ERROR NE 0 THEN BEGIN
+ IF PRINTERR THEN PRINT,!ERROR_STATE.MSG ELSE $
+ ERRMSG = !ERROR_STATE.MSG
+ RETURN,-1
+ ENDIF
+ ENDELSE
+
+ IF SIZE(EXT_NO,/TNAME) NE 'STRING' THEN $
+ IF EXT_NO LE 0 THEN RETURN, UNIT
+
+;For Uncompresed files test that the first 8 characters are 'SIMPLE'
+
+ IF ucmprs EQ ' ' THEN BEGIN
+ simple = BytArr(6)
+ READU,unit,simple
+ if string(simple) NE 'SIMPLE' then begin
+ IF ~KEYWORD_SET(LUNIT) THEN Free_Lun, unit
+ ERRMSG = "ERROR - FITS File must begin with 'SIMPLE'"
+ if printerr THEN MESSAGE,errmsg,/CON
+ return,-1
+ endif
+ point_lun,unit,0
+ endif
+
+ stat = FXMOVE(unit, exten, SILENT = Silent, EXT_NO = extnum, $
+ ERRMSG=errmsg)
+
+ IF stat LT 0 THEN BEGIN
+ IF ~KEYWORD_SET(LUNIT) THEN Free_Lun, unit
+ IF PrintErr THEN MESSAGE,ErrMsg
+ RETURN, stat
+ ENDIF ELSE RETURN, unit
+END
diff --git a/Code/script_idl_mv/astrolib/fxread.pro b/Code/script_idl_mv/astrolib/fxread.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d609ff24cb8402ff990be5da179b929e9d82c50f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxread.pro
@@ -0,0 +1,588 @@
+ PRO FXREAD, FILENAME, DATA, HEADER, P1, P2, P3, P4, P5, $
+ NANVALUE=NANVALUE, PROMPT=PROMPT, AVERAGE=AVERAGE, $
+ YSTEP=Y_STEP, NOSCALE=NOSCALE, NOUPDATE=NOUPDATE, $
+ ERRMSG=ERRMSG, NODATA=NODATA, COMPRESS = COMPRESS, $
+ EXTENSION=EXTENSION0
+;+
+; NAME:
+; FXREAD
+; Purpose :
+; Read basic FITS files.
+; Explanation :
+; Read an image array from a disk FITS file. Optionally allows the
+; user to read in only a subarray and/or every Nth pixel.
+; Use :
+; FXREAD, FILENAME, DATA [, HEADER [, I1, I2 [, J1, J2 ]] [, STEP]]
+; Inputs :
+; FILENAME = String containing the name of the file to be read.
+; Opt. Inputs :
+; I1,I2 = Data range to read in the first dimension. If passed, then
+; HEADER must also be passed. If not passed, or set to -1,-1,
+; then the entire range is read.
+; J1,J2 = Data range to read in the second dimension. If passed, then
+; HEADER and I1,J2 must also be passed. If not passed, or set
+; to -1,-1, then the entire range is read.
+; STEP = Step size to use in reading the data. If passed, then
+; HEADER must also be passed. Default value is 1. Ignored if
+; less than 1.
+; Outputs :
+; DATA = Data array to be read from the file.
+; Opt. Outputs:
+; HEADER = String array containing the header for the FITS file.
+; Keywords :
+; /COMPRESS - If this keyword is set and non-zero, then then treat
+; the file as gzip compressed. By default FXREAD assumes
+; the file is gzip compressed if it ends in ".gz"
+; NANVALUE = Value signalling data dropout. All points corresponding to
+; IEEE NaN (not-a-number) are set to this value. Ignored
+; unless DATA is of type float or double-precision.
+; EXTENSION = FITS extension. It can be a scalar integer,
+; indicating the extension number (extension number 0
+; is the primary HDU). It can also be a scalar string,
+; indicating the extension name (EXTNAME keyword).
+; Default: 0 (primary HDU)
+; PROMPT = If set, then the optional parameters are prompted for at the
+; keyboard.
+; AVERAGE = If set, then the array size is reduced by averaging pixels
+; together rather than by subselecting pixels. Ignored unless
+; STEP is nontrivial. Note: this is much slower.
+; YSTEP = If passed, then STEP is the step size in the 1st dimension,
+; and YSTEP is the step size in the 2nd dimension. Otherwise,
+; STEP applies to both directions.
+; NOSCALE = If set, then the output data will not be scaled using the
+; optional BSCALE and BZERO keywords in the FITS header.
+; Default is to scale, if and only if BSCALE and BZERO are
+; present and nontrivial.
+; NOUPDATE = If set, then the optional BSCALE and BZERO keywords in the
+; optional HEADER array will not be changed. The default is
+; to reset these keywords to BSCALE=1, BZERO=0. Ignored if
+; NOSCALE is set.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXREAD, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+; NODATA = If set, then the array is not read in, but the
+; primary header is read.
+;
+; Calls :
+; GET_DATE, FXADDPAR, FXHREAD, FXPAR, WHERENAN
+; Common :
+; None.
+; Restrictions:
+; Groups are not supported.
+;
+; The optional parameters I1, I2, and STEP only work with one or
+; two-dimensional arrays. J1 and J2 only work with two-dimensional
+; arrays.
+;
+; Use of the AVERAGE keyword is not compatible with arrays with missing
+; pixels.
+;
+; Side effects:
+; If the keywords BSCALE and BZERO are present in the FITS header, and
+; have non-trivial values, then the returned array DATA is formed by the
+; equation
+;
+; DATA = BSCALE*original + BZERO
+;
+; However, this behavior can overridden by using the /NOSCALE keyword.
+;
+; If the data is scaled, then the optional HEADER array is changed so
+; that BSCALE=1 and BZERO=0. This is so that these scaling parameters
+; are not applied to the data a second time by another routine. Also,
+; history records are added storing the original values of these
+; constants. Note that only the returned array is modified--the header
+; in the FITS file itself is untouched.
+;
+; If the /NOUPDATE keyword is set, however, then the BSCALE and BZERO
+; keywords are not changed. It is then the user's responsibility to
+; ensure that these parameters are not reapplied to the data. In
+; particular, these keywords should not be present in any header when
+; writing another FITS file, unless the user wants their values to be
+; applied when the file is read back in. Otherwise, FITS readers will
+; read in the wrong values for the data array.
+;
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, May 1992, based in part on READFITS by W. Landsman, and
+; STSUB by M. Greason and K. Venkatakrishna.
+; W. Thompson, Jun 1992, added code to interpret BSCALE and BZERO
+; records, and added NOSCALE and NOUPDATE
+; keywords.
+; W. Thompson, Aug 1992, changed to call FXHREAD, and to add history
+; records for BZERO, BSCALE.
+; Minimium IDL Version:
+; V6.0 (uses V6.0 notation)
+; Written :
+; William Thompson, GSFC, May 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 17 November 1993.
+; Corrected bug with AVERAGE keyword on non-IEEE compatible
+; machines.
+; Corrected bug with subsampling on VAX machines.
+; Version 3, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 4, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 5, Zarro (SAC/GSFC), 14 Feb 1997
+; Added I/O error checking
+; Version 6, 20-May-1998, David Schlegel/W. Thompson
+; Allow a single pixel to be read in.
+; Change the signal to read in the entire array to be -1
+; Version 7 C. Markwardt 22 Sep 2003
+; If the image is empty (NAXIS EQ 0), or NODATA is set, then
+; return only the header.
+; Version 8 W. Landsman 29 June 2004
+; Added COMPRESS keyword, check for .gz extension
+; Version 9, William Thompson, 19-Aug-2004
+; Make sure COMPRESS is treated as a scalar
+; Version 10, Craig Markwardt, 01 Mar 2004
+; Add EXTENSION keyword and ability to read different
+; extensions than the primary one.
+; Version 11, W. Landsman September 2006
+; Assume since V5.5, remove VMS support
+; Version 11.1, W. Landsman November 2007
+; Allow for possibility number of bytes requires 64 bit integer
+; Version 12, William Thompson, 18-Jun-2010, update BLANK value.
+; Version 13, W. Landsman Remove IEEE_TO_HOST, V6.0 notation
+; Version 14, William Thompson, 25-Sep-2014, fix BSCALE bug in version 13
+;-
+;
+ ON_ERROR, 2
+;
+; This parameter will be used later in conjunction with the average keyword.
+;
+ ALREADY_CONVERTED = 0
+ READ_OK=0
+;
+; Parse the input parameters.
+;
+ CASE N_PARAMS() OF
+ 2: BEGIN & I1=-1 & I2=-1 & J1=-1 & J2=-1 & STEP=1 & END
+ 3: BEGIN & I1=-1 & I2=-1 & J1=-1 & J2=-1 & STEP=1 & END
+ 4: BEGIN & I1=-1 & I2=-1 & J1=-1 & J2=-1 & STEP=P1 & END
+ 5: BEGIN & I1=P1 & I2=P2 & J1=-1 & J2=-1 & STEP=1 & END
+ 6: BEGIN & I1=P1 & I2=P2 & J1=-1 & J2=-1 & STEP=P3 & END
+ 7: BEGIN & I1=P1 & I2=P2 & J1=P3 & J2=P4 & STEP=1 & END
+ 8: BEGIN & I1=P1 & I2=P2 & J1=P3 & J2=P4 & STEP=P5 & END
+ ELSE: BEGIN
+ MESSAGE = 'Syntax: FXREAD, FILENAME, DATA ' + $
+ '[, HEADER [, I1, I2 [, J1, J2 ] [, STEP ]]'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END
+ ENDCASE
+
+ ;; Extension number
+ IF N_ELEMENTS(EXTENSION0) EQ 0 THEN EXTENSION = 0L $
+ ELSE EXTENSION = EXTENSION0[0]
+
+ SZ = SIZE(EXTENSION)
+ ETYPE = SZ[SZ[0]+1]
+ IF ETYPE EQ 8 THEN BEGIN
+ MESSAGE = 'EXTENSION must not be a structure'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+
+
+;
+; Determine if file is compressed, get the UNIT number, and open the file.
+;
+ IF NOT KEYWORD_SET(COMPRESS) THEN $
+ COMPRESS = STRLOWCASE( STRMID(FILENAME, STRLEN(FILENAME)-3,3)) EQ '.gz'
+ OPENR, UNIT, FILENAME, /GET_LUN, ERROR=ERROR,COMPRESS=COMPRESS[0]
+ IF ERROR NE 0 THEN BEGIN
+ MESSAGE='Error opening '+FILENAME
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Read in the FITS header.
+;
+
+ ;; Starting extension number is zero
+ I_EXT = 0L
+ FOUND_EXT = 0
+
+ WHILE NOT FOUND_EXT DO BEGIN
+ FXHREAD,UNIT,HEADER,STATUS
+ IF STATUS NE 0 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Unable to read requested FITS header extension'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+;
+; Extract the keywords BITPIX, NAXIS, NAXIS1, ...
+;
+ START = 0L
+ BITPIX = FXPAR(HEADER,'BITPIX', START=START)
+ NAXIS = FXPAR(HEADER,'NAXIS', START=START)
+ GCOUNT = FXPAR(HEADER,'GCOUNT', START=START)
+ IF GCOUNT EQ 0 THEN GCOUNT = 1
+ PCOUNT = FXPAR(HEADER,'PCOUNT', START=START)
+ IF NAXIS GT 0 THEN BEGIN
+ DIMS = FXPAR(HEADER,'NAXIS*') ;Read dimensions
+ NDATA = DIMS[0]
+ IF NAXIS GT 1 THEN FOR I=2,NAXIS DO NDATA = NDATA*DIMS[I-1]
+ ENDIF ELSE NDATA = 0
+ NBYTES = LONG64(ABS(BITPIX) / 8) * GCOUNT * (PCOUNT + NDATA)
+ NREC = (NBYTES + 2879) / 2880
+
+ IF ETYPE EQ 7 THEN BEGIN
+ EXTNAME = STRTRIM(STRUPCASE(FXPAR(HEADER,'EXTNAME', $
+ START=START)),2)
+ IF EXTNAME EQ EXTENSION THEN FOUND_EXT = 1
+ END ELSE IF I_EXT EQ EXTENSION THEN FOUND_EXT = 1
+
+ IF NOT FOUND_EXT THEN BEGIN
+ ;; Check to be sure there are extensions
+ IF I_EXT EQ 0 THEN BEGIN
+ IF NOT FXPAR(HEADER,'EXTEND', START=START) THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Requested extension not found, and file ' + $
+ FILENAME + ' does not contain extensions'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDIF
+
+ POINT_LUN, -UNIT, POINTLUN ;Current position
+ MHEAD0 = POINTLUN + NREC*2880L
+ POINT_LUN, UNIT, MHEAD0 ;Next FITS extension
+
+ I_EXT++
+ ENDIF
+ ENDWHILE
+
+ ;;
+ ;; If we got here, then we have arrived at the requested
+ ;; extension. We still need to be sure that it is an image
+ ;; and not a table (for extensions beyond the primary one,
+ ;; that is).
+ ;;
+ IF I_EXT GT 0 THEN BEGIN
+ XTENSION = STRTRIM(STRUPCASE(FXPAR(HEADER,'XTENSION', START=START)),2)
+ IF (XTENSION NE 'IMAGE') THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Extension ' + STRTRIM(EXTENSION,2) + $
+ ' is not an image'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ ENDIF
+
+ ;; Handle case of empty image, or no data requested
+ IF NAXIS EQ 0 OR KEYWORD_SET(NODATA) THEN BEGIN
+ ;; Make DATA an undefined variable, reflecting no data
+ DATA = 0 & DUMMY = TEMPORARY(DATA)
+
+ ERRMSG = ''
+ FREE_LUN,UNIT
+ RETURN
+ ENDIF
+
+ DIMS = FXPAR(HEADER,'NAXIS*')
+ N1 = DIMS[0]
+ IF NAXIS EQ 2 THEN N2 = DIMS[1] ELSE N2 = 1
+;
+; Determine the array type from the keyword BITPIX.
+;
+ CASE BITPIX OF
+ 8: IDLTYPE = 1 ; Byte
+ 16: IDLTYPE = 2 ; Integer*2
+ 32: IDLTYPE = 3 ; Integer*4
+ -32: IDLTYPE = 4 ; Real*4
+ -64: IDLTYPE = 5 ; Real*8
+ ENDCASE
+;
+; Set the default values for the optional parameters.
+;
+ IF (I1 EQ -1) && (I2 EQ -1) THEN BEGIN
+ I1 = 0
+ I2 = N1-1
+ ENDIF
+ IF (J1 EQ -1) && (J2 EQ -1) THEN BEGIN
+ J1 = 0
+ J2 = N2-1
+ ENDIF
+;
+; If the prompt keyword was set, the prompt for the parameters.
+;
+ IF KEYWORD_SET(PROMPT) THEN BEGIN
+ ANSWER = ''
+ READ,'Enter lower limit for X ['+STRTRIM(I1,2)+']: ', ANSWER
+ IF ANSWER NE '' THEN I1 = (ANSWER)
+;
+ ANSWER = ''
+ READ,'Enter upper limit for X ['+STRTRIM(I2,2)+']: ', ANSWER
+ IF ANSWER NE '' THEN I2 = LONG(ANSWER)
+;
+ ANSWER = ''
+ READ,'Enter lower limit for Y ['+STRTRIM(J1,2)+']: ', ANSWER
+ IF ANSWER NE '' THEN J1 = LONG(ANSWER)
+;
+ ANSWER = ''
+ READ,'Enter upper limit for Y ['+STRTRIM(J2,2)+']: ', ANSWER
+ IF ANSWER NE '' THEN J2 = LONG(ANSWER)
+;
+ ANSWER = ''
+ READ,'Enter step size ['+STRTRIM(STEP,2)+']: ', ANSWER
+ IF ANSWER NE '' THEN STEP = LONG(ANSWER)
+ ENDIF
+;
+; Differentiate between XSTEP and YSTEP.
+;
+ XSTEP = STEP > 1
+ IF N_ELEMENTS(Y_STEP) EQ 1 THEN YSTEP = Y_STEP ELSE YSTEP = XSTEP
+;
+; If any of the optional parameters were passed, then update the dimensions
+; accordingly. First check I1 and I2.
+;
+ IF (I1 NE 0) || (I2 NE N1-1) THEN BEGIN
+ IF NAXIS GT 2 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'Range parameters can only be set for ' + $
+ 'one or two-dimensional arrays'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF (MIN([I1,I2]) LT 0) OR (MAX([I1,I2]) GE DIMS[0]) THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'I1,I2 must be in the range 0 to ' + $
+ STRTRIM(DIMS[0]-1,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF I1 GT I2 THEN BEGIN
+ MESSAGE = 'I2 must be >= I1'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ DIMS[0] = I2 - I1 + 1
+ ENDIF
+;
+; Next, check J1 and J2.
+;
+ IF (J1 NE 0) || (J2 NE N2-1) THEN BEGIN
+ IF NAXIS NE 2 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'J1, J2 can only be set for ' + $
+ 'two-dimensional arrays'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF (MIN([J1,J2]) LT 0) OR (MAX([J1,J2]) GE DIMS[1]) THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'J1,J2 must be in the range 0 to ' + $
+ STRTRIM(DIMS[1]-1,2)
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF J1 GT J2 THEN BEGIN
+ MESSAGE = 'J2 must be >= J1'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ DIMS[1] = J2 - J1 + 1
+ ENDIF
+;
+; Next, check XSTEP. Note that the dimensions of the final result are
+; somewhat differ depending on whether the keyword AVERAGE is set or not.
+;
+ IF XSTEP GT 1 THEN BEGIN
+ IF NAXIS GT 2 THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'STEP can only be set for one or ' + $
+ 'two-dimensional arrays'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF XSTEP NE LONG(XSTEP) THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'STEP must be an integer value'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF KEYWORD_SET(AVERAGE) THEN BEGIN
+ DIMS[0] = DIMS[0] / LONG(XSTEP)
+ END ELSE BEGIN
+ DIMS[0] = LONG(DIMS[0] + XSTEP - 1) / LONG(XSTEP)
+ INDEX = LINDGEN(DIMS[0])*XSTEP
+ ENDELSE
+ ENDIF
+;
+; Finally, check YSTEP. This parameter is ignored for anything other than
+; two-dimensional arrays.
+;
+ IF (NAXIS EQ 2) && (YSTEP GT 1) THEN BEGIN
+ IF YSTEP NE LONG(YSTEP) THEN BEGIN
+ FREE_LUN,UNIT
+ MESSAGE = 'YSTEP must be an integer value'
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ END ELSE IF KEYWORD_SET(AVERAGE) THEN BEGIN
+ DIMS[1] = DIMS[1] / LONG(YSTEP)
+ END ELSE BEGIN
+ DIMS[1] = LONG(DIMS[1]+YSTEP-1) / LONG(YSTEP)
+ ENDELSE
+ END ELSE YSTEP = 1
+;
+; Make the array.
+;
+ DATA = MAKE_ARRAY(DIMENSION=DIMS,TYPE=IDLTYPE,/NOZERO)
+;
+; Find the start of the data to be read in.
+;
+ POINT_LUN,-UNIT,OFFSET ;Current position
+ DELTA = N1*ABS(BITPIX)/8
+ IF J1 NE 0 THEN BEGIN
+ OFFSET = OFFSET + J1*DELTA
+ POINT_LUN,UNIT,OFFSET
+ ENDIF
+;
+; If the I range, XSTEP or YSTEP is non-trivial, then read in the file line by
+; line. If pixel averaging, then read in YSTEP lines.
+;
+ ON_IOERROR,QUIT
+ IF (DIMS[0] NE N1) || (XSTEP GT 1) || (YSTEP GT 1) THEN BEGIN
+ IF NAXIS EQ 1 THEN NJ = 1 ELSE NJ = DIMS[1]
+ FOR J = 0,NJ-1 DO BEGIN
+ IF YSTEP GT 1 THEN POINT_LUN,UNIT,OFFSET+J*YSTEP*DELTA
+ IF (YSTEP GT 1) && KEYWORD_SET(AVERAGE) && (NAXIS EQ 2) $
+ THEN LINE = MAKE_ARRAY(N1,YSTEP,TYPE=IDLTYPE,/NOZERO) $
+ ELSE LINE = MAKE_ARRAY(N1,TYPE=IDLTYPE,/NOZERO)
+ READU,UNIT,LINE
+;
+; If I1,I2 do not match the array size, then extract the relevant subarray.
+;
+ IF (I1 NE 0) || (I2 NE N1-1) THEN LINE = LINE[I1:I2,*]
+;
+; Suppose that the step size is non-trivial. If AVERAGE was set, then convert
+; to the host format, and use REBIN to average the data. (Note that missing
+; pixels are not correctly handled in this case.) Otherwise, select out the
+; relevant portion of the data.
+;
+ IF (XSTEP GT 1) || (YSTEP GT 1) THEN BEGIN
+ IF KEYWORD_SET(AVERAGE) THEN BEGIN
+ SWAP_ENDIAN_INPLACE, LINE, /SWAP_IF_LITTLE
+ ALREADY_CONVERTED = 1
+ IF NAXIS EQ 1 THEN BEGIN
+ DATA[0,J] = REBIN(LINE[0:XSTEP*DIMS[0]]-1,DIMS[0])
+ END ELSE BEGIN
+ DATA[0,J] = REBIN(LINE[0:XSTEP*DIMS[0]-1,*],DIMS[0],1)
+ ENDELSE
+ END ELSE DATA[0,J] = LINE[INDEX]
+;
+; Otherwise, if the step size is trivial, then simply store the line in the
+; data array.
+;
+ END ELSE BEGIN
+ DATA[0,J] = LINE
+ ENDELSE
+ ENDFOR
+;
+; Otherwise, if the file doesn't have to be read in line by line, then just
+; read the data array.
+;
+ END ELSE READU,UNIT,DATA
+;
+; Convert the data from IEEE to host format, keeping track of any IEEE NaN
+; values. Don't do this if the conversion has already taken place.
+;
+ IF ~ALREADY_CONVERTED THEN BEGIN
+ IF (N_ELEMENTS(NANVALUE) EQ 1) && (IDLTYPE GE 4) && $
+ (IDLTYPE LE 6) THEN W = WHERENAN(DATA,COUNT) ELSE $
+ COUNT = 0
+ SWAP_ENDIAN_INPLACE,DATA, /SWAP_IF_LITTLE
+ END ELSE COUNT = 0
+;
+; If the parameters BZERO and BSCALE are non-trivial, then adjust the array by
+; these values. Also update the BLANK keyword, if present.
+;
+ IF ~KEYWORD_SET(NOSCALE) THEN BEGIN
+ BZERO = FXPAR(HEADER,'BZERO')
+ BSCALE = FXPAR(HEADER,'BSCALE')
+ BLANK = FXPAR(HEADER,'BLANK',COUNT=NBLANK)
+ GET_DATE,DTE
+ IF (BSCALE NE 0) && (BSCALE NE 1) THEN BEGIN
+ DATA *= BSCALE
+ IF ~KEYWORD_SET(NOUPDATE) THEN BEGIN
+ FXADDPAR,HEADER,'BSCALE',1.
+ FXADDPAR,HEADER,'HISTORY',DTE + $
+ ' applied BSCALE = '+ STRTRIM(BSCALE,2)
+ IF NBLANK EQ 1 THEN BEGIN
+ print, bscale, blank
+ BLANK *= BSCALE
+ FXADDPAR,HEADER,'BLANK',BLANK
+ ENDIF
+ ENDIF
+ ENDIF
+ IF BZERO NE 0 THEN BEGIN
+ DATA += BZERO
+ IF ~KEYWORD_SET(NOUPDATE) THEN BEGIN
+ FXADDPAR,HEADER,'BZERO',0.
+ FXADDPAR,HEADER,'HISTORY',DTE + $
+ ' applied BZERO = '+ STRTRIM(BZERO,2)
+ IF NBLANK EQ 1 THEN BEGIN
+ BLANK += BZERO
+ FXADDPAR,HEADER,'BLANK',BLANK
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDIF
+;
+; Store NANVALUE everywhere where the data corresponded to IEE NaN.
+;
+ IF COUNT GT 0 THEN DATA[W] = NANVALUE
+;
+; Close the file and return.
+;
+ READ_OK=1
+QUIT: ON_IOERROR,NULL
+ FREE_LUN, UNIT
+ IF NOT READ_OK THEN BEGIN
+ MESSAGE='Error reading file '+FILENAME
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN BEGIN
+ ERRMSG = MESSAGE
+ RETURN
+ END ELSE MESSAGE, MESSAGE
+ ENDIF
+ IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = ''
+ RETURN
+ END
diff --git a/Code/script_idl_mv/astrolib/fxwrite.pro b/Code/script_idl_mv/astrolib/fxwrite.pro
new file mode 100644
index 0000000000000000000000000000000000000000..30e2c7c189436cf8db45077eaf970a3a323992f1
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/fxwrite.pro
@@ -0,0 +1,312 @@
+ PRO FXWRITE, FILENAME, HEADER, DATA, NANVALUE=NANVALUE, $
+ NOUPDATE=NOUPDATE, ERRMSG=ERRMSG, APPEND=APPEND
+;+
+; NAME:
+; FXWRITE
+; Purpose :
+; Write a disk FITS file.
+; Explanation :
+; Creates or appends to a disk FITS file and writes a FITS
+; header, and optionally an image data array.
+; Use :
+; FXWRITE, FILENAME, HEADER [, DATA ]
+; Inputs :
+; FILENAME = String containing the name of the file to be written.
+; HEADER = String array containing the header for the FITS file.
+; Opt. Inputs :
+; DATA = IDL data array to be written to the file. If not passed,
+; then it is assumed that extensions will be added to the
+; file.
+; Outputs :
+; None.
+; Opt. Outputs:
+; None.
+; Keywords :
+; NANVALUE = Value signalling data dropout. All points corresponding to
+; this value are set to be IEEE NaN (not-a-number). Ignored
+; unless DATA is of type float, double-precision or complex.
+; NOUPDATE = If set, then the optional BSCALE and BZERO keywords in the
+; HEADER array will not be changed. The default is to reset
+; these keywords to BSCALE=1, BZERO=0.
+; APPEND = If set, then an existing file will be appended to.
+; Appending to a non-existent file will create it. If
+; a primary HDU already exists then it will be modified
+; to have EXTEND = T.
+; ERRMSG = If defined and passed, then any error messages will be
+; returned to the user in this parameter rather than
+; depending on the MESSAGE routine in IDL. If no errors are
+; encountered, then a null string is returned. In order to
+; use this feature, ERRMSG must be defined first, e.g.
+;
+; ERRMSG = ''
+; FXWRITE, ERRMSG=ERRMSG, ...
+; IF ERRMSG NE '' THEN ...
+;
+; Calls :
+; CHECK_FITS, GET_DATE, FXADDPAR, FXPAR
+; Common :
+; None.
+; Restrictions:
+; If DATA is passed, then HEADER must be consistent with it. If no data
+; array is being written to the file, then HEADER must also be consistent
+; with that. The routine FXHMAKE can be used to create a FITS header.
+;
+; If found, then the optional keywords BSCALE and BZERO in the HEADER
+; array is changed so that BSCALE=1 and BZERO=0. This is so that these
+; scaling parameters are not applied to the data a second time by another
+; routine. Also, history records are added storing the original values
+; of these constants. (Other values of BZERO are used for unsigned
+; integers.)
+;
+; If the /NOUPDATE keyword is set, however, then the BSCALE and BZERO
+; keywords are not changed. The user should then be aware that FITS
+; readers will apply these numbers to the data, even if the data is
+; already converted to floating point form.
+;
+; Groups are not supported.
+;
+; Side effects:
+; HEADER may be modified. One way it may be modified is describe
+; above under NOUPDATE. The first header card may also be
+; modified to conform to the FITS standard if it does not
+; already agree (i.e. use of either the SIMPLE or XTENSION
+; keyword depending on whether the image is the primary HDU or
+; not).
+; Category :
+; Data Handling, I/O, FITS, Generic.
+; Prev. Hist. :
+; W. Thompson, Jan 1992, from WRITEFITS by J. Woffard and W. Landsman.
+; Differences include:
+;
+; * Made DATA array optional, and HEADER array mandatory.
+; * Changed order of HEADER and DATA parameters.
+; * No attempt made to fix HEADER array.
+;
+; W. Thompson, May 1992, changed open statement to force 2880 byte fixed
+; length records (VMS). The software here does not
+; depend on this file configuration, but other
+; FITS readers might.
+; W. Thompson, Aug 1992, added code to reset BSCALE and BZERO records,
+; and added the NOUPDATE keyword.
+; Written :
+; William Thompson, GSFC, January 1992.
+; Modified :
+; Version 1, William Thompson, GSFC, 12 April 1993.
+; Incorporated into CDS library.
+; Version 2, William Thompson, GSFC, 31 May 1994
+; Added ERRMSG keyword.
+; Version 3, William Thompson, GSFC, 23 June 1994
+; Modified so that ERRMSG is not touched if not defined.
+; Version 4, William Thompson, GSFC, 12 August 1999
+; Catch error if unable to open file.
+; Version 4.1 Wayne Landsman, GSFC, 02 May 2000
+; Remove !ERR in call to CHECK_FITS, Use ARG_PRESENT()
+; Version 5, William Thompson, GSFC, 22 September 2004
+; Recognize unsigned integer types
+; Version 5.1 W. Landsman 14 November 2004
+; Allow for need for 64bit number of bytes
+; Version 6, Craig Markwardt, GSFC, 30 May 2005
+; Ability to append to existing files
+; Version 7, W. Landsman GSFC, Mar 2014
+; Remove HOST_TO_IEEE, Use V6.0 notation
+; Version :
+; Version 6, 30 May 2005
+;-
+;
+ ON_ERROR, 2
+;
+; Check the number of parameters.
+;
+ IF N_PARAMS() LT 2 THEN BEGIN
+ MESSAGE = 'Syntax: FXWRITE, FILENAME, HEADER [, DATA ]'
+ GOTO, HANDLE_ERROR
+ ENDIF
+;
+; Check the header against the data being written to the file. If the data
+; array is not passed, then NAXIS should be set to zero, and EXTEND should be
+; true.
+;
+ IF N_PARAMS() EQ 2 THEN BEGIN
+ IF (FXPAR(HEADER,'NAXIS') NE 0) THEN BEGIN
+ MESSAGE = 'NAXIS should be zero for no primary data array'
+ GOTO, HANDLE_ERROR
+ END ELSE IF (~FXPAR(HEADER,'EXTEND')) THEN BEGIN
+ MESSAGE = 'EXTEND should be true for no primary data array'
+ GOTO, HANDLE_ERROR
+ ENDIF
+ END ELSE BEGIN
+ CHECK_FITS, DATA, HEADER, /FITS, ERRMSG = MESSAGE
+ IF MESSAGE NE '' THEN GOTO, HANDLE_ERROR
+ ENDELSE
+;
+; Set the BSCALE and BZERO keywords to their default values.
+;
+ SZ = SIZE(DATA)
+ TYPE = SZ[SZ[0]+1]
+ IF N_PARAMS() EQ 3 THEN NEWDATA = DATA
+ IF ~KEYWORD_SET(NOUPDATE) THEN BEGIN
+ BZERO = FXPAR(HEADER,'BZERO')
+ BSCALE = FXPAR(HEADER,'BSCALE')
+ GET_DATE,DTE
+ IF (BSCALE NE 0) AND (BSCALE NE 1) THEN BEGIN
+ FXADDPAR,HEADER,'BSCALE',1.
+ FXADDPAR,HEADER,'HISTORY',DTE+' reset BSCALE, was '+ $
+ STRTRIM(BSCALE,2)
+ ENDIF
+;
+; If an unsigned data type then redefine BZERO to allow all the data to be
+; stored in the file.
+;
+ BZERO0 = 0
+ IF (TYPE EQ 12) && (~KEYWORD_SET(NOUPDATE)) THEN BEGIN
+ BZERO0 = '8000'X
+ NEWDATA = FIX(TEMPORARY(NEWDATA) - BZERO)
+ ENDIF
+ IF (TYPE EQ 13) && (~KEYWORD_SET(NOUPDATE)) THEN BEGIN
+ BZERO0 = '80000000'X
+ NEWDATA = LONG(TEMPORARY(NEWDATA) - BZERO)
+ ENDIF
+ IF BZERO NE BZERO0 THEN BEGIN
+ FXADDPAR,HEADER,'BZERO',BZERO0
+ FXADDPAR,HEADER,'HISTORY',DTE+' reset BZERO, was '+ $
+ STRTRIM(BZERO,2)
+ ENDIF
+ ENDIF
+;
+; Get the UNIT number, and open the file.
+;
+ GET_LUN, UNIT
+ OPENW, UNIT, FILENAME, 2880, /BLOCK, ERROR=ERR, APPEND=APPEND
+ VERB = 'creating'
+ IF KEYWORD_SET(APPEND) THEN VERB = 'appending to'
+ IF ERR NE 0 THEN BEGIN
+ MESSAGE = 'Error '+VERB+' file '+FILENAME
+ GOTO, HANDLE_ERROR
+ ENDIF
+
+;
+; Special processing is required when we are appending to
+; the file, to ensure that the FITS standards are met.
+; (i.e. primary HDU must have EXTEND = T, and the header
+; to be written must have XTENSION = 'IMAGE').
+;
+
+ POINT_LUN, -UNIT, POS
+ IF POS GT 0 THEN BEGIN
+ ;; Release the file and call FXHMODIFY to edit the
+ ;; header of the primary HDU. It is required to have
+ ;; EXTEND=T. FXHMODIFY calls FXADDPAR, which
+ ;; automatically places the EXTEND keyword in the
+ ;; required position.
+ FREE_LUN, UNIT
+ FXHMODIFY, FILENAME, ERRMSG=MESSAGE, $ ; (EXTENSION=0 implied)
+ 'EXTEND', 'T', ' FITS dataset may contain extensions'
+ IF MESSAGE NE '' THEN GOTO, HANDLE_ERROR
+
+ ;; Re-open the file
+ GET_LUN, UNIT
+ OPENW, UNIT, FILENAME, 2880, /BLOCK, ERROR=ERR, APPEND=APPEND
+ IF ERR NE 0 THEN BEGIN
+ MESSAGE = 'Error re-opening file '+FILENAME
+ GOTO, HANDLE_ERROR
+ ENDIF
+
+ ;; Revise the header so that it begins with an
+ ;; XTENSION keyword... if it doesn't already
+ IF STRMID(HEADER[0], 0, 9) EQ 'SIMPLE =' THEN BEGIN
+ ;; Extra work to preserve the comment
+ DUMMY = FXPAR(HEADER, 'SIMPLE', COMMENT=COMMENT)
+ FXADDPAR, DUMMYHEADER, 'XTENSION', 'IMAGE', COMMENT
+ HEADER[0] = DUMMYHEADER[0]
+ ENDIF
+
+ ;; Find last NAXIS* keyword, since PCOUNT/GCOUNT follow them
+ NAXIS = FXPAR(HEADER, 'NAXIS', COUNT=COUNT_NAXIS)
+ IF NAXIS[0] GT 0 THEN PCOUNT_AFTER='NAXIS'+strtrim(NAXIS[0],2)
+ ;; Required PCOUNT/GCOUNT keywords for following extensions
+ FXADDPAR, HEADER, 'PCOUNT', 0, ' number of random group parameters', $
+ AFTER=PCOUNT_AFTER
+ FXADDPAR, HEADER, 'GCOUNT', 1, ' number of random groups', $
+ AFTER='PCOUNT'
+
+ ENDIF ELSE BEGIN
+ ;; In the off chance that this header was used before to
+ ;; write a header with XTENSION, make sure this *new* file
+ ;; has SIMPLE = T
+
+ IF STRMID(HEADER[0], 0, 9) EQ 'XTENSION=' THEN BEGIN
+ ;; Extra work to preserve the comment
+ DUMMY = FXPAR(HEADER, 'XTENSION', COMMENT=COMMENT)
+ FXADDPAR, DUMMYHEADER, 'SIMPLE', 'T', COMMENT
+ HEADER[0] = DUMMYHEADER[0]
+ ENDIF
+
+ ENDELSE
+
+
+;
+; Determine if an END line occurs, and add one if necessary
+;
+ ENDLINE = WHERE( STRMID(HEADER,0,8) EQ 'END ', NEND)
+ ENDLINE = ENDLINE[0]
+ IF NEND EQ 0 THEN BEGIN
+ MESSAGE, 'WARNING - An END statement has been appended ' + $
+ 'to the FITS header', /INFORMATIONAL
+ HEADER = [HEADER, 'END' + STRING(REPLICATE(32B,77))]
+ ENDLINE = N_ELEMENTS(HEADER) - 1
+ ENDIF
+ NMAX = ENDLINE + 1 ;Number of 80 byte records
+ NHEAD = FIX((NMAX+35)/36) ;Number of 2880 byte records
+;
+; Convert to byte and force into 80 character lines
+;
+ BHDR = REPLICATE(32B, 80, 36*NHEAD)
+ FOR N = 0,ENDLINE DO BHDR[0,N] = BYTE( STRMID(HEADER[N],0,80) )
+ WRITEU, UNIT, BHDR
+;
+; If passed, then write the data array.
+;
+ IF N_PARAMS() EQ 3 THEN BEGIN
+;
+; If necessary, then byte-swap the data before writing it out. Also, replace
+; any values corresponding data dropout with IEEE NaN.
+;
+ IF (N_ELEMENTS(NANVALUE) EQ 1) && (TYPE GE 4) && $
+ (TYPE LE 6) THEN BEGIN
+ W = WHERE(DATA EQ NANVALUE, COUNT)
+ CASE TYPE OF
+ 4: NAN = FLOAT( REPLICATE('FF'XB,4),0,1)
+ 5: NAN = DOUBLE( REPLICATE('FF'XB,8),0,1)
+ 6: NAN = COMPLEX(REPLICATE('FF'XB,8),0,1)
+ 9: NAN = DCOMPLEX(REPLICATE('FF'XB,16),0,1)
+ ENDCASE
+ END ELSE COUNT = 0
+;
+ SWAP_ENDIAN_INPLACE, NEWDATA, /SWAP_IF_LITTLE
+ IF COUNT GT 0 THEN NEWDATA[W] = NAN
+;
+ WRITEU,UNIT,NEWDATA
+;
+; If necessary, then pad out to an integral multiple of 2880 bytes.
+;
+ BITPIX = FXPAR( HEADER, 'BITPIX' )
+ NBYTES = LONG64(N_ELEMENTS(DATA)) * (ABS(BITPIX) / 8 )
+ NPAD = NBYTES MOD 2880
+ IF NPAD NE 0 THEN BEGIN
+ NPAD = 2880 - NPAD
+ WRITEU,UNIT,BYTARR(NPAD)
+ ENDIF
+ ENDIF
+;
+; Close the file and return.
+;
+ FREE_LUN, UNIT
+ IF ARG_PRESENT(ERRMSG) THEN ERRMSG = ''
+ RETURN
+;
+HANDLE_ERROR:
+ IF N_ELEMENTS(UNIT) EQ 1 THEN FREE_LUN, UNIT
+ IF ARG_PRESENT(ERRMSG) THEN ERRMSG = 'FXWRITE: ' + MESSAGE $
+ ELSE MESSAGE, MESSAGE
+;
+ END
diff --git a/Code/script_idl_mv/astrolib/gal_flat.pro b/Code/script_idl_mv/astrolib/gal_flat.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d6407e283088b44e7721aa17c7c4a8be0520b136
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/gal_flat.pro
@@ -0,0 +1,94 @@
+FUNCTION GAL_FLAT,IMAGE,ANG,INC,CEN,INTERP = interp
+;+
+; NAME:
+; GAL_FLAT
+;
+; PURPOSE:
+; Transforms the image of a galaxy so that the galaxy appears face-on
+; EXPLANATION:
+; Either a nearest-neighbor approximations or a bilinear interpolation
+; may be used.
+;
+; CALLING SEQUENCE:
+; RESULT = GAL_FLAT( image, ang, inc, [, cen, /INTERP ] )
+;
+; INPUTS:
+; IMAGE - Image to be transformed
+; ANG - Angle of major axis, counterclockwise from Y-axis, degrees
+; For an image in standard orientation (North up, East left)
+; this is the Position Angle
+; INC - Angle of inclination of galaxy, degrees
+;
+; OPTIONAL INPUTS:
+; CEN - Two element vector giving the X and Y position of galaxy center
+; If not supplied, then the galaxy center is assumed to coincide
+; with the image center
+;
+; INPUT KEYWORDS:
+; INTERP - If present, and non-zero, then bilinear interpolation will be
+; performed. Otherwise a nearest neighbor approximation is used.
+;
+; OUTPUTS:
+; RESULT - the transformed image, same dimensions and type as IMAGE
+;
+; METHOD:
+; A set of 4 equal spaced control points are corrected for inclination
+; using the procedure POLYWARP. These control points are used by
+; POLY_2D to correct the whole image.
+;
+; REVISION HISTORY:
+; Written by R. S. Hill, SASC Technologies Inc., 4 December 1985
+; Code cleaned up a bit W. Landsman December 1992
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+
+ if ( N_params() lt 3 ) then begin
+ print,'Syntax - result = gal_flat( image, ang, inc, [ cen, /INTERP ])'
+ print,'ANG - Position Angle of major axis (degrees)'
+ print,'INC - Inclination of galaxy (degrees)'
+ return, -1
+ endif
+
+ if not keyword_set( INTERP ) then interp = 0
+
+ angr = (ang+90)/!RADEG
+ tanang = tan(angr)
+ cosang = cos(angr)
+ cosinc = cos(inc/!RADEG)
+; Parameters of image
+ dims = SIZE(image)
+
+ if N_elements(cen) NE 2 then begin
+
+ xcen = dims[1]/2.0 ;Center
+ ycen = dims[2]/2.0
+ if not !QUIET then message,'Galaxy nucleus assumed in image center',/CONT
+
+ endif else begin
+
+ xcen = cen[0]
+ ycen = cen[1]
+
+ endelse
+; Equation of rotation axis
+ b = ycen - xcen*tanang
+; Fiducial grid (as in ROT_INT)
+ gridx = xcen + [ [-1,1], [-1,1] ] * dims[1]/6.0
+ gridy = ycen + [ [-1,-1], [1,1] ] * dims[2]/6.0
+; Distorted version of grid
+ yprime = gridx*tanang + b ;Equation of major axis
+ r0 = (gridy-yprime)*cos(angr) ;Dist of control pts to major axis
+ delr = r0*(1.0-cosinc) ;Correct distance for inclination
+ dely = -delr*cos(angr)
+ delx = delr*sin(angr)
+ distx = gridx + delx
+ disty = gridy + dely
+; Parameters of undistorted grid
+ x0 = dims[1]/3.0
+ y0 = dims[2]/3.0
+ dx = x0 ;In this case only
+ dy = y0
+; Do it
+ polywarp, distx, disty, gridx, gridy, 1, kx, ky
+ RETURN,poly_2d( image, kx, ky, interp, MISSING = 0)
+ end
diff --git a/Code/script_idl_mv/astrolib/gal_uvw.pro b/Code/script_idl_mv/astrolib/gal_uvw.pro
new file mode 100644
index 0000000000000000000000000000000000000000..69e63b970300f868258414f0a6aec3d3e9adb5e9
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/gal_uvw.pro
@@ -0,0 +1,130 @@
+pro gal_uvw, u, v, w, distance = distance, LSR = lsr, ra=ra,dec=dec, $
+ pmra = pmra, pmdec=pmdec, vrad = vrad, plx = plx
+;+
+; NAME:
+; GAL_UVW
+; PURPOSE:
+; Calculate the Galactic space velocity (U,V,W) of star
+; EXPLANATION:
+; Calculates the Galactic space velocity U, V, W of star given its
+; (1) coordinates, (2) proper motion, (3) distance (or parallax), and
+; (4) radial velocity.
+; CALLING SEQUENCE:
+; GAL_UVW, U, V, W, [/LSR, RA=, DEC=, PMRA= ,PMDEC=, VRAD= , DISTANCE=
+; PLX= ]
+; OUTPUT PARAMETERS:
+; U - Velocity (km/s) positive toward the Galactic *anti*center
+; V - Velocity (km/s) positive in the direction of Galactic rotation
+; W - Velocity (km/s) positive toward the North Galactic Pole
+; REQUIRED INPUT KEYWORDS:
+; User must supply a position, proper motion,radial velocity and distance
+; (or parallax). Either scalars or vectors can be supplied.
+; (1) Position:
+; RA - Right Ascension in *Degrees*
+; Dec - Declination in *Degrees*
+; (2) Proper Motion
+; PMRA = Proper motion in RA in arc units (typically milli-arcseconds/yr)
+; If given mu_alpha --proper motion in seconds of time/year - then
+; this is equal to 15*mu_alpha*cos(dec)
+; PMDEC = Proper motion in Declination (typically mas/yr)
+; (3) Radial Velocity
+; VRAD = radial velocity in km/s
+; (4) Distance or Parallax
+; DISTANCE - distance in parsecs
+; or
+; PLX - parallax with same distance units as proper motion measurements
+; typically milliarcseconds (mas)
+;
+; OPTIONAL INPUT KEYWORD:
+; /LSR - If this keyword is set, then the output velocities will be
+; corrected for the solar motion (U,V,W)_Sun = (-8.5, 13.38, 6.49)
+; (Coskunoglu et al. 2011 MNRAS) to the local standard of rest.
+; Note that the value of the solar motion through the LSR remains
+; poorly determined.
+; EXAMPLE:
+; (1) Compute the U,V,W coordinates for the halo star HD 6755.
+; Use values from Hipparcos catalog, and correct to the LSR
+; ra = ten(1,9,42.3)*15. & dec = ten(61,32,49.5)
+; pmra = 628.42 & pmdec = 76.65 ;mas/yr
+; dis = 139 & vrad = -321.4
+; gal_uvw,u,v,w,ra=ra,dec=dec,pmra=pmra,pmdec=pmdec,vrad=vrad,dis=dis,/lsr
+; ===> u=141.2 v = -491.7 w = 93.9 ;km/s
+;
+; (2) Use the Hipparcos Input and Output Catalog IDL databases (see
+; http://idlastro.gsfc.nasa.gov/ftp/zdbase/) to obtain space velocities
+; for all stars within 10 pc with radial velocities > 10 km/s
+;
+; dbopen,'hipp_new,hic' ;Need Hipparcos output and input catalogs
+; list = dbfind('plx>100,vrad>10') ;Plx > 100 mas, Vrad > 10 km/s
+; dbext,list,'pmra,pmdec,vrad,ra,dec,plx',pmra,pmdec,vrad,ra,dec,plx
+; ra = ra*15. ;Need right ascension in degrees
+; GAL_UVW,u,v,w,ra=ra,dec=dec,pmra=pmra,pmdec=pmdec,vrad=vrad,plx = plx
+; forprint,u,v,w ;Display results
+; METHOD:
+; Follows the general outline of Johnson & Soderblom (1987, AJ, 93,864)
+; except that U is positive outward toward the Galactic *anti*center, and
+; the J2000 transformation matrix to Galactic coordinates is taken from
+; the introduction to the Hipparcos catalog.
+; REVISION HISTORY:
+; Written, W. Landsman December 2000
+; fix the bug occuring if the input arrays are longer than 32767
+; and update the Sun velocity Sergey Koposov June 2008
+; vectorization of the loop -- performance on large arrays
+; is now 10 times higher Sergey Koposov December 2008
+; More recent value of solar motion WL/SK Jan 2011
+;-
+ compile_opt idl2
+ if N_Params() EQ 0 then begin
+ print,'Syntax - GAL_UVW, U, V, W, [/LSR, RA=, DEC=, PMRA= ,PMDEC=, VRAD='
+ print,' Distance=, PLX='
+ print,' U, V, W - output Galactic space velocities (km/s)'
+ return
+ endif
+
+ Nra = N_elements(ra)
+ if (nra EQ 0) or (N_elements(dec) EQ 0) then message, $
+ 'ERROR - The RA, Dec (J2000) position keywords must be supplied (degrees)'
+ if N_elements(distance) GT 0 then begin
+ bad = where(distance LE 0, Nbad)
+ if Nbad GT 0 then message,'ERROR - All distances must be > 0'
+ plx = 1e3/distance ;Parallax in milli-arcseconds
+ endif else begin
+ if N_elements(plx) EQ 0 then message, $
+ 'ERROR - Either a parallax or distance must be specified'
+ bad = where(plx LE 0.0, Nbad)
+ if Nbad GT 0 then message,'ERROR - Parallaxes must be > 0'
+ endelse
+
+ cosd = cos(dec/!RADEG)
+ sind = sin(dec/!RADEG)
+ cosa = cos(ra/!RADEG)
+ sina = sin(ra/!RADEG)
+
+ k = 4.74047 ;Equivalent of 1 A.U/yr in km/s
+ A_G = [ [ 0.0548755604, +0.4941094279, -0.8676661490], $
+ [ 0.8734370902, -0.4448296300, -0.1980763734], $
+ [ 0.4838350155, 0.7469822445, +0.4559837762] ]
+
+ vec1 = vrad
+ vec2 = k*pmra/plx
+ vec3 = k*pmdec/plx
+
+ u = ( A_G[0,0]*cosa*cosd+A_G[0,1]*sina*cosd+A_G[0,2]*sind)*vec1+$
+ (-A_G[0,0]*sina +A_G[0,1]*cosa )*vec2+$
+ (-A_G[0,0]*cosa*sind-A_G[0,1]*sina*sind+A_G[0,2]*cosd)*vec3
+ v = ( A_G[1,0]*cosa*cosd+A_G[1,1]*sina*cosd+A_G[1,2]*sind)*vec1+$
+ (-A_G[1,0]*sina +A_G[1,1]*cosa )*vec2+$
+ (-A_G[1,0]*cosa*sind-A_G[1,1]*sina*sind+A_G[1,2]*cosd)*vec3
+ w = ( A_G[2,0]*cosa*cosd+A_G[2,1]*sina*cosd+A_G[2,2]*sind)*vec1+$
+ (-A_G[2,0]*sina +A_G[2,1]*cosa )*vec2+$
+ (-A_G[2,0]*cosa*sind-A_G[2,1]*sina*sind+A_G[2,2]*cosd)*vec3
+
+ lsr_vel=[-8.5,13.38,6.49]
+ if keyword_set(lsr) then begin
+ u = u+lsr_vel[0]
+ v = v+lsr_vel[1]
+ w = w+lsr_vel[2]
+ end
+
+ return
+ end
diff --git a/Code/script_idl_mv/astrolib/galage.pro b/Code/script_idl_mv/astrolib/galage.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c42c49461c2e47c8d3ea9a4f1a35d8cbe22c355a
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/galage.pro
@@ -0,0 +1,130 @@
+;+
+; NAME:
+; GALAGE
+;
+; PURPOSE:
+; Determine the age of a galaxy given its redshift and a formation redshift.
+;
+; CALLING SEQUENCE:
+; age = galage(z, [zform, H0 =, k=, lambda0 =, Omega_m= , q0 =, /SILENT])'
+;
+; INPUTS:
+; z - positive numeric vector or scalar of measured redshifts
+; zform - redshift of galaxy formation (> z), numeric positive scalar
+; To determine the age of the universe at a given redshift, set zform
+; to a large number (e.g. ~1000).
+;
+; OPTIONAL KEYWORD INPUTS:
+; H0 - Hubble constant in km/s/Mpc, positive scalar, default is 70
+; /SILENT - If set, then the adopted cosmological parameters are not
+; displayed at the terminal.
+;
+; No more than two of the following four parameters should be
+; specified. None of them need be specified -- the adopted defaults
+; are given.
+; k - curvature constant, normalized to the closure density. Default is
+; 0, (indicating a flat universe)
+; Omega_m - Matter density, normalized to the closure density, default
+; is 0.3. Must be non-negative
+; Lambda0 - Cosmological constant, normalized to the closure density,
+; default is 0.7
+; q0 - Deceleration parameter, numeric scalar = -R*(R'')/(R')^2, default
+; is -0.55
+;
+; OUTPUTS:
+; age - age of galaxy in years, will have the same number of elements
+; as the input Z vector
+;
+; EXAMPLE:
+; (1) Determine the age of a galaxy observed at z = 1.5 in a cosmology with
+; Omega_matter = 0.3 and Lambda = 0.0. Assume the formation redshift was
+; at z = 25, and use the default Hubble constant (=70 km/s/Mpc)
+;
+; IDL> print,galage(1.5,25,Omega_m=0.3, Lambda = 0)
+; ===> 3.35 Gyr
+;
+; (2) Plot the age of a galaxy in Gyr out to a redshift of z = 5, assuming
+; the default cosmology (omega_m=0.3, lambda=0.7), and zform = 100
+;
+; IDL> z = findgen(50)/10.
+; IDL> plot,z,galage(z,100)/1e9,xtit='z',ytit = 'Age (Gyr)'
+;
+; PROCEDURE:
+; For a given formation time zform and a measured z, integrate dt/dz from
+; zform to z. Analytic formula of dt/dz in Gardner, PASP 110:291-305, 1998
+; March (eq. 7)
+;
+; COMMENTS:
+; (1) Integrates using the IDL Astronomy Library procedure QSIMP. (The
+; intrinsic IDL QSIMP() function is not called because of its ridiculous
+; restriction that only scalar arguments can be passed to the integrating
+; function.) The function 'dtdz' is defined at the beginning of the
+; routine (so it can compile first).
+;
+; (2) Should probably be fixed to use a different integrator from QSIMP when
+; computing age from an "infinite" redshift of formation. But using a
+; large value of zform seems to work adequately.
+;
+; (3) An alternative set of IDL procedures for computing cosmological
+; parameters is available at
+; http://cerebus.as.arizona.edu/~ioannis/research/red/
+; PROCEDURES CALLED:
+; COSMO_PARAM, QSIMP
+; HISTORY:
+; STIS version by P. Plait (ACC) June 1999
+; IDL Astro Version W. Landsman (Raytheon ITSS) April 2000
+; Avoid integer overflow for more than 32767 redshifts July 2001
+;-
+;
+; define function dtdz
+;
+
+function dtdz, z, lambda0 = lambda0, q0 = q0
+ term1 = (1.0d + z)
+ term2 = 2.0d * (q0 + lambda0) * z + 1.0d - lambda0
+ term3 = (1.0d + z) * (1.0d +z)
+ return, 1.0 / (term1 * sqrt(term2 * term3 + lambda0))
+ end
+
+;;;;;;;;;;;;;;;;;;;;;;;;;
+
+function galage, z, zform, h0 = h0, Omega_m=omega_m, lambda0 = lambda0, k = k, $
+ q0 = q0, SILENT = silent
+
+ if N_params() LE 1 then begin
+ print,$
+ 'Syntax: age = GALAGE(z, zform, [H0= , Omega_M = ,lambda0 =, k= , q0=, /SIL]'
+ return, 0
+ endif
+
+;
+; initialize numbers
+;
+
+ if N_elements(h0) EQ 0 then h0 = 70.0
+ COSMO_PARAM, Omega_m, lambda0, k, q0
+ if not keyword_set(silent) then $
+ print,'GALAGE: H0:', h0, ' Omega_m:', omega_m, ' Lambda0',lambda0, $
+ ' q0: ',q0, ' k: ', k, f='(A,I3,A,f5.2,A,f5.2,A,f5.2,A,F5.2)'
+
+ nz = N_elements(z)
+ age = z*0. ;Return same dimensions and data type as Z
+
+;
+; use qsimp to integrate dt/dz to get age for each z
+; watch out for null case of z >= zform
+;
+
+ for i= 0L, nz-1 do begin
+ if (z[i] ge zform) then age_z = 0 else $
+ qsimp,'dtdz', z[i], zform, age_z, q0 = q0, lambda0 = lambda0
+ age[i] = age_z
+ endfor
+
+; convert units of age: km/s/Mpc to years, divide by H0
+; 3.085678e19 km --> 1 Mpc
+; 3.15567e+07 sec --> 1 year
+
+ return, age * 3.085678e+19 / 3.15567e+7/ H0
+ end
+
diff --git a/Code/script_idl_mv/astrolib/gaussian.pro b/Code/script_idl_mv/astrolib/gaussian.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1f640a1a10cd43548d67c9fac36be9d48fad921f
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/gaussian.pro
@@ -0,0 +1,107 @@
+function gaussian, xi, parms, pderiv, DOUBLE=double
+;+
+; NAME:
+; GAUSSIAN
+; PURPOSE:
+; Compute the 1-d Gaussian function and optionally the derivative
+; EXPLANATION:
+; Compute the 1-D Gaussian function and optionally the derivative
+; at an array of points.
+;
+; CALLING SEQUENCE:
+; y = gaussian( xi, parms,[ pderiv ])
+;
+; INPUTS:
+; xi = array, independent variable of Gaussian function.
+;
+; parms = parameters of Gaussian, 2, 3 or 4 element array:
+; parms[0] = maximum value (factor) of Gaussian,
+; parms[1] = mean value (center) of Gaussian,
+; parms[2] = standard deviation (sigma) of Gaussian.
+; (if parms has only 2 elements then sigma taken from previous
+; call to gaussian(), which is stored in a common block).
+; parms[3] = optional, constant offset added to Gaussian.
+; OUTPUT:
+; y - Function returns array of Gaussian evaluated at xi. Values will
+; be floating pt. (even if xi is double) unless the /DOUBLE keyword
+; is set.
+;
+; OPTIONAL INPUT:
+; /DOUBLE - set this keyword to return double precision for both
+; the function values and (optionally) the partial derivatives.
+; OPTIONAL OUTPUT:
+; pderiv = [N,3] or [N,4] output array of partial derivatives,
+; computed only if parameter is present in call.
+;
+; pderiv[*,i] = partial derivative at all xi absisca values
+; with respect to parms[i], i=0,1,2,[3].
+;
+;
+; EXAMPLE:
+; Evaulate a Gaussian centered at x=0, with sigma=1, and a peak value
+; of 10 at the points 0.5 and 1.5. Also compute the derivative
+;
+; IDL> f = gaussian( [0.5,1.5], [10,0,1], DERIV )
+; ==> f= [8.825,3.25]. DERIV will be a 2 x 3 array containing the
+; numerical derivative at the two points with respect to the 3 parameters.
+;
+; COMMON BLOCKS:
+; None
+; HISTORY:
+; Written, Frank Varosi NASA/GSFC 1992.
+; Converted to IDL V5.0 W. Landsman September 1997
+; Use machar() for machine precision, added /DOUBLE keyword,
+; add optional constant 4th parameter W. Landsman November 2001
+;-
+ On_error,2
+ common gaussian, sigma
+
+ if N_params() LT 2 then begin
+ print,'Syntax - y = GAUSSIAN( xi, parms,[ pderiv, /DOUBLE ])'
+ print,' parms[0] = maximum value (factor) of Gaussian'
+ print,' parms[1] = mean value (center) of Gaussian'
+ print,' parms[2] = standard deviation (sigma) of Gaussian'
+ print,' parms[3] = optional constant to be added to Gaussian'
+ return, -1
+ endif
+
+ common gaussian, sigma
+
+ Nparmg = N_elements( parms )
+ npts = N_elements(xi)
+ ptype = size(parms,/type)
+ if (ptype LE 3) or (ptype GE 12) then parms = float(parms)
+ if (Nparmg GE 3) then sigma = parms[2]
+
+ double = keyword_set(DOUBLE)
+ if double then $ ;Double precision?
+ gauss = dblarr( npts ) else $
+ gauss = fltarr( npts )
+
+ z = ( xi - parms[1] )/sigma
+ zz = z*z
+
+; Get smallest value expressible on computer. Set lower values to 0 to avoid
+; floating underflow
+ minexp = alog((machar(DOUBLE=double)).xmin)
+
+ w = where( zz LT -2*minexp, nw )
+ if (nw GT 0) then gauss[w] = exp( -zz[w] / 2 )
+
+ if N_params() GE 3 then begin
+
+ if double then $
+ pderiv = dblarr( npts, Nparmg ) else $
+ pderiv = fltarr( npts, Nparmg )
+ fsig = parms[0] / sigma
+
+ pderiv[0,0] = gauss
+ pderiv[0,1] = gauss * z * fsig
+
+ if (Nparmg GE 3) then pderiv[0,2] = gauss * zz * fsig
+ if (Nparmg GE 4) then pderiv[0,3] = replicate(1, npts)
+ endif
+
+ if Nparmg LT 4 then return, parms[0] * gauss else $
+ return, parms[0] * gauss + parms[3]
+ end
diff --git a/Code/script_idl_mv/astrolib/gcirc.pro b/Code/script_idl_mv/astrolib/gcirc.pro
new file mode 100644
index 0000000000000000000000000000000000000000..06e0d717ef4b85b23102dc2c0a3fc7457d814eef
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/gcirc.pro
@@ -0,0 +1,123 @@
+PRO gcirc,u,ra1,dc1,ra2,dc2,dis
+;+
+; NAME:
+; GCIRC
+; PURPOSE:
+; Computes rigorous great circle arc distances.
+; EXPLANATION:
+; Input position can either be either radians, sexagesimal RA, Dec or
+; degrees. All computations are double precision.
+;
+; CALLING SEQUENCE:
+; GCIRC, U, RA1, DC1, RA2, DC2, DIS
+;
+; INPUTS:
+; U -- integer = 0,1, or 2: Describes units of inputs and output:
+; 0: everything radians
+; 1: RAx in decimal hours, DCx in decimal
+; degrees, DIS in arc seconds
+; 2: RAx and DCx in degrees, DIS in arc seconds
+; RA1 -- Right ascension or longitude of point 1
+; DC1 -- Declination or latitude of point 1
+; RA2 -- Right ascension or longitude of point 2
+; DC2 -- Declination or latitude of point 2
+;
+; OUTPUTS:
+; DIS -- Angular distance on the sky between points 1 and 2
+; See U above for units; double precision
+;
+; PROCEDURE:
+; "Haversine formula" see
+; http://en.wikipedia.org/wiki/Great-circle_distance
+;
+; NOTES:
+; (1) If RA1,DC1 are scalars, and RA2,DC2 are vectors, then DIS is a
+; vector giving the distance of each element of RA2,DC2 to RA1,DC1.
+; Similarly, if RA1,DC1 are vectors, and RA2, DC2 are scalars, then DIS
+; is a vector giving the distance of each element of RA1, DC1 to
+; RA2, DC2. If both RA1,DC1 and RA2,DC2 are vectors then DIS is a
+; vector giving the distance of each element of RA1,DC1 to the
+; corresponding element of RA2,DC2. If the input vectors are not the
+; same length, then excess elements of the longer ones will be ignored.
+;
+; (2) The function SPHDIST provides an alternate method of computing
+; a spherical distance.
+;
+; (3) The haversine formula can give rounding errors for antipodal
+; points.
+;
+; PROCEDURE CALLS:
+; None
+;
+; MODIFICATION HISTORY:
+; Written in Fortran by R. Hill -- SASC Technologies -- January 3, 1986
+; Translated from FORTRAN to IDL, RSH, STX, 2/6/87
+; Vector arguments allowed W. Landsman April 1989
+; Prints result if last argument not given. RSH, RSTX, 3 Apr. 1998
+; Remove ISARRAY(), V5.1 version W. Landsman August 2000
+; Added option U=2 W. Landsman October 2006
+; Use double precision for U=0 as advertised R. McMahon/W.L. April 2007
+; Use havesine formula, which has less roundoff error in the
+; milliarcsecond regime W.L. Mar 2009
+;-
+ compile_opt idl2
+ On_error,2 ;Return to caller
+
+ npar = N_params()
+ IF (npar ne 6) and (npar ne 5) THEN BEGIN
+ print,'Calling sequence: GCIRC,U,RA1,DC1,RA2,DC2[,DIS]'
+ print,' U = 0 ==> Everything in radians'
+ print, $
+ ' U = 1 ==> RAx decimal hours, DCx decimal degrees, DIS arc sec'
+ print,' U = 2 ==> RAx, DCx decimal degrees, DIS arc sec'
+ RETURN
+ ENDIF
+
+
+ d2r = !DPI/180.0d0
+ as2r = !DPI/648000.0d0
+ h2r = !DPI/12.0d0
+
+; Convert input to double precision radians
+ CASE u OF
+ 0: BEGIN
+ rarad1 = double(ra1)
+ rarad2 = double(ra2)
+ dcrad1 = double(dc1)
+ dcrad2 = double(dc2)
+ END
+ 1: BEGIN
+ rarad1 = ra1*h2r
+ rarad2 = ra2*h2r
+ dcrad1 = dc1*d2r
+ dcrad2 = dc2*d2r
+ END
+ 2: BEGIN
+ rarad1 = ra1*d2r
+ rarad2 = ra2*d2r
+ dcrad1 = dc1*d2r
+ dcrad2 = dc2*d2r
+ END
+ ELSE: MESSAGE, $
+ 'U must be 0 (radians), 1 ( hours, degrees) or 2 (degrees)'
+ ENDCASE
+
+ deldec2 = (dcrad2-dcrad1)/2.0d
+ delra2 = (rarad2-rarad1)/2.0d
+ sindis = sqrt( sin(deldec2)*sin(deldec2) + $
+ cos(dcrad1)*cos(dcrad2)*sin(delra2)*sin(delra2) )
+ dis = 2.0d*asin(sindis)
+
+ IF (u ne 0) THEN dis = dis/as2r
+
+ IF (npar eq 5) && (N_elements(dis) EQ 1) THEN BEGIN
+ IF (u ne 0) && (dis ge 0.1) && (dis le 1000) $
+ THEN fmt = '(F10.4)' $
+ ELSE fmt = '(E15.8)'
+ IF (u ne 0) THEN units = ' arcsec' ELSE units = ' radians'
+ print,'Angular separation is ' + string(dis,format=fmt) + units
+ ENDIF
+
+ RETURN
+ END
+
diff --git a/Code/script_idl_mv/astrolib/gcntrd.pro b/Code/script_idl_mv/astrolib/gcntrd.pro
new file mode 100644
index 0000000000000000000000000000000000000000..344d6ca7787bb2e2753242a8ce4bdce0de538696
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/gcntrd.pro
@@ -0,0 +1,326 @@
+pro gcntrd,img,x,y,xcen,ycen,fwhm, maxgood = maxgood, keepcenter=keepcenter, $
+ SILENT = silent, DEBUG = debug
+
+;+
+; NAME:
+; GCNTRD
+; PURPOSE:
+; Compute the stellar centroid by Gaussian fits to marginal X,Y, sums
+; EXPLANATION:
+; GCNTRD uses the DAOPHOT "FIND" centroid algorithm by fitting Gaussians
+; to the marginal X,Y distributions. User can specify bad pixels
+; (either by using the MAXGOOD keyword or setting them to NaN) to be
+; ignored in the fit. Pixel values are weighted toward the center to
+; avoid contamination by neighboring stars.
+;
+; CALLING SEQUENCE:
+; GCNTRD, img, x, y, xcen, ycen, [ fwhm , /SILENT, /DEBUG, MAXGOOD = ,
+; /KEEPCENTER ]
+;
+; INPUTS:
+; IMG - Two dimensional image array
+; X,Y - Scalar or vector integers giving approximate stellar center
+;
+; OPTIONAL INPUT:
+; FWHM - floating scalar; Centroid is computed using a box of half
+; width equal to 1.5 sigma = 0.637* FWHM. GCNTRD will prompt
+; for FWHM if not supplied
+;
+; OUTPUTS:
+; XCEN - the computed X centroid position, same number of points as X
+; YCEN - computed Y centroid position, same number of points as Y
+;
+; Values for XCEN and YCEN will not be computed if the computed
+; centroid falls outside of the box, or if there are too many bad pixels,
+; or if the best-fit Gaussian has a negative height. If the centroid
+; cannot be computed, then a message is displayed (unless /SILENT is
+; set) and XCEN and YCEN are set to -1.
+;
+; OPTIONAL OUTPUT KEYWORDS:
+; MAXGOOD= Only pixels with values less than MAXGOOD are used to in
+; Gaussian fits to determine the centroid. For non-integer
+; data, one can also flag bad pixels using NaN values.
+; /SILENT - Normally GCNTRD prints an error message if it is unable
+; to compute the centroid. Set /SILENT to suppress this.
+; /DEBUG - If this keyword is set, then GCNTRD will display the subarray
+; it is using to compute the centroid.
+; /KeepCenter By default, GCNTRD first convolves a small region around
+; the supplied position with a lowered Gaussian filter, and then
+; finds the maximum pixel in a box centered on the input X,Y
+; coordinates, and then extracts a new box about this maximum
+; pixel. Set the /KeepCenter keyword to skip the convolution
+; and finding the maximum pixel, and instead use a box
+; centered on the input X,Y coordinates.
+; PROCEDURE:
+; Unless /KEEPCENTER is set, a small area around the initial X,Y is
+; convolved with a Gaussian kernel, and the maximum pixel is found.
+; This pixel is used as the center of a square, within
+; which the centroid is computed as the Gaussian least-squares fit
+; to the marginal sums in the X and Y directions.
+;
+; EXAMPLE:
+; Find the centroid of a star in an image im, with approximate center
+; 631, 48. Assume that bad (saturated) pixels have a value of 4096 or
+; or higher, and that the approximate FWHM is 3 pixels.
+;
+; IDL> GCNTRD, IM, 631, 48, XCEN, YCEN, 3, MAXGOOD = 4096
+; MODIFICATION HISTORY:
+; Written June 2004, W. Landsman following algorithm used by P. Stetson
+; in DAOPHOT2.
+; Modified centroid computation (as in IRAF/DAOFIND) to allow shifts of
+; more than 1 pixel from initial guess. March 2008
+; First perform Gaussian convolution prior to finding maximum pixel
+; to smooth out noise W. Landsman Jan 2009
+;-
+ On_error,2
+ compile_opt idl2
+
+ if N_params() LT 5 then begin
+ print,'Syntax: GCNTRD, img, x, y, xcen, ycen, [ fwhm, '
+ print,' /KEEPCENTER, /SILENT, /DEBUG, MAXGOOD= ]'
+ PRINT,'img - Input image array'
+ PRINT,'x,y - Input scalar integers giving approximate X,Y position'
+ PRINT,'xcen,ycen - Output scalars giving centroided X,Y position'
+ return
+ endif else if N_elements(fwhm) NE 1 then $
+ read,'Enter approximate FWHM of image in pixels: ',fwhm
+
+
+ sz_image = size(img)
+ if sz_image[0] NE 2 then message, $
+ 'ERROR - Image array (first parameter) must be 2 dimensional'
+
+ xsize = sz_image[1]
+ ysize = sz_image[2]
+ dtype = sz_image[3]
+ npts = N_elements(x)
+ maxbox = 13
+ radius = 0.637*FWHM > 2.001 ;Radius is 1.5 sigma
+ radsq = radius^2
+ sigsq = ( fwhm/2.35482 )^2
+ nhalf = fix(radius) < (maxbox-1)/2 ;
+ nbox = 2*nhalf +1 ;# of pixels in side of convolution box
+
+ xcen = x*0. - 1 & ycen = y*0 - 1.
+ ix = round(x) ;Central X pixel
+ iy = round(y) ;Central Y pixel
+
+;Create the Gaussian convolution kernel in variable "g"
+ mask = bytarr( nbox, nbox ) ;Mask identifies valid pixels in convolution box
+ g = fltarr( nbox, nbox )
+ row2 = (findgen(Nbox)-nhalf)^2
+ g[0,nhalf] = row2
+ for i = 1, nhalf do begin
+ temp = row2 + i^2
+ g[0,nhalf-i] = temp
+ g[0,nhalf+i] = temp
+ endfor
+ mask = fix(g LE radsq)
+ good = where( mask, pixels) ;Value of c are now equal to distance to center
+ g = exp(-0.5*g/sigsq) ;Make g into a Gaussian kernel
+
+; In fitting Gaussians to the marginal sums, pixels will arbitrarily be
+; assigned weights ranging from unity at the corners of the box to
+; NHALF^2 at the center (e.g. if NBOX = 5 or 7, the weights will be
+;
+; 1 2 3 4 3 2 1
+; 1 2 3 2 1 2 4 6 8 6 4 2
+; 2 4 6 4 2 3 6 9 12 9 6 3
+; 3 6 9 6 3 4 8 12 16 12 8 4
+; 2 4 6 4 2 3 6 9 12 9 6 3
+; 1 2 3 2 1 2 4 6 8 6 4 2
+; 1 2 3 4 3 2 1
+;
+; respectively). This is done to desensitize the derived parameters to
+; possible neighboring, brighter stars.
+
+
+ x_wt = fltarr(nbox,nbox)
+ wt = nhalf - abs(findgen(nbox)-nhalf ) + 1
+ for i=0,nbox-1 do x_wt[0,i] = wt
+ y_wt = transpose(x_wt)
+ pos = strtrim(x,2) + ' ' + strtrim(y,2)
+
+if ~keyword_set(Keepcenter) then begin
+; Precompute convolution kernel
+ c = g*mask ;Convolution kernel now in c
+ sumc = total(c)
+ sumcsq = total(c^2) - sumc^2/pixels
+ sumc = sumc/pixels
+ c[good] = (c[good] - sumc)/sumcsq
+endif
+
+ for i = 0,npts-1 do begin ;Loop over number of points to centroid
+
+ if ~keyword_set(keepcenter) then begin
+ if ( (ix[i] LT nhalf) || ((ix[i] + nhalf) GT xsize-1) || $
+ (iy[i] LT nhalf) || ((iy[i] + nhalf) GT ysize-1) ) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' too near edge of image'
+ goto, DONE
+ endif
+ x1 = (ix[i]-nbox) > 0
+ x2 = (ix[i] + nbox) < (xsize-1)
+ y1 = (iy[i]-nbox) > 0
+ y2 = (iy[i] + nbox) < (ysize-1)
+ h = img[x1:x2, y1:y2]
+ h = convol(float(h), c)
+ h= h[ nbox-nhalf: nbox + nhalf, nbox -nhalf: nbox + nhalf]
+ d= img[ix[i]-nhalf: ix[i]+nhalf, iy[i]-nhalf:iy[i]+nhalf]
+
+ if N_elements(maxgood) GT 0 then begin
+ ig = where(d lt maxgood, Ng)
+ mx = max(d[ig],/nan)
+ endif
+ mx = max( h,/nan) ;Maximum pixel value in BIGBOX
+
+ mx_pos = where(h EQ mx, Nmax) ;How many pixels have maximum value?
+ idx = mx_pos mod nbox ;X coordinate of Max pixel
+ idy = mx_pos / nbox ;Y coordinate of Max pixel
+ if NMax GT 1 then begin ;More than 1 pixel at maximum?
+ idx = round(total(idx)/Nmax)
+ idy = round(total(idy)/Nmax)
+ endif else begin
+ idx = idx[0]
+ idy = idy[0]
+ endelse
+ xmax = ix[i] - (nhalf) + idx ;X coordinate in original image array
+ ymax = iy[i] - (nhalf) + idy ;Y coordinate in original image array
+ endif else begin
+ xmax = ix[i]
+ ymax = iy[i]
+ endelse
+
+; ---------------------------------------------------------------------
+; check *new* center location for range
+; added by Hogg
+
+ if ( (xmax LT nhalf) || ((xmax + nhalf) GT xsize-1) || $
+ (ymax LT nhalf) || ((ymax + nhalf) GT ysize-1) ) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' moved too near edge of image'
+ xcen[i] = -1 & ycen[i] = -1
+ goto, DONE
+ endif
+; ---------------------------------------------------------------------
+
+; Extract subimage centered on maximum pixel
+
+ d = img[xmax-nhalf : xmax+nhalf, ymax-nhalf : ymax+nhalf]
+
+
+ if keyword_set(DEBUG) then begin
+ message,'Subarray used to compute centroid:',/inf
+ imlist,img,xmax,ymax,dx = nbox,dy=nbox
+ endif
+
+ if N_elements(maxgood) GT 0 then $
+ mask = (d lt maxgood) else $
+ if (dtype eq 4) || (dtype EQ 5) then mask = finite(d) else $
+ mask = replicate(1b, nbox, nbox)
+ maskx = total(mask,2) GT 0
+ masky = total(mask,1) GT 0
+
+; At least 3 points are needed in the partial sum to compute the Gaussian
+
+ if (total(maskx) LT 3) || (total(masky) LT 3) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' has insufficient good points'
+ goto, DONE
+ endif
+
+ ywt = y_wt*mask
+ xwt = x_wt*mask
+ wt1 = wt*maskx
+ wt2 = wt*masky
+
+; Centroid computation: The centroid computation was modified in Mar 2008 and
+; now differs from DAOPHOT which multiplies the correction dx by 1/(1+abs(dx)).
+; The DAOPHOT method is more robust (e.g. two different sources will not merge)
+; especially in a package where the centroid will be subsequently be
+; redetermined using PSF fitting. However, it is less accurate, and introduces
+; biases in the centroid histogram. The change here is the same made in the
+; IRAF DAOFIND routine (see
+; http://iraf.net/article.php?story=7211&query=daofind )
+
+ sd = total(d*ywt,2,/nan)
+ sg = total(g*ywt,2)
+ sumg = total(wt1*sg)
+ sumgsq = total(wt1*sg*sg)
+
+ sumgd = total(wt1*sg*sd)
+ sumgx = total(wt1*sg)
+ sumd = total(wt1*sd)
+ p = total(wt1)
+ xvec = nhalf - findgen(nbox)
+ dgdx = sg*xvec
+ sdgdxs = total(wt1*dgdx^2)
+ sdgdx = total(wt1*dgdx)
+ sddgdx = total(wt1*sd*dgdx)
+ sgdgdx = total(wt1*sg*dgdx)
+
+ hx = (sumgd - sumg*sumd/p) / (sumgsq - sumg^2/p)
+
+; HX is the height of the best-fitting marginal Gaussian. If this is not
+; positive then the centroid does not make sense
+
+ if (hx LE 0) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' cannot be fit by a Gaussian'
+ xcen[i] = -1 & ycen[i] = -1
+ goto, DONE
+ endif
+
+ skylvl = (sumd - hx*sumg)/p
+ dx = (sgdgdx - (sddgdx-sdgdx*(hx*sumg + skylvl*p)))/(hx*sdgdxs/sigsq)
+ if (abs(dx) GE nhalf) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' is too far from initial guess'
+ goto, DONE
+ endif
+
+
+
+ xcen[i] = xmax + dx ;X centroid in original array
+
+
+;Now repeat computation for Y centroid
+
+ sd = total(d*xwt,1,/nan)
+ sg = total(g*xwt,1)
+ sumg = total(wt2*sg)
+ sumgsq = total(wt2*sg*sg)
+
+ sumgd = total(wt2*sg*sd)
+ sumd = total(wt2*sd)
+ p = total(wt2)
+
+ yvec = nhalf - findgen(nbox)
+ dgdy = sg*yvec
+ sdgdys = total(wt2*dgdy^2)
+ sdgdy = total(wt2*dgdy)
+ sddgdy = total(wt2*sd*dgdy)
+ sgdgdy = total(wt2*sg*dgdy)
+
+ hy = (sumgd - sumg*sumd/p) / (sumgsq - sumg^2/p)
+
+ if (hy LE 0) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' cannot be fit by a Gaussian'
+ goto, DONE
+ endif
+
+ skylvl = (sumd - hy*sumg)/p
+ dy = (sgdgdy - (sddgdy-sdgdy*(hy*sumg + skylvl*p)))/(hy*sdgdys/sigsq)
+ if (abs(dy) GE nhalf) then begin
+ if ~keyword_set(SILENT) then message,/INF, $
+ 'Position '+ pos[i] + ' is too far from initial guess'
+ goto, DONE
+ endif
+ ycen[i] = ymax + dy ;Y centroid in original array
+DONE:
+
+ endfor
+
+return
+end
diff --git a/Code/script_idl_mv/astrolib/geo2eci.pro b/Code/script_idl_mv/astrolib/geo2eci.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d11208c674e569b362e5eb7ec76ef80c4de626ed
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/geo2eci.pro
@@ -0,0 +1,79 @@
+;+
+; NAME:
+; GEO2ECI
+;
+; PURPOSE:
+; Convert geographic spherical coordinates to Earth-centered inertial coords
+;
+; EXPLANATION:
+; Converts from geographic spherical coordinates [latitude, longitude,
+; altitude] to ECI (Earth-Centered Inertial) [X,Y,Z] rectangular
+; coordinates. JD time is also needed.
+;
+; Geographic coordinates are in degrees/degrees/km
+; Geographic coordinates assume the Earth is a perfect sphere, with radius
+; equal to its equatorial radius.
+; ECI coordinates are in km from Earth center at epoch TOD (True of Date)
+;
+; CALLING SEQUENCE:
+; ECIcoord=geo2eci(gcoord,JDtime)
+;
+; INPUT:
+; gcoord: geographic [latitude,longitude,altitude], or a an array [3,n]
+; of n such coordinates
+; JDtime: Julian Day time, double precision. Can be a 1-D array of n
+; such times.
+;
+; KEYWORD INPUTS:
+; None
+;
+; OUTPUT:
+; a 3-element array of ECI [X,Y,Z] coordinates, or an array [3,n] of
+; n such coordinates, double precision. The TOD epoch is the
+; supplied JDtime.
+;
+; COMMON BLOCKS:
+; None
+;
+; PROCEDURES USED:
+; CT2LST - Convert Local Civil Time to Local Mean Sidereal Time
+;
+; EXAMPLES:
+;
+; IDL> ECIcoord=geo2eci([0,0,0], 2452343.38982663D)
+; IDL> print,ECIcoord
+; -3902.9606 5044.5548 0.0000000
+;
+; (The above is the ECI coordinates of the intersection of the equator and
+; Greenwich's meridian on 2002/03/09 21:21:21.021)
+;
+; MODIFICATION HISTORY:
+; Written by Pascal Saint-Hilaire (shilaire@astro.phys.ethz.ch)
+; on 2002/05/14
+; Update documentation to specify epoch is TOD.
+; R. Redmon NOAA/NGDC April 2014
+;
+;-
+
+;====================================================================================
+FUNCTION geo2eci,incoord,JDtim
+
+ Re=6378.137 ; Earth's equatorial radius, in km
+
+ lat = DOUBLE(incoord[0,*])*!DPI/180.
+ lon = DOUBLE(incoord[1,*])*!DPI/180.
+ alt = DOUBLE(incoord[2,*])
+ JDtime= DOUBLE(JDtim)
+
+ ct2lst,gst,0,0,JDtime
+ angle_sid=gst*2.*!DPI/24. ; sidereal angle
+
+ theta=lon+angle_sid ; azimuth
+ r=(alt+Re)*cos(lat)
+ X=r*cos(theta)
+ Y=r*sin(theta)
+ Z=(alt+Re)*sin(lat)
+
+ RETURN,[X,Y,Z]
+END
+;====================================================================================
diff --git a/Code/script_idl_mv/astrolib/geo2geodetic.pro b/Code/script_idl_mv/astrolib/geo2geodetic.pro
new file mode 100644
index 0000000000000000000000000000000000000000..225384ab7b0a10b2d5d09810ce0e8a3c97079642
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/geo2geodetic.pro
@@ -0,0 +1,153 @@
+;+
+; NAME:
+; GEO2GEODETIC
+;
+; PURPOSE:
+; Convert from geographic/planetographic to geodetic coordinates
+; EXPLANATION:
+; Converts from geographic (latitude, longitude, altitude) to geodetic
+; (latitude, longitude, altitude). In geographic coordinates, the
+; Earth is assumed a perfect sphere with a radius equal to its equatorial
+; radius. The geodetic (or ellipsoidal) coordinate system takes into
+; account the Earth's oblateness.
+;
+; Geographic and geodetic longitudes are identical.
+; Geodetic latitude is the angle between local zenith and the equatorial plane.
+; Geographic and geodetic altitudes are both the closest distance between
+; the satellite and the ground.
+;
+; The PLANET keyword allows a similar transformation for the other
+; planets (planetographic to planetodetic coordinates).
+;
+; The EQUATORIAL_RADIUS and POLAR_RADIUS keywords allow the
+; transformation for any ellipsoid.
+;
+; Latitudes and longitudes are expressed in degrees, altitudes in km.
+;
+; REF: Stephen P. Keeler and Yves Nievergelt, "Computing geodetic
+; coordinates", SIAM Rev. Vol. 40, No. 2, pp. 300-309, June 1998
+;
+; Planetary constants from "Allen's Astrophysical Quantities",
+; Fourth Ed., (2000)
+;
+; CALLING SEQUENCE:
+; ecoord=geo2geodetic(gcoord,[ PLANET=,EQUATORIAL_RADIUS=, POLAR_RADIUS=])
+;
+; INPUT:
+; gcoord = a 3-element array of geographic [latitude,longitude,altitude],
+; or an array [3,n] of n such coordinates.
+;
+;
+; OPTIONAL KEYWORD INPUT:
+; PLANET = keyword specifying planet (default is Earth). The planet
+; may be specified either as an integer (1-9) or as one of the
+; (case-independent) strings 'mercury','venus','earth','mars',
+; 'jupiter','saturn','uranus','neptune', or 'pluto'
+;
+; EQUATORIAL_RADIUS : Self-explanatory. In km. If not set, PLANET's
+; value is used.
+; POLAR_RADIUS : Self-explanatory. In km. If not set, PLANET's value is
+; used.
+;
+; OUTPUT:
+; a 3-element array of geodetic/planetodetic [latitude,longitude,altitude],
+; or an array [3,n] of n such coordinates, double precision.
+;
+; COMMON BLOCKS:
+; None
+;
+; RESTRICTIONS:
+;
+; Whereas the conversion from geodetic to geographic coordinates is given
+; by an exact, analytical formula, the conversion from geographic to
+; geodetic isn't. Approximative iterations (as used here) exist, but tend
+; to become less good with increasing eccentricity and altitude.
+; The formula used in this routine should give correct results within
+; six digits for all spatial locations, for an ellipsoid (planet) with
+; an eccentricity similar to or less than Earth's.
+; More accurate results can be obtained via calculus, needing a
+; non-determined amount of iterations.
+; In any case,
+; IDL> PRINT,geodetic2geo(geo2geodetic(gcoord)) - gcoord
+; is a pretty good way to evaluate the accuracy of geo2geodetic.pro.
+;
+; EXAMPLES:
+;
+; Locate the geographic North pole, altitude 0., in geodetic coordinates
+; IDL> geo=[90.d0,0.d0,0.d0]
+; IDL> geod=geo2geodetic(geo); convert to equivalent geodetic coordinates
+; IDL> PRINT,geod
+; 90.000000 0.0000000 21.385000
+;
+; As above, but for the case of Mars
+; IDL> geod=geo2geodetic(geo,PLANET='Mars')
+; IDL> PRINT,geod
+; 90.000000 0.0000000 18.235500
+;
+; MODIFICATION HISTORY:
+; Written by Pascal Saint-Hilaire (shilaire@astro.phys.ethz.ch), May 2002
+; Generalized for all solar system planets by Robert L. Marcialis
+; (umpire@lpl.arizona.edu), May 2002
+; Modified 2002/05/18, PSH: added keywords EQUATORIAL_RADIUS and
+; POLAR_RADIUS
+;-
+
+;================================================================================
+FUNCTION geo2geodetic,gcoord,PLANET=planet, $
+ EQUATORIAL_RADIUS=equatorial_radius, POLAR_RADIUS=polar_radius
+
+ sz_gcoord = size(gcoord,/DIMEN)
+ if sz_gcoord[0] LT 3 then message, $
+ 'ERROR - 3 coordinates (latitude,longitude,altitude) must be specified'
+
+ if N_elements(PLANET) GT 0 then begin
+ if size(planet,/tname) EQ 'STRING' then begin
+ choose_planet=['mercury','venus','earth','mars','jupiter','saturn', $
+ 'uranus','neptune','pluto']
+ index=where(choose_planet eq strlowcase(planet))
+ index=index[0] ; make it a scalar
+ if index eq -1 then index = 2 ; default is Earth
+ endif else index = planet-1
+ endif else index=2
+
+ Requator = [2439.7d0,6051.8d0,6378.137D, 3397.62d0, 71492d0, $
+ 60268.d0, 25559.d0, 24764.d0, 1195.d0]
+ Rpole = [2439.7d0, 6051.8d0, 6356.752d0, 3379.3845d0, 67136.5562d0, $
+ 54890.7686d0, 24986.1354d0, 24347.6551d0, 1195.d0]
+ Re = Requator[index] ; equatorial radius
+ Rp = Rpole[index] ; polar radius
+
+ IF KEYWORD_SET(EQUATORIAL_RADIUS) THEN Re=DOUBLE(equatorial_radius[0])
+ IF KEYWORD_SET(POLAR_RADIUS) THEN Rp=DOUBLE(polar_radius[0])
+
+ e = sqrt(Re^2 - Rp^2)/Re
+ ;f=1/298.257D ; flattening = (Re-Rp)/Re [not needed, here]
+
+ glat=DOUBLE(gcoord[0,*])*!DPI/180.
+ glon=DOUBLE(gcoord[1,*])
+ galt=DOUBLE(gcoord[2,*])
+
+ x= (Re+galt) * cos(glat) * cos(glon)
+ y= (Re+galt) * cos(glat) * sin(glon)
+ z= (Re+galt) * sin(glat)
+ r=sqrt(x^2+y^2)
+
+ s=(r^2 + z ^2)^0.5 * (1 - Re*((1-e^2)/((1-e^2)*r^2 + z^2))^0.5)
+ t0=1+s*(1- (e*z)^2/(r^2 + z^2) )^0.5 /Re
+ dzeta1=z * t0
+ xi1=r*(t0 - e^2)
+ rho1= (xi1^2 + dzeta1^2)^0.5
+ c1=xi1/rho1
+ s1=dzeta1/rho1
+ b1=Re/(1- (e*s1)^2)^0.5
+ u1= b1*c1
+ w1= b1*s1*(1- e^2)
+ ealt= ((r - u1)^2 + (z - w1)^2)^0.5
+ elat= atan(s1,c1)
+
+ elat=elat*180./!DPI
+ elon=glon
+
+ RETURN,[elat,elon,ealt]
+END
+;===============================================================================
diff --git a/Code/script_idl_mv/astrolib/geo2mag.pro b/Code/script_idl_mv/astrolib/geo2mag.pro
new file mode 100644
index 0000000000000000000000000000000000000000..21f878675bbb4902a5c3fadd1ba63c16af50a842
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/geo2mag.pro
@@ -0,0 +1,103 @@
+;+
+; NAME:
+; GEO2MAG()
+;
+; PURPOSE:
+; Convert from geographic to geomagnetic coordinates
+; EXPLANATION:
+; Converts from GEOGRAPHIC (latitude,longitude) to GEOMAGNETIC (latitude,
+; longitude). (Altitude remains the same)
+;
+; Latitudes and longitudes are expressed in degrees.
+;
+; CALLING SEQUENCE:
+; mcoord=geo2mag(gcoord)
+;
+; INPUT:
+; gcoord = a 2-element array of geographic [latitude,longitude], or an
+; array [2,n] of n such coordinates.
+;
+; KEYWORD INPUTS:
+; None
+;
+; OUTPUT:
+; a 2-element array of magnetic [latitude,longitude], or an array [2,n]
+; of n such coordinates
+;
+; COMMON BLOCKS:
+; None
+;
+; EXAMPLES:
+; geographic coordinates of magnetic south pole
+;
+; IDL> mcoord=geo2mag([79.3,288.59])
+; IDL> print,mcoord
+; 89.999992 -173.02325
+;
+; MODIFICATION HISTORY:
+; Written by Pascal Saint-Hilaire (Saint-Hilaire@astro.phys.ethz.ch),
+; May 2002
+;
+;-
+
+;====================================================================================
+FUNCTION geo2mag,incoord
+
+ ; SOME 'constants'...
+ Dlong=288.59D ; longitude (in degrees) of Earth's magnetic south pole
+ ;(which is near the geographic north pole!) (1995)
+ Dlat=79.30D ; latitude (in degrees) of same (1995)
+ R = 1D ; distance from planet center (value unimportant --
+ ;just need a length for conversion to rectangular coordinates)
+
+ ; convert first to radians
+ Dlong=Dlong*!DPI/180.
+ Dlat=Dlat*!DPI/180.
+
+ glat=DOUBLE(incoord[0,*])*!DPI/180.
+ glon=DOUBLE(incoord[1,*])*!DPI/180.
+ galt=glat * 0. + R
+
+ coord=[glat,glon,galt]
+
+ ;convert to rectangular coordinates
+ ; X-axis: defined by the vector going from Earth's center towards
+ ; the intersection of the equator and Greenwitch's meridian.
+ ; Z-axis: axis of the geographic poles
+ ; Y-axis: defined by Y=Z^X
+ x=coord[2,*]*cos(coord[0,*])*cos(coord[1,*])
+ y=coord[2,*]*cos(coord[0,*])*sin(coord[1,*])
+ z=coord[2,*]*sin(coord[0,*])
+
+ ;Compute 1st rotation matrix : rotation around plane of the equator,
+ ;from the Greenwich meridian to the meridian containing the magnetic
+ ;dipole pole.
+ geolong2maglong=dblarr(3,3)
+ geolong2maglong[0,0]=cos(Dlong)
+ geolong2maglong[0,1]=sin(Dlong)
+ geolong2maglong[1,0]=-sin(Dlong)
+ geolong2maglong[1,1]=cos(Dlong)
+ geolong2maglong[2,2]=1.
+ out=geolong2maglong # [x,y,z]
+
+ ;Second rotation : in the plane of the current meridian from geographic
+ ; pole to magnetic dipole pole.
+ tomaglat=dblarr(3,3)
+ tomaglat[0,0]=cos(!DPI/2-Dlat)
+ tomaglat[0,2]=-sin(!DPI/2-Dlat)
+ tomaglat[2,0]=sin(!DPI/2-Dlat)
+ tomaglat[2,2]=cos(!DPI/2-Dlat)
+ tomaglat[1,1]=1.
+ out= tomaglat # out
+
+ ;convert back to latitude, longitude and altitude
+ mlat=atan(out[2,*],sqrt(out[0,*]^2+out[1,*]^2))
+ mlat=mlat*180./!DPI
+ mlon=atan(out[1,*],out[0,*])
+ mlon=mlon*180./!DPI
+ ;malt=sqrt(out[0,*]^2+out[1,*]^2+out[2,*]^2)-R
+; I don't care about that one...just put it there for completeness' sake
+
+ RETURN,[mlat,mlon]
+END
+;===============================================================================
diff --git a/Code/script_idl_mv/astrolib/geodetic2geo.pro b/Code/script_idl_mv/astrolib/geodetic2geo.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0615516b34a6c711dcf80bd3efa7cd30524d6283
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/geodetic2geo.pro
@@ -0,0 +1,125 @@
+;+
+; NAME:
+; GEODETIC2GEO
+;
+; PURPOSE:
+; Convert from geodetic (or planetodetic) to geographic coordinates
+; EXPLANATION:
+; Converts from geodetic (latitude, longitude, altitude) to geographic
+; (latitude, longitude, altitude). In geographic coordinates, the
+; Earth is assumed a perfect sphere with a radius equal to its equatorial
+; radius. The geodetic (or ellipsoidal) coordinate system takes into
+; account the Earth's oblateness.
+;
+; Geographic and geodetic longitudes are identical.
+; Geodetic latitude is the angle between local zenith and the equatorial
+; plane. Geographic and geodetic altitudes are both the closest distance
+; between the satellite and the ground.
+;
+; The PLANET keyword allows a similar transformation for the other
+; planets (planetodetic to planetographic coordinates).
+;
+; The EQUATORIAL_RADIUS and POLAR_RADIUS keywords allow the
+; transformation for any ellipsoid.
+;
+; Latitudes and longitudes are expressed in degrees, altitudes in km.
+;
+; REF: Stephen P. Keeler and Yves Nievergelt, "Computing geodetic
+; coordinates", SIAM Rev. Vol. 40, No. 2, pp. 300-309, June 1998
+; Planetary constants from "Allen's Astrophysical Quantities",
+; Fourth Ed., (2000)
+;
+; CALLING SEQUENCE:
+; gcoord = geodetic2geo(ecoord, [ PLANET= ] )
+;
+; INPUT:
+; ecoord = a 3-element array of geodetic [latitude,longitude,altitude],
+; or an array [3,n] of n such coordinates.
+;
+; OPTIONAL KEYWORD INPUT:
+; PLANET = keyword specifying planet (default is Earth). The planet
+; may be specified either as an integer (1-9) or as one of the
+; (case-independent) strings 'mercury','venus','earth','mars',
+; 'jupiter','saturn','uranus','neptune', or 'pluto'
+;
+; EQUATORIAL_RADIUS : Self-explanatory. In km. If not set, PLANET's value
+; is used. Numeric scalar
+; POLAR_RADIUS : Self-explanatory. In km. If not set, PLANET's value is
+; used. Numeric scalar
+;
+; OUTPUT:
+; a 3-element array of geographic [latitude,longitude,altitude], or an
+; array [3,n] of n such coordinates, double precision
+;
+; The geographic and geodetic longitudes will be identical.
+; COMMON BLOCKS:
+; None
+;
+; EXAMPLES:
+;
+; IDL> geod=[90,0,0] ; North pole, altitude 0., in geodetic coordinates
+; IDL> geo=geodetic2geo(geod)
+; IDL> PRINT,geo
+; 90.000000 0.0000000 -21.385000
+;
+; As above, but the equivalent planetographic coordinates for Mars
+; IDL> geod=geodetic2geo(geod,PLANET='Mars');
+; IDL> PRINT,geod
+; 90.000000 0.0000000 -18.235500
+;
+; MODIFICATION HISTORY:
+; Written by Pascal Saint-Hilaire (shilaire@astro.phys.ethz.ch),
+; May 2002
+;
+; Generalized for all solar system planets by Robert L. Marcialis
+; (umpire@lpl.arizona.edu), May 2002
+;
+; Modified 2002/05/18, PSH: added keywords EQUATORIAL_RADIUS and
+; POLAR_RADIUS
+;
+;-
+;===================================================================================
+FUNCTION geodetic2geo,ecoord,PLANET=planet, $
+ EQUATORIAL_RADIUS=equatorial_radius, POLAR_RADIUS=polar_radius
+
+ sz_ecoord = size(ecoord,/DIMEN)
+ if sz_ecoord[0] LT 3 then message, $
+ 'ERROR - 3 coordinates (latitude,longitude,altitude) must be specified'
+
+ if N_elements(PLANET) GT 0 then begin
+ if size(planet,/tname) EQ 'STRING' then begin
+ choose_planet=['mercury','venus','earth','mars','jupiter','saturn', $
+ 'uranus','neptune','pluto']
+ index=where(choose_planet eq strlowcase(planet))
+ index=index[0] ; make it a scalar
+ if index eq -1 then index = 2 ; default is Earth
+ endif else index = planet-1
+ endif else index=2
+
+ Requator = [2439.7d0,6051.8d0,6378.137D, 3397.62d0, 71492d0, $
+ 60268.d0, 25559.d0, 24764.d0, 1195.d0]
+ Rpole = [2439.7d0, 6051.8d0, 6356.752d0, 3379.3845d0, 67136.5562d0, $
+ 54890.7686d0, 24986.1354d0, 24347.6551d0, 1195.d0]
+ ;f=1/298.257D ; flattening = (Re-Rp)/Re
+ Re = Requator(index) ; equatorial radius
+ Rp = Rpole(index) ; polar radius
+
+ IF KEYWORD_SET(EQUATORIAL_RADIUS) THEN Re=DOUBLE(equatorial_radius[0])
+ IF KEYWORD_SET(POLAR_RADIUS) THEN Rp=DOUBLE(polar_radius[0])
+
+ e = sqrt(Re^2 - Rp^2)/Re
+ elat = DOUBLE(ecoord[0,*])*!DPI/180.
+ elon = DOUBLE(ecoord[1,*])
+ ealt = DOUBLE(ecoord[2,*])
+
+ beta=sqrt(1-(e*sin(elat))^2)
+ r=(Re/beta + ealt)*cos(elat)
+ z=(Re*(1-e^2)/beta + ealt)*sin(elat)
+
+ glat=atan(z,r)*180./!DPI
+ glon=elon
+ galt=sqrt(r^2+z^2) - Re
+
+ RETURN,[glat,glon,galt]
+END
+;===================================================================================
diff --git a/Code/script_idl_mv/astrolib/get_coords.pro b/Code/script_idl_mv/astrolib/get_coords.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0e3427c97b020bc56b0538adc289ab659bf5a901
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/get_coords.pro
@@ -0,0 +1,165 @@
+pro GET_COORDS, Coords, PromptString, NumVals, InString=InString, Quiet=Quiet
+;*******************************************************************************
+;+
+; NAME:
+; GET_COORDS
+;
+; PURPOSE:
+; Converts a string with angular coordinates to floating point values.
+; EXPLANATION:
+; Although called by ASTRO.PRO, this is a general purpose routine.
+; The user may input as floating point or sexagesimal. If user inputs
+; calling procedure's job to convert hours to degrees if needed.
+; Since the input string is parsed character-by-character, ANY character
+; that is not a digit, minus sign or decimal point may be used as a
+; delimiter, i.e. acceptable examples of user input are:
+;
+; 1:03:55 -10:15:31
+; 1 3 55.0 -10 15 31
+; 1*3 55 -10abcd15efghij31
+; 1.065278 hello -10.25861
+;
+; CALLING SEQUENCE:
+; GET_COORDS, Coords, [ PromptString, NumVals, INSTRING =, /QUIET ]
+;
+; OPTIONAL INPUT:
+; PromptString - A string to inform the user what data are to be entered
+;
+; OPTIONAL KEYWORD INPUT:
+; InString - a keyword that, if set, is assumed to already contain the
+; input data string to be parsed. If this keyword is set, then
+; the user is not prompted for any input.
+; /Quiet - if set the program won't printout any error messages, but bad
+; input is still flagged by Coords=[-999,-999].
+;
+; OUTPUT:
+; Coords - a 2 element floating array containing the coordinates. The
+; vector [-999,-999] is returned if there has been an error.
+;
+; OPTIONAL OUTPUT:
+; NumVals - the number of separate values entered by the user: 2 if the
+; user entered the coordinates as floating point numbers, 6 if
+; the user entered the coordinates as sexagesimal numbers. Some
+; calling procedures might find this information useful (e.g., to
+; to print some output in the same format as the user's input).
+;
+; REVISION HISTORY:
+; Written by Joel Parker, 5 MAR 90
+; Included InString and Quiet keywords. Cleaned up some of the code and
+; comments. JWmP, 16 Jun 94
+;
+;*******************************************************************************
+; Converted to IDL V5.0 W. Landsman September 1997
+;-
+
+On_error,2
+
+if (N_params() eq 0) then begin
+ print,'Syntax - ' + $
+ 'GET_COORDS, Coords, [PromptString, NumVals, INSTRING=, /QUIET]'
+ return
+endif
+
+;
+; Define some parameters and variables.
+;
+if (N_Params() lt 2) then PromptString = " Please input the coordinates"
+Bell = string(7B)
+Minus = 45 ; ascii of "-"
+Decimal = 46 ; ascii of "."
+Zero = 48 ; ascii of "0"
+Nine = 57 ; ascii of "9"
+ValArr = dblarr(6)
+SignArr = intarr(6) + 1
+NumVals = 0
+StartPos = -1
+
+;
+; If the InString keyword is not set, then prompt the user for input. If
+; nothing is entered, return [-999,-999] as a warning flag to the calling
+; procedure.
+;
+if keyword_set(InString) then begin
+ Coords = InString
+endif else begin
+ Coords = ""
+ print,form = "(1X,A,$)", + PromptString + " {RETURN to exit} "
+ read, Coords
+endelse
+
+Coords = strtrim(Coords) + " " ; The final space is needed for parsing purposes
+if (Coords eq " ") then begin
+ Coords = [-999,-999]
+ return
+endif
+
+;
+; All's well. Get the byte values for the characters in the input string.
+;
+BCoords = byte(Coords)
+
+;
+; Begin the loop that parses the input string.
+; Start by loading the byte value of the next character into the BC variable.
+; Check to see if the character is a minus sign (if so, set the flag in the
+; SignArr array to -1). Check to see if the character is a numeral between 0-9
+; or a decimal (if so, then the NumFlag is set to 1).
+;
+for N = 0,(strlen(Coords)-1) do begin
+ BC = BCoords[N]
+ if (BC eq Minus) then SignArr[NumVals] = -1
+ NumFlag = ((BC ge Zero) and (BC le Nine)) or (BC eq Decimal)
+
+;
+; If the number flag is set, but StartPos = -1, then we are starting a new
+; value. Load the character's position in StartPos.
+;
+ if (NumFlag and (StartPos eq -1)) then StartPos = N
+
+;
+; If the number flag is NOT set, but StartPos > -1, then we have just
+; finished reading a number. Read the number from StartPos to the current
+; position, and reset StartPos to -1.
+; Put the resulting number in the ValArr.
+;
+ if (~(NumFlag) && (StartPos gt -1)) then begin
+ if (NumVals lt 6) then begin
+ ValArr[NumVals] = float(strmid(Coords, StartPos, (N - StartPos)))
+ endif
+ StartPos = -1
+ NumVals = NumVals + 1
+ endif
+endfor
+
+;
+; Coords should be a 2 or 6 element vector {depending on the type of input}.
+; It is converted to a 2 element vector such that Coords = [RA/Long, Dec/Lat].
+;
+case NumVals of
+
+ 2 : Coords = (ValArr * SignArr)[0:1]
+
+ 6 : begin
+ Temp = where(SignArr[0:2] eq -1)
+ if (Temp[0] eq -1) then XSign = 1 else XSign = -1
+ Temp = where(SignArr[3:5] eq -1)
+ if (Temp[0] eq -1) then YSign = 1 else YSign = -1
+ X = (ValArr[0] + (ValArr[1] / 60.) + (ValArr[2] / 3600.)) * XSign
+ Y = (ValArr[3] + (ValArr[4] / 60.) + (ValArr[5] / 3600.)) * YSign
+ Coords = [X,Y]
+ end
+
+ else : begin
+ Coords = [-999,-999]
+ if ~keyword_set(Quiet) then begin
+ print, Bell
+ print, "ERROR - Invalid Input!"
+ print, "Coordinates must be input as 2 or 6 values."
+ print, "For example: 1.568 -10.343 or 1 34 4.8 10 20 34.8"
+ endif
+ endelse
+
+endcase
+
+return
+end ; procedure GET_COORDS by Joel Parker 16 Jun 94
diff --git a/Code/script_idl_mv/astrolib/get_date.pro b/Code/script_idl_mv/astrolib/get_date.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d18e854924735b9f76f31d084c0eb995edae5ab1
--- /dev/null
+++ b/Code/script_idl_mv/astrolib/get_date.pro
@@ -0,0 +1,109 @@
+pro get_date, dte, in_date, OLD = old, TIMETAG = timetag
+;+
+; NAME:
+; GET_DATE
+; PURPOSE:
+; Return the (current) UTC date in CCYY-MM-DD format for FITS headers
+; EXPLANATION:
+; This is the format required by the DATE and DATE-OBS keywords in a
+; FITS header.
+;
+; CALLING SEQUENCE:
+; GET_DATE, FITS_date, [ in_date, /OLD, /TIMETAG ]
+; OPTIONAL INPUTS:
+; in_date - string (scalar or vector) containing dates in IDL
+; systime() format (e.g. 'Tue Sep 25 14:56:14 2001')
+; OUTPUTS:
+; FITS_date = A scalar character string giving the current date. Actual
+; appearance of dte depends on which keywords are supplied.
+;
+; No Keywords supplied - dte is a 10 character string with the format
+; CCYY-MM-DD where represents a calendar year, the
+; ordinal number of a calendar month within the calendar year,
+; and