code: def _vis_calibrate(
      data,
      chn,
      calib_type,
      pre_launch_coeffs=False,
      calib_coeffs=None,
      mask=True,
  ):
      """Calibrate visible channel data.
  
      *calib_type* in count, reflectance, radiance.
  
      """
      # Calibration count to albedo, the calibration is performed separately for
      # two value ranges.
      if calib_type not in ["counts", "radiance", "reflectance"]:
          raise ValueError("Calibration " + calib_type + " unknown!")
  
      channel_data = data["hrpt"][:, :, chn]
      chunks = get_aapp_chunks(channel_data.shape)
      line_chunks = chunks[0]
      channel = da.from_array(channel_data, chunks=chunks)
      mask &= channel != 0
  
      if calib_type == "counts":
          return channel
  
      channel = channel.astype(CHANNEL_DTYPE)
  
      if calib_type == "radiance":
          logger.info(
              "Radiances are not yet supported for "
              + "the VIS/NIR channels!"
          )
  
      if pre_launch_coeffs:
          coeff_idx = 2
      else:
          # check that coeffs are valid
          if np.all(data["calvis"][:, chn, 0, 4] == 0):
              logger.info(
                  "No valid operational coefficients, fall back to pre-launch"
              )
              coeff_idx = 2
          else:
              coeff_idx = 0
  
      intersection = da.from_array(
          data["calvis"][:, chn, coeff_idx, 4], chunks=line_chunks
      )
  
      if calib_coeffs is not None:
          logger.info(
              "Updating from external calibration coefficients."
          )
          slope1 = da.from_array(calib_coeffs[0], chunks=line_chunks)
          intercept1 = da.from_array(
              calib_coeffs[1], chunks=line_chunks
          )
          slope2 = da.from_array(calib_coeffs[2], chunks=line_chunks)
          intercept2 = da.from_array(
              calib_coeffs[3], chunks=line_chunks
          )
      else:
          slope1 = (
              da.from_array(
                  data["calvis"][:, chn, coeff_idx, 0],
                  chunks=line_chunks,
              )
              * 1e-10
          )
          intercept1 = (
              da.from_array(
                  data["calvis"][:, chn, coeff_idx, 1],
                  chunks=line_chunks,
              )
              * 1e-7
          )
          slope2 = (
              da.from_array(
                  data["calvis"][:, chn, coeff_idx, 2],
                  chunks=line_chunks,
              )
              * 1e-10
          )
          intercept2 = (
              da.from_array(
                  data["calvis"][:, chn, coeff_idx, 3],
                  chunks=line_chunks,
              )
              * 1e-7
          )
  
          # In the level 1b file, the visible coefficients are stored as 4-byte integers. Scaling factors then convert
          # them to real numbers which are applied to the measured counts. The coefficient is different depending on
          # whether the counts are less than or greater than the high-gain/low-gain transition value (nominally 500).
          # The slope for visible channels should always be positive (reflectance increases with count). With the
          # pre-launch coefficients the channel 2, 3a slope is always positive but with the operational coefs the stored
          # number in the high-reflectance regime overflows the maximum 2147483647, i.e. it is negative when
          # interpreted as a signed integer. So you have to modify it. Also chanel 1 is treated the same way in AAPP.
          slope2 = da.where(slope2 < 0, slope2 + 0.4294967296, slope2)
  
      channel = da.where(
          channel <= intersection[:, None],
          channel * slope1[:, None] + intercept1[:, None],
          channel * slope2[:, None] + intercept2[:, None],
      )
  
      channel = channel.clip(min=0)
  
      return da.where(mask, channel, np.nan)
  
imports: import functools
  import logging
  from datetime import datetime, timedelta
  import dask.array
  import numpy
  import xarray
  from dask import delayed
  from satpy.readers.file_handlers import BaseFileHandler
  from satpy.utils import get_chunk_size_limit
label_desc: Use image node_id 4 for calling a global function with example usage: _vis_calibrate(data, chn, calib_type, pre_launch_coeffs, calib_coeffs, mask) and returns: da, channel