IF *newrmf IF *withspectrum template = *spectrumset ELSE template = *evlist OR *srclist ELSE template = *rmfset IF *srclist == "" IF template.root.length >= 10 *srclist = template with "SRCLI_0000" substituted ELSE *srclist = "srcli." + template.suffix IF *evlist == "" IF template.root.length >= 10 *evlist = template with "EVENLI0000" substituted ELSE *evlist = "evenli." + template.suffix IF *newrmf AND *rmfset == "" IF template.root.length >= 10 *rmfset = template with ("RSPMAT",*order,*source) substituted ELSE *rmfset = "rspmat." + template.suffix
IF GratingDataServer::beta(source,order,energy) within matrix channel space // prepare various distributions in wrap-around order for convolution // small angle scattering distribution D = GratingDataServer::scatteringDistribution(source,order,energy) (a,b) = GratingDataServer::scatteringDistributionContribs D[peak] += (1-a)*(1-b) // mirror point spread distribution IF *withmirrorpsf PsfDataServer::dispersionFigureDistribution(source,order,energy) // custom angular distribution IF *withangdist customFigureDistribution(order,energy) // grating bow induced misalignment distribution GratingDataServer::bowingFigureDistribution(source,order,energy) // geometric defocus approximation distribution GeometryDataServer::lsfDefocusDistribution(source,order,energy) // finite energy band broadening distribution GratingDataServer::broadeningDistribution(source,order,energy) // prepare the primary distribution on the matrix channel grid GratingDataServer::misalignmentFigureDistribution(source,order,energy) LSF = convolution(primary,various...) ELSE // distributions peak outside the matrix channel space, so skip // convolutions, and instead just use the tail of the small angle // scattering distribution where it overlaps the channel space LSF = GratingDataServer::scatteringDistribution(source,order,energy) // scale the LSF by the effective area IF dyneffarecorr scale = EffectiveAreaDataServer::realisticEffectiveAreaCurve(source,order)::area(energy) ELSE scale = EffectiveAreaDataServer::intrinsicEffectiveAreaCurve(source,order)::area(energy) IF withrectification scale = EffectiveAreaDataServer::effectiveAreaRectification(scale)::area(energy) NarrowLSF = scale * LSF
// place the large angle scattering distribution on the matrix channel // grid and scale it by the effective area LSF = GratingDataServer::scatteringDistribution(source,order,energy) scale = EffectiveAreaDataServer::intrinsicEffectiveAreaCurve(source,order)::area(energy) BroadLSF = scale * LSF
dpsi = source.DELTA_XDSP * pi/10800 k = (energy * 10800) / (0.678 * pi) FOREACH span = interval [min,max] of cross-dispersion channels s += (atan(k*(xdsp(max+0.5)+dpsi)) - atan(k*(xdsp(min-0.5)+dpsi))) / pi n += span.length empiricalCrossLA = s/n
// analyze the exposure maps within the spatial selection regions FOREACH node FOREACH b = dispersion channel of node src.exposure[node,b] = EXPMAP<node>[b] summed over src.spans[node,b] bkg.exposure[node,b] = EXPMAP<node>[b] summed over bkg.spans[node,b] D = EXPMAP<node>[b] * CanonicalCrossPsf::probability(beta(b),source) src.crossPSF[node,b] = D summed over src.spans[node,b] bkg.crossPSF[node,b] = D summed over bkg.spans[node,b] // compute the response matrix FOREACH incident energy bin // compute the loss factors specific to the narrow-featured LSF loss = 0 FOREACH node FOREACH b = dispersion channel of node y = src.crossPSF[node,b] IF *bkgcorrect AND bkg.exposure[node,b] y -= bkg.crossPSF[node,b] * src.exposure[node,b] / bkg.exposure[node,b] loss[b] += y * ccdQuantumDataServer(node)::efficiency(energy) // combine with the narrow-featured LSF for each reflection order LSF = 0 FOREACH order in [0,5] LSF += NarrowLSF(source,order,energy) response = LSF * loss // compute the loss factors specific to the broad-featured LSF loss = 0 FOREACH node FOREACH b = dispersion channel of node y = empiricalCrossLA(src.spans[node,b],source,energy) IF *bkgcorrect y -= empiricalCrossLA(bkg.spans[node,b],source,energy) loss[b] += y * src.exposure[node,b] * ccdQuantumDataServer(node)::efficiency(energy) // combine with the broad-featured LSF for each reflection order LSF = 0 FOREACH order in [0,5] LSF += BroadLSF(source,order,energy) response += LSF * loss // apply loss factors that are not specific to the type of LSF; // the redistribution function varies slowly with incident energy // and so it is recomputed no more often than every .02 keV. // Since version 1.13.4, the redistribution is calculated for all // input energies. IF redistLoss is stale FOREACH b = response channel redistLoss[b] = CanonicalRedist::spectrum(energy) summed over banana[b] response *= redistLoss * GratingDataServer::selfVignettingEfficiency // copy all response channels above LO_THRES to the output matrix
XMM-Newton SOC -- 2023-04-16