aboutsummaryrefslogtreecommitdiff
path: root/noao/artdata/t_mknoise.x
diff options
context:
space:
mode:
Diffstat (limited to 'noao/artdata/t_mknoise.x')
-rw-r--r--noao/artdata/t_mknoise.x577
1 files changed, 577 insertions, 0 deletions
diff --git a/noao/artdata/t_mknoise.x b/noao/artdata/t_mknoise.x
new file mode 100644
index 00000000..59e7258a
--- /dev/null
+++ b/noao/artdata/t_mknoise.x
@@ -0,0 +1,577 @@
+include <error.h>
+include <imhdr.h>
+include <mach.h>
+
+define LEN_UA 20000 # Maximum user header
+define LEN_COMMENT 70 # Maximum comment length
+
+# Cosmic ray data structure
+define LEN_MKO 4
+define MKO_X Memi[$1] # X position
+define MKO_Y Memi[$1+1] # Y position
+define MKO_Z Memi[$1+2] # Flux
+define MKO_SORT Memi[$1+3] # Sort index
+
+
+# T_MKNOISE -- Add cosmic rays and possion and readout noise to images.
+# New images may be created or noise added to existing images.
+# The noise is not completely random for reasons of speed.
+
+procedure t_mknoise ()
+
+int ilist # Input image list
+int olist # Output image list
+int objects # List of cosmic ray files
+int nl # Number of lines
+int nc # Number of columns
+real background # Background level
+real gain # Gain (electrons/DN)
+int ranbuf # Random number buffer size
+real rdnoise # Read noise (in electrons)
+bool poisson # Add Poisson noise?
+long seed # Random number seed
+int nobjects # Number of random cosmic rays
+real energy # Maximum random energy (electrons)
+bool cmmts # Add comments?
+
+bool new, fcmmts
+long seed1
+real x, y, z, dmin, dmax
+int i, j, k, l, nx, ny, nlines, c1, c2, c3, c4, l1, l2, l3, l4, irbuf, ipbuf
+pointer sp, input, output, fname, comment, rbuf, pbuf
+pointer in, out, buf, obuf, lines, newlines, obj, ptr1, ptr2
+pointer mko, mkt
+
+long clgetl(), clktime()
+bool clgetb(), streq()
+int imtopenp(), imtlen(), imtgetim()
+int clgeti(), access(), nowhite(), open(), fscan(), nscan()
+real clgetr(), urand()
+pointer immap(), imgl2r(), impl2r()
+pointer mkt_star()
+errchk open, immap, imgl2r, impl2r, malloc, realloc, mkt_gstar
+
+int mko_compare()
+extern mko_compare
+pointer mko_sort
+common /mko_qsort/ mko_sort
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (comment, max (SZ_FNAME,LEN_COMMENT), TY_CHAR)
+
+ # Get parameters which apply to all images.
+ ilist = imtopenp ("input")
+ olist = imtopenp ("output")
+ objects = imtopenp ("cosrays")
+ background = clgetr ("background")
+ gain = clgetr ("gain")
+ ranbuf = clgeti ("ranbuf")
+ if (ranbuf == 0)
+ ranbuf = -1
+ rdnoise = clgetr ("rdnoise") / gain
+ if (rdnoise > 0. && ranbuf > 0)
+ call salloc (rbuf, ranbuf, TY_REAL)
+ poisson = clgetb ("poisson")
+ if (poisson && ranbuf > 0)
+ call salloc (pbuf, ranbuf, TY_REAL)
+ seed = clgetl ("seed")
+ if (IS_INDEFL(seed))
+ seed1 = seed1 + clktime (long (0))
+ else
+ seed1 = seed
+ cmmts = clgetb ("comments")
+
+ if (imtlen (ilist) == 0)
+ call error (1, "No input image list")
+
+ # Loop through input, output, and cosmic ray lists.
+ # Missing output images take the input image name.
+ # The cosmic ray list will repeat if shorter than input list.
+
+ Memc[fname] = EOS
+ while (imtgetim (ilist, Memc[input], SZ_FNAME) != EOF) {
+ if (imtgetim (olist, Memc[output], SZ_FNAME) == EOF)
+ call strcpy (Memc[input], Memc[output], SZ_FNAME)
+ i = imtgetim (objects, Memc[fname], SZ_FNAME)
+
+ # Map images. Check for new, existing, and in-place images.
+ if (streq (Memc[input], Memc[output])) {
+ ifnoerr (in = immap (Memc[input], READ_WRITE, LEN_UA)) {
+ out = in
+ new = false
+ } else {
+ iferr (out = immap (Memc[output], NEW_IMAGE, LEN_UA)) {
+ call erract (EA_WARN)
+ next
+ }
+ in = out
+
+ call clgstr ("header", Memc[comment], SZ_FNAME)
+ iferr (call mkh_header (out, Memc[comment], true, false))
+ call erract (EA_WARN)
+
+ IM_NDIM(in) = 2
+ IM_LEN(in,1) = clgeti ("ncols")
+ IM_LEN(in,2) = clgeti ("nlines")
+ IM_PIXTYPE(in) = TY_REAL
+ call clgstr ("title", IM_TITLE(out), SZ_IMTITLE)
+ new = true
+ }
+ } else {
+ iferr (in = immap (Memc[input], READ_ONLY, LEN_UA)) {
+ call erract (EA_WARN)
+ next
+ }
+ iferr (out = immap (Memc[output], NEW_COPY, in)) {
+ call erract (EA_WARN)
+ call imunmap (in)
+ next
+ }
+ new = false
+ }
+ nc = IM_LEN(in,1)
+ nl = IM_LEN(in,2)
+ IM_MIN(out) = MAX_REAL
+ IM_MAX(out) = -MAX_REAL
+
+ call imaddr (out, "gain", gain)
+ call imaddr (out, "rdnoise", rdnoise * gain)
+
+ # Read the object list.
+ call malloc (mko, LEN_MKO, TY_STRUCT)
+ call mkt_init ()
+
+ # Set cosmic ray templates.
+ mkt = mkt_star ("gaussian")
+
+ # Read the object list. If none or a nonexistent list is given
+ # and a number of random events is specified then generate them.
+ # If a nonexistent object list is given then write the random
+ # events out.
+
+ fcmmts = false
+ energy = INDEF
+ nobjects = 0
+ i = nowhite (Memc[fname], Memc[fname], SZ_FNAME)
+ if (access (Memc[fname], 0, 0) == YES) {
+ i = open (Memc[fname], READ_ONLY, TEXT_FILE)
+ while (fscan (i) != EOF) {
+ call gargr (x)
+ call gargr (y)
+ call gargr (z)
+ if (nscan() < 3) {
+ fcmmts = true
+ next
+ }
+ if (x < 1 || x > nc || y < 1 || y > nl)
+ next
+ if (nobjects == 0) {
+ j = 100
+ call malloc (MKO_X(mko), j, TY_REAL)
+ call malloc (MKO_Y(mko), j, TY_REAL)
+ call malloc (MKO_Z(mko), j, TY_REAL)
+ call malloc (MKO_SORT(mko), j, TY_INT)
+ } else if (nobjects == j) {
+ j = j + 100
+ call realloc (MKO_X(mko), j, TY_REAL)
+ call realloc (MKO_Y(mko), j, TY_REAL)
+ call realloc (MKO_Z(mko), j, TY_REAL)
+ call realloc (MKO_SORT(mko), j, TY_INT)
+ }
+
+ Memr[MKO_X(mko)+nobjects] = x
+ Memr[MKO_Y(mko)+nobjects] = y
+ Memr[MKO_Z(mko)+nobjects] = z / gain
+ Memi[MKO_SORT(mko)+nobjects] = nobjects
+ nobjects = nobjects + 1
+ }
+ call close (i)
+ } else {
+ nobjects = clgeti ("ncosrays")
+ if (nobjects > 0) {
+ energy = clgetr ("energy") / gain
+ call malloc (MKO_X(mko), nobjects, TY_REAL)
+ call malloc (MKO_Y(mko), nobjects, TY_REAL)
+ call malloc (MKO_Z(mko), nobjects, TY_REAL)
+ call malloc (MKO_SORT(mko), nobjects, TY_INT)
+ do i = 0, nobjects-1 {
+ Memr[MKO_X(mko)+i] = 1 + (nc-1) * urand (seed1)
+ Memr[MKO_Y(mko)+i] = 1 + (nl-1) * urand (seed1)
+ Memr[MKO_Z(mko)+i] = energy * urand (seed1)
+ Memi[MKO_SORT(mko)+i] = i
+ }
+ if (Memc[fname] != EOS) {
+ i = open (Memc[fname], NEW_FILE, TEXT_FILE)
+ do j = 0, nobjects-1 {
+ call fprintf (i, "%g %g %g\n")
+ call pargr (Memr[MKO_X(mko)+j])
+ call pargr (Memr[MKO_Y(mko)+j])
+ call pargr (gain * Memr[MKO_Z(mko)+j])
+ }
+ call close (i)
+ }
+ }
+ }
+
+ # If no objects are requested then do the image I/O
+ # line by line to add requested background and noise
+ # and then go on to the next image.
+
+ irbuf = 0
+ ipbuf = 0
+ if (nobjects == 0) {
+ call mkt_free ()
+ call mfree (mko, TY_STRUCT)
+
+ if (new) {
+ do i = 1, nl {
+ obuf = impl2r (out, i)
+ if (background == 0.)
+ call aclrr (Memr[obuf], nc)
+ else
+ call amovkr (background, Memr[obuf], nc)
+ if (poisson)
+ call mkpnoise (Memr[obuf], Memr[obuf], nc, 0.,
+ gain, pbuf, ranbuf, ipbuf, seed1)
+ if (rdnoise > 0.)
+ call mkrnoise (Memr[obuf], nc, rdnoise,
+ rbuf, ranbuf, irbuf, seed1)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ }
+ } else {
+ do i = 1, nl {
+ obuf = impl2r (out, i)
+ ptr1 = imgl2r (in, i)
+ if (background == 0.)
+ call amovr (Memr[ptr1], Memr[obuf], nc)
+ else
+ call aaddkr (Memr[ptr1], background,
+ Memr[obuf], nc)
+ if (poisson)
+ call mkpnoise (Memr[obuf], Memr[obuf], nc, 0.,
+ gain, pbuf, ranbuf, ipbuf, seed1)
+ if (rdnoise > 0.)
+ call mkrnoise (Memr[obuf], nc, rdnoise,
+ rbuf, ranbuf, irbuf, seed1)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ }
+ }
+
+ # Add comment history of task parameters.
+ if (cmmts) {
+ call strcpy ("# ", Memc[comment], LEN_COMMENT)
+ call cnvtime (clktime (0), Memc[comment+2], LEN_COMMENT-2)
+ call mkh_comment (out, Memc[comment])
+ call mkh_comment (out, "begin mknoise")
+ call mkh_comment1 (out, "background", 'r')
+ call mkh_comment1 (out, "gain", 'r')
+ call mkh_comment1 (out, "rdnoise", 'r')
+ call mkh_comment1 (out, "poisson", 'b')
+ call mkh_comment1 (out, "seed", 'i')
+ }
+
+ IM_LIMTIME(out) = IM_MTIME(out) + 1
+ if (in != out)
+ call imunmap (in)
+ call imunmap (out)
+ next
+ }
+
+ # Add the cosmic rays.
+ #
+ # The object list is first sorted in Y for efficiency.
+ # Get buffer of as many lines as possible to minimize random
+ # access and speed up adding the objects. Ideally the whole
+ # image should be in memory but if not we scroll a buffer
+ # using the fact that the objects are ordered in Y.
+ # Use error checking to determine how much memory is available.
+
+ mko_sort = MKO_Y(mko)
+ call qsort (Memi[MKO_SORT(mko)], nobjects, mko_compare)
+
+ for (nlines=nl;; nlines = 0.8 * nlines)
+ ifnoerr (call malloc (buf, nlines * nc, TY_REAL))
+ break
+ call malloc (lines, nlines, TY_INT)
+ call malloc (lines, nlines, TY_INT)
+ call malloc (newlines, nl, TY_INT)
+ call amovki (YES, Memi[newlines], nl)
+
+ # Fill the line buffer.
+ do l = 1, nlines {
+ j = mod (l, nlines)
+ ptr2 = buf + j * nc
+ Memi[lines+j] = l
+ if (new)
+ call aclrr (Memr[ptr2], nc)
+ else
+ call amovr (Memr[imgl2r(in,l)], Memr[ptr2], nc)
+ Memi[newlines+l-1] = NO
+ }
+
+ do i = 0, nobjects-1 {
+ j = Memi[MKO_SORT(mko)+i]
+ x = Memr[MKO_X(mko)+j]
+ y = Memr[MKO_Y(mko)+j]
+ z = Memr[MKO_Z(mko)+j]
+
+ call mkt_gstar (mkt, obj, nx, ny, x, y, z)
+
+ c1 = x - nx/2 + 0.5
+ c2 = c1 + nx - 1
+ c3 = max (1, c1)
+ c4 = min (nc, c2)
+ l1 = y - ny/2 + 0.5
+ l2 = l1 + ny - 1
+ l3 = max (1, l1)
+ l4 = min (nl, l2)
+ k = c4 - c3 + 1
+ ptr1 = obj + (l3 - l1) * nx + c3 - c1
+ c3 = c3 - 1
+ do l = l3, l4 {
+ j = mod (l, nlines)
+ if (l != Memi[lines+j]) {
+ ptr2 = buf + j * nc
+ obuf = impl2r (out, Memi[lines+j])
+ call amovr (Memr[ptr2], Memr[obuf], nc)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ Memi[lines+j] = l
+ if (Memi[newlines+l-1] == NO)
+ call amovr (Memr[imgl2r(out,l)], Memr[ptr2], nc)
+ else if (new)
+ call aclrr (Memr[ptr2], nc)
+ else
+ call amovr (Memr[imgl2r(in,l)], Memr[ptr2], nc)
+ Memi[newlines+l-1] = NO
+ }
+ ptr2 = buf + j * nc + c3
+ call aaddr (Memr[ptr1], Memr[ptr2], Memr[ptr2], k)
+ ptr1 = ptr1 + nx
+ }
+ }
+
+ # Flush out the line buffer. If the whole image is in memory then
+ # we can add the background and noise before flushing the data.
+ # Otherwise, we need a second pass reading the image in line
+ # by line and adding the background and noise.
+
+ if (nlines == nl) {
+ do i = 1, nlines {
+ j = mod (i, nlines)
+ ptr2 = buf + j * nc
+ l = Memi[lines+j]
+ if (background != 0.)
+ call aaddkr (Memr[ptr2], background, Memr[ptr2], nc)
+ if (poisson)
+ call mkpnoise (Memr[ptr2], Memr[ptr2], nc, 0., gain,
+ pbuf, ranbuf, ipbuf, seed1)
+ if (rdnoise > 0.)
+ call mkrnoise (Memr[ptr2], nc, rdnoise,
+ rbuf, ranbuf, irbuf, seed1)
+ obuf = impl2r (out, l)
+ call amovr (Memr[ptr2], Memr[obuf], nc)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ }
+ } else {
+ do i = 1, nlines {
+ j = mod (i, nlines)
+ ptr2 = buf + j * nc
+ l = Memi[lines+j]
+ obuf = impl2r (out, l)
+ call amovr (Memr[ptr2], Memr[obuf], nc)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ }
+
+ call imflush (out)
+ do i = 1, nl {
+ obuf = impl2r (out, i)
+ ptr1 = imgl2r (out, i)
+ if (background == 0.)
+ call amovr (Memr[ptr1], Memr[obuf], nc)
+ else
+ call aaddkr (Memr[ptr1], background, Memr[obuf], nc)
+ if (poisson)
+ call mkpnoise (Memr[obuf], Memr[obuf], nc, 0., gain,
+ pbuf, ranbuf, ipbuf, seed1)
+ if (rdnoise > 0.)
+ call mkrnoise (Memr[obuf], nc, rdnoise,
+ rbuf, ranbuf, irbuf, seed1)
+ call alimr (Memr[obuf], nc, dmin, dmax)
+ IM_MIN(out) = min (IM_MIN(out), dmin)
+ IM_MAX(out) = max (IM_MAX(out), dmax)
+ }
+ }
+
+ # Since each image is different and the object lists may be
+ # different we free most of the memory within the image list
+ # loop.
+
+ call mfree (buf, TY_REAL)
+ call mfree (lines, TY_INT)
+ call mkt_free ()
+ call mfree (MKO_X(mko), TY_REAL)
+ call mfree (MKO_Y(mko), TY_REAL)
+ call mfree (MKO_Z(mko), TY_REAL)
+ call mfree (MKO_SORT(mko), TY_INT)
+ call mfree (mko, TY_STRUCT)
+
+ # Add comment history of task parameters.
+ if (cmmts) {
+ call strcpy ("# ", Memc[comment], LEN_COMMENT)
+ call cnvtime (clktime (0), Memc[comment+2], LEN_COMMENT-2)
+ call mkh_comment (out, Memc[comment])
+ call mkh_comment (out, "begin mknoise")
+ call mkh_comment1 (out, "background", 'r')
+ call mkh_comment1 (out, "gain", 'r')
+ call mkh_comment1 (out, "rdnoise", 'r')
+ call mkh_comment1 (out, "poisson", 'b')
+ call mkh_comment1 (out, "seed", 'i')
+ if (fcmmts && Memc[fname] != EOS) {
+ call mkh_comment1 (out, "cosrays", 's')
+ i = open (Memc[fname], READ_ONLY, TEXT_FILE)
+ while (fscan (i) != EOF) {
+ call gargr (x)
+ call gargr (y)
+ call gargr (z)
+ if (nscan() < 3) {
+ call reset_scan ()
+ call gargstr (Memc[comment], LEN_COMMENT)
+ call mkh_comment (out, Memc[comment])
+ }
+ }
+ call close (i)
+ }
+ call sprintf (Memc[comment], LEN_COMMENT,
+ "%9tncosrays%24t%d")
+ call pargi (nobjects)
+ call mkh_comment (out, Memc[comment])
+ if (!IS_INDEF (energy))
+ call mkh_comment1 (out, "energy", 'r')
+ call mkh_comment1 (out, "radius", 'r')
+ call mkh_comment1 (out, "ar", 'r')
+ call mkh_comment1 (out, "pa", 'r')
+ }
+
+ IM_LIMTIME(out) = IM_MTIME(out) + 1
+ if (in != out)
+ call imunmap (in)
+ call imunmap (out)
+
+ }
+
+ call imtclose (ilist)
+ call imtclose (olist)
+ call sfree (sp)
+end
+
+
+# MKRNOISE -- Make gaussian read noise. A buffer of saved noise values may be
+# used to greatly speed up the noise. In this case new noise values
+# are randomly chosen from the buffer.
+
+procedure mkrnoise (data, ndata, rdnoise, buf, nbuf, ibuf, seed)
+
+real data[ndata] # Output data
+int ndata # Number of data points
+real rdnoise # Read noise (in data units)
+pointer buf # Random value buffer
+int nbuf # Size of random value buffer (may be zero)
+int ibuf # Number of random numbers saved
+ # ibuf < nbuf Save new values
+ # ibuf = nbuf Use saved values
+ # ibuf > nbuf Use new values
+long seed # Random number seed
+
+int i
+real val, urand(), gasdev()
+
+begin
+ if (ibuf == nbuf)
+ do i = 1, ndata
+ data[i] = data[i] + Memr[buf+int(nbuf*urand (seed))]
+ else if (ibuf > nbuf)
+ do i = 1, ndata
+ data[i] = data[i] + rdnoise * gasdev (seed)
+ else {
+ do i = 1, ndata {
+ if (ibuf < nbuf) {
+ val = rdnoise * gasdev (seed)
+ Memr[buf+ibuf] = val
+ ibuf = ibuf + 1
+ } else
+ val = Memr[buf+int(nbuf*urand (seed))]
+ data[i] = data[i] + val
+ }
+ }
+end
+
+
+# MKPNOISE -- Make poisson noise. For speed, values greater than 20
+# use a gaussian approximation with the square root of the value as
+# the sigma. The normalized gaussian values may be saved and reused
+# by random selection to speed things up.
+
+procedure mkpnoise (in, data, ndata, b, g, buf, nbuf, ibuf, seed)
+
+real in[ndata] # Data to add noise
+real data[ndata] # Output data
+int ndata # Number of data points
+real b # Background (in data units)
+real g # Gain
+pointer buf # Random value buffer
+int nbuf # Size of random value buffer (may be zero)
+int ibuf # Number of random numbers saved
+ # ibuf < nbuf Save new values
+ # ibuf = nbuf Use saved values
+ # ibuf > nbuf Use new values
+long seed # Random number seed
+
+int i
+real v, gv, urand(), poidev(), gasdev()
+
+begin
+ if (ibuf == nbuf)
+ do i = 1, ndata {
+ v = g * (in[i] + b)
+ if (v < 20.)
+ data[i] = data[i] + (poidev (v, seed) - v) / g
+ else
+ data[i] = data[i] +
+ sqrt (v) * Memr[buf+int(nbuf*urand(seed))] / g
+ }
+ else if (ibuf > nbuf)
+ do i = 1, ndata {
+ v = g * (in[i] + b)
+ data[i] = data[i] + (poidev (v, seed) - v) / g
+ }
+ else {
+ do i = 1, ndata {
+ v = g * (in[i] + b)
+ if (v < 20.)
+ data[i] = data[i] + (poidev (v, seed) - v) / g
+ else {
+ if (ibuf < nbuf) {
+ gv = gasdev (seed)
+ Memr[buf+ibuf] = gv
+ ibuf = ibuf + 1
+ } else
+ gv = Memr[buf+int(nbuf*urand (seed))]
+ data[i] = data[i] + sqrt (v) * gv / g
+ }
+ }
+ }
+end