code: def calculate_phenotypes(
      mt,
      genotype,
      beta,
      h2,
      popstrat=None,
      popstrat_var=None,
      exact_h2=False,
  ):
      r"""Calculates phenotypes by multiplying genotypes and betas.
  
      Parameters
      ----------
      mt : :class:`.MatrixTable`
          :class:`.MatrixTable` with all relevant fields passed as parameters.
      genotype : :class:`.Expression` or :class:`.CallExpression`
          Entry field of genotypes.
      beta : :class:`.Expression`
          Row field of SNP effects.
      h2 : :obj:`float` or :obj:`int` or :obj:`list` or :class:`numpy.ndarray`
          SNP-based heritability (:math:`h^2`) of simulated trait. Can only be
          ``None`` if running annotation-informed model.
      popstrat : :class:`.Expression`, optional
          Column field containing population stratification term.
      popstrat_var : :obj:`float` or :obj:`int`
          Variance of population stratification term.
      exact_h2: :obj:`bool`
          Whether to exactly simulate ratio of variance of genetic component of
          phenotype to variance of phenotype to be h2. If `False`, ratio will be
          h2 in expectation. Observed h2 in the simulation will be close to
          expected h2 for large-scale simulations.
  
      Returns
      -------
      :class:`.MatrixTable`
          :class:`.MatrixTable` with simulated phenotype as column field.
      """
      print("calculating phenotype")
      h2 = (
          h2.tolist()
          if isinstance(h2, np.ndarray)
          else ([h2] if not isinstance(h2, list) else h2)
      )
      assert popstrat_var is None or (
          popstrat_var >= 0
      ), "popstrat_var must be non-negative"
      uid = Env.get_uid(base=100)
      mt = annotate_all(
          mt=mt,
          row_exprs={"beta_" + uid: beta},
          col_exprs={}
          if popstrat is None
          else {"popstrat_" + uid: popstrat},
          entry_exprs={
              "gt_" + uid: genotype.n_alt_alleles()
              if genotype.dtype is hl.dtype("call")
              else genotype
          },
      )
      mt = mt.filter_rows(hl.agg.stats(mt["gt_" + uid]).stdev > 0)
      mt = normalize_genotypes(mt["gt_" + uid])
      if mt["beta_" + uid].dtype == hl.dtype(
          "array<float64>"
      ):  # if >1 traits
          if exact_h2:
              raise ValueError(
                  "exact_h2=True not supported for multitrait simulations"
              )
          else:
              mt = mt.annotate_cols(
                  y_no_noise=hl.agg.array_agg(
                      lambda beta: hl.agg.sum(beta * mt["norm_gt"]),
                      mt["beta_" + uid],
                  )
              )
              mt = mt.annotate_cols(
                  y=mt.y_no_noise
                  + hl.literal(h2).map(
                      lambda x: hl.rand_norm(0, hl.sqrt(1 - x))
                  )
              )
      else:
          if exact_h2 and min([h2[0], 1 - h2[0]]) != 0:
              print("exact h2")
              mt = mt.annotate_cols(
                  **{
                      "y_no_noise_"
                      + uid: hl.agg.sum(
                          mt["beta_" + uid] * mt["norm_gt"]
                      )
                  }
              )
              y_no_noise_stdev = mt.aggregate_cols(
                  hl.agg.stats(mt["y_no_noise_" + uid]).stdev
              )
              mt = mt.annotate_cols(
                  y_no_noise=hl.sqrt(h2[0])
                  * mt["y_no_noise_" + uid]
                  / y_no_noise_stdev
              )  # normalize genetic component of phenotype to have variance of exactly h2
              mt = mt.annotate_cols(
                  **{
                      "noise_"
                      + uid: hl.rand_norm(0, hl.sqrt(1 - h2[0]))
                  }
              )
              noise_stdev = mt.aggregate_cols(
                  hl.agg.stats(mt["noise_" + uid]).stdev
              )
              mt = mt.annotate_cols(
                  noise=hl.sqrt(1 - h2[0])
                  * mt["noise_" + uid]
                  / noise_stdev
              )
              mt = mt.annotate_cols(
                  y=mt.y_no_noise
                  + hl.sqrt(1 - h2[0])
                  * mt["noise_" + uid]
                  / noise_stdev
              )
          else:
              mt = mt.annotate_cols(
                  y_no_noise=hl.agg.sum(
                      mt["beta_" + uid] * mt["norm_gt"]
                  )
              )
              mt = mt.annotate_cols(
                  y=mt.y_no_noise + hl.rand_norm(0, hl.sqrt(1 - h2[0]))
              )
      if popstrat is not None:
          var_factor = (
              1
              if popstrat_var is None
              else (popstrat_var ** (1 / 2))
              / mt.aggregate_cols(
                  hl.agg.stats(mt["popstrat_" + uid])
              ).stdev
          )
          mt = mt.rename({"y": "y_no_popstrat"})
          mt = mt.annotate_cols(
              y=mt.y_no_popstrat + mt["popstrat_" + uid] * var_factor
          )
      mt = _clean_fields(mt, uid)
      return mt
  
imports: import hail
  from hail.typecheck import typecheck, oneof, nullable
  from hail.expr.expressions import expr_float64, expr_int32, expr_array, expr_call
  from hail.matrixtable import MatrixTable
  from hail.table import Table
  from hail.utils.java import Env
  import numpy
  import pandas
  import scipy.stats
label_desc: Use image node_id 7 for calling a global function with example usage: calculate_phenotypes(mt, genotype, beta, h2, popstrat, popstrat_var, exact_h2) and returns: mt