diff --git a/geminidr/core/primitives_ccd.py b/geminidr/core/primitives_ccd.py
index 39fbcdb961..e1d580447e 100644
--- a/geminidr/core/primitives_ccd.py
+++ b/geminidr/core/primitives_ccd.py
@@ -128,10 +128,10 @@ def subtractOverscan(self, adinputs=None, **params):
region be a vertical strip) is determined in one of the following
ways, according to the *function* and *order* parameters:
- "poly": a polynomial of degree *order* (1=linear, etc)
- "spline": using *order* equally-sized cubic spline pieces or, if
+ :"poly": a polynomial of degree *order* (1=linear, etc)
+ :"spline": using *order* equally-sized cubic spline pieces or, if
order=None or 0, a spline that provides a reduced chi^2=1
- "none": no function is fit, and the value for each row is determined
+ :"none": no function is fit, and the value for each row is determined
by the overscan pixels in that row
The fitting is done iteratively but, in the first instance, a running
diff --git a/geminidr/doc/usermanuals/Makefile b/geminidr/doc/usermanuals/Makefile
new file mode 100644
index 0000000000..d4bb2cbb9e
--- /dev/null
+++ b/geminidr/doc/usermanuals/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/geminidr/doc/usermanuals/README b/geminidr/doc/usermanuals/README
new file mode 100644
index 0000000000..a66b976ad7
--- /dev/null
+++ b/geminidr/doc/usermanuals/README
@@ -0,0 +1,44 @@
+Generating the primitive documentation.
+---------------------------------------
+There are two steps:
+
+1) run the script to generate the docs from the docstrings and the parameter
+ files.
+ utility_scripts/generate_primdoc.py -d primitives/generated-doc
+
+2) use the template to write the primitive_name.rst file that will load the
+ generated subsections. The template is "primmitive_createExample.rst" in
+ "examples". This is a manual, human-driven task.
+
+
+
+
+
+Generating the recipe documentation.
+------------------------------------
+There are two steps:
+
+1) run the script to generate the automated part.
+ The generated file should have:
+ * name of the recipe (as heading with ====)
+ * module and name of recipe library
+ * recipe tags
+ * docstring which should include the type of inputs (tags) required.
+ * the recipe
+
+2) Then manually create the .rst that put them all together and adds additional
+ comments.
+ The
+
+
+Development
+-----------
+
+Dev and test for primitives
+* To try it out:
+ utility_scripts/generate_primdoc.py core gmos -d testdoc
+
+Dev and test for recipes
+
+* ./generate_recipedoc.py gmos -d testdoc
+
diff --git a/geminidr/doc/usermanuals/_static/css/code.xref-styles.css b/geminidr/doc/usermanuals/_static/css/code.xref-styles.css
new file mode 100644
index 0000000000..785c691ebf
--- /dev/null
+++ b/geminidr/doc/usermanuals/_static/css/code.xref-styles.css
@@ -0,0 +1,16 @@
+
+/* , a .rst-content tt, a .rst-content code */
+
+.rst-content code.xref {
+ background-color: transparent;
+ border: solid 1px transparent;
+ color: #2980B9;
+ padding: 0px 0px;
+ font-size: 80%;
+ }
+
+.rst-content code.xref:hover {
+ /* border: solid 1px #e1e4e5; */
+ text-decoration: underline;
+ }
+
diff --git a/geminidr/doc/usermanuals/_static/css/fonts.css b/geminidr/doc/usermanuals/_static/css/fonts.css
new file mode 100644
index 0000000000..b6c4949c81
--- /dev/null
+++ b/geminidr/doc/usermanuals/_static/css/fonts.css
@@ -0,0 +1,36 @@
+.red {
+ color: red;
+}
+
+.blue {
+ color: blue;
+}
+
+.green {
+ color: green;
+}
+
+.yellow {
+ color: yellow;
+}
+
+.gray {
+ color: gray;
+}
+
+.lightgray {
+ color: lightgray;
+}
+
+.small {
+ font-size: 80%;
+}
+
+.large {
+ font-size: 120%;
+}
+
+.bolditalic {
+ font-weight: bold;
+ font-style: italic;
+}
\ No newline at end of file
diff --git a/geminidr/doc/usermanuals/_static/css/rtd_theme_overrides.css b/geminidr/doc/usermanuals/_static/css/rtd_theme_overrides.css
new file mode 100644
index 0000000000..62910a0bb7
--- /dev/null
+++ b/geminidr/doc/usermanuals/_static/css/rtd_theme_overrides.css
@@ -0,0 +1,20 @@
+/* override RTD table width restrictions */
+
+@media screen and (min-width: 767px) {
+
+ .wy-table-responsive table td, .wy-table-responsive table th {
+ /* !important prevents the common CSS stylesheets from
+ overriding this as on RTD the are loaded after this stylesheet */
+ white-space: normal !important;
+ }
+
+ .wy-table-responsive {
+ /* margin-bottom: 24px; */
+ /* max-width: 100%; */
+ overflow: visible !important;
+ }
+
+ .wy-nav-content {
+ max-width: 1200px !important;
+ }
+}
diff --git a/geminidr/doc/usermanuals/_static/css/todo-styles.css b/geminidr/doc/usermanuals/_static/css/todo-styles.css
new file mode 100644
index 0000000000..09f3659575
--- /dev/null
+++ b/geminidr/doc/usermanuals/_static/css/todo-styles.css
@@ -0,0 +1,7 @@
+div.admonition-todo {
+border-top: 2px solid red;
+border-bottom: 2px solid red;
+border-left: 2px solid red;
+border-right: 2px solid red;
+background-color: #ff6347
+}
diff --git a/geminidr/doc/usermanuals/_static/img/DRAGONS - DGlogo.png b/geminidr/doc/usermanuals/_static/img/DRAGONS - DGlogo.png
new file mode 100644
index 0000000000..4eea0a1432
Binary files /dev/null and b/geminidr/doc/usermanuals/_static/img/DRAGONS - DGlogo.png differ
diff --git a/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon blue.png b/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon blue.png
new file mode 100644
index 0000000000..fd7dd0eb6b
Binary files /dev/null and b/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon blue.png differ
diff --git a/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon.png b/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon.png
new file mode 100644
index 0000000000..5304018c30
Binary files /dev/null and b/geminidr/doc/usermanuals/_static/img/DRAGONS - Icon.png differ
diff --git a/geminidr/doc/usermanuals/conf.py b/geminidr/doc/usermanuals/conf.py
new file mode 100644
index 0000000000..9f53864d7c
--- /dev/null
+++ b/geminidr/doc/usermanuals/conf.py
@@ -0,0 +1,150 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'DRAGONS Data Reduction User Reference'
+copyright = '2023, Association of Universities for Research in Astronomy'
+author = 'DRAGONS Team'
+
+# The short X.Y version
+version = '3.1'
+
+# The full version, including alpha/beta/rc tags
+release = '3.1.1-dev'
+#rtdurl = 'v'+release
+#rtdurl = 'release-'+release
+rtdurl = 'latest'
+
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.todo',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+today = 'May 2023'
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+#html_theme = 'alabaster'
+html_theme = 'sphinx_rtd_theme'
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+html_logo = "_static/img/DRAGONS - Icon blue.png"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'DRAGONSDRUserReference.tex', 'DRAGONS Data Reduction User Reference',
+ 'DRAGONS Team', 'manual'),
+]
+
+# -- Options for todo extension ----------------------------------------------
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+
+# -- Finishing with a setup that will run always -----------------------------
+def setup(app):
+
+ # -- Adding custom styles ---
+ app.add_css_file('css/todo-style.css')
+ app.add_css_file('css/rtf_theme_overrides.css')
+ app.add_css_file('css/fonts.css')
+ app.add_css_file('css/code.xref-styles.css')
+
+rst_epilog = """
+.. role:: raw-html(raw)
+ :format: html
+
+.. |caldb| replace:: :raw-html:`caldb`
+.. |dataselect| replace:: :raw-html:`dataselect`
+.. |descriptors| replace:: :raw-html:`descriptors`
+.. |descriptor| replace:: :raw-html:`descriptors`
+.. |reduce| replace:: :raw-html:`reduce`
+.. |showd| replace:: :raw-html:`showd`
+.. |showrecipes| replace:: :raw-html:`showrecipes`
+.. |showpars| replace:: :raw-html:`showpars`
+.. |typewalk| replace:: :raw-html:`typewalk`
+.. |atfile| replace:: :raw-html:`"at-file" Facility`
+.. |astrodatauser| replace:: :raw-html:`Astrodata User Manual`
+
+.. |RSUser| replace:: :raw-html:`Recipe System Users Manual`
+
+""".format(v = rtdurl)
diff --git a/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_docstring.rst b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_docstring.rst
new file mode 100644
index 0000000000..74cccb23d4
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_docstring.rst
@@ -0,0 +1,34 @@
+
+This primitive subtracts the overscan level from the image. The
+level for each row (currently the primitive requires that the overscan
+region be a vertical strip) is determined in one of the following
+ways, according to the *function* and *order* parameters:
+
+:"poly": a polynomial of degree *order* (1=linear, etc)
+:"spline": using *order* equally-sized cubic spline pieces or, if
+ order=None or 0, a spline that provides a reduced chi^2=1
+:"none": no function is fit, and the value for each row is determined
+ by the overscan pixels in that row
+
+The fitting is done iteratively but, in the first instance, a running
+median of the rows is calculated and rows that deviate from this median
+are rejected (and used in place of the actual value if function="none")
+
+Parameters
+----------
+suffix: str
+ suffix to be added to output files
+niterate: int
+ number of rejection iterations
+high_reject: float/None
+ number of standard deviations above which to reject high pixels
+low_reject: float/None
+ number of standard deviations above which to reject low pixels
+nbiascontam: int/None
+ number of columns adjacent to the illuminated region to reject
+function: str/None
+ function to fit ("chebyshev" | "spline" | "none")
+order: int/None
+ order of polynomial fit or number of spline pieces
+bias_type: str
+ For multiple overscan regions, selects which one to use
diff --git a/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_param.rst b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_param.rst
new file mode 100644
index 0000000000..2bed542a44
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_param.rst
@@ -0,0 +1,23 @@
+Parameter defaults and options
+------------------------------
+::
+
+ function 'spline3' Fitting function
+ Allowed values:
+ none Row-by-row values
+ spline3 Cubic spline
+ chebyshev Chebyshev polynomial
+
+ order None Order of fitting function
+ Valid Range = [0,inf)
+ lsigma 3.0 Low rejection in sigma of fit
+ Valid Range = [0,inf)
+ hsigma 3.0 High rejection in sigma of fit
+ Valid Range = [0,inf)
+ niter 0 Maximum number of rejection iterations
+ Valid Range = [0,inf)
+ grow 0 Rejection growing radius
+ Valid Range = [0,inf)
+ suffix '_overscanSubtracted' Filename suffix
+ nbiascontam 0 Number of columns to exclude from averaging
+ Valid Range = [0,inf)
diff --git a/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_docstring.rst b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_docstring.rst
new file mode 100644
index 0000000000..ce82b05642
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_docstring.rst
@@ -0,0 +1,40 @@
+
+This primitive subtracts the overscan level from the image. The
+level for each row (currently the primitive requires that the overscan
+region be a vertical strip) is determined in one of the following
+ways, according to the *function* and *order* parameters:
+
+:"poly": a polynomial of degree *order* (1=linear, etc)
+:"spline": using *order* equally-sized cubic spline pieces or, if
+ order=None or 0, a spline that provides a reduced chi^2=1
+:"none": no function is fit, and the value for each row is determined
+ by the overscan pixels in that row
+
+The fitting is done iteratively but, in the first instance, a running
+median of the rows is calculated and rows that deviate from this median
+are rejected (and used in place of the actual value if function="none")
+
+The GMOS-specific version of this primitive sets the "nbiascontam" and
+"order" parameters to their Gemini-IRAF defaults if they are None. It
+also removes the bottom 48 (ubinned) rows of the Hamamatsu CCDs from
+consideration in a polynomial fit. It then calls the generic version
+of the primitive.
+
+Parameters
+----------
+suffix: str
+ suffix to be added to output files
+niterate: int
+ number of rejection iterations
+high_reject: float
+ number of standard deviations above which to reject high pixels
+low_reject: float
+ number of standard deviations above which to reject low pixels
+overscan_section: str/None
+ comma-separated list of IRAF-style overscan sections
+nbiascontam: int/None
+ number of columns adjacent to the illuminated region to reject
+function: str
+ function to fit ("polynomial" | "spline" | "none")
+order: int
+ order of Chebyshev fit or spline/None
diff --git a/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_param.rst b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_param.rst
new file mode 100644
index 0000000000..b31afcd5f3
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_param.rst
@@ -0,0 +1,23 @@
+Parameter defaults and options
+------------------------------
+::
+
+ function 'none' Fitting function
+ Allowed values:
+ none Row-by-row values
+ spline3 Cubic spline
+ chebyshev Chebyshev polynomial
+
+ order None Order of fitting function
+ Valid Range = [0,inf)
+ lsigma 3.0 Low rejection in sigma of fit
+ Valid Range = [0,inf)
+ hsigma 3.0 High rejection in sigma of fit
+ Valid Range = [0,inf)
+ niter 0 Maximum number of rejection iterations
+ Valid Range = [0,inf)
+ grow 0 Rejection growing radius
+ Valid Range = [0,inf)
+ suffix '_overscanSubtracted' Filename suffix
+ nbiascontam None Number of columns to exclude from averaging
+ Valid Range = [0,inf)
diff --git a/geminidr/doc/usermanuals/examples/primitives/primitive_createExample.rst b/geminidr/doc/usermanuals/examples/primitives/primitive_createExample.rst
new file mode 100644
index 0000000000..648c62b303
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/primitive_createExample.rst
@@ -0,0 +1,87 @@
+.. primitive_createExample.rst
+
+.. _primitive_createExample:
+
+*************
+createExample
+*************
+This primitive is a fake one and used to show the format of the primitive
+rst files and the expected content. This first paragraph (this paragraph) in
+written by the author directly in this file and provides a general description
+of the purpose and function of a primitive with this name.
+
+Implementations
+***************
+(REMOVE this text in real doc: The Implementations section contains all the
+implementations sharing the name of this primitive.)
+
+* :ref:`primitive_createExample_core.blah`
+* :ref:`primitive_createExample_instrument.instrument_blah`
+
+.. _primitive_createExample_core.blah:
+
+Generic Implementation - core.primitive_blah module
+===================================================
+(REMOVE this text in real doc: If there is an implementation in `core`,
+that the one we want here. If there isn't, just skip.)
+
+.. generated with `utility_scripts/generate_primdoc.py`
+.. contains:
+.. Top description from docstring
+.. Inputs and Outputs section of the docstring
+.. Parameters section of the docstring
+..
+.. The "Inputs and Outputs" section and the "Parameters" section in the
+.. docstring must be underlined with "---" the length of the title for
+.. compatibility with this document. (Actually, this document was adapted
+.. to use "---" as the section indicators at this level to match what we
+.. already use in the docstrings.)
+
+.. include:: generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_docstring.rst
+
+.. generated with `utility_scripts/generate_primdoc.py`
+.. contains:
+.. Parameter defaults from pex.config system
+.. showpars-like format
+
+.. include:: generated_doc/geminidr.core.primitives_ccd.CCD.subtractOverscan_param.rst
+
+Algorithm
+---------
+This section is optional but recommended. The author write in here any
+relevant information about how the primitive accomplishes its task. Free
+form. Use screenshots and diagram when useful.
+
+Issues and Limitations
+----------------------
+This section is optional but recommended. The author write in here any
+relevant information about known issues and limitations. Free
+form. Use screenshots and diagram when useful.
+
+----
+
+.. _primitive_createExample_instrument.instrument_blah:
+
+ Implementation - instrument.primitives_instrument_blah module
+=================================================================================
+.. example: GMOS Longslit Implementation - gmos.primitives_gmos module
+
+(REMOVE this text in real doc: The description from the docstring for this
+implementation will be shown here, the parameter defaults too. HOWEVER,
+if another implementation is re-used and only the parameter defaults are
+different, it might smarter to just include the `-param.rst` file to avoid
+unnecessary duplication and just refer to the appropriate implementation for
+the rest of the info.)
+
+.. include:: generated_doc/geminidr.gmos.primitives_gmos.GMOS.subtractOverscan_param.rst
+
+Algorithm
+---------
+Optional, okay to refer to the section from another implementation to avoid
+unnecessary duplication.
+
+Issues and Limitations
+----------------------
+Optional, okay to refer to the section from another implementation to avoid
+unnecessary duplication.
+
diff --git a/geminidr/doc/usermanuals/examples/primitives/primitives_index.rst b/geminidr/doc/usermanuals/examples/primitives/primitives_index.rst
new file mode 100644
index 0000000000..3e2369bb0b
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/primitives/primitives_index.rst
@@ -0,0 +1,14 @@
+.. primitives_index.rst
+
+.. _primitives_index:
+
+********************
+Primitives Reference
+********************
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ primitive_createExample
+
diff --git a/geminidr/doc/usermanuals/.notempty b/geminidr/doc/usermanuals/examples/recipes/generated_doc/.not_empty
similarity index 100%
rename from geminidr/doc/usermanuals/.notempty
rename to geminidr/doc/usermanuals/examples/recipes/generated_doc/.not_empty
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..cf7ed6b46d
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'ARC', 'GMOS', 'LS', 'SPECT'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeProcessedArc.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeProcessedArc.rst
new file mode 100644
index 0000000000..93205b644e
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeProcessedArc.rst
@@ -0,0 +1,21 @@
+makeProcessedArc
+================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT
+| **Astrodata Tags**: {'ARC', 'GMOS', 'LS', 'SPECT'}
+::
+
+ def makeProcessedArc(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.mosaicDetectors()
+ p.makeIRAFCompatible()
+ p.determineWavelengthSolution()
+ p.determineDistortion()
+ p.storeProcessedArc()
+ p.writeOutputs()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..9e6c6d9efa
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_BIAS
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'GMOS', 'BIAS', 'CAL'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeProcessedBias.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeProcessedBias.rst
new file mode 100644
index 0000000000..13003cd585
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeProcessedBias.rst
@@ -0,0 +1,31 @@
+makeProcessedBias
+=================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_BIAS
+| **Astrodata Tags**: {'GMOS', 'BIAS', 'CAL'}
+
+This recipe performs the standardization and corrections needed to convert
+the raw input bias images into a single stacked bias image. This output
+processed bias is stored on disk using storeProcessedBias and has a name
+equal to the name of the first input bias image with "_bias.fits" appended.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeProcessedBias(p):
+
+ p.prepare()
+ p.addDQ(add_illum_mask=False)
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.stackBiases()
+ p.makeIRAFCompatible()
+ p.storeProcessedBias()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..4fec79e16d
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_DARK
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'GMOS', 'CAL', 'DARK'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeProcessedDark.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeProcessedDark.rst
new file mode 100644
index 0000000000..7eb9c1e88e
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_DARK.makeProcessedDark.rst
@@ -0,0 +1,35 @@
+makeProcessedDark
+=================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_DARK
+| **Astrodata Tags**: {'GMOS', 'CAL', 'DARK'}
+
+This recipe performs the standardization and corrections needed to convert
+the raw input dark images into a single stacked dark image. This output
+processed bias is stored on disk using storeProcessedDark and has a name
+equal to the name of the first input bias image with "_dark.fits" appended.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeProcessedDark(p):
+
+ p.prepare()
+ p.addDQ(add_illum_mask=False)
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ # Force "varclip" due to large number of CRs
+ p.stackDarks(reject_method="varclip")
+ p.makeIRAFCompatible()
+ p.storeProcessedDark()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..171ffbbf1f
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'GMOS', 'FLAT', 'CAL', 'IMAGE'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeProcessedFlat.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeProcessedFlat.rst
new file mode 100644
index 0000000000..94cb950de2
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE.makeProcessedFlat.rst
@@ -0,0 +1,35 @@
+makeProcessedFlat
+=================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_IMAGE
+| **Astrodata Tags**: {'GMOS', 'FLAT', 'CAL', 'IMAGE'}
+
+This recipe performs the standardization and corrections needed to
+convert the raw input flat images into a single stacked and normalized
+flat image. This output processed flat is stored on disk using
+storeProcessedFlat and has a name equal to the name of the first input
+flat image with "_flat.fits" appended.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeProcessedFlat(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.stackFlats()
+ p.normalizeFlat()
+ p.makeIRAFCompatible()
+ p.storeProcessedFlat()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..5466e3de17
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'LS', 'GMOS', 'FLAT', 'SPECT'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatNoStack.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatNoStack.rst
new file mode 100644
index 0000000000..da2a2bb307
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatNoStack.rst
@@ -0,0 +1,20 @@
+makeProcessedFlatNoStack
+========================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'FLAT', 'SPECT'}
+::
+
+ def makeProcessedFlatNoStack(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.normalizeFlat()
+ p.thresholdFlatfield()
+ p.makeIRAFCompatible()
+ p.storeProcessedFlat()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatStack.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatStack.rst
new file mode 100644
index 0000000000..1b38502ae1
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedFlatStack.rst
@@ -0,0 +1,21 @@
+makeProcessedFlatStack
+======================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'FLAT', 'SPECT'}
+::
+
+ def makeProcessedFlatStack(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.stackFrames()
+ p.normalizeFlat()
+ p.thresholdFlatfield()
+ p.makeIRAFCompatible()
+ p.storeProcessedFlat()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedSlitIllum.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedSlitIllum.rst
new file mode 100644
index 0000000000..eadfb5c860
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT.makeProcessedSlitIllum.rst
@@ -0,0 +1,20 @@
+makeProcessedSlitIllum
+======================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_FLAT_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'FLAT', 'SPECT'}
+::
+
+ def makeProcessedSlitIllum(p):
+ p.prepare()
+ p.addDQ(static_bpm=None)
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.stackFrames()
+ p.makeSlitIllum()
+ p.makeIRAFCompatible()
+ p.storeProcessedSlitIllum()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.alignAndStack.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.alignAndStack.rst
new file mode 100644
index 0000000000..8e6877db5b
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.alignAndStack.rst
@@ -0,0 +1,26 @@
+alignAndStack
+=============
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+This recipe stack already preprocessed data.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def alignAndStack(p):
+
+ p.detectSources()
+ p.adjustWCSToReference()
+ p.resampleToCommonFrame()
+ p.scaleCountsToReference()
+ p.stackFrames(zero=True)
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..608dc5144e
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeProcessedFringe.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeProcessedFringe.rst
new file mode 100644
index 0000000000..56187b7f48
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeProcessedFringe.rst
@@ -0,0 +1,33 @@
+makeProcessedFringe
+===================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+This recipe creates a fringe frame from the inputs files. The output
+is stored on disk using storeProcessedFringe and has a name equal
+to the name of the first input bias image with "_fringe.fits" appended.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeProcessedFringe(p):
+ p.prepare()
+ p.addDQ()
+ #p.addIllumMaskToDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.flatCorrect()
+ p.makeFringeFrame()
+ p.storeProcessedFringe()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduce.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduce.rst
new file mode 100644
index 0000000000..9dc95f3be7
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduce.rst
@@ -0,0 +1,40 @@
+reduce
+======
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+This recipe performs the standardization and corrections needed to
+convert the raw input science images into a stacked image.
+
+::
+
+ Parameters
+ ----------
+ p : GMOSImage object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def reduce(p):
+
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.flatCorrect()
+ p.fringeCorrect()
+ p.QECorrect()
+ p.mosaicDetectors()
+ p.detectSources()
+ p.adjustWCSToReference()
+ p.resampleToCommonFrame()
+ p.flagCosmicRaysByStacking()
+ p.scaleCountsToReference()
+ p.stackFrames(zero=True)
+ p.storeProcessedScience(suffix="_image")
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDs.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDs.rst
new file mode 100644
index 0000000000..4911406b97
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDs.rst
@@ -0,0 +1,51 @@
+reduceSeparateCCDs
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+This recipe performs the standardization and corrections needed to
+convert the raw input science images into a stacked image. To deal
+with different color terms on the different CCDs, the images are
+split by CCD midway through the recipe and subsequently reduced
+separately. The relative WCS is determined from mosaicked versions
+of the images and then applied to each of the CCDs separately.
+
+::
+
+ Parameters
+ ----------
+ p : GMOSImage object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def reduceSeparateCCDs(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.flatCorrect()
+ p.fringeCorrect()
+ p.tileArrays(tile_all=False)
+ p.mosaicDetectors(outstream="mosaic")
+ p.detectSources(stream="mosaic")
+ p.adjustWCSToReference(stream="mosaic")
+ p.applyWCSAdjustment(reference_stream="mosaic")
+ p.clearStream(stream="mosaic")
+ p.detectSources()
+ p.scaleCountsToReference()
+ p.sliceIntoStreams(root_stream_name="ccd", copy=False)
+ p.clearStream(stream="main")
+ for ccd in (1, 2, 3):
+ p.resampleToCommonFrame(instream=f"ccd{ccd}")
+ p.detectSources()
+ p.flagCosmicRaysByStacking()
+ p.stackFrames(zero=True)
+ p.appendStream(stream="all", from_stream="main", copy=False)
+ p.mergeInputs(instream="all")
+ p.storeProcessedScience(suffix="_image")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDsCentral.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDsCentral.rst
new file mode 100644
index 0000000000..fc6045574a
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDsCentral.rst
@@ -0,0 +1,50 @@
+reduceSeparateCCDsCentral
+=========================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_IMAGE
+| **Astrodata Tags**: {'GMOS', 'IMAGE'}
+
+This recipe performs the standardization and corrections needed to
+convert the raw input science images into a stacked image. To deal
+with different color terms on the different CCDs, the images are
+split by CCD midway through the recipe and subsequently reduced
+separately. The relative WCS is determined from the central CCD
+(CCD2) and then applied to CCDs 1 and 3.
+
+::
+
+ Parameters
+ ----------
+ p : GMOSImage object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def reduceSeparateCCDsCentral(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.flatCorrect()
+ p.fringeCorrect()
+ p.tileArrays(tile_all=False)
+ p.sliceIntoStreams(root_stream_name="ccd")
+ p.detectSources(stream="ccd2")
+ p.adjustWCSToReference(stream="ccd2")
+ p.applyWCSAdjustment(stream="main", reference_stream="ccd2")
+ p.clearAllStreams()
+ p.detectSources()
+ p.scaleCountsToReference()
+ p.sliceIntoStreams(root_stream_name="ccd")
+ for ccd in (1, 2, 3):
+ p.resampleToCommonFrame(instream=f"ccd{ccd}")
+ p.detectSources()
+ p.flagCosmicRaysByStacking()
+ p.stackFrames(zero=True)
+ p.appendStream(stream="all", from_stream="main", copy=False)
+ p.mergeInputs(instream="all")
+ p.storeProcessedScience(suffix="_image")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..9b4a6a69b8
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'LS', 'GMOS', 'SPECT'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceScience.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceScience.rst
new file mode 100644
index 0000000000..8a1ec5d550
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceScience.rst
@@ -0,0 +1,43 @@
+reduceScience
+=============
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'SPECT'}
+
+todo: add docstring
+
+::
+
+ Parameters
+ ----------
+ p : :class:`geminidr.gmos.primitives_gmos_longslit.GMOSLongslit`
+
+
+::
+
+ def reduceScience(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.QECorrect()
+ p.flagCosmicRays()
+ p.distortionCorrect()
+ p.findApertures()
+ p.skyCorrectFromSlit()
+ p.adjustWCSToReference()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.scaleCountsToReference()
+ p.stackFrames()
+ p.findApertures()
+ p.traceApertures()
+ p.storeProcessedScience(suffix="_2D")
+ p.extractSpectra()
+ p.fluxCalibrate()
+ p.storeProcessedScience(suffix="_1D")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceStandard.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceStandard.rst
new file mode 100644
index 0000000000..f4c58230a6
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceStandard.rst
@@ -0,0 +1,40 @@
+reduceStandard
+==============
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'SPECT'}
+
+todo: add docstring
+
+::
+
+ Parameters
+ ----------
+ p : :class:`geminidr.gmos.primitives_gmos_longslit.GMOSLongslit`
+
+
+::
+
+ def reduceStandard(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.QECorrect()
+ p.distortionCorrect()
+ p.findApertures(max_apertures=1)
+ p.skyCorrectFromSlit()
+ p.traceApertures()
+ p.extractSpectra()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.scaleCountsToReference()
+ p.stackFrames()
+ p.calculateSensitivity()
+ p.storeProcessedStandard()
+ p.writeOutputs()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceWithMultipleStandards.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceWithMultipleStandards.rst
new file mode 100644
index 0000000000..1ca0016bf1
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_LS_SPECT.reduceWithMultipleStandards.rst
@@ -0,0 +1,43 @@
+reduceWithMultipleStandards
+===========================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'SPECT'}
+
+todo: add docstring
+
+::
+
+ Parameters
+ ----------
+ p : :class:`geminidr.gmos.primitives_gmos_longslit.GMOSLongslit`
+
+
+::
+
+ def reduceWithMultipleStandards(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.QECorrect()
+ p.flagCosmicRays()
+ p.distortionCorrect()
+ p.findApertures()
+ p.skyCorrectFromSlit()
+ p.adjustWCSToReference()
+ p.fluxCalibrate()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.scaleCountsToReference()
+ p.stackFrames()
+ p.findApertures()
+ p.traceApertures()
+ p.storeProcessedScience(suffix="_2D")
+ p.extractSpectra()
+ p.storeProcessedScience(suffix="_1D")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_NS_LS_SPECT.reduce.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_NS_LS_SPECT.reduce.rst
new file mode 100644
index 0000000000..6cf4364f82
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_NS_LS_SPECT.reduce.rst
@@ -0,0 +1,52 @@
+reduce
+======
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_NS_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'SPECT', 'NODANDSHUFFLE'}
+
+This recipe reduces GMOS N&S longslit science data.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def reduce(p):
+ """
+ This recipe reduces GMOS N&S longslit science data.
+
+ Parameters
+ ----------
+ p : PrimitivesBASE object
+ A primitive set matching the recipe_tags.
+ """
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.darkCorrect()
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.flagCosmicRays()
+ p.skyCorrectNodAndShuffle()
+ p.QECorrect()
+ p.flushPixels()
+ p.distortionCorrect()
+ p.combineNodAndShuffleBeams()
+ p.adjustWCSToReference()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.stackFrames()
+ p.findApertures()
+ p.traceApertures()
+ p.storeProcessedScience(suffix="_2D")
+ p.extractSpectra()
+ p.fluxCalibrate()
+ p.storeProcessedScience(suffix="_1D")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_SLITILLUM_LS_SPECT.makeProcessedSlitIllum.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_SLITILLUM_LS_SPECT.makeProcessedSlitIllum.rst
new file mode 100644
index 0000000000..6c8feba90b
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_SLITILLUM_LS_SPECT.makeProcessedSlitIllum.rst
@@ -0,0 +1,20 @@
+makeProcessedSlitIllum
+======================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_SLITILLUM_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'SLITILLUM', 'SPECT'}
+::
+
+ def makeProcessedSlitIllum(p):
+ p.prepare()
+ p.addDQ(static_bpm=None)
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.stackFrames()
+ p.makeSlitIllum()
+ p.makeIRAFCompatible()
+ p.storeProcessedSlitIllum()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..17d5f39c51
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.makeIRAFCompatible.rst
@@ -0,0 +1,25 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: {'LS', 'GMOS', 'STANDARD', 'SPECT'}
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceScience.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceScience.rst
new file mode 100644
index 0000000000..b46e2cfb3d
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceScience.rst
@@ -0,0 +1,44 @@
+reduceScience
+=============
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'STANDARD', 'SPECT'}
+
+todo: add docstring
+
+::
+
+ Parameters
+ ----------
+ p : :class:`geminidr.gmos.primitives_gmos_longslit.GMOSLongslit`
+
+
+::
+
+ def reduceScience(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.QECorrect()
+ p.flagCosmicRays()
+ p.distortionCorrect()
+ p.findApertures()
+ p.skyCorrectFromSlit()
+ p.adjustWCSToReference()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.scaleCountsToReference()
+ p.stackFrames()
+ p.findApertures()
+ p.traceApertures()
+ p.storeProcessedScience(suffix="_2D")
+ p.extractSpectra()
+ p.fluxCalibrate()
+ p.storeProcessedScience(suffix="_1D")
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceStandard.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceStandard.rst
new file mode 100644
index 0000000000..0173c1fd11
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT.reduceStandard.rst
@@ -0,0 +1,41 @@
+reduceStandard
+==============
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_STANDARD_LS_SPECT
+| **Recipe Imported From**: geminidr.gmos.recipes.sq.recipes_LS_SPECT
+| **Astrodata Tags**: {'LS', 'GMOS', 'STANDARD', 'SPECT'}
+
+todo: add docstring
+
+::
+
+ Parameters
+ ----------
+ p : :class:`geminidr.gmos.primitives_gmos_longslit.GMOSLongslit`
+
+
+::
+
+ def reduceStandard(p):
+ p.prepare()
+ p.addDQ()
+ p.addVAR(read_noise=True)
+ p.overscanCorrect()
+ p.biasCorrect()
+ p.ADUToElectrons()
+ p.addVAR(poisson_noise=True)
+ p.attachWavelengthSolution()
+ p.flatCorrect()
+ p.QECorrect()
+ p.distortionCorrect()
+ p.findApertures(max_apertures=1)
+ p.skyCorrectFromSlit()
+ p.traceApertures()
+ p.extractSpectra()
+ p.resampleToCommonFrame(conserve=True) # default force_linear=True, ie. linearized.
+ p.scaleCountsToReference()
+ p.stackFrames()
+ p.calculateSensitivity()
+ p.storeProcessedStandard()
+ p.writeOutputs()
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_common.makeIRAFCompatible.rst b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_common.makeIRAFCompatible.rst
new file mode 100644
index 0000000000..3c324502e1
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/generated_doc/geminidr.gmos.recipes.sq.recipes_common.makeIRAFCompatible.rst
@@ -0,0 +1,24 @@
+makeIRAFCompatible
+==================
+
+| **Recipe Library**: geminidr.gmos.recipes.sq.recipes_common
+| **Astrodata Tags**: None
+
+Add header keywords needed to run some Gemini IRAF tasks. This is needed
+only if the reduced file will be used as input to Gemini IRAF tasks.
+
+::
+
+ Parameters
+ ----------
+ p : PrimitivesBASEE object
+ A primitive set matching the recipe_tags.
+
+::
+
+ def makeIRAFCompatible(p):
+
+ p.makeIRAFCompatible()
+ p.writeOutputs()
+ return
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/gmos_cal_bias_sq_recipes.rst b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_bias_sq_recipes.rst
new file mode 100644
index 0000000000..1fa8801a75
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_bias_sq_recipes.rst
@@ -0,0 +1,28 @@
+.. gmos_cal_bias_sq_recipes.rst
+
+.. _gmos_cal_bias_sq_recipes:
+
+*****************
+GMOS Bias Recipes
+*****************
+
+Default Recipe
+**************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeProcessedBias.rst
+
+.. The include auto-generated file contains:
+.. name of the recipe (as heading with ====)
+.. module and name of recipe library
+.. recipe tags
+.. docstring which should include the type of inputs (tags) required.
+.. the recipe
+
+(REMOVE this text: Anything additional information about the recipe, it's
+usage, likely primitives and parameters to play with, etc. can be added by
+the author here, as necessary.)
+
+Utility Recipes
+***************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_BIAS.makeIRAFCompatible.rst
diff --git a/geminidr/doc/usermanuals/examples/recipes/gmos_cal_sq_recipes.rst b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_sq_recipes.rst
new file mode 100644
index 0000000000..3d8e7a7e20
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_sq_recipes.rst
@@ -0,0 +1,30 @@
+.. gmos_cal_sq_recipes.rst
+
+.. _gmos_cal_sq_recipes:
+
+*************************
+GMOS Calibrations Recipes
+*************************
+
+.. toctree::
+ :maxdepth: 1
+ :caption: All modes
+
+ gmos_cal_bias_sq_recipes
+ .. gmos_cal_dark_sq_recipes
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Imaging
+
+ .. gmos_cal_flat_img_sq_recipes
+ .. gmos_cal_fringe_img_sq_recipes
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Longslit spectroscopy
+
+ .. gmos_cal_flat_ls_spect_sq_recipes
+ gmos_cal_wavecal_ls_sq_recipes
+ .. gmos_cal_standard_ls_sq_recipes
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/gmos_cal_wavecal_ls_sq_recipes.rst b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_wavecal_ls_sq_recipes.rst
new file mode 100644
index 0000000000..87a81043ae
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/gmos_cal_wavecal_ls_sq_recipes.rst
@@ -0,0 +1,29 @@
+.. gmos_cal_wavecal_sq_recipes.rst
+
+.. _gmos_cal_wavecal_sq_recipes:
+
+***************************************************
+GMOS Wavelength Calibrations and Distortion Recipes
+***************************************************
+
+Default Recipe
+**************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeProcessedArc.rst
+
+.. The include auto-generated file contains:
+.. name of the recipe (as heading with ====)
+.. module and name of recipe library
+.. recipe tags
+.. docstring which should include the type of inputs (tags) required.
+.. the recipe
+
+(REMOVE this text: Anything additional information about the recipe, it's
+usage, likely primitives and parameters to play with, etc. can be added by
+the author here, as necessary.)
+
+Utility Recipes
+***************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_ARC_LS_SPECT.makeIRAFCompatible.rst
+
diff --git a/geminidr/doc/usermanuals/examples/recipes/gmos_img_sq_recipes.rst b/geminidr/doc/usermanuals/examples/recipes/gmos_img_sq_recipes.rst
new file mode 100644
index 0000000000..b78f2eab8e
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/gmos_img_sq_recipes.rst
@@ -0,0 +1,32 @@
+.. gmos_img_sq_recipes.rst
+
+.. _gmos_img_sq_recipes:
+
+****************************
+GMOS Imaging Science Recipes
+****************************
+
+Default Recipe
+**************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduce.rst
+
+(REMOVE this text: Anything additional information about the recipe, it's
+usage, likely primitives and parameters to play with, etc. can be added by
+the author here, as necessary.)
+
+Reducing the CCDs Separately
+****************************
+
+(REMOVE this text: Anything additional information about the recipe, it's
+usage, likely primitives and parameters to play with, etc. can be added by
+the author here, as necessary.)
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDs.rst
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.reduceSeparateCCDsCentral.rst
+
+Utility Recipes
+***************
+
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.alignAndStack.rst
+.. include:: generated_doc/geminidr.gmos.recipes.sq.recipes_IMAGE.makeIRAFCompatible.rst
\ No newline at end of file
diff --git a/geminidr/doc/usermanuals/examples/recipes/gmos_sq_recipes.rst b/geminidr/doc/usermanuals/examples/recipes/gmos_sq_recipes.rst
new file mode 100644
index 0000000000..915a7969af
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/gmos_sq_recipes.rst
@@ -0,0 +1,19 @@
+.. gmos_sq_recipes.rst
+
+.. _gmos_sq_recipes:
+
+********************
+GMOS Science Recipes
+********************
+
+.. toctree::
+ :maxdepth: 2
+
+ Recipes for GMOS Calibrations (All Modes)
+
+.. toctree::
+ :maxdepth: 1
+
+ gmos_img_sq_recipes
+ .. gmos_ls_sq_recipes
+ .. gmos_ns_sq_recipes
\ No newline at end of file
diff --git a/geminidr/doc/usermanuals/examples/recipes/recipes_index.rst b/geminidr/doc/usermanuals/examples/recipes/recipes_index.rst
new file mode 100644
index 0000000000..01fa001c84
--- /dev/null
+++ b/geminidr/doc/usermanuals/examples/recipes/recipes_index.rst
@@ -0,0 +1,16 @@
+.. recipes_index.rst
+
+.. _recipes_index:
+
+*****************
+Recipes Reference
+*****************
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+
+ gmos_sq_recipes
+.. niri_sq_recipes
+
diff --git a/geminidr/doc/usermanuals/index.rst b/geminidr/doc/usermanuals/index.rst
new file mode 100644
index 0000000000..f6176e0168
--- /dev/null
+++ b/geminidr/doc/usermanuals/index.rst
@@ -0,0 +1,21 @@
+.. DRAGONS Data Reduction User Reference documentation master file, created by
+ sphinx-quickstart on Thu Jan 13 15:47:04 2022.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+DRAGONS Data Reduction User Reference
+=====================================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ primitives/primitives_index
+ recipes/recipes_index
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/geminidr/doc/usermanuals/make.bat b/geminidr/doc/usermanuals/make.bat
new file mode 100644
index 0000000000..153be5e2f6
--- /dev/null
+++ b/geminidr/doc/usermanuals/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/geminidr/doc/usermanuals/primitives/generated-doc/.notempty b/geminidr/doc/usermanuals/primitives/generated-doc/.notempty
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/geminidr/doc/usermanuals/primitives/primitives_index.rst b/geminidr/doc/usermanuals/primitives/primitives_index.rst
new file mode 100644
index 0000000000..7fa1b6b1ab
--- /dev/null
+++ b/geminidr/doc/usermanuals/primitives/primitives_index.rst
@@ -0,0 +1,13 @@
+.. primitives_index.rst
+
+.. _primitives_index:
+
+********************
+Primitives Reference
+********************
+
+.. toctree::
+ :maxdepth: 1
+
+.. primitive_subtractOverscan
+
diff --git a/geminidr/doc/usermanuals/recipes/generated_doc/.not_empty b/geminidr/doc/usermanuals/recipes/generated_doc/.not_empty
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/geminidr/doc/usermanuals/recipes/recipes_index.rst b/geminidr/doc/usermanuals/recipes/recipes_index.rst
new file mode 100644
index 0000000000..fb89405902
--- /dev/null
+++ b/geminidr/doc/usermanuals/recipes/recipes_index.rst
@@ -0,0 +1,19 @@
+.. recipes_index.rst
+
+.. _recipes_index:
+
+*****************
+Recipes Reference
+*****************
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+.. gmos_sq_recipes
+.. f2_sq_recipes
+.. gnirs_sq_recipes
+.. gsaoi_sq_recipes
+.. niri_sq_recipes
+
+
diff --git a/geminidr/doc/usermanuals/utility_scripts/generate_primdoc.py b/geminidr/doc/usermanuals/utility_scripts/generate_primdoc.py
index 640789c97d..ba1245435a 100755
--- a/geminidr/doc/usermanuals/utility_scripts/generate_primdoc.py
+++ b/geminidr/doc/usermanuals/utility_scripts/generate_primdoc.py
@@ -9,6 +9,9 @@
For this to work, the separators in the main sphinx document must be
followed exactly because the generated files use that convention.
+
+Usage:
+ generate_primdoc -d primitives/generated-doc
"""
import sys
@@ -134,6 +137,15 @@ def find_prims_params(module):
paramclasses_in_module = []
for name, clss in inspect.getmembers(module, inspect.isclass):
+ # exceptions to skip
+ if clss.__module__ == 'geminidr.core.parameters_generic':
+ continue
+ # This parameter module is not associated with any primitive
+ # module. Just skip it.
+ if name == 'core_stacking_config':
+ continue
+ # This is a utility parameter config class. Skip it.
+
if clss.__module__ == module.__name__ and hasattr(clss, 'tagset'):
primclasses_in_module.append(clss)
elif issubclass(clss, config.Config):
@@ -166,7 +178,12 @@ def write_primitives_rst(primclass, destination):
# first the docstring
filename = f'{rootfilename}_docstring.rst'
f = open(os.path.join(destination, filename), 'w')
- f.write(textwrap.dedent(getattr(primclass_instance, name).__doc__))
+ docstring = getattr(primclass_instance, name).__doc__
+ if docstring:
+ f.write(textwrap.dedent(docstring))
+ else: # no docstring
+ f.write('')
+ print('WARNING: no docstring for ', primclass.__name__, name)
f.close()
# then the overridden parameters
@@ -176,7 +193,8 @@ def write_primitives_rst(primclass, destination):
f.write(PARAMHEADER)
for k, v in params.items():
if not k.startswith("debug"):
- f.write(f'{k:20s} {v!r:20s} {params.doc(k)}\n')
+ formatted_doc = params.doc(k).replace('\n', '\n ')
+ f.write(f' {k:20s} {v!r:20s} {formatted_doc}\n')
f.close()
return
@@ -210,12 +228,13 @@ def write_parameters_rst(paramclass, destination, module):
rootfilename = f'{primmod.__name__}.{clss.__name__}.{associated_primname}'
- filename = f'{rootfilename}-param.rst'
+ filename = f'{rootfilename}_param.rst'
f = open(os.path.join(destination, filename), 'w')
f.write(PARAMHEADER)
for k, v in params.items():
if not k.startswith("debug"):
- f.write(f'{k:20s} {v!r:20s} {params.doc(k)}\n')
+ formatted_doc = params.doc(k).replace('\n', '\n ')
+ f.write(f' {k:20s} {v!r:20s} {formatted_doc}\n')
f.close()
return
@@ -240,6 +259,7 @@ def main(argv=None):
+
## KL Development Notes
# Parameters classes. I will need to do module name parsing to associate with
# the primitive.
@@ -259,4 +279,7 @@ def main(argv=None):
# For the parameters doc, I need to add only a parameter section to the doc when
# only the parameters or defaults are changed. Eg. if everything else is as
-# the generic, just different defaults, no point in repeating the docstring.
\ No newline at end of file
+# the generic, just different defaults, no point in repeating the docstring.
+
+# make testdoc
+# utility_scripts/generate_primdoc.py core gmos -d testdoc
\ No newline at end of file
diff --git a/geminidr/doc/usermanuals/utility_scripts/generate_recipedoc.py b/geminidr/doc/usermanuals/utility_scripts/generate_recipedoc.py
new file mode 100755
index 0000000000..a2ebbc65c6
--- /dev/null
+++ b/geminidr/doc/usermanuals/utility_scripts/generate_recipedoc.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+
+"""
+Generate .rst files to document the recipes. The .rst files are
+meant to be included in the sphinx doc. The script scans geminidr and
+find all the recipes and generate one rst for each.
+
+For this to work, the section separators in the main sphinx document
+must be followed exactly because the generated files use that convention.
+"""
+
+import sys
+import argparse
+import re
+
+import os.path
+import pkgutil
+from importlib import import_module
+import types
+import inspect
+import textwrap
+
+SHORT_DESCRIPTION = "General documentation for recipes."
+
+DOCUMENTED_INSTPKG = {'f2', 'gmos', 'gnirs', 'gsaoi', 'niri'}
+DRPKG = 'geminidr'
+
+def parse_args(command_line_args):
+ """
+ Parse the command line.
+ """
+ parser = argparse.ArgumentParser(description=SHORT_DESCRIPTION)
+ parser.add_argument('pkgs', type=str, nargs="*",
+ help="List of packages to generate, eg. 'gmos'. "
+ "If none specified, every packages in 'geminidr'"
+ " will be generated.")
+ parser.add_argument('--destination', '-d', nargs=1, dest='dest',
+ type=str, default='.', action='store', required=False,
+ help='Destination directory for the output files')
+ parser.add_argument('--context', nargs=1, dest='context', type=str,
+ default='sq', action='store', required=False,
+ help='Which type of recipes? qa, ql, or sq')
+ parser.add_argument('--verbose', '-v', default=False, action='store_true',
+ help='Toggle verbose mode')
+ parser.add_argument('--debug', default=False, action='store_true',
+ help='Toggle debug mode')
+
+ args = parser.parse_args(command_line_args)
+ if isinstance(args.dest, str):
+ args.dest = [args.dest]
+ if isinstance(args.context, str):
+ args.context = [args.context]
+
+ if args.debug:
+ print(args)
+
+ return args
+
+def generate_recipedoc(documented_instpkg, destination, context):
+ """
+ Primary function to generate the recipe rst documentation.
+ """
+ instpkgs = get_matching_instpkg(documented_instpkg, DRPKG)
+
+ for instpkg in instpkgs:
+ # get list of module (name). those are the recipe libraries.
+ modulenames = get_list_of_recipe_modules(instpkg, DRPKG, context)
+
+ # keyed on recipe name
+ # recipename_key = {'function': func, # the local one
+ # 'tagssets': [tagset1, tagset2, ..],
+ # 'default' : None/tagsets}
+
+ recipes_to_document = {}
+
+ for modulename in modulenames:
+ #print(modulename)
+ module = import_module(modulename)
+
+ # Get the list of recipes (will need name, docstring, content)
+ recipes_in_module = find_recipes(module)
+ #print(recipes_in_module)
+ for recipe in recipes_in_module:
+ write_recipe_rst(recipe, modulename, destination)
+
+
+ # print("recipe:", recipe)
+ # print("module:",inspect.getmodule(recipe['function']))
+ # try:
+ # print("tags:",module.recipe_tags)
+ # except AttributeError:
+ # if 'recipes_common' in modulename:
+ # pass
+ # else:
+ # raise
+ # print()
+ # recipename = recipe['function'].__name__
+ # mod_recipe_key = f'{modulename}.{recipename}'
+ # if mod_recipe_key not in recipes_to_document:
+ # recipes_to_document[mod_recipe_key] = {'function': None,
+ # 'tagsets': None,
+ # 'default': False}
+ # # if recipe['origin'] == 'local':
+ # # recipes_to_document[recipename]['function'] = recipe['function']
+ # recipes_to_document[mod_recipe_key]['function'] = recipe['function']
+ #
+ # try:
+ # recipes_to_document[mod_recipe_key]['tagsets'] = module.recipe_tags
+ # except AttributeError:
+ # if 'recipes_common' in modulename:
+ # pass
+ # else:
+ # raise
+ #
+ # if recipe['default']:
+ # recipes_to_document[mod_recipe_key]['default'] = True
+
+ # for recipe in recipes_to_document:
+ # print("recipe name: ", recipes_to_document[recipe]['function'].__name__)
+ # print("module: ", inspect.getmodule(recipes_to_document[recipe]['function']))
+ # print("content of 'recipe' key:", recipes_to_document[recipe])
+ #break
+
+ return
+
+def get_matching_instpkg(documented_instpkg, drpkg):
+ """
+ Walkthrough the drpkg and confirm that the requested instrument
+ packages are in the approved list and are indeed packages.
+ """
+ drpkg_mod = import_module(drpkg)
+ drpkg_importer = pkgutil.ImpImporter(drpkg_mod.__path__[0])
+ instpkgs = []
+ for pkgname, ispkg in drpkg_importer.iter_modules():
+ if ispkg:
+ if pkgname in documented_instpkg:
+ instpkgs.append(pkgname)
+
+ return instpkgs
+
+def get_list_of_recipe_modules(instpkg, drpkg, context):
+ """
+ Find the names of all the modules in this instrument package.
+ Keep only first level modules, it does not look in packages.
+ """
+ instpkg_module = import_module(os.extsep.join([drpkg, instpkg, 'recipes', context]))
+ instpkg_importer = pkgutil.ImpImporter(instpkg_module.__path__[0])
+ modulenames = []
+ for modulename, ispkg in instpkg_importer.iter_modules():
+ if ispkg:
+ continue
+ modulenames.append(os.extsep.join([instpkg_module.__name__, modulename]))
+
+ return modulenames
+
+
+def find_recipes(module):
+ recipes_in_module = []
+
+ all_names = []
+ for name, func in inspect.getmembers(module, inspect.isfunction):
+
+ try:
+ tags = module.recipe_tags
+ except AttributeError:
+ if 'recipes_common' in module.__name__:
+ tags = None
+ else:
+ raise
+
+ if inspect.getmodule(func) == module:
+ origin = 'local'
+ else:
+ origin = 'imported'
+
+ entry = {'function': func,
+ 'tags': tags,
+ 'origin': origin,
+ 'default': False}
+
+ if name == '_default':
+ entry['default'] = True
+
+ if func.__name__ in all_names:
+ i = all_names.index(func.__name__)
+ if recipes_in_module[i]['default']:
+ if entry['default']: # 2 defaults, something is wrong
+ raise
+ # else do skip this duplicate, keep the default
+ else:
+ if entry['default']:
+ dummy = all_names.pop(i)
+ dummy = recipes_in_module.pop(i)
+ all_names.append(func.__name__)
+ recipes_in_module.append(entry)
+ else: # same name, none default, something is wrong
+ raise
+ else:
+ all_names.append(func.__name__)
+ recipes_in_module.append(entry)
+
+ return recipes_in_module
+
+
+def write_recipe_rst(recipe, modulename, destination):
+ """
+ Format the recipe information for importing into the rst recipe template.
+
+ modulename is used for unique file name when a recipe is imported.
+ Otherwise, the module one gets from inspecting the function is the parent
+ module where the recipe really lives.
+ """
+
+ # Extract info from "recipe"
+
+ # Name, modules, tags
+ recipename = recipe['function'].__name__
+ recipetags = recipe['tags']
+ if recipe['origin'] == 'imported':
+ recipe_library = f'{modulename}\n'
+ recipe_imported = f'{inspect.getmodule(recipe["function"]).__name__}'
+ else:
+ recipe_library = modulename
+
+ # Format the docstring to have the parameters in a code block.
+ docstring = recipe['function'].__doc__
+ if docstring:
+ noindent_docstring = textwrap.dedent(docstring)
+ param_regex = r'\b(Parameters\s+-*[\w\s().,;:-]+)'
+ param_section = textwrap.indent(
+ re.search(param_regex, noindent_docstring)[0],
+ 4 * " ")
+ formatted_docstring = re.sub(param_regex, f'::\n\n{param_section}',
+ noindent_docstring)
+ else: # no docstring
+ formatted_docstring = None
+ print('WARNING: no docstring for ', modulename, recipename)
+
+ # The source includes the docstring, we want just the recipe,
+ # regex sub the docstring out.
+ # regex from:
+ # https://stackoverflow.com/questions/59270042/efficent-way-to-remove-docstring-with-regex
+ # TODO: regex for the ''' ''' style too.
+ source_with_doc = inspect.getsource(recipe['function'])
+ doc_reg = r'\b(def.+|class.+)\s+"{3}[\w\s()"\'`.,;:-]+"{3}'
+ result = re.search(doc_reg, source_with_doc)
+ source = re.sub(doc_reg, r'\1', source_with_doc)
+
+ # define filename and open it.
+ filename = f'{modulename}.{recipename}.rst'
+ f = open(os.path.join(destination, filename), 'w')
+
+ f.write(f'{recipename}\n')
+ ndelim = len(recipename)
+ f.write(f'{"="*ndelim}\n\n')
+
+ f.write(f'| **Recipe Library**: {recipe_library}')
+ if recipe['origin'] == 'imported':
+ f.write(f'| **Recipe Imported From**: {recipe_imported}')
+ f.write(f'\n| **Astrodata Tags**: {recipetags}\n')
+
+ if formatted_docstring:
+ f.write(f'{formatted_docstring}\n')
+
+ #f.write(f'**Recipe**::\n\n')
+ f.write(f'::\n\n')
+ f.write(f'{textwrap.indent(source, 4*" ")}\n')
+
+ f.close()
+
+
+
+
+ return
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv[1:]
+
+ args = parse_args(argv)
+
+ if args.pkgs:
+ documented_instpkg = set(args.pkgs)
+ else:
+ documented_instpkg = DOCUMENTED_INSTPKG
+
+ if not os.path.isdir(args.dest[0]):
+ os.makedirs(args.dest[0])
+
+ generate_recipedoc(documented_instpkg, args.dest[0], args.context[0])
+
+if __name__ == '__main__':
+ sys.exit(main())
+
+
diff --git a/geminidr/gmos/primitives_gmos.py b/geminidr/gmos/primitives_gmos.py
index 14d6ab25c6..7e987b3126 100644
--- a/geminidr/gmos/primitives_gmos.py
+++ b/geminidr/gmos/primitives_gmos.py
@@ -233,10 +233,10 @@ def subtractOverscan(self, adinputs=None, **params):
region be a vertical strip) is determined in one of the following
ways, according to the *function* and *order* parameters:
- "poly": a polynomial of degree *order* (1=linear, etc)
- "spline": using *order* equally-sized cubic spline pieces or, if
+ :"poly": a polynomial of degree *order* (1=linear, etc)
+ :"spline": using *order* equally-sized cubic spline pieces or, if
order=None or 0, a spline that provides a reduced chi^2=1
- "none": no function is fit, and the value for each row is determined
+ :"none": no function is fit, and the value for each row is determined
by the overscan pixels in that row
The fitting is done iteratively but, in the first instance, a running