package org.opensha2.mfd; import org.opensha2.eq.Earthquakes; import org.opensha2.function.EvenlyDiscretizedFunc; /** * Base implementation for magnitude-frequency distributions (MFDs) that give * the rate of one or more earthquakes with differing magnitudes per year. * * * @author Nitin Gupta * @author Peter Powers */ public class IncrementalMfd extends EvenlyDiscretizedFunc { // TODO Mfds should be immutable protected String defaultInfo; protected String defaultName; private final boolean floats; // TODO this copy of constructor works, but is difficult; there are // both methods and protected access to numerous fields in numerous parents. // We should be able to duplicate the class by copying x and y values with // other fields being returned lazily a la XY_Series // public static IncrementalMfd copyOf(IncrementalMfd mfd) { IncrementalMfd copy = new IncrementalMfd(mfd.minX, mfd.num, mfd.delta, mfd.floats); for (int i = 0; i < mfd.getNum(); i++) { copy.set(i, mfd.getY(i)); } return copy; } /** * todo constructors * @param min * @param num * @param delta using the parameters we call the parent class constructors to * initialise the parent class variables */ public IncrementalMfd(double min, int num, double delta, boolean floats) { super(min, num, delta); this.floats = floats; setTolerance(delta / 1000000); } /** * todo constructors * @param min * @param max * @param num using the min, max and num we calculate the delta */ public IncrementalMfd(double min, double max, int num, boolean floats) { super(min, max, num); this.floats = floats; setTolerance(delta / 1000000); } /** * This function finds IncrRate for the given magnitude * @param mag */ public double getIncrRate(double mag) { int xIndex = getXIndex(mag); return getIncrRate(xIndex); } /** * This function finds the IncrRate at the given index * @param index */ public double getIncrRate(int index) { return getY(index); } /** * This function finds the cumulative Rate at a specified magnitude (the rate * greater than and equal to that mag) * @param mag */ public double getCumRate(double mag) { return getCumRate(getXIndex(mag)); } /** * This function finds the cumulative Rate at a specified index (the rate * greater than and equal to that index) * @param index */ public double getCumRate(int index) { double sum = 0.0; for (int i = index; i < num; ++i) { sum += getIncrRate(i); } return sum; } /** * This function finds the moment Rate at a specified magnitude * @param mag */ public double getMomentRate(double mag) { return getIncrRate(mag) * Earthquakes.magToMoment(mag); } /** * This function finds the moment Rate at a specified index * @param index */ public double getMomentRate(int index) { return getIncrRate(index) * Earthquakes.magToMoment(getX(index)); } /** * This function return the sum of all the moment rates as a double variable */ public double getTotalMomentRate() { double sum = 0.0; for (int i = 0; i < num; ++i) { sum += getMomentRate(i); } return sum; } /** * This function returns the sum of all the incremental rate as the double * varibale */ public double getTotalIncrRate() { double sum = 0.0; for (int i = 0; i < num; ++i) { sum += getIncrRate(i); } return sum; } /** * This function normalises the values of all the Incremental rate at each * point, by dividing each one by the totalIncrRate, so that after * normalization the sum addition of all incremental rate at each point comes * to be 1. */ public void normalizeByTotalRate() { double totalIncrRate = getTotalIncrRate(); for (int i = 0; i < num; ++i) { double newRate = getIncrRate(i) / totalIncrRate; super.set(i, newRate); } } /** * This returns the object of the class EvenlyDiscretizedFunc which contains * all the points with Cum Rate Distribution (the rate greater than and equal * to each magnitude) */ public EvenlyDiscretizedFunc getCumRateDist() { EvenlyDiscretizedFunc cumRateDist = new EvenlyDiscretizedFunc(minX, num, delta); double sum = 0.0; for (int i = num - 1; i >= 0; --i) { sum += getIncrRate(i); cumRateDist.set(i, sum); } cumRateDist.setInfo(this.getInfo()); cumRateDist.setName(name()); return cumRateDist; } /** * This returns the object of the class EvenlyDiscretizedFunc which contains * all the points with Cum Rate Distribution (the rate greater than and equal * to each magnitude). It differs from getCumRateDist() in the X Values * because the values are offset by delta/2 in the CumDist returned by this * method. */ public EvenlyDiscretizedFunc getCumRateDistWithOffset() { EvenlyDiscretizedFunc cumRateDist = new EvenlyDiscretizedFunc(minX - delta / 2, num, delta); double sum = 0.0; for (int i = num - 1; i >= 0; --i) { sum += getIncrRate(i); cumRateDist.set(i, sum); } cumRateDist.setInfo(this.getInfo()); cumRateDist.setName(name()); return cumRateDist; } /** * This returns the object of the class EvenlyDiscretizedFunc which contains * all the points with Moment Rate Distribution */ public EvenlyDiscretizedFunc getMomentRateDist() { EvenlyDiscretizedFunc momentRateDist = new EvenlyDiscretizedFunc(minX, num, delta); for (int i = num - 1; i >= 0; --i) { momentRateDist.set(i, getMomentRate(i)); } momentRateDist.setInfo(this.getInfo()); momentRateDist.setName(name()); return momentRateDist; } /** * This returns the object of the class EvenlyDiscretizedFunc which contains * cumulative Moment Rate (the total moment rate for all points greater than * and equal to each mag) */ public EvenlyDiscretizedFunc getCumMomentRateDist() { EvenlyDiscretizedFunc momentRateDist = new EvenlyDiscretizedFunc(minX, num, delta); double totMoRate = 0; for (int i = num - 1; i >= 0; --i) { totMoRate += getMomentRate(i); momentRateDist.set(i, totMoRate); } momentRateDist.setInfo(this.getInfo()); momentRateDist.setName(name()); return momentRateDist; } /** * Using this function each data point is scaled to ratio of specified * newTotalMomentRate and oldTotalMomentRate. * @param newTotMoRate */ public void scaleToTotalMomentRate(double newTotMoRate) { double oldTotMoRate = getTotalMomentRate(); if (D) { System.out.println("old Mo. Rate = " + oldTotMoRate); } if (D) { System.out.println("target Mo. Rate = " + newTotMoRate); } double scaleRate = newTotMoRate / oldTotMoRate; for (int i = 0; i < num; ++i) { super.set(i, scaleRate * getIncrRate(i)); } if (D) { System.out.println("actual Mo. Rate = " + getTotalMomentRate()); } } /** * Using this function each data point is scaled to the ratio of the CumRate * at a given magnitude and the specified rate. * @param mag * @param rate */ public void scaleToCumRate(double mag, double rate) { int index = getXIndex(mag); scaleToCumRate(index, rate); } /** * Using this function each data point is scaled to the ratio of the CumRate * at a given index and the specified rate * @param index * @param rate */ public void scaleToCumRate(int index, double rate) { double temp = getCumRate(index); double scaleCumRate = rate / temp; for (int i = 0; i < num; ++i) { super.set(i, scaleCumRate * getIncrRate(i)); } } /** * Using this function each data point is scaled to the ratio of the IncrRate * at a given magnitude and the specified newRate * @param mag * @param newRate */ public void scaleToIncrRate(double mag, double newRate) { int index = getXIndex(mag); scaleToIncrRate(index, newRate); } /** * Using this function each data point is scaled to the ratio of the IncrRate * at a given index and the specified newRate * @param index * @param newRate */ public void scaleToIncrRate(int index, double newRate) { double temp = getIncrRate(index); double scaleIncrRate = newRate / temp; for (int i = 0; i < num; ++i) { super.set(i, scaleIncrRate * getIncrRate(i)); } } /** * Returns the default Info String for the Distribution * @return String */ public String getDefaultInfo() { return defaultInfo; } /** * Returns the default Name for the Distribution * @return String */ public String getDefaultName() { defaultName = "Incremental Mag Freq Dist"; return defaultName; } /** * Returns the Name of the Distribution that user has set from outside, if it * is null then it returns the default Name from the distribution. Makes the * call to the parent "getName()" method to get the metadata set outside the * application. * @return String */ @Override public String name() { if (name != null && !(name.trim().equals(""))) { return super.name(); } return getDefaultName(); } /** * Returns the info of the distribution that user has set from outside, if it * is null then it returns the default info from the distribution. Makes the * call to the parent "getInfo()" method to get the metadata set outside the * application. * @return String */ @Override public String getInfo() { if (info != null && !(info.equals(""))) { return super.getInfo(); } return getDefaultInfo(); } // /** Returns a copy of this and all points in this DiscretizedFunction */ // public IncrementalMfd deepClone() { // // IncrementalMfd f = new IncrementalMfd( // minX, num, delta // ); // // f.tolerance = tolerance; // f.setInfo(this.getInfo()); // f.setName(name()); // for(int i = 0; i<num; i++) // f.set(i, points[i]); // // return f; // } /** * This returns the maximum magnitude with a non-zero rate */ public double getMinMagWithNonZeroRate() { for (int i = 0; i < num; i++) { if (getY(i) > 0) { return getX(i); } } return Double.NaN; } /** * This returns the maximum magnitude with a non-zero rate */ public double getMaxMagWithNonZeroRate() { for (int i = num - 1; i >= 0; i--) { if (getY(i) > 0) { return getX(i); } } return Double.NaN; } /** * This computes the b-value (the slope of the line of a linear-log plot, * meaning after computing log10 of all y-axis values) between the the given * x-axis values. If Double.NaN is passed in, then the first (or last) * non-zero rate is used for min_bValMag (or max_bValMag). * @param min_bValMag * @param max_bValMag */ // TODO commented out; not used here; requires commons-math for Regression // public double compute_bValue(double min_bValMag, double max_bValMag) { // int firstIndex, lastIndex; // // if(Double.isNaN(min_bValMag)) // firstIndex = getClosestXIndex(getMinMagWithNonZeroRate()); // else // firstIndex = getClosestXIndex(min_bValMag); // // if(Double.isNaN(max_bValMag)) // lastIndex = getClosestXIndex(getMaxMagWithNonZeroRate()); // else // lastIndex = getClosestXIndex(max_bValMag); // // SimpleRegression regression = new SimpleRegression(); // for(int i=firstIndex; i<=lastIndex; i++) { // if(getY(i)>0.0) // avoid taking log of zero // regression.addData(getX(i), Math.log10(getY(i))); // } // //// if(getX(lastIndex)-getX(firstIndex) <1.0) //// return Double.NaN; // // return regression.getSlope(); // } /** * This sets all y-axis values above the given total moment rate to zero. The * final total moment rate will be something less than the value passed in. * @param moRate */ public void setValuesAboveMomentRateToZero(double moRate) { double mag = findMagJustAboveMomentRate(moRate); if (Double.isNaN(mag)) { return; } zeroAboveMag(mag); } /** * This finds the smallest magnitude such that all those less than and equal * to this have a cumulative moment rate less than that passed in. * @param moRate - in Nm/yr */ public double findMagJustAboveMomentRate(double moRate) { double cumMoRate = 0; int targetIndex = -1; for (int i = 0; i < getNum(); i++) { cumMoRate += getMomentRate(i); if (cumMoRate > moRate) { targetIndex = i - 1; break; } } if (targetIndex == -1) { return Double.NaN; } else { return getX(targetIndex); } } /** * Sets the rate of all magnitudes above the supplied magnitude to 0. * @param mag TODO this is awful this assumes you know the (almost) exact * magnitude (wihtin tolerance) of a mag in the MFD; if you just pick * an arbitrary value, internally an index of -1 will be returned and * all values will be set to Zero */ public void zeroAboveMag(double mag) { for (int i = getXIndex(mag) + 1; i < getNum(); i++) { set(i, 0); } } public void zeroAboveMag2(double mag) { for (int i = 0; i < getNum(); i++) { if (getX(i) > mag) { set(i, 0); } } } /** * Sets the rate of all magnitudes above the supplied magnitude to 0. * @param mag */ public void zeroAtAndAboveMag(double mag) { for (int i = getXIndex(mag); i < getNum(); i++) { set(i, 0); } } /** * This computes the b-value (the slope of the line of a linear-log plot, * meaning after computing log10 of all y-axis values) between the smallest * and largest mags with non-zero rates (zeros at the beginning and end of the * distribution are ignored). */ // NOTE commented out; not used // public double compute_bValue() { // return compute_bValue(Double.NaN, Double.NaN); // } /** * Returns whether ruptures generated using this MFD should float. May not be * applicable to all source types (e.g. grid or point sources). * @return {@code true} if ruptures should float, {@code false} otherwise */ public boolean floats() { return floats; } }