/**
   * This methods makes the GCIM results in a string for output to either console or external window
   */
  public String getGcimResultsString() {

    for (int i = 0; i < numIMi; i++) {

      HashMap<TectonicRegionType, ScalarIMR> imriMap = imiAttenRels.get(i);
      ScalarIMR firstIMRiFromMap = TRTUtils.getFirstIMR(imriMap);

      GcimResultsString += "----------------------" + "\n";
      // Get the IM name for printing
      if (firstIMRiFromMap.getIntensityMeasure().getName() == SA_Param.NAME) {
        GcimResultsString +=
            "Results for SA period: "
                + ((SA_Param) firstIMRiFromMap.getIntensityMeasure()).getPeriodParam().getValue()
                + "\n";
      } else if (firstIMRiFromMap.getIntensityMeasure().getName() == SA_InterpolatedParam.NAME) {
        GcimResultsString +=
            "Results for SA Interpolated period: "
                + ((SA_InterpolatedParam) firstIMRiFromMap.getIntensityMeasure())
                    .getPeriodInterpolatedParam()
                    .getValue()
                + "\n";
      } else {
        GcimResultsString +=
            "Results for " + firstIMRiFromMap.getIntensityMeasure().getName() + "\n";
      }
      for (int j = 0; j < zApprox.length; j++) {
        GcimResultsString += imiArray[j][i] + "\t" + cdfIMi_IMjArray[j][i] + "\n";
      }
      GcimResultsString += "----------------------" + "\n";
      GcimResultsString += "\n";
    }
    return GcimResultsString;
  }
 private static void setSAPeriodInIMR(ScalarIMR imr, double period) {
   ((Parameter<Double>) imr.getIntensityMeasure())
       .getIndependentParameter(PeriodParam.NAME)
       .setValue(new Double(period));
 }
  /**
   * this function performs the GCIM computations to obtain the conditional distribution of a single
   * input intensity measure. Returns true if it was successfully else return false
   *
   * @param imiNumber - the imi counter used for storing results in array
   * @param imri: selected IMRi object (that for which the distribution is desired i.e. IMi)
   * @param imCorrelationRelationship: selected correlation object for IMi and IMj
   * @param maxDist: maxDist of sources to consider
   * @param magDistFilter: Magnitude-Distance filter for sources
   * @return boolean
   */
  public boolean getSingleGcim(
      int imiNumber,
      HashMap<TectonicRegionType, ScalarIMR> imriMap,
      HashMap<TectonicRegionType, ImCorrelationRelationship> imijCorrRelMap,
      double maxDist,
      ArbitrarilyDiscretizedFunc magDistFilter) {

    // Set the site in imri
    for (ScalarIMR imri : imriMap.values()) {
      imri.resetParameterEventListeners();
      imri.setUserMaxDistance(maxDist);
      imri.setSite(site);
    }

    // Get total number of sources
    int numSources = eqkRupForecast.getNumSources();

    double[][] mulnIMi_RupIMj = new double[numSources][];
    double[][] stdlnIMi_RupIMj = new double[numSources][];
    double mulnIMi_Rup, stdlnIMi_Rup, mulnIMi_IMj, varlnIMi_IMj, stdlnIMi_IMj, cdfIMi_RupIMj;

    mulnIMi_RupIMjArray[imiNumber] = new double[numSources][];
    stdlnIMi_RupIMjArray[imiNumber] = new double[numSources][];

    boolean includeMagDistFilter;
    if (magDistFilter == null) includeMagDistFilter = false;
    else includeMagDistFilter = true;
    double magThresh = 0.0;

    int numRupRejected = 0;
    // loop over all of the ruptures
    for (int i = 0; i < numSources; i++) {
      // get source and all its details
      ProbEqkSource source = eqkRupForecast.getSource(i);

      int numRuptures = eqkRupForecast.getNumRuptures(i);
      mulnIMi_RupIMj[i] = new double[numRuptures];
      stdlnIMi_RupIMj[i] = new double[numRuptures];

      mulnIMi_RupIMjArray[imiNumber][i] = new double[numRuptures];
      stdlnIMi_RupIMjArray[imiNumber][i] = new double[numRuptures];

      // check the distance of the source
      double distance = source.getMinDistance(site);
      if (distance > maxDist) {
        continue;
      }

      // set the IMR according to the tectonic region of the source (if there is more than one)
      TectonicRegionType trt = source.getTectonicRegionType();
      ScalarIMR imri = TRTUtils.getIMRforTRT(imriMap, trt);
      ImCorrelationRelationship imijCorrRel = Utils.getIMCorrRelForTRT(imijCorrRelMap, trt);

      // compute the correlation coefficient between lnIMi and lnIMj for the given source
      double rho_lnIMilnIMj = imijCorrRel.getImCorrelation();

      // loop over ruptures
      for (int j = 0; j < numRuptures; j++) {

        ProbEqkRupture rupture = source.getRupture(j);

        // apply magThreshold if we're to use the mag-dist cutoff filter
        if (includeMagDistFilter && rupture.getMag() < magThresh) {
          numRupRejected += 1;
          continue;
        }

        // set the rupture in the imr
        imri.setEqkRupture(rupture);

        // get the unconditional mean, stdDev of lnIMi for the given rupture
        mulnIMi_Rup = imri.getMean();
        stdlnIMi_Rup = imri.getStdDev();

        // get the conditional mean, stdDev of lnIMi for the given rupture
        mulnIMi_RupIMj[i][j] = mulnIMi_Rup + stdlnIMi_Rup * rho_lnIMilnIMj * epsilonIMj[i][j];
        stdlnIMi_RupIMj[i][j] = stdlnIMi_Rup * Math.sqrt(1 - Math.pow(rho_lnIMilnIMj, 2.0));

        // store in array
        mulnIMi_RupIMjArray[imiNumber][i][j] = mulnIMi_RupIMj[i][j];
        stdlnIMi_RupIMjArray[imiNumber][i][j] = stdlnIMi_RupIMj[i][j];
      }
    }

    // compute the conditional mean and variance of lnIMi (independent of Rup)
    mulnIMi_IMj = 0;
    // loop over all of the ruptures
    for (int i = 0; i < numSources; i++) {
      int numRuptures = eqkRupForecast.getNumRuptures(i);
      for (int j = 0; j < numRuptures; j++) {
        mulnIMi_IMj += mulnIMi_RupIMj[i][j] * pRup_IMj[i][j];
      }
    }

    varlnIMi_IMj = 0;
    // loop over all of the ruptures
    for (int i = 0; i < numSources; i++) {
      int numRuptures = eqkRupForecast.getNumRuptures(i);
      for (int j = 0; j < numRuptures; j++) {
        varlnIMi_IMj +=
            (Math.pow(stdlnIMi_RupIMj[i][j], 2.0)
                    + Math.pow(mulnIMi_RupIMj[i][j] - mulnIMi_IMj, 2.0))
                * pRup_IMj[i][j];
      }
    }
    stdlnIMi_IMj = Math.sqrt(varlnIMi_IMj);

    // Initially assuming that that lnIMi|IMj=imj is lognormal determine the range of
    // IMi values to compute the CDF of lnIMi|IMj=imj for, then compute this cdf
    for (int n = 0; n < zApprox.length; n++) {
      imiArray[n][imiNumber] = Math.exp(mulnIMi_IMj + zApprox[n] * stdlnIMi_IMj);

      cdfIMi_IMjArray[n][imiNumber] = 0.0;
      // loop over all of the ruptures
      for (int i = 0; i < numSources; i++) {
        int numRuptures = eqkRupForecast.getNumRuptures(i);
        for (int j = 0; j < numRuptures; j++) {
          double z =
              (Math.log(imiArray[n][imiNumber]) - mulnIMi_RupIMj[i][j]) / stdlnIMi_RupIMj[i][j];
          cdfIMi_RupIMj = GaussianDistCalc.getCDF(z);
          cdfIMi_IMjArray[n][imiNumber] += cdfIMi_RupIMj * pRup_IMj[i][j];
        }
      }
    }

    return true;
  }