Kode

package com.pdi.casper.analysis;

import java.text.DecimalFormat;
import java.util.List;

import com.pdi.casper.analysis.results.AnalysisResult;
import com.pdi.casper.analysis.results.RegressionResult;
import com.pdi.casper.data.DataSet;
import com.pdi.casper.data.rows.AREvent;
import com.pdi.casper.data.rows.AnalysisData;
import com.pdi.casper.data.rows.ObservationData;
import com.pdi.casper.ui.analysis.jide.datamodels.BaseModel;
import com.pdi.utilities.Log;

public class Analysis {
	public static final long FLAG_BEAUFORTTOOHIGH = 1;
	public static final long FLAG_VGTOOLOW = 2;
	public static final long FLAG_DIFGTMCR = 4;
	public static final long FLAG_KQGTKQ0 = 8;
	public static final long FLAG_WEATHERPROBLEM = 16;
	public static final long FLAG_PROPELLER_FEXDEVTOOHIGH = 32;
	public static final long FLAG_FBISNAN = 64;
	public static final long FLAG_PDINDEXWRONG = 128;

	public static final long FLAG_FN_OUT_OF_RANGE = 256;
	public static final long FLAG_POINT_APPROX_FAULT_9X4 = 512;
	public static final long FLAG_HULLDRAFT = 1024;

	public static final long WARNFLAG_BADWEATHERDATA = 1;
	public static final long WARNFLAG_CONSIDERWSDATA = 2;
	public static final long WARNFLAG_POWERSOURCEDROPPED = 4;
	public static final long WARNFLAG_CURRENTTOOHIGH = 8;

	public static final long INFOFLAG_POWERFORCEDUSER = 1;
	public static final long INFOFLAG_RPMFORCEDUSER = 2;
	public static final long INFOFLAG_POWERRPMCORRECTETCP = 4;
	public static final long INFOFLAG_EXCLUDEDBYUSER = 8;
	public static final long INFOFLAG_CORRECTED = 16;
	public static final long INFOFLAG_POWERFROMQA = 32;
	public static final long INFOFLAG_RPMFROMQA = 64;
	public static final long INFOFLAG_USEQA = 128;

	public static long[] HULLFLAGS = { FLAG_VGTOOLOW, FLAG_DIFGTMCR, FLAG_KQGTKQ0, FLAG_PDINDEXWRONG, FLAG_FBISNAN, FLAG_HULLDRAFT, FLAG_FN_OUT_OF_RANGE, FLAG_POINT_APPROX_FAULT_9X4 };
	public static long[] PROPELLERFLAGS = { FLAG_BEAUFORTTOOHIGH, FLAG_WEATHERPROBLEM, FLAG_PROPELLER_FEXDEVTOOHIGH };
	public static long[] HULLWARNFLAGS = { WARNFLAG_POWERSOURCEDROPPED };
	public static long[] PROPELLERWARNFLAGS = { WARNFLAG_BADWEATHERDATA, WARNFLAG_CONSIDERWSDATA, WARNFLAG_CURRENTTOOHIGH };
	public static long[] HULLINFOFLAGS = {};
	public static long[] PROPELLERINFOFLAGS = { INFOFLAG_POWERRPMCORRECTETCP };
	public static final DecimalFormat f0 = new DecimalFormat("#0");
	public static final DecimalFormat f2 = new DecimalFormat("#0.00");
	public static final DecimalFormat f3 = new DecimalFormat("#0.000");
	public static final DecimalFormat f4 = new DecimalFormat("#0.0000");
	
	public static AnalysisResult solveAll(BaseModel data, boolean runQuietly) {
		AnalysisResult res = new AnalysisResult();

		// 1. Flagging!
		clearHullFlags(data.hullSet);
		clearPropFlags(data.propSet);
		
		// 2. do analysis
		res.hullRes = solveHull(data, runQuietly);
		res.propRes = solveProp(data, runQuietly);

		// 3. categorize each observation according to TM's states
		for (int i = 0; i < data.hullSet.size(); i++) {
			DataSet dataset = data.hullSet.get(i);
			if (dataset.getCalc().alertFlags >=0) {
			  dataset.getCalc().alertFlags = categorize(dataset, data.hullEvent, data.propEvent);
			}
		}
		return res;
	}

	/*
	static double calcWak(Ship ship, ObservationData observation, AnalysisData calc) {
		double[] sdata = Functions.setSData2(ship, observation.ta, observation.tf);
		double trim = (observation.ta - observation.tf) / ship.lw;

		WakeThrustResult wtRes = Functions.wakeThrust(ship.ne, sdata, ship.dp, trim);
		double wi = wtRes.w;
		double x = Functions.cor3(ship.cow, ship.cowx, ship.td, ship.vd, calc.tm, observation.vg, ship.vdMin, ship.vdMax);
		wi = wi * x;
		double kw1 = calc.fbw / ship.r1;
		double wak = (kw1 + 1) * (wi - ship.wp) + ship.wp;
		return wak;
	}
	*/

	public static void clearHullFlags(List<DataSet> set) {
		for (int i = 0; i < set.size(); i++) {
			DataSet d = set.get(i);
			AnalysisData cd = d.getCalc();
			cd.clearCorrections();

			cd.flags = clearFlags(HULLFLAGS, cd.flags);
			cd.infoFlags = clearFlags(HULLINFOFLAGS, cd.infoFlags);
			cd.warnFlags = clearFlags(HULLWARNFLAGS, cd.warnFlags);
			if ((cd.infoFlags & Analysis.INFOFLAG_POWERFORCEDUSER) == 0) {
				cd.userForcedEa = 0;
			}
			if ((cd.infoFlags & Analysis.INFOFLAG_RPMFORCEDUSER) == 0) {
				cd.userForcedRPM = 0;
			}

		}
	}

	public static void clearPropFlags(List<DataSet> set) {
		for (int i = 0; i < set.size(); i++) {
			DataSet d = set.get(i);
			AnalysisData cd = d.getCalc();

			cd.flags = clearFlags(PROPELLERFLAGS, cd.flags);
			cd.infoFlags = clearFlags(PROPELLERINFOFLAGS, cd.infoFlags);
			cd.warnFlags = clearFlags(PROPELLERWARNFLAGS, cd.warnFlags);
		}
	}

	

	public static long clearFlags(long[] flags, long flag) {
		long res = flag;
		for (int i = 0; i < flags.length; i++) {
			if ((res & flags[i]) > 0) {
				res = res - flags[i];
			}
		}
		return res;
	}

	static RegressionResult solveHull(BaseModel data, boolean runQuietly) {
		RegressionResult res = new RegressionResult();
		try {
			res = HullRegression.solve(data.ship, data.analysisConfig, data.hullSet, data.hullEvent, runQuietly, true);
		} catch (Exception e) {
			Log.error(e);
			e.printStackTrace();
		}
		return res;
	}

	static RegressionResult solveProp(BaseModel data, boolean runQuietly) {
		RegressionResult res = new RegressionResult();
		try {
			res = PropRegression.solve(data.ship, data.analysisConfig, data.propSet, data.weatherMap, data.propEvent, runQuietly);
		} catch (Exception e) {
			Log.error(e);
			e.printStackTrace();
		}
		return res;
	}

	public static String getFlagName(long flag) {
		String res = "";
		if ((flag & FLAG_BEAUFORTTOOHIGH) > 0)
			res += "Beaufort too high, ";
		if ((flag & FLAG_VGTOOLOW) > 0)
			res += "Speed too low, ";
		if ((flag & FLAG_DIFGTMCR) > 0)
			res += "Powers too diverse, ";
		if ((flag & FLAG_KQGTKQ0) > 0)
			res += "Kq too large, ";
		if ((flag & FLAG_PROPELLER_FEXDEVTOOHIGH) > 0)
			res += "Propeller fex dev too high, ";
		if ((flag & FLAG_FBISNAN) > 0)
			res += "fb is NAN, ";
		if ((flag & FLAG_PDINDEXWRONG) > 0)
			res += "pd (Controlable pitch index) wrong, ";
		if ((flag & FLAG_FN_OUT_OF_RANGE) > 0)
			res += "FN out of range, ";
		if ((flag & FLAG_POINT_APPROX_FAULT_9X4) > 0)
			res += "Point approx fault 9x4, ";
		if ((flag & FLAG_HULLDRAFT) > 0)
			res += "Error due to draft values, ";

		res = res.trim();
		if (res.endsWith(","))
			res = res.substring(0, res.length() - 1);
		return res;
	}

	public static String getWarnFlagName(long flag) {
		String res = "";
		if ((flag & WARNFLAG_BADWEATHERDATA) > 0)
			res += "Bad weather data, ";
		if ((flag & WARNFLAG_CONSIDERWSDATA) > 0)
			res += "Consider using WS data, ";
		if ((flag & WARNFLAG_POWERSOURCEDROPPED) > 0)
			res += "One or more power sources has been dropped, ";
		if ((flag & WARNFLAG_CURRENTTOOHIGH) > 0)
			res += "Current too high, ";

		res = res.trim();
		if (res.endsWith(","))
			res = res.substring(0, res.length() - 1);
		return res;
	}

	public static String getAlertFlagName(long flag) {
		return "" + flag;
	}

	public static String getInfoFlagName(long flag) {
		String res = "";
		if ((flag & INFOFLAG_POWERFORCEDUSER) > 0)
			res += "Power forced by user, ";
		if ((flag & INFOFLAG_POWERRPMCORRECTETCP) > 0)
			res += "Power and RPM corrected by C/P algorithm, ";

		if ((flag & INFOFLAG_RPMFORCEDUSER) > 0)
			res += "RPM forced by user, ";
		if ((flag & INFOFLAG_EXCLUDEDBYUSER) > 0)
			res += "Excluded by user, ";

		res = res.trim();
		if (res.endsWith(","))
			res = res.substring(0, res.length() - 1);
		return res;
	}

	/*
	 * public static RegressionResult solveHull(BaseModel data, boolean runQuietly) { RegressionResult res = new RegressionResult(); try { res = HullRegression.solve(data.ship, data.hullSet, data.hullEvent,runQuietly); } catch (Exception e) { Log.error(e); e.printStackTrace(); } return res; }
	 */

	static boolean isFBGreater(AnalysisData cd, double fbLimit) {
		return (cd.fb - cd.fbw) > fbLimit;
	}

	static boolean isFBSmaller(AnalysisData cd, double fbLimit) {
		return (cd.fbw - cd.fb) > fbLimit;
	}

	static boolean isFBOnLine(AnalysisData cd, double fbLimit) {
		return !isFBSmaller(cd, fbLimit) && !isFBGreater(cd, fbLimit);
	}

	static boolean isFPRGreater(AnalysisData cd, double fprLimit) {
		return (cd.fex - cd.fpr) > fprLimit;
	}

	static boolean isFPRSmaller(AnalysisData cd, double fprLimit) {
		return (cd.fpr - cd.fex) > fprLimit;
	}

	static boolean isFPROnLine(AnalysisData cd, double fprLimit) {
		return !isFPRSmaller(cd, fprLimit) && !isFPRGreater(cd, fprLimit);
	}

	static boolean isVCGreater(ObservationData od, AnalysisData cd, double vcLimit) {
		return (od.vg - cd.vaw) > vcLimit;
	}

	static boolean isVCSmaller(ObservationData od, AnalysisData cd, double vcLimit) {
		return (od.vg - cd.vaw) < -vcLimit;
	}

	static boolean isVCOnLine(ObservationData od, AnalysisData cd, double vcLimit) {
		return !isVCSmaller(od, cd, vcLimit) && !isVCGreater(od, cd, vcLimit);
	}

	public static int categorize(DataSet dataset, AREvent hullEvent, AREvent propEvent) {
		ObservationData od = dataset.getObservation();
		AnalysisData cd = dataset.getCalc();
		int res = 0;
		// 1 and 2
		if (isVCOnLine(od, cd, hullEvent.vcLimit) && isFBOnLine(cd, hullEvent.fbLimit)) {
			if (isFPRGreater(cd, propEvent.fprLimit))
				res = 1;
			if (isFPRSmaller(cd, propEvent.fprLimit))
				res = 2;
		} else if (isFPROnLine(cd, propEvent.fprLimit)) {
			if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit))
				res = 3;
			if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit))
				res = 4;
		} else if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit) && isFPRGreater(cd, propEvent.fprLimit)) {
			res = 5;
		} else if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit) && isFPRSmaller(cd, propEvent.fprLimit)) {
			res = 6;
		} else if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit) && isFPRSmaller(cd, propEvent.fprLimit)) {
			res = 7;
		} else if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit) && isFPRGreater(cd, propEvent.fprLimit)) {
			res = 8;
		}
		
		return res;
	}

	public static boolean isCalcError(AnalysisData cd) {
		return cd.isFlag(FLAG_KQGTKQ0);
	}

	public static boolean isPropellerError(AnalysisData cd) {
		return cd.isFlag(FLAG_BEAUFORTTOOHIGH) || cd.isFlag(FLAG_PROPELLER_FEXDEVTOOHIGH);
	}

	public static boolean isHullError(AnalysisData cd) {
		return cd.isFlag(FLAG_VGTOOLOW) || cd.isFlag(FLAG_DIFGTMCR) || cd.isFlag(FLAG_KQGTKQ0) || cd.isFlag(FLAG_PDINDEXWRONG) || cd.isFlag(FLAG_FBISNAN);
	}

	public static boolean isInAnalysis(AnalysisData cd) {
		return !cd.isInfoFlag(INFOFLAG_EXCLUDEDBYUSER) && cd.alertFlags >= 0;
	}
	/*
	 * public static void categorize(DataSet dataset, AREvent hullEvent, AREvent propEvent) { ObservationData od = dataset.getObservation(); AnalysisData cd = dataset.getCalc(); int res = 0; // 1 and 2 if (isVCOnLine(od, cd, hullEvent.vcLimit) && isFBOnLine(cd, hullEvent.fbLimit) ) { if (isFPRGreater(cd, propEvent.fprLimit)) res = 1; if (isFPRSmaller(cd, propEvent.fprLimit)) res = 2; } else if (isFPROnLine(cd, propEvent.fprLimit)) { if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit)) res = 3; if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit)) res = 4; } else if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit) && isFPRGreater(cd, propEvent.fprLimit)) { res = 5; }else if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit) && isFPRSmaller(cd, propEvent.fprLimit)) { res = 6; }
	 * else if (isVCGreater(od, cd, hullEvent.vcLimit) && isFBGreater(cd, hullEvent.fbLimit) && isFPRSmaller(cd, propEvent.fprLimit)) { res = 7; }else if (isVCSmaller(od, cd, hullEvent.vcLimit) && isFBSmaller(cd, hullEvent.fbLimit) && isFPRGreater(cd, propEvent.fprLimit)) { res = 8; } cd.alertFlags = res; }
	 */

	public static void flagObservation(DataSet d, long flag) {
		AnalysisData cd = d.getCalc();
		Analysis.flagObservation(cd, flag);
	}

	public static void warnObservation(DataSet d, long flag) {
		AnalysisData cd = d.getCalc();
		Analysis.warnObservation(cd, flag);
	}

	public static void flagObservation(AnalysisData cd, long flag) {
		cd.fex = 0;
		cd.setFlag(flag);
	}

	public static void warnObservation(AnalysisData cd, long flag) {
	
		cd.setWarnFlag(flag);
	}

}

/*
 * 
 * ======================== HullAnalysis ========================
 * 
 * setting: -------- calc.ex (power from fuel index) calc.ef (power from fuel) calc.tc (power from turbo charger) calc.tm (mean trim) calc.ea (power used) calc.rpa (revolutions of main engine) calc.pda (propeller pitch ratio) calc.wa (actual wake factor) calc.wi (initial wake factor) calc.tra (actual propeller trust) calc.ve (inflow speed to propeller) calc.phkMax (maximum power for given calc.rpa) calc.kw1 (added wake factor) calc.fb (added resistance)
 * 
 * 
 * ======================== HullRegression ========================
 * 
 * using: -------- calc.fb
 * 
 * setting: --------- calc.z2 calc.fbw calc.kw1w calc.waw calc.vaw
 * 
 * 
 * 
 * ======================== PropellerAnalysis ========================
 * 
 * using: --------- calc.vaw calc.tm calc.phpMax calc.ea calc.kw1w
 * 
 * setting: ----------- calc.rb calc.rf calc.rt calc.wi calc.ti calc.kd calc.rtot calc.twi calc.twa calc.trbi calc.trw calc.tri calc.fw calc.fwi calc.fwa calc.fp calc.trb calc.tex calc.fex
 * 
 * ======================== PropellerRegression ========================
 * 
 * using: ------ calc.fex
 * 
 * setting: -------- calc.z2 (er der et problem her, hullRegression sætter også z2? calc.fpr
 */