SUBROUTINE SPCONVOL( STATUS ) *+ * Name: * SPCONVOL * Purpose: * Convolve the spatial response attached to an ASTERIX dataset with * a cube or image containing an intrinsic source profile. If a cube * is supplied then the energy axis of the cube must agree with that * of the spatial response. * Language: * FORTRAN * Type of Module: * ADAM A-task * Invocation: * CALL SPCONVOL( STATUS ) * Arguments: * STATUS = INTEGER (Given and Returned) * The global status. * Description: * Convolves each psf element of a spatial response structure with a * user supplied mask. This dataset may be either 2 or 3 dimensional. * Usage: * {routine_name} {parameter_usage} * ADAM Parameters: * INP = UNIV (Read) * Input dataset whose spatial response will be convolved * SOURCE = UNIV (Read) * The source model * Examples: * {routine_example_text} * {routine_example_description} * Pitfalls: * {pitfall_description}... * Notes: * {routine_notes}... * Prior Requirements: * {routine_prior_requirements}... * Side Effects: * {routine_side_effects}... * Algorithm: * {algorithm_description}... * Accuracy: * {routine_accuracy} * Timing: * {routine_timing} * Implementation Status: * {routine_implementation_status} * External Routines Used: * {name_of_facility_or_package}: * {routine_used}... * Implementation Deficiencies: * {routine_deficiencies}... * {machine}-specific features used: * {routine_machine_specifics}... * {DIY_prologue_heading}: * {DIY_prologue_text} * References: * {routine_references}... * Keywords: * {routine_keywords}... * Copyright: * {routine_copyright} * Authors: * DJA: David J. Allan (ROSAT) * {enter_new_authors_here} * History: * 16-Aug-1994 (DJA): * V1.8-0 Original version. * 25-Nov-1994 (DJA): * V1.8-1 User interface now uses USI exclusively. * 25-Apr-1995 (DJA): * V1.8-2 Updated data interfaces. * {enter_changes_here} * Bugs: * {note_any_bugs_here} *- * Type Definitions: IMPLICIT NONE ! No implicit typing * Global Constants: INCLUDE 'SAE_PAR' ! Standard SAE constants INCLUDE 'DAT_PAR' ! Standard HDS constants INCLUDE 'PRM_PAR' ! Standard PRM constants INCLUDE 'PSF_PAR' ! Asterix PSF constants INCLUDE 'MATH_PAR' ! Asterix MATH constants * Status: INTEGER STATUS ! Global status * Local Constants: CHARACTER*(DAT__SZNAM) SRESP ! Spatial response ! object name PARAMETER ( SRESP = 'SPATIAL_RESP' ) INTEGER MXHLINE ! Max lines of history PARAMETER ( MXHLINE = 4 ) * Local Variables: CHARACTER*(DAT__SZLOC) ALOC ! Input ASTERIX structure CHARACTER*80 HTXT(MXHLINE) ! History text CHARACTER*(DAT__SZLOC) RLOC ! Response object REAL CUTOFF ! Cutoff amplitude INTEGER CP_PTR ! Cursor over spatial response INTEGER EBIN ! Loop over energy axis INTEGER IFID ! Input dataset id INTEGER INDX(3) ! Index triplet INTEGER IPSF ! PSF handle INTEGER NELM ! Product of dimensions INTEGER NERBIN ! Response energy bin INTEGER NLINE ! Amount of history text INTEGER NRDIMS(5) ! Old response dims INTEGER NRDPTR ! New response data INTEGER NRNELM ! Product of dimensions INTEGER NPSF ! Number of psfs in response INTEGER NSPBIN ! Number of spatial ! bins in response INTEGER NUSED ! Length of compressed ! response INTEGER PSFSIZ ! New psf size in bytes INTEGER RDIMS(5) ! Old response dims INTEGER RDPTR ! Old response data INTEGER RIPTR ! Old response index INTEGER RNDIM ! Dimensionality of response INTEGER SBIN ! Loop over spatial bins INTEGER SDIMS(5) ! Source model dims INTEGER SDPTR ! Source model data INTEGER SEBIN ! Source model E bin INTEGER SEDPTR ! Source model E slice INTEGER SFID ! Source profile dataset INTEGER SNDIM ! Source model dim'ality INTEGER X_AX,Y_AX,E_AX,T_AX ! Axis numbers INTEGER XSMAX, YSMAX ! Psf extreme sizes LOGICAL EDEP ! Response is energy dependent? LOGICAL OK ! General validity check LOGICAL RADIAL ! Psf is only function of R LOGICAL THERE ! Component exists? * Version CHARACTER*30 VERSION PARAMETER ( VERSION = 'SPCONVOL Version 1.8-2' ) *. * Check inherited global status. IF ( STATUS .NE. SAI__OK ) RETURN * Initialise ASTERIX CALL AST_INIT() * Version annoucement CALL MSG_PRNT( VERSION ) * Get dataset CALL USI_ASSOC( 'INP', 'BinDS', 'UPDATE', IFID, STATUS ) * Locate ASTERIX structure CALL ADI1_LOCAST( IFID, .FALSE., ALOC, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Check to see if response exists CALL DAT_THERE( ALOC, SRESP, THERE, STATUS ) IF ( .NOT. THERE ) THEN STATUS = SAI__ERROR CALL ERR_REP( ' ', 'Dataset does not contain a spatial'/ : /' response - attach one using SPRESP', STATUS ) GOTO 99 END IF * Locate spatial response structure CALL DAT_FIND( ALOC, SRESP, RLOC, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Get intrinsic source profile dataset CALL USI_ASSOC( 'SOURCE', 'BinDS|Array', 'READ', SFID, STATUS ) * Introduce to the psf system CALL PSF_GETSLOT( SFID, IPSF, STATUS ) CALL PSF_CHKAXES( IPSF, STATUS ) IF ( STATUS .NE. SAI__OK ) GOTO 99 * Get its axis identifiers CALL PSF_QAXES( IPSF, X_AX, Y_AX, E_AX, T_AX, STATUS ) * Energy axis must be last at the moment IF ( (E_AX .GT. 0) .AND. (E_AX.NE.3) ) THEN STATUS = SAI__ERROR CALL ERR_REP( ' ', 'Energy dependent source models must have'/ : /' energy has the 3rd dimension - reorder using AXORDER', : STATUS ) GOTO 99 END IF * Get intrinsic profile dimensions CALL BDI_CHK( SFID, 'Data', OK, STATUS ) CALL BDI_GETSHP( SFID, 2, SDIMS, SNDIM, STATUS ) * Check source model is pixel centred IF ( (((SDIMS(1)/2)*2).EQ.SDIMS(1)) .OR. : (((SDIMS(2)/2)*2).EQ.SDIMS(2)) ) THEN STATUS = SAI__ERROR CALL ERR_REP( ' ', 'Source model must be pixel centred', : STATUS ) GOTO 99 END IF * Map source profile data CALL BDI_MAPR( SFID, 'Data', 'READ', SDPTR, STATUS ) * Get expanded response dimensions CALL CMP_GET1I( RLOC, 'DIMS', 5, RDIMS, RNDIM, STATUS ) * Map the index CALL CMP_MAPV( RLOC, 'INDEX', '_INTEGER', 'UPDATE', : RIPTR, NELM, STATUS ) * Map the data CALL CMP_MAPV( RLOC, 'DATA_ARRAY', '_REAL', 'READ', : RDPTR, NELM, STATUS ) * Get radial cutoff CALL CMP_GET0R( RLOC, 'CUTOFF', CUTOFF, STATUS ) * Is it a radial response? CALL CMP_GET0L( RLOC, 'RADIAL', RADIAL, STATUS ) * Is this an energy dependent response? IF ( RADIAL ) THEN EDEP = (RNDIM.GT.3) ELSE EDEP = (RNDIM.GT.4) END IF * Check energy axes are compatible if both the source profile and response * are energy dependent IF ( (E_AX.GT.0) .AND. EDEP ) THEN IF ( SDIMS(E_AX) .NE. RDIMS(RNDIM) ) THEN STATUS = SAI__ERROR CALL ERR_REP( ' ', 'Source model energy dimension differs'/ : /' from that of the response', STATUS ) GOTO 99 END IF * If the response is not energy dependent, but the source model is, then * abort. In the fullness of time we'll do something better here, such as * uprating the response to energy dependence. ELSE IF ( (E_AX.GT.0) .AND. .NOT. EDEP ) THEN STATUS = SAI__ERROR CALL ERR_REP( ' ', 'SPCONVOL cannot yet handle energy '/ : /'dependent source models for energy '/ : /'independent responses', STATUS ) GOTO 99 END IF * Create new response dimensions - these are the same as the old ones * except the first are are increased to handle the increased size of * source profile. CALL ARR_COP1I( RNDIM, RDIMS, NRDIMS, STATUS ) NRDIMS(1) = NRDIMS(1) + (SDIMS(1)/2)*2 NRDIMS(2) = NRDIMS(2) + (SDIMS(2)/2)*2 CALL ARR_SUMDIM( RNDIM, NRDIMS, NRNELM ) * Map workspace for convolved psfs CALL DYN_MAPR( RNDIM, NRDIMS, NRDPTR, STATUS ) CALL ARR_INIT1R( 0.0, NRNELM, %VAL(NRDPTR), STATUS ) * If not energy dependent source model, pad 3rd dimension IF ( E_AX .EQ. 0 ) SDIMS(3) = 1 * Size of energy axis of response IF ( EDEP ) THEN NERBIN = NRDIMS(RNDIM) ELSE NERBIN = 1 NRDIMS(RNDIM+1) = 1 END IF * Fill it with data PSFSIZ = NRDIMS(1)*NRDIMS(2)*VAL__NBR CP_PTR = NRDPTR * Number of psfs in response CALL ARR_SUMDIM( RNDIM-2, NRDIMS(3), NPSF ) * Number of spatial bins NSPBIN = NPSF / NERBIN * Loop over energy axis of response IPSF = 1 DO EBIN = 1, NERBIN * Choose energy slice of source model if appropriate IF ( E_AX .GT. 0 ) THEN SEBIN = EBIN ELSE SEBIN = 1 END IF * Locate slice of source model SEDPTR = SDPTR + (SEBIN-1)*SDIMS(1)*SDIMS(2)*VAL__NBR * Loop over spatially resolved psfs DO SBIN = 1, NSPBIN * Locate the index data CALL ARR_COP1I( 3, %VAL(RIPTR+3*(IPSF-1)*VAL__NBI), : INDX, STATUS ) * The input psf starts at INDX(1) in the response data array, and * has size INDX(2)*2+1 by INDX(3)*2+1. Convolve that with the * appropriate source model CALL SPCONVOL_CONV( INDX(2)*2+1, INDX(3)*2+1, %VAL(RDPTR), : SDIMS(1), SDIMS(2), %VAL(SEDPTR), : NRDIMS(1), NRDIMS(2), %VAL(CP_PTR), : STATUS ) * Advance to next psf IPSF = IPSF + 1 CP_PTR = CP_PTR + PSFSIZ END DO END DO * Re-compress given CUTOFF. We process the array in memory sequential order * which means that we can overwrite the SP_PTR array. CALL SPRESP_COMP( NRDIMS(1), NRDIMS(2), NPSF, %VAL(NRDPTR), : CUTOFF, %VAL(RIPTR), %VAL(NRDPTR), : NUSED, STATUS ) * Find maximum sizes used in compressed index. Adjust expanded * dimensions so fit the largest psf in the index. Doesn't save * any disk space but saves memory in the psf system when the * response has to be uncompressed CALL SPRESP_SQSH( NPSF, %VAL(RIPTR), XSMAX, YSMAX, STATUS ) NRDIMS(1) = XSMAX*2 + 1 NRDIMS(2) = YSMAX*2 + 1 * Write the expanded dimensions CALL HDX_PUTI( RLOC, 'DIMS', RNDIM, NRDIMS, STATUS ) * Report compression factor CALL MSG_SETR( 'FAC', REAL(NRNELM)/REAL(NUSED) ) CALL MSG_PRNT( 'Response compressed by a factor ^FAC' ) * Unmap the old data CALL CMP_UNMAP( RLOC, 'DATA_ARRAY', STATUS ) * Write compressed data to file CALL HDX_PUTR( RLOC, 'DATA_ARRAY', NUSED, %VAL(NRDPTR), STATUS ) * Unmap the index CALL CMP_UNMAP( RLOC, 'INDEX', STATUS ) * Add a bit of history CALL HSI_ADD( IFID, VERSION, STATUS ) HTXT(1) = 'Convolved with : {SOURCE}' NLINE = MXHLINE CALL USI_TEXT( 1, HTXT, NLINE, STATUS ) CALL HSI_PTXT( IFID, NLINE, HTXT, STATUS ) * Release response CALL DAT_ANNUL( RLOC, STATUS ) * Tidy up 99 CALL AST_CLOSE() CALL AST_ERR( STATUS ) END SUBROUTINE SPCONVOL_CONV( INX, INY, IDATA, MNX, MNY, MASK, : ONX, ONY, ODATA, STATUS ) *+ * Name: * SPCONVOL_CONV * Purpose: * Convolve the array IDATA with the mask MASK to produce ODATA. The * output array has already been zeroed, and the dimensions are * large enough that no checking has to be done for mask overflow. * Language: * FORTRAN * Type of Module: * ADAM A-task * Invocation: * CALL SPCONVOL( STATUS ) * Arguments: * STATUS = INTEGER (Given and Returned) * The global status. * Description: * Attach a spatial response structure to a dataset. A spatial response * is stored as a function of X,Y offset from the source position, in * either pixel centred or vertex centred form, as a function of detector * position and/or energy. * * Usage: * {routine_name} {parameter_usage} * Examples: * {routine_example_text} * {routine_example_description} * Pitfalls: * {pitfall_description}... * Notes: * {routine_notes}... * Prior Requirements: * {routine_prior_requirements}... * Side Effects: * {routine_side_effects}... * Algorithm: * {algorithm_description}... * Accuracy: * {routine_accuracy} * Timing: * {routine_timing} * Implementation Status: * {routine_implementation_status} * {machine}-specific features used: * {routine_machine_specifics}... * {DIY_prologue_heading}: * {DIY_prologue_text} * References: * {routine_references}... * Keywords: * {routine_keywords}... * Authors: * DJA: David J. Allan (ROSAT) * {enter_new_authors_here} * History: * 16-Aug-94 (DJA): * Original version. * {enter_changes_here} * Bugs: * {note_any_bugs_here} *- * Type Definitions: IMPLICIT NONE ! No implicit typing * Global Constants: INCLUDE 'SAE_PAR' ! Standard SAE constants * Status: INTEGER STATUS ! Global status * Import: INTEGER INX, INY REAL IDATA(INX,INY) INTEGER MNX, MNY REAL MASK(-MNX/2:MNX/2,-MNY/2:MNY/2) * Export: INTEGER ONX, ONY REAL ODATA(ONX,ONY) * Local Variables: INTEGER I,J ! Loop over IDATA INTEGER II,JJ ! Loop over MASK INTEGER OX,OY ! IDATA->ODATA offset *. * Check inherited global status. IF ( STATUS .NE. SAI__OK ) RETURN * Offsets to bring IDATA into centre of ODATA OX = (ONX-INX)/2 OY = (ONY-INY)/2 * Loop over input data pixels DO J = 1, INY DO I = 1, INX * Loop over mask DO JJ = -MNY/2, MNY/2 DO II = -MNX/2, MNX/2 ODATA(I+OX+II,J+OY+JJ) = : ODATA(I+OX+II,J+OY+JJ) + MASK(II,JJ)*IDATA(I,J) END DO END DO * End of loop over input pixels END DO END DO END