docs: def directional_irradiance(self, altitude=90, azimuth=180,
                                 ground_reflectance=0.2, isotrophic=True):
          """Returns the irradiance components facing a given altitude and azimuth.
  
          This method computes unobstructed solar flux facing a given
          altitude and azimuth. The default is set to return the golbal horizontal
          irradiance, assuming an altitude facing straight up (90 degrees).
  
          Args:
              altitude: A number between -90 and 90 that represents the
                  altitude at which irradiance is being evaluated in degrees.
              azimuth: A number between 0 and 360 that represents the
                  azimuth at wich irradiance is being evaluated in degrees.
              ground_reflectance: A number between 0 and 1 that represents the
                  reflectance of the ground. Default is set to 0.2. Some
                  common ground reflectances are:
                      urban: 0.18
                      grass: 0.20
                      fresh grass: 0.26
                      soil: 0.17
                      sand: 0.40
                      snow: 0.65
                      fresh_snow: 0.75
                      asphalt: 0.12
                      concrete: 0.30
                      sea: 0.06
              isotrophic: A boolean value that sets whether an istotrophic sky is
                  used (as opposed to an anisotrophic sky). An isotrophic sky
                  assummes an even distribution of diffuse irradiance across the
                  sky while an anisotrophic sky places more diffuse irradiance
                  near the solar disc. Default is set to True for isotrophic
  
          Returns:
              total_irradiance: A data collection of total solar irradiance.
              direct_irradiance: A data collection of direct solar irradiance.
              diffuse_irradiance: A data collection of diffuse sky solar irradiance.
              reflected_irradiance: A data collection of ground reflected solar irradiance.
          """
          # function to convert polar coordinates to xyz.
          def pol2cart(phi, theta):
              mult = math.cos(theta)
              x = math.sin(phi) * mult
              y = math.cos(phi) * mult
              z = math.sin(theta)
              return Vector3(x, y, z)
  
          # convert the altitude and azimuth to a normal vector
          normal = pol2cart(math.radians(azimuth), math.radians(altitude))
  
          # create sunpath and get altitude at every timestep of the year
          direct_irr, diffuse_irr, reflected_irr, total_irr = [], [], [], []
          sp = Sunpath.from_location(self.location)
          sp.is_leap_year = self.is_leap_year
          for dt, dnr, dhr in zip(self.datetimes, self.direct_normal_irradiance,
                                  self.diffuse_horizontal_irradiance):
              sun = sp.calculate_sun_from_date_time(dt)
              sun_vec = pol2cart(math.radians(sun.azimuth),
                                 math.radians(sun.altitude))
              vec_angle = sun_vec.angle(normal)
  
              # direct irradiance on surface
              srf_dir = 0
              if sun.altitude > 0 and vec_angle < math.pi / 2:
                  srf_dir = dnr * math.cos(vec_angle)
  
              # diffuse irradiance on surface
              if isotrophic is True:
                  srf_dif = dhr * ((math.sin(math.radians(altitude)) / 2) + 0.5)
              else:
                  y = max(0.45, 0.55 + (0.437 * math.cos(vec_angle)) + 0.313 *
                          math.cos(vec_angle) * 0.313 * math.cos(vec_angle))
                  srf_dif = self.dhr * (y * (
                      math.sin(math.radians(abs(90 - altitude)))) +
                      math.cos(math.radians(abs(90 - altitude))))
  
              # reflected irradiance on surface.
              e_glob = dhr + dnr * math.cos(math.radians(90 - sun.altitude))
              srf_ref = e_glob * ground_reflectance * (0.5 - (math.sin(
                  math.radians(altitude)) / 2))
  
              # add it all together
              direct_irr.append(srf_dir)
              diffuse_irr.append(srf_dif)
              reflected_irr.append(srf_ref)
              total_irr.append(srf_dir + srf_dif + srf_ref)
  
          # create the headers
          a_per = AnalysisPeriod(timestep=self.timestep, is_leap_year=self.is_leap_year)
          direct_hea = diffuse_hea = reflected_hea = total_hea = \
              Header(Irradiance(), 'W/m2', a_per, self.metadata)
  
          # create the data collections
          direct_irradiance = HourlyContinuousCollection(direct_hea, direct_irr)
          diffuse_irradiance = HourlyContinuousCollection(diffuse_hea, diffuse_irr)
          reflected_irradiance = HourlyContinuousCollection(reflected_hea, reflected_irr)
          total_irradiance = HourlyContinuousCollection(total_hea, total_irr)
  
          return total_irradiance, direct_irradiance, \
              diffuse_irradiance, reflected_irradiance