def specific_process_photons(self, photons, intersect, interpos, intercoos): # A ray through the center is not broken. # So, find out where a central ray would go. p_opt_axis = self.geometry['center'] - self.d_center_optax * self.geometry['e_z'] focuspoints = h2e(p_opt_axis) + self.focallength * norm_vector(h2e(photons['dir'][intersect])) dir = norm_vector(e2h(focuspoints - h2e(interpos[intersect]), 0)) pol = parallel_transport(photons['dir'].data[intersect, :], dir, photons['polarization'].data[intersect, :]) angle = np.arccos(np.abs(inner1d(h2e(dir), norm_vector(h2e(photons['dir'][intersect]))))) return {'dir': dir, 'polarization': pol, 'probability': reflectivity_interpolator(photons['energy'][intersect], angle / 4, grid=False)**2 }
def intersect(self, dir, pos): '''Calculate the intersection point between a ray and the element Parameters ---------- dir : `numpy.ndarray` of shape (N, 4) homogeneous coordinates of the direction of the ray pos : `numpy.ndarray` of shape (N, 4) homogeneous coordinates of a point on the ray Returns ------- intersect : boolean array of length N ``True`` if an intersection point is found. interpos : `numpy.ndarray` of shape (N, 4) homogeneous coordinates of the intersection point. Values are set to ``np.nan`` if no intersection point is found. interpos_local : `numpy.ndarray` of shape (N, 2) y and z coordinates in the coordinate system of the active plane. ''' p_rays = pluecker.dir_point2line(h2e(dir), h2e(pos)) radius = np.linalg.norm(self.geometry['v_y']) height = np.linalg.norm(self.geometry['v_x']) intersect = np.zeros(pos.shape[0], dtype=bool) # ray passes through cylinder caps? for fac in [-1, 1]: cap_midpoint = self.geometry['center'] + fac * self.geometry['v_x'] cap_plane = pluecker.point_dir2plane(cap_midpoint, self.geometry['e_x']) interpos = pluecker.intersect_line_plane(p_rays, cap_plane) r = np.linalg.norm(h2e(cap_midpoint) - h2e(interpos), axis=-1) intersect[r < radius] = True # Ray passes through the side of a cylinder # Note that we don't worry about rays parallel to x because those are # tested by passing through the caps already n = norm_vector(np.cross(h2e(self.geometry['e_x']), h2e(dir))) d = np.abs(inner1d(n, h2e(self.geometry['center']) - h2e(pos))) n2 = norm_vector(np.cross(h2e(dir), n)) k = inner1d(h2e(pos) - h2e(self.geometry['center']), n2) / inner1d(h2e(self.geometry['e_x']), n2) intersect[(d < radius) & (np.abs(k) < height)] = True return intersect, None, None
def specific_process_photons(self, photons, intersect, interpos, intercoos): p3 = norm_vector(h2e(photons['dir'].data[intersect])) angle = np.arccos(np.abs(np.dot(p3, self.geometry['plane'][:3]))) # Area is filled by L2 bars + area shadowed by L2 bars shadowarea = 3. * (self.period**2 - self.innerfree**2) + 2 * self.innerfree * 0.5 * np.sin(angle) shadowfraction = shadowarea / (3. * self.period**2) return {'probability': 1. - shadowfraction}
def fresnel(self, photons, intersect, interpos, intercoos): '''The incident angle can easily be calculated from e_x and photons['dir'].''' d = self.D(intercoos[intersect, 0]) dir = norm_vector(photons['dir'].data[intersect, :]) arccosang = np.arccos(np.einsum('j,ij', -self.geometry['e_x'], dir)) # get rs and rp from interpol of table rs = self.rs.ev(arccosang, d) rp = self.rp.ev(arccosang, d) scale = 2. / (rs + rp) return rs * scale, rp * scale
def specific_process_photons(self, photons, intersect, interpos, intercoos): # A ray through the center is not broken. # So, find out where a central ray would go. focuspoints = h2e(self.geometry['center']) + \ self.focallength * norm_vector(h2e(photons['dir'][intersect])) dir = e2h(focuspoints - h2e(interpos[intersect]), 0) pol = parallel_transport(photons['dir'].data[intersect, :], dir, photons['polarization'].data[intersect, :]) # Single reflection, so get change in angle refl_angle = np.arccos( inner1d(norm_vector(dir), photons['dir'].data[intersect, :])) refl = self.reflectivity(photons['energy'][intersect], refl_angle / 2) r = np.sqrt(intercoos[intersect, 0]**2 + intercoos[intersect, 1]**2) phi = np.arctan2(intercoos[intersect, 0], intercoos[intersect, 1]) shell = np.zeros(intersect.sum()) sector = np.zeros_like(shell) * np.nan for s in self.shells: ind = ((s['r_in'] < r) & (r < s['r_out'])) shell[ind] = s['shell'] for chan in self.conf['channels']: # Get angle rotation around direction rotang = mat2euler(conf['rotchan'][chan])[2] halfang = conf['shell_half_opening_angle'] for x in [0, np.pi]: sector[angle_between(phi, rotang + x - halfang, rotang + x + halfang)] = int(chan) refl[(shell < 1) | np.isnan(sector)] = 0 return { 'dir': dir, 'polarization': pol, 'probability': refl, 'refl_ang': refl_angle, 'shell': shell, 'sector': sector }
def specific_process_photons(self, photons, intersect, interpos, intercoos): p3 = norm_vector(photons['dir'].data[intersect]) ex, ey, en = self.geometry.get_local_euklid_bases(intercoos[intersect, :]) angle = np.arccos(np.abs(inner1d(p3, en))) # fractional area NOT covered by the hexagon structure openfraction = (self.innerfree / self.period)**2 # fractional area shadowed by inclined hexagon structure shadowarea = (self.bardepth * self.innerfree * np.sin(angle)) totalarea = self.period**2 / 2 * np.sqrt(3) shadowfraction = shadowarea / totalarea return {'probability': openfraction - shadowfraction}
def specific_process_photons(self, photons, intersect, interpos, intercoos): p3 = norm_vector(photons['dir'].data[intersect]) ex, ey, en = self.geometry.get_local_euklid_bases( intercoos[intersect, :]) angle = np.arccos(np.abs(np.einsum("ij,ij->i", p3, en))) # fractional area NOT covered by the hexagon structure openfraction = (self.innerfree / self.period)**2 # fractional area shadowed by inclined hexagon structure shadowarea = (self.bardepth * self.innerfree * np.sin(angle)) totalarea = self.period**2 / 2 * np.sqrt(3) shadowfraction = shadowarea / totalarea return {'probability': openfraction - shadowfraction}
hdulist.close() for ix, offx in enumerate(pointing_offsets): for iy, offy in enumerate(pointing_offsets): for ie, e in enumerate(energies): print('{} {} {} - {}'.format(ix, iy, ie, time.ctime())) mysource = DefaultSource(coords=SkyCoord(0. * u.rad, 0. * u.rad), energy=e) photons = mysource.generate_photons(n_photons) offsetcoord = SkyCoord(offx, offy) mypointing = DefaultPointing(coords=offsetcoord, jitter=0.) photons = mypointing(photons) photons = arc(photons) # Reformat and delete columns not required for SIXTE to save space photons['POS'] = h2e(photons['pos']) # Make sure direction is normalized photons['DIR'] = norm_vector(h2e(photons['dir'])) photons.rename_column('probability', 'weight') photons.rename_column('aperture', 'channel') photons.keep_columns(['POS', 'DIR', 'time', 'weight', 'ra', 'dec', 'channel', 'order', 'energy', 'xou', 'facet']) photons.meta['A_GEOM'] = (arc.elements[0].area.to(u.cm**2).value, 'Geometric opening area in cm') filename = '{0}_{1}_{2}.fits'.format(ie, ix, iy) # Drop photons that are absorbed or miss grating photons = photons[np.isfinite(photons['order']) & (photons['weight'] > 0.)] photons.write(pjoin(outdir, filename), overwrite=True) # Add spectrum hdu spechdu = fits.table_to_hdu(spectab[[ie]]) # double [[]] to get table, not row with fits.open(pjoin(outdir, filename), 'append') as hdulist: hdulist.append(spechdu) hdulist.flush()