class_docstr: Equalized DNB composite using the error function (erf).
  
  The logic for this code was taken from Polar2Grid and was originally
  developed by Curtis Seaman and Steve Miller. The original code was
  written in IDL and is included as comments in the code below.
class_docstr_tok: ["Equalized","DNB","composite","using","the","error","function","(","erf",")",".","The","logic","for","this","code","was","taken","from","Polar2Grid","and","was","originally","developed","by","Curtis","Seaman","and","Steve","Miller",".","The","original","code","was","written","in","IDL","and","is","included","as","comments","in","the","code","below","."]
docstr: Create the composite DataArray object for ERFDNB.
docstr_tok: ["Create","the","composite","DataArray","object","for","ERFDNB","."]
code: def __call__(self, datasets, **info):
      """Create the composite DataArray object for ERFDNB."""
      if len(datasets) != 4:
          raise ValueError(
              "Expected 4 datasets, got %d" % (len(datasets),)
          )
  
      from scipy.special import erf
  
      dnb_data = datasets[0]
      sza_data = datasets[1]
      lza_data = datasets[2]
      output_dataset = dnb_data.where(
          ~(dnb_data.isnull() | sza_data.isnull())
      )
      # this algorithm assumes units of "W cm-2 sr-1" so if there are other
      # units we need to adjust for that
      if dnb_data.attrs.get("units", "W m-2 sr-1") == "W m-2 sr-1":
          unit_factor = 10000.0
      else:
          unit_factor = 1.0
  
      # convert to decimal instead of %
      moon_illum_fraction = da.mean(datasets[3].data) * 0.01
  
      # From Steve Miller and Curtis Seaman
      # maxval = 10.^(-1.7 - (((2.65+moon_factor1+moon_factor2))*(1+erf((solar_zenith-95.)/(5.*sqrt(2.0))))))
      # minval = 10.^(-4. - ((2.95+moon_factor2)*(1+erf((solar_zenith-95.)/(5.*sqrt(2.0))))))
      # scaled_radiance = (radiance - minval) / (maxval - minval)
      # radiance = sqrt(scaled_radiance)
  
      # Version 2: Update from Curtis Seaman
      # maxval = 10.^(-1.7 - (((2.65+moon_factor1+moon_factor2))*(1+erf((solar_zenith-95.)/(5.*sqrt(2.0))))))
      # minval = 10.^(-4. - ((2.95+moon_factor2)*(1+erf((solar_zenith-95.)/(5.*sqrt(2.0))))))
      # saturated_pixels = where(radiance gt maxval, nsatpx)
      # saturation_pct = float(nsatpx)/float(n_elements(radiance))
      # print, 'Saturation (%) = ', saturation_pct
      #
      # while saturation_pct gt 0.005 do begin
      #   maxval = maxval*1.1
      #   saturated_pixels = where(radiance gt maxval, nsatpx)
      #   saturation_pct = float(nsatpx)/float(n_elements(radiance))
      #   print, saturation_pct
      # endwhile
      #
      # scaled_radiance = (radiance - minval) / (maxval - minval)
      # radiance = sqrt(scaled_radiance)
  
      moon_factor1 = 0.7 * (1.0 - moon_illum_fraction)
      moon_factor2 = 0.0022 * lza_data.data
      erf_portion = 1 + erf(
          (sza_data.data - 95.0) / (5.0 * np.sqrt(2.0))
      )
      max_val = (
          da.power(
              10,
              -1.7 - (2.65 + moon_factor1 + moon_factor2) * erf_portion,
          )
          * unit_factor
      )
      min_val = (
          da.power(10, -4.0 - (2.95 + moon_factor2) * erf_portion)
          * unit_factor
      )
  
      # Update from Curtis Seaman, increase max radiance curve until less
      # than 0.5% is saturated
      if self.saturation_correction:
          delayed = dask.delayed(self._saturation_correction)(
              output_dataset.data, unit_factor, min_val, max_val
          )
          output_dataset.data = da.from_delayed(
              delayed, output_dataset.shape, output_dataset.dtype
          )
          output_dataset.data = output_dataset.data.rechunk(
              dnb_data.data.chunks
          )
      else:
          inner_sqrt = (output_dataset - min_val) / (max_val - min_val)
          # clip negative values to 0 before the sqrt
          inner_sqrt.data = np.clip(inner_sqrt.data, 0, None)
          output_dataset.data = np.sqrt(inner_sqrt).data
  
      info = dnb_data.attrs.copy()
      info.update(self.attrs)
      info["standard_name"] = "equalized_radiance"
      info["mode"] = "L"
      output_dataset.attrs = info
      return output_dataset
  
imports: from __future__ import annotations
  import logging
  import math
  from datetime import datetime
  import dask
  import dask.array
  import numpy
  import xarray
  from satpy.composites import CompositeBase, GenericCompositor
  from satpy.dataset import combine_metadata
label_desc: Use image node_id 3 for calling the ERFDNB obj's underlying member method code with example usage: obj.__call__(datasets) and returns: output_dataset