Exemple #1
0
    def sun_elevetion(self):
        """
        doc is not correct!!!

        This function uses telemetry data from the airplain (any timeseries including Lat and Lon) to calculate
        the sun's elevation. Based on the sun's elevation an airmass factor is calculated which the data is corrected for.

        Arguments
        ---------
        sun_intensities: Sun_Intensities_TS instance
        picco: any timeseries instance containing Lat and Lon
        """
        if not self.housekeeping:
            txt = 'For this calculation we need information on Lat, Lon, Altitude. Please set the attribute housekeeping with a timeseries that has these informations'
            raise AttributeError(txt)

        if not self.__sun_elevation:
            cols = self.housekeeping.data.columns
            merged = self.merge(self.housekeeping, recognize_gaps=False)
            merged = merged._del_all_columns_but(cols)

            ts = solar.get_sun_position_TS(merged)
            ts = ts._del_all_columns_but(['Solar_position_elevation'])
            self.__sun_elevation = ts
        # picco_t = timeseries.TimeSeries(picco.data.loc[:, ['Lat', 'Lon', 'Altitude']])  # only Altitude, Lat and Lon
        # sun_int_su = self.merge(picco_t)
        # out = sun_int_su.get_sun_position()
        # #     sun_int_su = sun_int_su.zoom_time(spiral_up_start, spiral_up_end)
        # arrays = np.array([sun_int_su.data.index, sun_int_su.data.Altitude, sun_int_su.data.Solar_position_elevation])
        # tuples = list(zip(*arrays))
        # index = pd.MultiIndex.from_tuples(tuples, names=['Time', 'Altitude', 'Sunelevation'])
        # sun_int_su.data.index = index
        # sun_int_su.data = sun_int_su.data.drop(
        #     ['Altitude', 'Solar_position_elevation', 'Solar_position_azimuth', 'Lon', 'Lat'], axis=1)
        return self.__sun_elevation
Exemple #2
0
    def sun_elevetion(self):
        """
        doc is not correct!!!

        This function uses telemetry data from the airplain (any timeseries including Lat and Lon) to calculate
        the sun's elevation. Based on the sun's elevation an airmass factor is calculated which the data is corrected for.

        Arguments
        ---------
        sun_intensities: Sun_Intensities_TS instance
        picco: any timeseries instance containing Lat and Lon
        """
        if not self.housekeeping:
            txt = 'For this calculation we need information on Lat, Lon, Altitude. Please set the attribute housekeeping with a timeseries that has these informations'
            raise AttributeError(txt)

        if not self.__sun_elevation:
            cols = self.housekeeping.data.columns
            merged = self.merge(self.housekeeping, recognize_gaps=False)
            merged = merged._del_all_columns_but(cols)

            ts = solar.get_sun_position_TS(merged)
            ts = ts._del_all_columns_but(['Solar_position_elevation'])
            self.__sun_elevation = ts
        # picco_t = timeseries.TimeSeries(picco.data.loc[:, ['Lat', 'Lon', 'Altitude']])  # only Altitude, Lat and Lon
        # sun_int_su = self.merge(picco_t)
        # out = sun_int_su.get_sun_position()
        # #     sun_int_su = sun_int_su.zoom_time(spiral_up_start, spiral_up_end)
        # arrays = np.array([sun_int_su.data.index, sun_int_su.data.Altitude, sun_int_su.data.Solar_position_elevation])
        # tuples = list(zip(*arrays))
        # index = pd.MultiIndex.from_tuples(tuples, names=['Time', 'Altitude', 'Sunelevation'])
        # sun_int_su.data.index = index
        # sun_int_su.data = sun_int_su.data.drop(
        #     ['Altitude', 'Solar_position_elevation', 'Solar_position_azimuth', 'Lon', 'Lat'], axis=1)
        return self.__sun_elevation
Exemple #3
0
 def get_sun_position(self):
     """read docstring of solar.get_sun_position_TS"""
     out = solar.get_sun_position_TS(self)
     return out
Exemple #4
0
def simulate_from_rayleigh(
        time_series,
        layerbounderies,
        # altitude,
        # layerbounderies,
        pressure,
        temp,
        wl,
        no_angles,
        rotations,
        airmassfct,
        sun_azimuth):
    """ Fix this documentation!


    Simulates miniSASP signal from a size distribution layer series
    Arguments
    ---------
    layerbounderies: array-like
    altitude: float or array-like.
        Altitude for which the mSASP signal is simulated for in meters
    pressure: array, bool
        Atmospheric pressure in mbar. If False, value is taken from international standard atmosphere.
    temp: array, bool in K
    wl: wavelength in nm

    no_angles: int
        total number of angles considered. This included the number in multiple roations. most likely this is
        int(opt_prop.angular_scatt_func.shape[0] / 2) * rotations

    rotations: int.
        number of rotations the of the mSASP.

    Returns
    -------
    pandas.DataFrame
        containing the sky brightness as a function of mSASPS azimuth angle"""
    layerbounderies = np.unique(layerbounderies.flatten())
    altitude = (layerbounderies[1:] + layerbounderies[:-1]) / 2.
    time_series = solar.get_sun_position_TS(time_series)
    where = array_tools.find_closest(time_series.data.Altitude.values,
                                     altitude)
    solar_elev = time_series.data.Solar_position_elevation.values[where]
    solar_az = time_series.data.Solar_position_azimuth.values[where]
    alts = time_series.data.Altitude.values[
        where]  # thats over acurate, cal simply use the layerbounderies

    if (type(pressure).__name__ == 'bool') or (type(temp).__name__ == 'bool'):
        if pressure and temp:
            # temp = time_series.data.Temperature
            # pressure = time_series.data.Barometric_pressure_Pa
            lb = pd.DataFrame(index=layerbounderies)
            select_list = ["Temperature", "Altitude", "Pressure_Pa"]

            bla = []
            for i in ["Temperature", "Altitude", "Pressure_Pa"]:
                if i not in time_series.data.columns:
                    bla.append(i)

            if len(bla) != 0:
                txt = 'The underlying housekeeping data has to have the following attributes for this operation to work: %s' % (
                    ["Temperature", "Altitude", "Pressure_Pa"])
                txt += '\nmissing:'
                for i in bla:
                    txt += '\n \t' + i
                # print(txt)
                raise AttributeError(txt)

            hkt = time_series.data.loc[:, select_list]

            hkt.index = hkt.Altitude
            hkt = hkt.sort_index()

            hkt_lb = pd.concat([hkt, lb]).sort_index().interpolate()
            hkt_lb = hkt_lb.groupby(hkt_lb.index).mean().reindex(lb.index)
            temp = hkt_lb.Temperature.values + 273.15
            pressure = hkt_lb.Pressure_Pa.values

        else:
            p, t = atmstd.standard_atmosphere(layerbounderies)
            if type(pressure).__name__ == 'bool':
                if pressure == False:
                    pressure = p
            if type(temp).__name__ == 'bool':
                if temp == False:
                    temp = t
    # print(pressure, temp)
    if (layerbounderies.shape != pressure.shape) or (layerbounderies.shape !=
                                                     temp.shape):
        raise ValueError('altitude, pressure and tmp have to have same shape')

    # time = time_series.data.index[where]

    what_mSASP_sees_rayleigh = pd.DataFrame()
    what_mSASP_sees_AOD_rayleigh = np.zeros(altitude.shape)

    for alt in range(altitude.shape[0]):
        # get the sun position at the time when the plane was at the particular altitude,

        sol_el = solar_elev[alt]
        sol_az = solar_az[alt]
        # print(alts[alt:])

        # return ray_scatt_fct

        # angles between mSASP positions and sun. This is used to pick the angle in the phase functions
        if sun_azimuth:
            sun_azimuth = sol_az
        else:
            sun_azimuth = 0
        mSASP2Sunangles = angle_MSASP_sun(
            sol_el,
            sun_azimuth=sun_azimuth,
            no_angles=no_angles,
            # pretty arbitrary number ... this is just to get a reasonal number of angles
            no_rotations=rotations)

        ray_scatt_fct = bray.rayleigh_angular_scattering_intensity(
            layerbounderies[alt:], pressure[alt:], temp[alt:], wl,
            mSASP2Sunangles.values.transpose())
        ray_scatt_fct = pd.DataFrame(ray_scatt_fct,
                                     index=mSASP2Sunangles.index)
        # return layerbounderies[alt:], pressure[alt:],temp[alt:], wl, ray_scatt_fct
        if airmassfct:
            slant_adjust = 1. / np.sin(solar_elev[alt])
        else:
            slant_adjust = 1.
        # closest_phase2sun_azi = array_tools.find_closest(ray_scatt_fct.index.values,
        #                                                  mSASP2Sunangles.mSASP_sun_angle.values)
        what_mSASP_sees_rayleigh[alts[alt]] = pd.Series(
            ray_scatt_fct.values.transpose()[0] * slant_adjust)
        # what_mSASP_sees_rayleigh.index = mSASP2Sunangles.index.values

        what_mSASP_sees_AOD_rayleigh[alt] = bray.rayleigh_optical_depth(
            layerbounderies[alt:], pressure[alt:], temp[alt:],
            wl) * slant_adjust
        # return layerbounderies[alt:],pressure[alt:],temp[alt:],wl, what_mSASP_sees_AOD_rayleigh[alt], slant_adjust

    what_mSASP_sees_rayleigh.index = mSASP2Sunangles.index
    what_mSASP_sees_AOD_rayleigh = pd.DataFrame(what_mSASP_sees_AOD_rayleigh,
                                                index=altitude,
                                                columns=['AOD_ray'])
    return what_mSASP_sees_rayleigh, what_mSASP_sees_AOD_rayleigh
Exemple #5
0
def simulate_from_size_dist_opt(opt_prop,
                                airmassfct=True,
                                rotations=2,
                                sun_azimuth=True,
                                pressure=True,
                                temp=True):
    """ Simulates miniSASP signal from a size distribution layer series (in particular from the optical property class
    derived from the layer series.
    The simulation calculates the position of the sun at the instruments position during the experiment. Slant angles
    are considert. The atmosphere above the top layer is unkonwn, therefore the measurement from the miniSASP at the top
    most layer should be added to all results.

    Note
    ----
    Temperature and pressure are currently not considered in the underlying Rayleigh calculations. Instead, an
    international standard atmosphere was used.

    Arguments
    ---------
    OpticalProperties class which was created from a layer series (dist_LS) using the sizedistribution module.
    airmassfct: bool, optional.
        If True, results will be corrected for the airmassfactor (slant angle only)
    rotations: int.
        Number of rotations of the mSASP to be simulated.
    pressure: bool or array-like.
        If True the opt_prop.paretn_timeseries.Barometric_pressure timeseries.
        If False standard atmosphere is used.
        If array-like the this array is used.
    temp: bool or array-like.
        If True the opt_prop.paretn_timeseries.Temperature timeseries.
        If False standard atmosphere is used.
        If array-like the this array is used.

    Returns
    -------
    dict:
        containing three (aerosol, rayleigh, sum) pandas DataFrames each with the sky brightness as a function of mSASPS
        azimuth angle.
    pandas DataFrame:
        AOD as a function of elevaton"""

    time_series = opt_prop.parent_dist_LS.parent_timeseries
    dist_ls = opt_prop.parent_dist_LS
    layerthickness = np.apply_along_axis(lambda line: line[1] - line[0], 1,
                                         dist_ls.layerbounderies)
    time_series = solar.get_sun_position_TS(time_series)
    where = array_tools.find_closest(time_series.data.Altitude.values,
                                     dist_ls.layercenters)
    alts = time_series.data.Altitude.values[where]
    solar_elev = time_series.data.Solar_position_elevation.values[where]
    solar_az = time_series.data.Solar_position_azimuth.values[where]
    # time = time_series.data.index[where]

    what_mSASP_sees_aerosols = pd.DataFrame()
    what_mSASP_sees_AOD_aerosols = np.zeros(alts.shape)

    for altitude in range(dist_ls.layercenters.shape[0]):
        # get the sun position at the time when the plane was at the particular altitude,
        sol_el = solar_elev[altitude]
        sol_az = solar_az[altitude]

        # angles between mSASP positions and sun. This is used to pick the angle in the phase functions
        if sun_azimuth:
            sun_azimuth = sol_az
        else:
            sun_azimuth = 0
        mSASP2Sunangles = angle_MSASP_sun(
            sol_el,
            sun_azimuth=sun_azimuth,
            no_angles=int(opt_prop.angular_scatt_func.shape[0] / 2) *
            rotations,
            # pretty arbitrary number ... this is just to get a reasonal number of angles
            no_rotations=rotations)

        # pick relevant angles in phase function for each layer, this includes selecting the relavant layers (selected altitude to top).
        closest_phase2sun_azi = array_tools.find_closest(
            opt_prop.angular_scatt_func.index.values,
            mSASP2Sunangles.mSASP_sun_angle.values)
        # minimize so values are calculated only once
        closest_phase2sun_azi = np.unique(closest_phase2sun_azi)
        phase_fct_rel = opt_prop.angular_scatt_func.iloc[closest_phase2sun_azi,
                                                         altitude:]
        # Integrate ofer selected intensities in phase function along vertical line (from selected height to top)
        # x = phase_fct_rel.columns.values
        # do_integ = lambda y: integrate.simps(y, x)
        # phase_fct_rel_integ = pd.DataFrame(phase_fct_rel.apply(do_integ, axis=1),
        #                                    columns=[alts[altitude]],
        #                                    # columns=[dist_ls.layercenters[altitude]]
        #                                    )  # these are the integrated intensities of scattered light into the relavant angles. Integration is from current (arbitrary) to top layer
        # print(phase_fct_rel.shape, layerthickness[altitude:].shape)
        phth = phase_fct_rel * layerthickness[altitude:]
        phase_fct_rel_integ = pd.DataFrame(phth.apply(np.sum, 1))
        # return phase_fct_rel, phase_fct_rel_integ

        if airmassfct:
            slant_adjust = 1. / np.sin(solar_elev[altitude])
        else:
            slant_adjust = 1.
        # similar to above this selects the different angels of mSASP to the sun. However, it keeps all of them (no unique)
        closest_phase2sun_azi = array_tools.find_closest(
            phase_fct_rel_integ.index.values,
            mSASP2Sunangles.mSASP_sun_angle.values)

        what_mSASP_sees_aerosols[dist_ls.layercenters[altitude]] = pd.Series(
            phase_fct_rel_integ.iloc[closest_phase2sun_azi].values.transpose()
            [0] * slant_adjust)
        # what_mSASP_sees_aerosols[dist_ls.layercenters[altitude]] = pd.Series(
        #     phase_fct_rel_integ.iloc[closest_phase2sun_azi].values.transpose()[0] * slant_adjust)

        # what_mSASP_sees_AOD_aerosols[altitude] = opt_prop.data_orig['AOD_layer'][altitude:].sum().values[0] * slant_adjust
        what_mSASP_sees_AOD_aerosols[altitude] = opt_prop.data_orig[
            'AOD_cum'].values[altitude][0] * slant_adjust
    what_mSASP_sees_aerosols.index = mSASP2Sunangles.index
    # what_mSASP_sees_AOD_aerosols = pd.DataFrame(what_mSASP_sees_AOD_aerosols, index = alts, columns = ['AOD_aerosols'])
    what_mSASP_sees_AOD = pd.DataFrame(what_mSASP_sees_AOD_aerosols,
                                       columns=['aerosol'])
    what_mSASP_sees_sky = {'aerosol': what_mSASP_sees_aerosols}

    what_mSASP_sees_rayleigh, what_mSASP_sees_AOD_rayleigh = simulate_from_rayleigh(
        time_series, dist_ls.layerbounderies, pressure, temp,
        opt_prop.wavelength, what_mSASP_sees_aerosols.shape[0], rotations,
        airmassfct, sun_azimuth)
    what_mSASP_sees_rayleigh.columns = dist_ls.layercenters
    what_mSASP_sees_sky['rayleigh'] = what_mSASP_sees_rayleigh

    what_mSASP_sees_sum = what_mSASP_sees_aerosols + what_mSASP_sees_rayleigh
    what_mSASP_sees_sky['sum'] = what_mSASP_sees_sum
    # what_mSASP_sees_sky['aerosols'] = what_mSASP_sees_aerosols

    what_mSASP_sees_AOD_sum = what_mSASP_sees_AOD_aerosols + what_mSASP_sees_AOD_rayleigh.values.transpose(
    )[0]
    # what_mSASP_sees_AOD['aerosols'] = what_mSASP_sees_AOD_aerosols
    what_mSASP_sees_AOD[
        'rayleigh'] = what_mSASP_sees_AOD_rayleigh.values.transpose()[0]
    what_mSASP_sees_AOD['sum'] = what_mSASP_sees_AOD_sum
    # return what_mSASP_sees_AOD_aerosols  , what_mSASP_sees_AOD_rayleigh.values.transpose()[0]

    # what_mSASP_sees_AOD_aerosols = pd.DataFrame(what_mSASP_sees_AOD_aerosols, index = alts, columns = ['AOD'])
    what_mSASP_sees_AOD.index = alts
    return what_mSASP_sees_sky, what_mSASP_sees_AOD
Exemple #6
0
 def get_sun_position(self):
     """read docstring of solar.get_sun_position_TS"""
     out = solar.get_sun_position_TS(self)
     return out
Exemple #7
0
def simulate_from_rayleigh(time_series,
                           layerbounderies,
                           # altitude,
                           # layerbounderies,
                           pressure,
                           temp,
                           wl,
                           no_angles,
                           rotations,
                           airmassfct,
                           sun_azimuth):
    """ Fix this documentation!


    Simulates miniSASP signal from a size distribution layer series
    Arguments
    ---------
    layerbounderies: array-like
    altitude: float or array-like.
        Altitude for which the mSASP signal is simulated for in meters
    pressure: array, bool
        Atmospheric pressure in mbar. If False, value is taken from international standard atmosphere.
    temp: array, bool in K
    wl: wavelength in nm

    no_angles: int
        total number of angles considered. This included the number in multiple roations. most likely this is
        int(opt_prop.angular_scatt_func.shape[0] / 2) * rotations

    rotations: int.
        number of rotations the of the mSASP.

    Returns
    -------
    pandas.DataFrame
        containing the sky brightness as a function of mSASPS azimuth angle"""
    layerbounderies = np.unique(layerbounderies.flatten())
    altitude = (layerbounderies[1:] + layerbounderies[:-1]) / 2.
    time_series = solar.get_sun_position_TS(time_series)
    where = array_tools.find_closest(time_series.data.Altitude.values, altitude)
    solar_elev = time_series.data.Solar_position_elevation.values[where]
    solar_az = time_series.data.Solar_position_azimuth.values[where]
    alts = time_series.data.Altitude.values[where]  # thats over acurate, cal simply use the layerbounderies

    if (type(pressure).__name__ == 'bool') or (type(temp).__name__ == 'bool'):
        if pressure and temp:
            # temp = time_series.data.Temperature
            # pressure = time_series.data.Barometric_pressure_Pa
            lb = pd.DataFrame(index=layerbounderies)
            select_list = ["Temperature", "Altitude", "Pressure_Pa"]

            bla = []
            for i in ["Temperature", "Altitude", "Pressure_Pa"]:
                if i not in time_series.data.columns:
                    bla.append(i)

            if len(bla) != 0:
                txt='The underlying housekeeping data has to have the following attributes for this operation to work: %s'%(["Temperature", "Altitude", "Pressure_Pa"])
                txt+='\nmissing:'
                for i in bla:
                    txt += '\n \t' + i
                # print(txt)
                raise AttributeError(txt)

            hkt = time_series.data.loc[:, select_list]

            hkt.index = hkt.Altitude
            hkt = hkt.sort_index()

            hkt_lb = pd.concat([hkt, lb]).sort_index().interpolate()
            hkt_lb = hkt_lb.groupby(hkt_lb.index).mean().reindex(lb.index)
            temp = hkt_lb.Temperature.values + 273.15
            pressure = hkt_lb.Pressure_Pa.values

        else:
            p, t = atmstd.standard_atmosphere(layerbounderies)
            if type(pressure).__name__ == 'bool':
                if pressure == False:
                    pressure = p
            if type(temp).__name__ == 'bool':
                if temp == False:
                    temp = t
    # print(pressure, temp)
    if (layerbounderies.shape != pressure.shape) or (layerbounderies.shape != temp.shape):
        raise ValueError('altitude, pressure and tmp have to have same shape')

    # time = time_series.data.index[where]

    what_mSASP_sees_rayleigh = pd.DataFrame()
    what_mSASP_sees_AOD_rayleigh = np.zeros(altitude.shape)

    for alt in range(altitude.shape[0]):
        # get the sun position at the time when the plane was at the particular altitude,

        sol_el = solar_elev[alt]
        sol_az = solar_az[alt]
        # print(alts[alt:])

        # return ray_scatt_fct

        # angles between mSASP positions and sun. This is used to pick the angle in the phase functions
        if sun_azimuth:
            sun_azimuth = sol_az
        else:
            sun_azimuth = 0
        mSASP2Sunangles = angle_MSASP_sun(sol_el,
                                          sun_azimuth=sun_azimuth,
                                          no_angles=no_angles,
                                          # pretty arbitrary number ... this is just to get a reasonal number of angles
                                          no_rotations=rotations)

        ray_scatt_fct = bray.rayleigh_angular_scattering_intensity(layerbounderies[alt:], pressure[alt:], temp[alt:],
                                                                   wl, mSASP2Sunangles.values.transpose())
        ray_scatt_fct = pd.DataFrame(ray_scatt_fct, index=mSASP2Sunangles.index)
        # return layerbounderies[alt:], pressure[alt:],temp[alt:], wl, ray_scatt_fct
        if airmassfct:
            slant_adjust = 1. / np.sin(solar_elev[alt])
        else:
            slant_adjust = 1.
        # closest_phase2sun_azi = array_tools.find_closest(ray_scatt_fct.index.values,
        #                                                  mSASP2Sunangles.mSASP_sun_angle.values)
        what_mSASP_sees_rayleigh[alts[alt]] = pd.Series(ray_scatt_fct.values.transpose()[0] * slant_adjust)
        # what_mSASP_sees_rayleigh.index = mSASP2Sunangles.index.values

        what_mSASP_sees_AOD_rayleigh[alt] = bray.rayleigh_optical_depth(layerbounderies[alt:], pressure[alt:],
                                                                        temp[alt:], wl) * slant_adjust
        # return layerbounderies[alt:],pressure[alt:],temp[alt:],wl, what_mSASP_sees_AOD_rayleigh[alt], slant_adjust

    what_mSASP_sees_rayleigh.index = mSASP2Sunangles.index
    what_mSASP_sees_AOD_rayleigh = pd.DataFrame(what_mSASP_sees_AOD_rayleigh, index=altitude, columns=['AOD_ray'])
    return what_mSASP_sees_rayleigh, what_mSASP_sees_AOD_rayleigh
Exemple #8
0
def simulate_from_size_dist_opt(opt_prop, airmassfct=True, rotations=2, sun_azimuth=True, pressure=True, temp=True):
    """ Simulates miniSASP signal from a size distribution layer series (in particular from the optical property class
    derived from the layer series.
    The simulation calculates the position of the sun at the instruments position during the experiment. Slant angles
    are considert. The atmosphere above the top layer is unkonwn, therefore the measurement from the miniSASP at the top
    most layer should be added to all results.

    Note
    ----
    Temperature and pressure are currently not considered in the underlying Rayleigh calculations. Instead, an
    international standard atmosphere was used.

    Arguments
    ---------
    OpticalProperties class which was created from a layer series (dist_LS) using the sizedistribution module.
    airmassfct: bool, optional.
        If True, results will be corrected for the airmassfactor (slant angle only)
    rotations: int.
        Number of rotations of the mSASP to be simulated.
    pressure: bool or array-like.
        If True the opt_prop.paretn_timeseries.Barometric_pressure timeseries.
        If False standard atmosphere is used.
        If array-like the this array is used.
    temp: bool or array-like.
        If True the opt_prop.paretn_timeseries.Temperature timeseries.
        If False standard atmosphere is used.
        If array-like the this array is used.

    Returns
    -------
    dict:
        containing three (aerosol, rayleigh, sum) pandas DataFrames each with the sky brightness as a function of mSASPS
        azimuth angle.
    pandas DataFrame:
        AOD as a function of elevaton"""

    time_series = opt_prop.parent_dist_LS.parent_timeseries
    dist_ls = opt_prop.parent_dist_LS
    layerthickness = np.apply_along_axis(lambda line: line[1] - line[0], 1, dist_ls.layerbounderies)
    time_series = solar.get_sun_position_TS(time_series)
    where = array_tools.find_closest(time_series.data.Altitude.values, dist_ls.layercenters)
    alts = time_series.data.Altitude.values[where]
    solar_elev = time_series.data.Solar_position_elevation.values[where]
    solar_az = time_series.data.Solar_position_azimuth.values[where]
    # time = time_series.data.index[where]

    what_mSASP_sees_aerosols = pd.DataFrame()
    what_mSASP_sees_AOD_aerosols = np.zeros(alts.shape)

    for altitude in range(dist_ls.layercenters.shape[0]):
        # get the sun position at the time when the plane was at the particular altitude,
        sol_el = solar_elev[altitude]
        sol_az = solar_az[altitude]


        # angles between mSASP positions and sun. This is used to pick the angle in the phase functions
        if sun_azimuth:
            sun_azimuth = sol_az
        else:
            sun_azimuth = 0
        mSASP2Sunangles = angle_MSASP_sun(sol_el,
                                          sun_azimuth=sun_azimuth,
                                          no_angles=int(opt_prop.angular_scatt_func.shape[0] / 2) * rotations,
                                          # pretty arbitrary number ... this is just to get a reasonal number of angles
                                          no_rotations=rotations)

        # pick relevant angles in phase function for each layer, this includes selecting the relavant layers (selected altitude to top).
        closest_phase2sun_azi = array_tools.find_closest(opt_prop.angular_scatt_func.index.values,
                                                         mSASP2Sunangles.mSASP_sun_angle.values)
        # minimize so values are calculated only once
        closest_phase2sun_azi = np.unique(closest_phase2sun_azi)
        phase_fct_rel = opt_prop.angular_scatt_func.iloc[closest_phase2sun_azi, altitude:]
        # Integrate ofer selected intensities in phase function along vertical line (from selected height to top)
        # x = phase_fct_rel.columns.values
        # do_integ = lambda y: integrate.simps(y, x)
        # phase_fct_rel_integ = pd.DataFrame(phase_fct_rel.apply(do_integ, axis=1),
        #                                    columns=[alts[altitude]],
        #                                    # columns=[dist_ls.layercenters[altitude]]
        #                                    )  # these are the integrated intensities of scattered light into the relavant angles. Integration is from current (arbitrary) to top layer
        # print(phase_fct_rel.shape, layerthickness[altitude:].shape)
        phth = phase_fct_rel * layerthickness[altitude:]
        phase_fct_rel_integ = pd.DataFrame(phth.apply(np.sum, 1))
        # return phase_fct_rel, phase_fct_rel_integ

        if airmassfct:
            slant_adjust = 1. / np.sin(solar_elev[altitude])
        else:
            slant_adjust = 1.
        # similar to above this selects the different angels of mSASP to the sun. However, it keeps all of them (no unique)
        closest_phase2sun_azi = array_tools.find_closest(phase_fct_rel_integ.index.values,
                                                         mSASP2Sunangles.mSASP_sun_angle.values)

        what_mSASP_sees_aerosols[dist_ls.layercenters[altitude]] = pd.Series(
            phase_fct_rel_integ.iloc[closest_phase2sun_azi].values.transpose()[0] * slant_adjust)
        # what_mSASP_sees_aerosols[dist_ls.layercenters[altitude]] = pd.Series(
        #     phase_fct_rel_integ.iloc[closest_phase2sun_azi].values.transpose()[0] * slant_adjust)

        # what_mSASP_sees_AOD_aerosols[altitude] = opt_prop.data_orig['AOD_layer'][altitude:].sum().values[0] * slant_adjust
        what_mSASP_sees_AOD_aerosols[altitude] = opt_prop.data_orig['AOD_cum'].values[altitude][0] * slant_adjust
    what_mSASP_sees_aerosols.index = mSASP2Sunangles.index
    # what_mSASP_sees_AOD_aerosols = pd.DataFrame(what_mSASP_sees_AOD_aerosols, index = alts, columns = ['AOD_aerosols'])
    what_mSASP_sees_AOD = pd.DataFrame(what_mSASP_sees_AOD_aerosols, columns=['aerosol'])
    what_mSASP_sees_sky = {'aerosol': what_mSASP_sees_aerosols}

    what_mSASP_sees_rayleigh, what_mSASP_sees_AOD_rayleigh = simulate_from_rayleigh(time_series,
                                                                                    dist_ls.layerbounderies,
                                                                                    pressure,
                                                                                    temp,
                                                                                    opt_prop.wavelength,
                                                                                    what_mSASP_sees_aerosols.shape[0],
                                                                                    rotations,
                                                                                    airmassfct,
                                                                                    sun_azimuth)
    what_mSASP_sees_rayleigh.columns = dist_ls.layercenters
    what_mSASP_sees_sky['rayleigh'] = what_mSASP_sees_rayleigh

    what_mSASP_sees_sum = what_mSASP_sees_aerosols + what_mSASP_sees_rayleigh
    what_mSASP_sees_sky['sum'] = what_mSASP_sees_sum
    # what_mSASP_sees_sky['aerosols'] = what_mSASP_sees_aerosols


    what_mSASP_sees_AOD_sum = what_mSASP_sees_AOD_aerosols + what_mSASP_sees_AOD_rayleigh.values.transpose()[0]
    # what_mSASP_sees_AOD['aerosols'] = what_mSASP_sees_AOD_aerosols
    what_mSASP_sees_AOD['rayleigh'] = what_mSASP_sees_AOD_rayleigh.values.transpose()[0]
    what_mSASP_sees_AOD['sum'] = what_mSASP_sees_AOD_sum
    # return what_mSASP_sees_AOD_aerosols  , what_mSASP_sees_AOD_rayleigh.values.transpose()[0]

    # what_mSASP_sees_AOD_aerosols = pd.DataFrame(what_mSASP_sees_AOD_aerosols, index = alts, columns = ['AOD'])
    what_mSASP_sees_AOD.index = alts
    return what_mSASP_sees_sky, what_mSASP_sees_AOD