<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def calc_exp(skydir, ltc, event_class, event_types, egy, cth_bins, npts=None):
 """Calculate the exposure on a 2D grid of energy and incidence angle. Parameters npts : int Number of points by which to sample the response in each incidence angle bin. If None then npts will be automatically set such that incidence angle is sampled on intervals of < 0.05 in Cos(Theta). Returns ------- exp : `~numpy.ndarray` 2D Array of exposures vs. energy and incidence angle. """


    if npts is None:
        npts = int(np.ceil(np.max(cth_bins[1:] - cth_bins[:-1]) / 0.025))

    exp = np.zeros((len(egy), len(cth_bins) - 1))
    cth_bins = utils.split_bin_edges(cth_bins, npts)
    cth = edge_to_center(cth_bins)
    ltw = ltc.get_skydir_lthist(skydir, cth_bins).reshape(-1, npts)
    for et in event_types:
        aeff = create_aeff(event_class, et, egy, cth)
        aeff = aeff.reshape(exp.shape + (npts,))
        exp += np.sum(aeff * ltw[np.newaxis, :, :], axis=-1)

    return exp