package net.sf.openrocket.simulation.customexpression;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.ArrayUtils;
import de.congrace.exp4j.CustomFunction;
import de.congrace.exp4j.InvalidCustomFunctionException;
import de.congrace.exp4j.Variable;
/*
* This is a singleton class which contains all the functions for custom expressions not provided by exp4j
*/
public class Functions {
private static Functions instance = null;
private static final Logger log = LoggerFactory.getLogger(Functions.class);
private static final Translator trans = Application.getTranslator();
private List<CustomFunction> allFunctions = new ArrayList<CustomFunction>();
public static Functions getInstance() {
if(instance == null) {
try {
instance = new Functions();
} catch (InvalidCustomFunctionException e) {
log.error("Invalid custom function.");
}
}
return instance;
}
public List<CustomFunction> getAllFunction(){
return allFunctions;
}
// A map of available operator strings (keys) and description of function (value)
public static final SortedMap<String, String> AVAILABLE_OPERATORS = new TreeMap<String, String>() {{
put("+" , trans.get("Operator.plus"));
put("-" , trans.get("Operator.minus"));
put("*" , trans.get("Operator.star"));
put("/" , trans.get("Operator.div"));
put("%" , trans.get("Operator.mod"));
put("^" , trans.get("Operator.pow"));
put("abs()" , trans.get("Operator.abs"));
put("ceil()" , trans.get("Operator.ceil"));
put("floor()" , trans.get("Operator.floor"));
put("sqrt()" , trans.get("Operator.sqrt"));
put("cbrt()" , trans.get("Operator.cbrt"));
put("exp()" , trans.get("Operator.exp"));
put("log()" , trans.get("Operator.ln"));
put("sin()" , trans.get("Operator.sin"));
put("cos()" , trans.get("Operator.cos"));
put("tan()" , trans.get("Operator.tan"));
put("asin()" , trans.get("Operator.asin"));
put("acos()" , trans.get("Operator.acos"));
put("atan()" , trans.get("Operator.atan"));
put("sinh()" , trans.get("Operator.hsin"));
put("cosh()" , trans.get("Operator.hcos"));
put("tanh()" , trans.get("Operator.htan"));
put("log10()" , trans.get("Operator.log10"));
put("round()" , trans.get("Operator.round"));
put("random()" , trans.get("Operator.random"));
put("expm1()" , trans.get("Operator.expm1"));
put("mean([:])" , trans.get("Operator.mean"));
put("min([:])" , trans.get("Operator.min"));
put("max([:])" , trans.get("Operator.max"));
put("var([:])" , trans.get("Operator.var"));
put("rms([:])" , trans.get("Operator.rms"));
put("stdev([:])", trans.get("Operator.stdev"));
put("lclip(,)" , trans.get("Operator.lclip"));
put("uclip(,)" , trans.get("Operator.uclip"));
put("binf([:],,)" , trans.get("Operator.binf"));
put("trapz([:])" , trans.get("Operator.trapz"));
put("tnear([:],)" , trans.get("Operator.tnear"));
}};
protected Functions() throws InvalidCustomFunctionException {
CustomFunction meanFn = new CustomFunction("mean") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double MEAN result, ", ArrayUtils.mean(vals));
}
};
allFunctions.add(meanFn);
CustomFunction minFn = new CustomFunction("min") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double MIN result, ", ArrayUtils.min(vals));
}
};
allFunctions.add(minFn);
CustomFunction maxFn = new CustomFunction("max") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double MAX result, ", ArrayUtils.max(vals));
}
};
allFunctions.add(maxFn);
CustomFunction varFn = new CustomFunction("var") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double VAR result, ", ArrayUtils.variance(vals));
}
};
allFunctions.add(varFn);
CustomFunction stdevFn = new CustomFunction("stdev") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double STDEV result, ", ArrayUtils.stdev(vals));
}
};
allFunctions.add(stdevFn);
CustomFunction rmsFn = new CustomFunction("rms") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] vals;
try{
vals = vars.get(0).getArrayValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double RMS result, ", ArrayUtils.rms(vals));
}
};
allFunctions.add(rmsFn);
CustomFunction lclipFn = new CustomFunction("lclip",2) {
@Override
public Variable applyFunction(List<Variable> vars) {
double val, clip;
try{
val = vars.get(0).getDoubleValue();
clip = vars.get(1).getDoubleValue();
} catch (Exception e) {
return new Variable("Invalid");
}
if (val < clip){
val = clip;
}
return new Variable("double LCLIP result, ", val);
}
};
allFunctions.add(lclipFn);
CustomFunction uclipFn = new CustomFunction("uclip",2) {
@Override
public Variable applyFunction(List<Variable> vars) {
double val, clip;
try{
val = vars.get(0).getDoubleValue();
clip = vars.get(1).getDoubleValue();
} catch (Exception e) {
return new Variable("Invalid");
}
if (val > clip){
val = clip;
}
return new Variable("double UCLIP result, ", val);
}
};
allFunctions.add(uclipFn);
CustomFunction binfFn = new CustomFunction("binf", 3) {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] range;
double min, max;
try{
range = vars.get(0).getArrayValue();
min = vars.get(1).getDoubleValue();
max = vars.get(2).getDoubleValue();
} catch (Exception e) {
return new Variable("Invalid");
}
int ins = 0;
for (double x: range){
if (x < max && x > min){
ins++;
}
}
return new Variable("double BINF result", (double) ins/ (double) range.length);
}
};
allFunctions.add(binfFn);
CustomFunction rombintFn = new CustomFunction("trapz") {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] range;
double dt = 0;
try{
range = vars.get(0).getArrayValue();
dt = vars.get(0).getStep();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double TRAPZ result", ArrayUtils.trapz(range, dt) );
}
};
allFunctions.add(rombintFn);
CustomFunction tnearFn = new CustomFunction("tnear", 2) {
@Override
public Variable applyFunction(List<Variable> vars) {
double[] range;
double dt = 0;
double start = 0;
double near = 0;
try{
range = vars.get(0).getArrayValue();
dt = vars.get(0).getStep();
start = vars.get(0).getStart();
near = vars.get(1).getDoubleValue();
} catch (Exception e) {
return new Variable("Invalid");
}
return new Variable("double TNEAR result", ArrayUtils.tnear(range, near, start, dt) );
}
};
allFunctions.add(tnearFn);
}
}