From db75b9c1b6dd23381540a3543aa58002160c0af0 Mon Sep 17 00:00:00 2001 From: Sean-Morrison Date: Sun, 8 Dec 2024 16:53:30 -0800 Subject: [PATCH] add boss_drp sql functions --- .../sdss5db/boss_drp/functions/specobjid.sql | 140 ++++++++++++++++++ .../boss_drp/functions/update_specprimary.sql | 103 +++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 schema/sdss5db/boss_drp/functions/specobjid.sql create mode 100644 schema/sdss5db/boss_drp/functions/update_specprimary.sql diff --git a/schema/sdss5db/boss_drp/functions/specobjid.sql b/schema/sdss5db/boss_drp/functions/specobjid.sql new file mode 100644 index 00000000..85d2b15c --- /dev/null +++ b/schema/sdss5db/boss_drp/functions/specobjid.sql @@ -0,0 +1,140 @@ +-- Drop the temporary table if it exists +DROP FUNCTION IF EXISTS boss_drp.BuildSpecObjid; +DROP FUNCTION IF EXISTS boss_drp.EncodeTag; +DROP FUNCTION IF EXISTS boss_drp.UnwrapSpecObjID; + +-- Create or replace the EncodeTag function +CREATE OR REPLACE FUNCTION boss_drp.EncodeTag(run2d VARCHAR, apred VARCHAR) +RETURNS VARCHAR(6) AS $$ +DECLARE + tag VARCHAR; + part1 INT; + part2 INT; + part3 INT; +BEGIN + -- Set the tag based on the values of run2d and apred + IF run2d IS NOT NULL THEN + tag := run2d; + ELSIF apred IS NOT NULL THEN + tag := apred; + ELSE + RETURN '000000'; + END IF; + + -- Check if 'v' is in tag and process accordingly + IF POSITION('v' IN tag) > 0 THEN + tag := REPLACE(tag, 'v', ''); + part1 := COALESCE(NULLIF(SPLIT_PART(tag, '_', 1), ''), '0')::INT; + part2 := COALESCE(NULLIF(SPLIT_PART(tag, '_', 2), ''), '0')::INT; + part3 := COALESCE(NULLIF(SPLIT_PART(tag, '_', 3), ''), '0')::INT; + RETURN CONCAT(TO_CHAR(part1, 'fm00'), TO_CHAR(part2, 'fm00'), TO_CHAR(part3, 'fm00')); + ELSIF POSITION('.' IN tag) > 0 THEN + part1 := COALESCE(NULLIF(SPLIT_PART(tag, '.', 1), ''), '0')::INT; + part2 := COALESCE(NULLIF(SPLIT_PART(tag, '.', 2), ''), '0')::INT; + part3 := COALESCE(NULLIF(SPLIT_PART(tag, '.', 3), ''), '0')::INT; + RETURN CONCAT(TO_CHAR(part1, 'fm00'), TO_CHAR(part2, 'fm00'), TO_CHAR(part3, 'fm00')); + ELSIF POSITION('DR' IN tag) > 0 THEN + tag := REPLACE(tag, 'DR', ''); + RETURN TO_CHAR(CAST(tag AS INT), 'fm000000'); + ELSE + RETURN TO_CHAR(CAST(tag AS INT), 'fm000000'); + END IF; +END; +$$ LANGUAGE plpgsql; + +-- Create or replace the BuildSpecObjid function +CREATE OR REPLACE FUNCTION boss_drp.BuildSpecObjid(sdssid BIGINT, field INT, mjd INT, specobjid NUMERIC(29), coadd VARCHAR, tag VARCHAR) +RETURNS numeric(29) AS $$ +DECLARE + SpecObjID_new VARCHAR; -- Size specifier added for VARCHAR return type +BEGIN + -- Test if specobjid is already defined + IF specobjid is NOT NULL THEN + return specobjid; + END IF; + + IF sdssid = -999 THEN + return NULL; + END IF; + + -- Map coadd values to corresponding codes + coadd := LOWER(coadd); + coadd := CASE + WHEN coadd = 'daily' THEN '00' + WHEN coadd = 'epoch' THEN '01' + WHEN coadd = 'allepoch' THEN '02' + WHEN coadd = 'spiders' THEN '02' + WHEN coadd = 'allvisit' THEN '10' + WHEN coadd = 'allstar' THEN '11' + ELSE '99' -- Default case if none of the above matches + END; + + -- Construct the SpecObjID by concatenating the parameters + SpecObjID_new := CONCAT(CAST(sdssid AS VARCHAR), TO_CHAR(field, 'fm0000000'), CAST(mjd AS VARCHAR), coadd, tag); + RETURN cast(SpecObjID_new as numeric(29)); +END;$$ LANGUAGE plpgsql; + + +-- Create or replace the UnwrapSpecObjID function +CREATE OR REPLACE FUNCTION boss_drp.UnwrapSpecObjID(SID numeric(29)) +RETURNS TABLE (sdssid BIGINT, field INT, mjd INT, coadd VARCHAR, tag VARCHAR, inst VARCHAR) AS $$ +DECLARE + luid INT; +BEGIN + IF LENGTH(CAST(SID AS TEXT)) > 20 THEN + RETURN QUERY SELECT -999, -999, -999, '', '', 'BOSS'; + RETURN; + END IF; + + -- Extract parts of the SID + luid := LENGTH(SID::TEXT); + tag := SUBSTRING(SID::TEXT FROM luid - 6 + 1); + CASE tag + WHEN '000017' THEN tag := 'DR17'; + WHEN '000103' THEN tag := '103'; + WHEN '000104' THEN tag := '104'; + WHEN '000026' THEN tag := '26'; + ELSE + tag := CONCAT_WS('.', + CAST(CAST(SUBSTRING(tag::TEXT FROM 1 FOR 2) AS INT) AS VARCHAR), + CAST(CAST(SUBSTRING(tag::TEXT FROM 3 FOR 2) AS INT) AS VARCHAR), + CAST(CAST(SUBSTRING(tag::TEXT FROM 5 FOR 2) AS INT) AS VARCHAR)); + END CASE; + + coadd := SUBSTRING(SID::TEXT FROM luid - 8 + 1 FOR 2); + mjd := CAST(SUBSTRING(SID::TEXT FROM luid - 13 + 1 FOR 5) AS INT); + field := CAST(SUBSTRING(SID::TEXT FROM luid - 20 + 1 FOR 7) AS INT); + sdssid := CAST(SUBSTRING(SID::TEXT FROM 1 FOR luid - 20) AS BIGINT); + + CASE coadd + WHEN '00' THEN coadd := 'daily'; + WHEN '01' THEN coadd := 'epoch'; + WHEN '02' THEN coadd := 'allepoch'; + -- WHEN '02' THEN coadd := 'spiders'; -- Commented out since it conflicts with 'allepoch' + WHEN '10' THEN coadd := 'allvisit'; + WHEN '11' THEN coadd := 'allstar'; + ELSE coadd := 'undefined'; -- Default case if none of the above matches + END CASE; + + IF coadd IN ('allvisit', 'allstar') THEN + inst := 'apogee'; + ELSIF coadd IN ('daily', 'epoch', 'allepoch', 'spiders') THEN + inst := 'boss'; + tag := REPLACE(tag, '.', '_'); + IF POSITION('_' IN tag) > 0 THEN + tag := CONCAT('v', tag); + ELSE + inst := 'sdss'; + END IF; + ELSE + inst := 'unknown'; + END IF; + + RETURN QUERY SELECT sdssid, field, mjd, coadd, tag, inst; +END; +$$ LANGUAGE plpgsql; + +/* +UPDATE boss_spectrum + SET specobjid = boss_drp.BuildSpecObjid(sdssid, field, mjd, specobjid, coadd, boss_drp.EncodeTag(run2d, apred)); +*/ diff --git a/schema/sdss5db/boss_drp/functions/update_specprimary.sql b/schema/sdss5db/boss_drp/functions/update_specprimary.sql new file mode 100644 index 00000000..813f6477 --- /dev/null +++ b/schema/sdss5db/boss_drp/functions/update_specprimary.sql @@ -0,0 +1,103 @@ +CREATE OR REPLACE FUNCTION boss_drp.update_specprimary( + run2d TEXT, + is_epoch BOOLEAN, + custom_name TEXT DEFAULT NULL, + sdss_id_list BIGINT[] DEFAULT NULL, + is_custom BOOLEAN DEFAULT FALSE +) +RETURNS VOID AS $$ +DECLARE + version_id INTEGER; +BEGIN + -- Log the start of the function + RAISE NOTICE 'Starting update_specprimary with run2d=%, is_epoch=%, custom_name=%, is_custom=%', run2d, is_epoch, custom_name, is_custom; + + -- Find the version_id + SELECT id INTO version_id + FROM boss_drp.boss_version + WHERE run2d = run2d + AND is_epoch = is_epoch + AND (NOT is_custom OR (custom_name IS NOT NULL AND name = custom_name)); + + IF version_id IS NULL THEN + RAISE EXCEPTION 'No version found with run2d=%, is_epoch=%, custom_name=%, is_custom=%', run2d, is_epoch, custom_name, is_custom; + END IF; + + -- Start transaction + BEGIN + -- Check and add temp_zw_primtest and temp_score columns if they don't exist + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'boss_spectrum' AND column_name = 'temp_zw_primtest') THEN + RAISE NOTICE 'Adding temp_zw_primtest column to boss_drp.boss_spectrum'; + EXECUTE 'ALTER TABLE boss_drp.boss_spectrum ADD COLUMN temp_zw_primtest INTEGER'; + END IF; + + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'boss_spectrum' AND column_name = 'temp_score') THEN + RAISE NOTICE 'Adding temp_score column to boss_drp.boss_spectrum'; + EXECUTE 'ALTER TABLE boss_drp.boss_spectrum ADD COLUMN temp_score DOUBLE PRECISION'; + END IF; + + -- Update temp_zw_primtest column based on conditions + RAISE NOTICE 'Updating temp_zw_primtest column based on conditions'; + UPDATE boss_drp.boss_spectrum + SET temp_zw_primtest = CASE + WHEN OBJTYPE LIKE 'GALAXY%' THEN ZWARNING_NOQSO + ELSE ZWARNING + END + WHERE boss_version_id = version_id + AND (sdss_id_list IS NULL OR SDSS_ID = ANY(sdss_id_list)); + + -- Update temp_score column based on conditions + RAISE NOTICE 'Updating temp_score column based on conditions'; + UPDATE boss_drp.boss_spectrum + SET temp_score = ( + (4 * (CASE WHEN SN_MEDIAN > 0 THEN 1 ELSE 0 END)) + + (2 * (CASE WHEN FIELDQUALITY LIKE 'good%' THEN 1 ELSE 0 END)) + + (1 * (CASE WHEN temp_zw_primtest = 0 THEN 1 ELSE 0 END)) + + (CASE WHEN SN_MEDIAN > 0 THEN 1 ELSE 0 END) + ) / (SN_MEDIAN + 1) + WHERE boss_version_id = version_id + AND (sdss_id_list IS NULL OR SDSS_ID = ANY(sdss_id_list)); + + -- Create a CTE for ranking the scores + RAISE NOTICE 'Creating CTE for ranking the scores and using it to update SPECPRIMARY, SPECBOSS, and NSPECOBS columns'; + WITH RankedScores AS ( + SELECT *, ROW_NUMBER() OVER (PARTITION BY SDSS_ID ORDER BY temp_score DESC) AS rank + FROM boss_drp.boss_spectrum + WHERE boss_version_id = version_id + AND (sdss_id_list IS NULL OR SDSS_ID = ANY(sdss_id_list)) + ) + -- Update SPECPRIMARY, SPECBOSS, and NSPECOBS columns based on rankings + UPDATE boss_drp.boss_spectrum + SET SPECPRIMARY = CASE WHEN RS.rank = 1 THEN 1 ELSE 0 END, + SPECBOSS = CASE WHEN RS.rank = 1 THEN 1 ELSE 0 END, + NSPECOBS = CountPerID.nspectobs + FROM RankedScores RS + JOIN ( + SELECT SDSS_ID, COUNT(*) AS nspectobs + FROM boss_drp.boss_spectrum + WHERE boss_version_id = version_id + AND (sdss_id_list IS NULL OR SDSS_ID = ANY(sdss_id_list)) + GROUP BY SDSS_ID + ) CountPerID + ON boss_drp.boss_spectrum.SDSS_ID = CountPerID.SDSS_ID + WHERE boss_drp.boss_spectrum.id = RS.id; + + -- Drop the temporary columns + RAISE NOTICE 'Dropping temporary columns temp_zw_primtest and temp_score'; + EXECUTE 'ALTER TABLE boss_drp.boss_spectrum DROP COLUMN IF EXISTS temp_zw_primtest, DROP COLUMN IF EXISTS temp_score'; + + -- Commit the transaction + COMMIT; + + -- Log the end of the function + RAISE NOTICE 'Completed update_specprimary function'; + + EXCEPTION + WHEN OTHERS THEN + -- Rollback the transaction in case of error + ROLLBACK; + RAISE; + END; + +END; +$$ LANGUAGE plpgsql;