package org.opensha2.etc;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SuppressWarnings("javadoc")
public class HazMat {
/*
* Developer notes:
*
* Mathworks has gone out of its way to make it more and more difficult to use
* Java in Matlab as time goes on, despite it being a first-class citizen.
* Specifically, the Matlab classpath includes a dizzying number of 3rd party
* libraries, many of which are now well out of date. The problem posed to
* nshmp-haz is the inclusion of v.15 of Google Guava (this, one can only
* determine by unpacking the included google-collections.jar as they haven't
* bothered to update the name of the dependency) whereas the current Guava
* release is v.20. The aggressive deprecation and removal of bad, unused, or
* superceeded code by Google has resulted in significant class and method
* variations within Guava over 5 update cycles. Nshmp-haz will not remove
* it's dependency on Guava, but putting nshmp-haz early on the Matlab
* classpath causes Matlab to crash as it can't find (now missing) methods in
* Guava.
*
* The unsatisfactory but functional workaround is to use a custom class
* loader that, once we want to use nshmp-haz classes, scans nshmp-haz.jar
* before looking in the matlab classpath. This approach is messy in that the
* sole point of entry is this class, which delegates to HazMatHelper (loaded
* with the custom class loader) and the methods of which must be accessed via
* reflection.
*
* Note that if nshmp-haz moves to Java 8, which will probably occur sooner
* rather than later, the custom class loader will also have to have Java 8 on
* it's classpath. Sigh.
*/
private static final List<Class<?>> INPUT_CLASSES = Arrays.asList(new Class<?>[] {
double.class,
double.class,
double.class,
double.class,
double.class,
double.class,
double.class,
double.class,
double.class,
double.class,
boolean.class,
double.class,
double.class });
private static final Class<?>[] MEAN_CLASSES;
private static final Class<?>[] SPECTRUM_CLASSES;
static {
/* Build custom class arrays needed to call methods via reflection. */
List<Class<?>> classes = new ArrayList<>();
classes.add(String.class);
classes.addAll(INPUT_CLASSES);
SPECTRUM_CLASSES = classes.toArray(new Class[INPUT_CLASSES.size() + 1]);
classes.add(0, String.class);
MEAN_CLASSES = classes.toArray(new Class[INPUT_CLASSES.size() + 2]);
}
private Object hazMatImpl;
HazMat(Object hazMatImpl) {
this.hazMatImpl = hazMatImpl;
}
public double[] gmmMean(String gmm, String imt, GmmParams in) {
try {
Method method = hazMatImpl.getClass().getMethod("gmmMean", MEAN_CLASSES);
return (double[]) method.invoke(hazMatImpl,
gmm,
imt,
in.Mw,
in.rJB,
in.rRup,
in.rX,
in.dip,
in.width,
in.zTop,
in.zHyp,
in.rake,
in.vs30,
in.vsInf,
in.z1p0,
in.z2p5);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public HazMatSpectrum gmmSpectrum(String gmm, GmmParams in) {
try {
Method method = hazMatImpl.getClass().getMethod("gmmSpectrum", SPECTRUM_CLASSES);
double[][] result = (double[][]) method.invoke(hazMatImpl,
gmm,
in.Mw,
in.rJB,
in.rRup,
in.rX,
in.dip,
in.width,
in.zTop,
in.zHyp,
in.rake,
in.vs30,
in.vsInf,
in.z1p0,
in.z2p5);
HazMatSpectrum spectrum = new HazMatSpectrum();
spectrum.periods = result[0];
spectrum.means = result[1];
spectrum.sigmas = result[2];
return spectrum;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static HazMat init(String nshmpHazPath) {
try {
URL nshmpHazUrl = Paths.get(nshmpHazPath).toUri().toURL();
List<URL> classpath = new ArrayList<>();
classpath.add(nshmpHazUrl);
ClassLoader loader = new ParentLastURLClassLoader(classpath);
Class<?> clazz = loader.loadClass(HazMatImpl.class.getName());
return new HazMat(clazz.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}