public interface ILoadFlowGenerator {
	Complex[] genFlow(Complex[] voltage);
}
 public interface IQChecker {
	
	boolean correct(AclfCase aclfCase);
	
	void setQLimitSparseFactor(double qLimitSparseFactor);
}
 public interface ISpecialBusChecker {
	
	void correct(AclfCase aclfCase);

	String getMethodName(); 
}
 public interface IVgcBuilder {
	VoltageGenCondition nowCondition();
	VoltageGenCondition nextCondition();
}
 public interface IVoltageGenerator {
	Complex[] genVoltage(VoltageGenCondition c);
}
 public class LFComparator {
	
	public static final double V_MIN = 0.5;
	public static final double V_MAX = 5;
	
	public static final double TH_ABS_MAX = Math.PI;

	public static final double P_ABS_MAX = 5;
	public static final double Q_ABS_MAX = 4;
	
	public static final double CONNECT_BUS_PQ_ERROR = 1e-10;
	
	public LFComparator() {
		// TODO Auto-generated constructor stub
	}
	
	public static boolean checkCase(RefInfo ref, AclfCase aclfCase) {
		boolean ok = true;
		//System.out.println("[DEBUG] checkCase started, case ID = "+aclfCase.toString());
		ok &= checkPQ(ref, aclfCase.getPower());
		ok &= checkVTh(ref, aclfCase.getVoltage());
		//System.out.println("\tcheckCase end, case ID = "+aclfCase.toString());
		return ok;
	}
	
	private static boolean checkVTh(RefInfo ref, Complex[] voltage) {
		boolean vok = true;
		boolean thok = true;
		double[] v = new double[ref.getNoBus()];
		double[] th = new double[ref.getNoBus()];
		for (int i=0; i<ref.getNoBus(); ++i) {
			v[i] = voltage[i].abs();
			th[i] = voltage[i].getArgument();
		}
		
		//System.out.println("[DEBUG] checkVTH started, V_MAX/ V_MIN = "+V_MAX+", "+V_MIN+"; TH_ABS_MAX = "+TH_ABS_MAX);
		for (int i=0; i<ref.getNoBus(); ++i) {
			if (v[i] > V_MAX || v[i] < V_MIN) {
//				System.out.println("[DEBUG] checkVTH at bus "+i+", V overflow = "+v[i]);
				vok = false;
			}
			if (Math.abs(th[i]) > TH_ABS_MAX) {
				System.out.println("[DEBUG] checkVTH at bus "+i+", th overflow = "+th[i]);
				thok = false;
			}
		}
//		if (!Complex.equals(voltage[ref.getSwingNo()], Complex.ONE)) {
//			vok = false;
//			System.out.println("[DEBUG] checkVTH at bus Swing, Vth !=1,0, = "+voltage[ref.getSwingNo()]);
//		}
		
//		if (vok && thok) {
//			System.out.println("\tcheckVTH passed.");
//		}
		
		return vok && thok;
	}

	private static boolean checkPQ(RefInfo ref, Complex[] power) {
		boolean pok = true;
		boolean qok = true;
		double[] p = new double[ref.getNoBus()];
		double[] q = new double[ref.getNoBus()];
		for (int i=0; i<ref.getNoBus(); ++i) {
			p[i] = power[i].getReal();
			q[i] = power[i].getImaginary();
		}

		//System.out.println("[DEBUG] checkPQ started, P_ABS_MAX = "+P_ABS_MAX+"; Q_ABS_MAX = "+Q_ABS_MAX);
		for (int i=0; i<ref.getNoBus(); ++i) {
			if (Math.abs(p[i]) > P_ABS_MAX) {
//				System.out.println("[DEBUG] checkPQ at bus "+i+", P overflow = "+p[i]);
				pok = false;
			}
			if (Math.abs(q[i]) > Q_ABS_MAX) {
//				System.out.println("[DEBUG] checkPQ at bus "+i+", Q overflow = "+q[i]);
				qok = false;
			}
			if (ref.getBusType()[i] == RefInfo.ONLY_PV_BUS_TYPE) {
				if (q[i] > ref.getMaxQGenLimit()[i] || q[i] < ref.getMinQGenLimit()[i]) {
					System.out.println("[DEBUG] checkPQ at ONLY_PV bus "+i+", Q limit overflow = "+q[i]
							+", limit max/min = "+ref.getMaxQGenLimit()[i]+", "+ref.getMinQGenLimit()[i]);
					qok = false;
				}
			}else if (ref.getBusType()[i] == RefInfo.CONNECT_BUS_TYPE) {
				if (power[i].abs() > CONNECT_BUS_PQ_ERROR) {
					pok = qok = false;
					System.out.println("[DEBUG] checkPQ at CONNECT bus "+i+", PQ !=0, = "+power[i]);
				}
			}
			
		}

//		if (pok && qok) {
//			System.out.println("\tcheckPQ passed.");
//		}
		return pok && qok;
	}

	public static void watch(AclfNetwork net, String statement) throws InterpssException {
		int noBus = net.getNoBus();
		double[] p = new double[noBus];
		double[] q = new double[noBus];
		double[] v = new double[noBus];
		double[] th = new double[noBus];

		for (int i=0; i<noBus; ++i) {
			AclfBus bus = net.getBusList().get(i);
			p[i] = bus.getGenP() - bus.getLoadP();
			q[i] = bus.getGenQ() - bus.getLoadQ();
			v[i] = bus.getVoltageMag();
			th[i] = bus.getVoltageAng();
		}
		
		//report
		String report = new String(" P");
		for (int i=0; i<noBus; ++i) {
			report += "\t" + p[i];
		}
		report += "\n Q";
		for (int i=0; i<noBus; ++i) {
			report += "\t" + q[i];
		}
		report += "\n V";
		for (int i=0; i<noBus; ++i) {
			report += "\t" + v[i];
		}
		report += "\n th";
		for (int i=0; i<noBus; ++i) {
			report += "\t" + th[i];
		}
		report += "\n";
		
		System.out.println("[REPORT] watch... "+statement);
		System.out.println(report);
		
	}
	
	/**
	 * compare the status of an AclfNetwork between before and after load flow
	 * @param net
	 * @throws InterpssException 
	 */
	public static boolean compareWatch(AclfNetwork net, String statement) throws InterpssException {
		
		int noActiveBus = net.getNoActiveBus();
		double[] preP = new double[noActiveBus];
		double[] preQ = new double[noActiveBus];
		double[] preV = new double[noActiveBus];
		double[] preTh = new double[noActiveBus];
		double[] afterP = new double[noActiveBus];
		double[] afterQ = new double[noActiveBus];
		double[] afterV = new double[noActiveBus];
		double[] afterTh = new double[noActiveBus];
		
		//get variables
		for (int i=0; i<noActiveBus; ++i) {
			AclfBus bus = net.getBusList().get(i);
			preP[i] = bus.getGenP() - bus.getLoadP();
			preQ[i] = bus.getGenQ() - bus.getLoadQ();
			preV[i] = bus.getVoltageMag();
			preTh[i] = bus.getVoltageAng();
		}
		
		//load flow
		CoreObjectFactory.createLoadflowAlgorithm(net).loadflow();
		
		//get variables
		for (int i=0; i<noActiveBus; ++i) {
			AclfBus bus = net.getBusList().get(i);
			afterP[i] = bus.getGenP() - bus.getLoadP();
			afterQ[i] = bus.getGenQ() - bus.getLoadQ();
			afterV[i] = bus.getVoltageMag();
			afterTh[i] = bus.getVoltageAng();
		}
		
		//compare and report
		System.out.println("[REPORT] compareWatch... "+statement);
		boolean f1 = compare(preP, afterP, "Bus P");
		boolean f2 = compare(preQ, afterQ, "Bus Q");
		boolean f3 = compare(preV, afterV, "Bus V");
		boolean f4 = compare(preTh, afterTh, "Bus Theta");
		return f1 && f2 && f3 && f4;
	}
	
	private static boolean compare(double[] a, double[] b, String arrayName) {
		boolean theSame = true;
		for (int i=0; i<a.length; ++i) {
			if (a[i] != b[i])
				theSame = false;
		}
		
		if (theSame) {
			System.out.println("  ======"+arrayName+"... are the same.");
			String report = new String("");
			for (int i=0; i<a.length; ++i) {
				report += "\t" + a[i];
			}
			System.out.println(report);
		}else {
			System.out.println("  ======"+arrayName+"... are not the same =======");
			String report = new String("  before");
			for (int i=0; i<a.length; ++i) {
				report += "\t" + a[i];
			}
			report += "\n  after ";
			for (int i=0; i<b.length; ++i) {
				report += "\t" + b[i];
			}
			//report += "\n";
			System.out.println(report);
		}
		
		return theSame;
	}

}
 public class LoadFlowGenerator extends AlgoObject implements ILoadFlowGenerator {

	public static final String NAME = "LoadFlowGenerator";
	public static final String NAME_IN_SHORT = "LFG";
	public static final String PARA_NEEDED = "NONE";
	
	private int noBus = 0;
	private Complex[][] yc = null;
	
	public LoadFlowGenerator(RefInfo refInfo) {
		super(refInfo);
		long startTime = System.currentTimeMillis();
		this.methodName = NAME;
		System.out.print("[REPORT] new "+methodName+"...");
		
		this.noBus = ref.getNoBus();
		this.yc = new Complex[noBus][noBus];
		
		Complex[][] y = ref.getY();
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j) 
				this.yc[i][j] = new Complex(y[i][j].getReal(), 0 - y[i][j].getImaginary());//È¡¹²éî
		
		AclfCase.init(this);
		//report
		System.out.println(" ...ready. Need to input parameter: "+PARA_NEEDED);
		addInitTime(startTime);
	}
	
	/**
	 * Éú³É³±Á÷µÄºËÐÄ·½·¨,¸´ÔÓ¶ÈÎªn^2
	 * @param onGoNet
	 * @return net£¨Ö±½ÓÉú³ÉºóÐÞ¸Äµ½ÍøÂç£©
	 */
	public Complex[] genFlow(Complex[] voltage) {
		long startTime = System.currentTimeMillis();
		addCallTimes();
		
		Complex[] power = new Complex[noBus];
		
		for (int i=0; i<noBus; ++i) {
			power[i] = new Complex(0, 0);
			for (int j=0; j<noBus; ++j) {//Y*V*
				power[i] = power[i].add(this.yc[i][j].multiply(voltage[j].conjugate()));
			}
			power[i] = voltage[i].multiply(power[i]);//VY*V*
		}
		
		addTimeUse(startTime);
		return power;
	}

	public int getNoBus() {
		return noBus;
	}

	public Complex[][] getYc() {
		return yc;
	}

	@Override
	public String keyMsg() {
		return NAME_IN_SHORT;
	}

}
 public class QChecker extends AlgoObject implements IQChecker {

	public static final String NAME = "Default_QChecker";
	public static final String NAME_IN_SHORT = "dQC";
	public static final String PARA_NEEDED = "qLimitSparseFactor";
	
	protected static final double DEFAULT_Q_SPARSE = 0.95;

	/**
	 * ÓÉÓÚÊµ¼ÊÖÐÈç¹ûÐ£Õýµ½¼«ÏÞµÄ»°ÍùÍùÔÙÎ¢µ÷ÓÖÓÐ³¬ÏÞÇé¿ö·¢Éú£¬ËùÒÔÐèÒªÉèËÉ³ÚÒò×Ó
	 */
	protected double qLimitSparseFactor = 0;
	
	/*
	 * ´ÓrefµÃµ½µÄÖ¸Õë£¬ÊÇ±ÜÃâ¶à²ãÒýÓÃºÍ±ÜÃâÖµÖØ¸´µÄÍ×Ð­
	 */
	protected int noBus = 0;
	protected double[][] b11r = null;
	protected int swingNo = 0;
	protected String[] busCode = null;
	protected int[] busType = null;
	protected double[] maxQGenLimit = null;
	protected double[] minQGenLimit = null;
	
	public QChecker(RefInfo refInfo) {
		super(refInfo);
		long startTime = System.currentTimeMillis();
		this.methodName = "Default_QChecker";
		System.out.print("[REPORT] new "+methodName+"...");
		
		this.qLimitSparseFactor = QChecker.DEFAULT_Q_SPARSE;
		
		noBus = ref.getNoBus();
		maxQGenLimit = ref.getMaxQGenLimit();
		minQGenLimit = ref.getMinQGenLimit();
		b11r = ref.getB11r();
		busCode = ref.getBusCode();
		busType = ref.getBusType();
		swingNo = ref.getSwingNo();
		
		//report
		System.out.println(" ...ready. Need to input parameter: "+PARA_NEEDED);
		addInitTime(startTime);
	}
	
	/**
	 * µ±Óöµ½Ô½ÏÞµÄÇé¿öÊ±µ÷ÓÃµÄ·½·¨£¬Ó¦ÓÃPQ·Ö½â·¨£¬ÓÃB¾ØÕóµÄÄæÇóµçÑ¹ÐÞÕýÁ¿
	 * Ö»ÐÞ¸ÄbusCode==GenPVµÄ½Úµã
	 * ÒÑÔÚLFTest()ÖÐÈ·ÈÏ£¬min/maxQGenLimit ¾ùÎª±êçÛÖµ
	 * -dV = br * dQ/V
	 * V = V - dV
	 * TODO£º×¢Òâ£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡ÕâÀïÏÞÖÆÁËPQ+PV½Úµã£¬µ«ÎÒÈÏÎªÖ»ÄÜÏÞÖÆ´¿PV½Úµã
	 * @param voltage µçÑ¹Öµ
	 * @param power µ±Ç°¹¦ÂÊ·Ö²¼£¬ÓÃÀ´ÌáÈ¡ÎÞ¹¦ÐÞÕýÁ¿
	 * @return
	 * @throws InterpssException
	 */
	@Override
	public boolean correct(AclfCase aclfCase) {
		long startTime = System.currentTimeMillis();
		
		Complex[] power = aclfCase.getPower();
		//get dQ[]
		boolean qOverflow = false;
		double[] dQ = new double[noBus];
		for (int i=0; i<noBus; ++i) {
			double q = power[i].getImaginary();
			if (busType[i] == RefInfo.ONLY_PV_BUS_TYPE /*busCode[i].equals("GenPV")*/) {
				if (q > maxQGenLimit[i]) {
					dQ[i] = maxQGenLimit[i] * this.qLimitSparseFactor - q;
					qOverflow = true;
				}else if (q < minQGenLimit[i]) {
					dQ[i] = minQGenLimit[i] * this.qLimitSparseFactor - q;
					qOverflow = true;
				}else
					dQ[i] = 0;
			}else {
				dQ[i] = 0;
			}
		}
		//Èç¹ûÃ»Ô½ÏÞÔòÌø¹ýÏÂÃæ£¬Ö±½Ó·µ»ØÃ»Ô½ÏÞ¾ÍÐÐÁË
		if (!qOverflow) {
			addTimeUse(startTime);
			return true;
		}
		addCallTimes();
		
		//Èç¹ûÔ½ÏÞÁË£¬ÐÞÕýµçÑ¹
		Complex[] voltage = aclfCase.getVoltage();
		//get dQ/V
		double[] dqv = new double[noBus]; 
		for (int i=0; i<noBus; ++i) {
			dqv[i] = dQ[i] / voltage[i].abs();
		}
		//¾ØÕó³Ë·¨  -dV = br * dQ/V
		double[] dV = new double[noBus]; 
		for (int i=0; i<noBus; ++i) {
			dV[i] = 0;
			if (i != swingNo && !busCode[i].equals("GenPV"))//×¢Òâµ½ÀíÂÛÉÏµÄb11r¾ØÕóÊÇÕâÀïµÄb11rÈ¥µôswingºÍPVÐÐÁÐ
				for (int j=0; j<noBus; ++j)
					if (j != swingNo && !busCode[i].equals("GenPV"))
						dV[i] -= b11r[i][j] * dqv[j];
		}
				
		//correct v += dV, theta = theta
		for (int i=0; i<noBus; ++i) 
			if (i != swingNo){
				double v = voltage[i].abs() + dV[i];
				voltage[i] = voltage[i].multiply(v/voltage[i].abs());
			}
		
		aclfCase.setVoltage(voltage);
		
		addTimeUse(startTime);
		return false;
	}

	/**
	 * Ö§³ÖÐÞ¸ÄÄ¬ÈÏÖµ
	 */
	@Override
	public void setQLimitSparseFactor(double qLimitSparseFactor) {
		this.qLimitSparseFactor = qLimitSparseFactor;
		System.out.println("[REPORT] "+methodName+" paramter set. qLimitSparseFactor = "+qLimitSparseFactor);
	}

	public int getNoBus() {
		return noBus;
	}

	public double[][] getB11r() {
		return b11r;
	}

	public String[] getBusCode() {
		return busCode;
	}

	public double[] getMaxQGenLimit() {
		return maxQGenLimit;
	}

	public double[] getMinQGenLimit() {
		return minQGenLimit;
	}

	public double getQLimitSparseFactor() {
		return qLimitSparseFactor;
	}

	@Override
	public String keyMsg() {
		return NAME_IN_SHORT+"-qf-"+this.qLimitSparseFactor;
	}
	
}
 public class SpecialBusChecker extends AlgoObject implements ISpecialBusChecker {

	public static final String NAME = "Default_SpecialBusChecker";
	public static final String NAME_IN_SHORT = "dSBC";
	public static final String PARA_NEEDED = "NONE";
	
	/**
	 * ³£Êý¾ØÕó,ÕâÊÇ¸úÐ£ÕýÓÐ¹ØµÄ¾ßÌå²ÎÊý£¬²»±£´æÔÚRefNetInfoÖÐ
	 */
	protected Complex[][] vt = null;
	
	/*
	 * ´ÓrefµÃµ½µÄÖ¸Õë£¬ÊÇ±ÜÃâ¶à²ãÒýÓÃºÍ±ÜÃâÖµÖØ¸´µÄÍ×Ð­
	 */
	protected int noBus = 0;
	protected int swingNo = 0;
	

	public SpecialBusChecker(RefInfo refInfo) {
		super(refInfo);
		long startTime = System.currentTimeMillis();
		this.methodName = NAME;
		System.out.print("[REPORT] new "+methodName+"...");
		
		this.noBus = ref.getNoBus();
		this.swingNo = ref.getSwingNo();
		
		Complex[][] yr = ref.getYr();
		int[] busType = ref.getBusType();
		//¼ÆËãm01, m01 = -1/yr00 * yr01, dI0 == m01 * dI1
		Complex[] m01 = new Complex[noBus];
		for (int i=0; i<noBus; ++i) {
			m01[i] = new Complex(0, 0);
			if (busType[i] == RefInfo.CONNECT_BUS_TYPE) //ÕâÀïËµÃ÷m01½öÔÚ1´¦ÓÐÖµ
				m01[i] = yr[swingNo][i].divide(yr[swingNo][swingNo]).multiply(-1);
		}
		//¼ÆËãz¾ØÕó, z = yr12,0 * m01 + yr12,1, dV = z * dI
		Complex[][] z = new Complex[noBus][noBus];
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j) {
				z[i][j] = new Complex(0.0, 0.0);
				if (i != swingNo && busType[j] == RefInfo.CONNECT_BUS_TYPE) //¶ÔiËµÃ÷z¹²12ÐÐ£¬¶ÔjËµÃ÷z¹²1ÁÐ
					z[i][j] = yr[i][swingNo].multiply(m01[j]).add(yr[i][j]);
			}
		
		//Éú³Évt, vt = z * -Y1, dV12 = vt * V012
		this.vt = new Complex[noBus][noBus];
		Complex[][] y = ref.getY();
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j) {
				vt[i][j] = new Complex(0.0, 0.0);
				if (i != swingNo)//ÕâÀïËµÃ÷vt¹²1+2ÐÐ£¬¶ÔjÃ»ÅÐ¶ÏËµÃ÷vt¹²0+1+2ÐÐ
					for (int k=0; k<noBus; ++k)
						if (busType[k] == RefInfo.CONNECT_BUS_TYPE)
							vt[i][j] = vt[i][j].subtract(z[i][k].multiply(y[k][j]));
			}
		
		//report
		System.out.println(" ...ready. Need to input parameter: "+PARA_NEEDED);
		addInitTime(startTime);
	}
	
	/**
	 * ±¾ÀàµÄÖ÷·½·¨£¬ÓÃÓÚ½«ÊäÈëÍøÂçµÄÁªÂç½Úµã¹¦ÂÊÐ£ÕýÎª0
	 * Ð£ÕýºóµÄµçÑ¹ÏòÁ¿Í¬Ê±ÐÞ¸Äµ½ÍøÂç
	 * @param net
	 * @return Ð£ÕýºóµÄµçÑ¹ÏòÁ¿
	 */
	@Override
	public void correct(AclfCase aclfCase) {
		long startTime = System.currentTimeMillis();
		addCallTimes();
		
		Complex[] voltage = aclfCase.getVoltage();
		
		//¾ØÕó³Ë·¨
		Complex[] dV = new Complex[noBus]; 
		for (int i=0; i<noBus; ++i) {
			dV[i] = new Complex(0.0, 0.0);
			if (i != swingNo)
				for (int j=0; j<noBus; ++j)
					dV[i] = dV[i].add(vt[i][j].multiply(voltage[j]));
		}
		
		//correct v += dV, theta = theta
		for (int i=0; i<noBus; ++i) {
			voltage[i] = voltage[i].add(dV[i]);
		}
		
		//ÏÔÊ½¸³Öµ£¬´¥·¢case.coincide£½false
		aclfCase.setVoltage(voltage);

		addTimeUse(startTime);
	}

	public int getNoBus() {
		return noBus;
	}

	public Complex[][] getVt() {
		return vt;
	}

	@Override
	public String keyMsg() {
		return NAME_IN_SHORT;
	}
}
 public class VoltageGenerator extends AlgoObject implements IVoltageGenerator {

	public static final String NAME = "Default_VoltageGenerator";
	public static final String NAME_IN_SHORT = "dVG";
	public static final String PARA_NEEDED = "NONE";
	
	protected double[][] b1r = null;
	protected int noBus = 0;
	protected int swingNo = 0;
	
	public VoltageGenerator(RefInfo refInfo) {
		super(refInfo);
		long startTime = System.currentTimeMillis();
		this.methodName = NAME;
		System.out.print("[REPORT] new "+methodName+"...");
		
		this.b1r = ref.getB1r();
		this.noBus = ref.getNoBus();
		this.swingNo = ref.getSwingNo();
		
		//report
		System.out.println(" ...ready. Need to input parameter: "+PARA_NEEDED);
		addInitTime(startTime);
	}
	
	/**
	 * ÓÐÄ¿µÄÐÔµÄÉú³É
	 * Éú³ÉµçÑ¹µÄÖ÷·½·¨£¬ÓÉ·ùÖµºÍÓÐ¹¦Éú³É¡££¨ÒòÎª¸ø¶¨ÓÐ¹¦Ò»¸öÊÇ·ûºÏ¹¤³ÌÉÏµÄÐèÒª£¬Ò»¸öÊÇ·ûºÏÊµ¼ÊÉú³ÉÖÐÏ÷¼õ¿Õ¼ä£¬Ìá¸ßÓÐÐ§ÐÔµÄ±ØÒª£©
	 * note: ÓÐ¹¦Ë®Æ½¸üÎªÖØÒª£¬·Å²ÎÊý±íÇ°Ãæ
	 * @param v
	 * @param p
	 * @return
	 */
	@Override
	public Complex[] genVoltage(VoltageGenCondition c) {
		long startTime = System.currentTimeMillis();
		addCallTimes();
		
		Complex[] voltage;
		if (c.isThVMethod()) {
			voltage = c.getVoltage();
		}else {
			voltage = toComplexV(c.getV(), genTheta(c.getP()));
		}
		
		addTimeUse(startTime);
		return voltage;
	}
	
	/**
	 * ¸ù¾Ý¸ø¶¨µÄp£¬ÀûÓÃÖ±Á÷³±Á÷µÃµ½Ïà½Ç£¬Ð´ËÀµÄ¡£
	 * P=B¦È => ¦È = B^-1 * P
	 * @param p
	 * @return
	 */
	private double[] genTheta(double[] p) {
		double[] theta = new double[noBus];
		
		for (int i=0; i<noBus; ++i) {
			theta[i] = 0;
			if (i != swingNo)
				for (int j=0; j<noBus; ++j) 
					if (j != swingNo)
					theta[i] -= this.b1r[i][j] * p[j];
		}
		
		return theta;
	}

	/**
	 * ¸ù¾ÝµçÑ¹·ùÖµºÍÏà½ÇÉú³ÉµçÑ¹ÏàÁ¿µÄÎ¨Ò»£¨»®ÖØµã£©·½·¨£¬Ö»ÐèÒªÔÚ´ËÏÔÊ½µØ½«swing½ÚµãµçÑ¹¸Ä»ØÀ´¾ÍºÃÁË
	 * @param v
	 * @param th
	 * @return
	 */
	 private Complex[] toComplexV(double[] v, double[] th) {
		Complex[] voltage = new Complex[noBus];
		for (int i=0; i<noBus; ++i) {
			voltage[i] = new Complex(v[i]*Math.cos(th[i]), v[i]*Math.sin(th[i]));
		}
//		//ÏÔÊ½µØ½«swing·ùÖµÐ£Õý
//		if (!Complex.equals(voltage[this.swingNo], new Complex(1, 0))) {
//			//Debug
//			System.out.println("[DEBUG] VoltageGenerator.toComplexV: voltage[swingNo] != (1, 0), == "+voltage[this.swingNo]+"\t, but it is already fixed to (1, 0)!");
//			String errStr = new String("");
//			for (int i=0; i<noBus; ++i) 
//				errStr += "Bus "+i+" V = "+voltage[i]+"\t";
//			System.out.println(errStr);
//			
//			voltage[this.swingNo] = new Complex(1, 0);
//		}
		return voltage;
	}
	
	public double[][] getB1r() {
		return b1r;
	}

	public int getNoBus() {
		return noBus;
	}

	public int getSwingNo() {
		return swingNo;
	}

	@Override
	public String keyMsg() {
		return NAME_IN_SHORT;
	}
}
 public class VThScanConditionBuilder extends AlgoObject implements IVgcBuilder {

	public static final String NAME = "VTHScanBuilder";
	public static final String NAME_IN_SHORT = "VTH";
	public static final String PARA_NEEDED = "vSparseFactor";

	private static final double DEFAULT_BOUNDARY_FACTOR = 1.0;
	private static final int DEFAULT_BEGIN_STATUS = -1;
	
	private VoltageGenCondition c = null;
	
	private int noBus = 0;
	private int swingNo = 0;
	
	private int status = 0;
	
	private double[] baseTheta = null;
	private double[] baseV = null;
	private double[] voltageMagError = null;
	private double boundaryFactor = 1;
	
	private Complex[] voltage = null;
	
	public VThScanConditionBuilder(RefInfo refInfo) {
		super(refInfo);
		long startTime = System.currentTimeMillis();
		this.methodName = NAME;
		System.out.print("[REPORT] new "+methodName+"...");
		
		c = new VoltageGenCondition(true);
		this.noBus = ref.getNoBus();
		this.swingNo = ref.getSwingNo();
		boundaryFactor = DEFAULT_BOUNDARY_FACTOR;
		this.status = DEFAULT_BEGIN_STATUS;

		baseTheta = new double[noBus];
		baseV = new double[noBus];
		voltageMagError = new double[noBus];
		voltage = new Complex[noBus];
		
		EList<AclfBus> busList = ref.getNet().getBusList();
		for (int i=0; i<noBus; ++i) {
			baseTheta[i] = busList.get(i).getVoltageAng();
			baseV[i] = busList.get(i).getVoltageMag();
			voltageMagError[i] = getVoltageMagError(busList.get(i).getBaseVoltage());
		}

		//report
		System.out.println(" ...ready. Need to input parameter: "+PARA_NEEDED);
		System.out.println("[WARNING] this method is only used in IEEE 14 bus system!");
		addInitTime(startTime);
	}
	
	public void setVBoundaryFactor(double f) {
		this.boundaryFactor = f;
		System.out.println("[REPORT] "+methodName+" paramter set. vBoundaryFactor = "+boundaryFactor);
	}

	@Override
	public VoltageGenCondition nowCondition() {
		return c;
	}

	@Override
	public VoltageGenCondition nextCondition() {
		long startTime = System.currentTimeMillis();
		
		this.status += 1;
		for (int i=0; i<noBus; ++i) 
			if (i != swingNo) {
				//Î»ÔËËã
				double mag = baseV[i] * (1 - boundaryFactor * voltageMagError[i] * (1 - 2 * (status & 1)));
				status = status>>>1;
				//ÕâÀïÊÇÓÐÎóµÄ...²»ÄÜÓÃµçÑ¹µÄ·ùÖµÀ´ÏÞÖÆ·ø½Ç
				double ang = baseTheta[i] * (1 - boundaryFactor * voltageMagError[i] * (1 - 2 * (status & 1)));
				status = status>>>1;
			
				voltage[i] = new Complex(mag * Math.cos(ang), mag * Math.sin(ang));
			}else
				voltage[i] = new Complex(1.0, 0);
		
		//ÏÔÊ½¸³Öµ£¬Æ½ºâ½Úµã»¹ÊÇ²»±äµÄ
		voltage[swingNo] = new Complex(1.0, 0.0);
		if (status == 1<<26)
			status = -1;
		c.setVoltage(voltage);
		
		addTimeUse(startTime);
		return c;
	}
	
	public VoltageGenCondition getC() {
		return c;
	}

	public int getNoBus() {
		return noBus;
	}

	public int getSwingNo() {
		return swingNo;
	}

	public int getStatus() {
		return status;
	}

	public double[] getBaseTheta() {
		return baseTheta;
	}

	public double[] getBaseV() {
		return baseV;
	}

	public double[] getVoltageMagError() {
		return voltageMagError;
	}

	public double getBoundaryFactor() {
		return boundaryFactor;
	}

	public Complex[] getVoltage() {
		return voltage;
	}

	/**
	 * ¶Ô¸ø¶¨µÄµçÑ¹µÈ¼¶·µ»ØÔÊÐíµÄµçÑ¹Æ«²î°Ù·Ö±È£¬Ref£ºµçÁ¦ÏµÍ³·ÖÎöÉÏ²á£¬P5.
	 * note: IEEE¸ñÊ½ÖÐ³ýÁË14busÓÐ135ºÍ35£¬10Ö®Íâ£¬ÆäËûµÄ¾ùÎª100
	 * note: ½öÔÚ¹¹Ôìº¯ÊýÖÐÖ´ÐÐÒ»´Î
	 * @param voltageLevel
	 * @return
	 */
	protected static double getVoltageMagError(double voltageLevel) {
		if (voltageLevel < 34)
			return 0.07;
		return 0.07;
	}

	@Override
	public String keyMsg() {
		return NAME_IN_SHORT+"-vsf-"+boundaryFactor;
	}
}
 public class AclfCase {
	
	/**
	 * ÓÃÓÚµçÑ¹·¢Éú±ä»¯Ö®ºó£¬ÐèÒªµ÷ÓÃpowerÊ±£¬×Ô¶¯¸üÐÂpower
	 */
	private static LoadFlowGenerator lfg = null;
	
	/**
	 * Ñù±¾×´Ì¬
	 * 0 - ÐÂµÄV£¬PV¶Ô²»ÉÏ
	 * 1 - V²»±ä£¬PV¶ÔµÃÉÏ
	 */
	private boolean coincide = false;
	
	private Complex[] voltage = null;
	private Complex[] power = null;

	public AclfCase(Complex[] voltage) {
		this.voltage = voltage;
		this.power = new Complex[voltage.length];//Ó¦µ±×¢Òâ´ËÊ±ÊÇ¿ÕµÄ
		this.coincide = false;
	}

	public boolean getCoincide() {
		return coincide;
	}

	public Complex[] getVoltage() {
		return voltage;
	}

	public void setVoltage(Complex[] voltage) {
		this.voltage = voltage;
		this.coincide = false;
	}

	public Complex[] getPower() {
		if (!this.coincide) {
			power = lfg.genFlow(voltage);
			coincide = true;
		}
		return power;
	}
	
	@Override
	public String toString() {
		String str = new String("");
		String[] busCode = lfg.getRefInfo().getBusCode();
		for (int i=0; i<voltage.length; ++i) {
			str += "Bus "+i+"\t"+busCode[i]+"\t";
			if (busCode[i].equals("Swing")) {
				str += getVoltage()[i];
			}else if (busCode[i].equals("GenPV")) {
				str += getPower()[i].getReal()+"\t"+getVoltage()[i].abs();
			}else if (busCode[i].equals("GenPQ")) {
				str += getPower()[i];
			}
			str += "\n";
		}
		return str;
	}
	
	/**
	 * ÔÚ³ÌÐò³õÊ¼»¯½×¶Î¸øÕâ¸ö¸³Öµ£¬Ö®ºó²»ÓÃÏÔÊ½µ÷ÓÃlfg
	 * @param lfg
	 */
	public static void init(LoadFlowGenerator lfg) {
		AclfCase.lfg = lfg;
	}
	
}
 public class RefInfo {
	
	public static int SWING_BUS_TYPE = 0;
	public static int ONLY_PV_BUS_TYPE = 1;
	public static int CONNECT_BUS_TYPE = 2;
	public static int OTHER_BUS_TYPE = 3;
	public static int PV_PQ_BUS_TYPE = 4;
	
	private int noBus = 0;
	private int swingNo = 0;
	private int[] busType = null;
	private String[] busCode = null;
	private double[][] b = null;
	private double[][] br = null;
	private double[][] b1 = null;
	private double[][] b1r = null;
	private double[][] b11 = null;
	private double[][] b11r = null;
	private Complex[][] y = null;
	private Complex[][] yr = null;
	
	/**
	 * Ô¤·ÀÓÐÊ²Ã´Ã»Ïëµ½µÄÐÅÏ¢»¹Òª´ÓÕâÀï»ñÈ¡
	 */
	private AclfNetwork net = null;
	
	/**
	 * ÐèÒª´æ´¢ÎÞ¹¦ÏÞÖÆÏòÁ¿À´¼ÓËÙ
	 * ÒòÎªÍøÂçÊÇÈ·¶¨µÄ£¬½ÚµãµÄÎÞ¹¦ÏÞÖÆÒ²ÊÇÈ·¶¨µÄ
	 */
	private double[] maxQGenLimit = null;
	private double[] minQGenLimit = null;
	
	public AclfNetwork getNet() {
		return net;
	}
	
	private boolean printReport = false;

	public boolean isPrintReport() {
		return printReport;
	}

	public void setPrintReport(boolean printReport) {
		this.printReport = printReport;
	}

	public RefInfo(AclfNetwork refNet) throws InterpssException {

		//report
		System.out.println("[REPORT] new NetInfoImpl...");
		
		this.printReport = true;
		
		this.net = refNet;
		this.noBus = refNet.getNoBus();
		
		this.busType = new int[noBus];
		this.busCode = new String[noBus];
		for (int i=0; i<noBus; ++i) {
			AclfBus bus = refNet.getBusList().get(i);
			String genCode = bus.getGenCode().getName();
			if (genCode.equals("Swing")) {//0 - Æ½ºâ½Úµã
				this.busType[i] = RefInfo.SWING_BUS_TYPE;
				this.swingNo = i;
			}else if (genCode.equals("GenPV")) {//1 - ´¿PV½Úµã
				if (Complex.equals(bus.getLoadPQ(), Complex.ZERO))
					this.busType[i] = RefInfo.ONLY_PV_BUS_TYPE;
				else
					this.busType[i] = RefInfo.PV_PQ_BUS_TYPE;
			}else if (genCode.equals("GenPQ") && bus.getGenP() == 0 && bus.getGenQ() == 0 && bus.getLoadP() == 0 && bus.getLoadQ() == 0) {//2 - ÁªÂç½Úµã
				this.busType[i] = RefInfo.CONNECT_BUS_TYPE;
			}else//3 - ÆäËûPQ½Úµã
				this.busType[i] = RefInfo.OTHER_BUS_TYPE;
			this.busCode[i] = genCode;
		}
		
		/*
		 * get Y matrix
		 * AX=B: 
		 * 	A--Y
		 * 	X--0
		 * 	B--0
		 */
		this.y = new Complex[noBus][noBus];
		this.b = new double[noBus][noBus];
		this.yr = new Complex[noBus][noBus];
		ISparseEqnComplex yeqn = refNet.formYMatrix();
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j) {
				this.y[i][j] = yeqn.getA(i, j);
				this.b[i][j] = y[i][j].getImaginary();
			}
		for (int i=0; i<noBus; ++i) {
			//°´ÁÐÇóÄæ
			for (int j=0; j<noBus; ++j)
				yeqn.setBi(new Complex(0.0, 0.0), j);
			yeqn.setBi(new Complex(1.0, 0.0), i);
			
			try {
				yeqn.solveEqn();
			} catch (IpssNumericException e) {
				e.printStackTrace();
			}
			
			for (int j=0; j<refNet.getNoBus(); ++j)
				this.yr[j][i] = yeqn.getX(j);
		}
		
		/*
		 * get B matrix
		 * AX=B: 
		 * 	A--B
		 * 	X--0
		 * 	B--0
		 */
		this.b1 = new double[noBus][noBus];
		this.b1r = new double[noBus][noBus];
		ISparseEqnDouble beqn = refNet.formB1Matrix();
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j)
				this.b1[i][j] = beqn.getAij(i, j);
		for (int i=0; i<noBus; ++i) {
			//°´ÁÐÇóÄæ
			for (int j=0; j<noBus; ++j)
				beqn.setBi(0.0, j);
			beqn.setBi(1, i);
			
			try {
				beqn.solveEqn();
			} catch (IpssNumericException e) {
				e.printStackTrace();
			}
			
			for (int j=0; j<noBus; ++j)
				this.b1r[j][i] = beqn.getXi(j);
		}
		this.br = new double[noBus][noBus];
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j)
				beqn.setAij(b[i][j], i, j);
		for (int i=0; i<noBus; ++i) {
			//°´ÁÐÇóÄæ
			for (int j=0; j<noBus; ++j)
				beqn.setBi(0.0, j);
			beqn.setBi(1, i);
			
			try {
				beqn.solveEqn();
			} catch (IpssNumericException e) {
				e.printStackTrace();
			}
			
			for (int j=0; j<noBus; ++j)
				this.br[j][i] = beqn.getXi(j);
		}

		/*
		 * get B matrix
		 * AX=B: 
		 * 	A--B
		 * 	X--0
		 * 	B--0
		 */
		this.b11 = new double[noBus][noBus];
		this.b11r = new double[noBus][noBus];
		ISparseEqnDouble b11eqn = refNet.formB11Matrix();
		for (int i=0; i<noBus; ++i)
			for (int j=0; j<noBus; ++j)
				this.b11[i][j] = b11eqn.getAij(i, j);
		for (int i=0; i<noBus; ++i) {
			//°´ÁÐÇóÄæ
			for (int j=0; j<noBus; ++j)
				b11eqn.setBi(0.0, j);
			b11eqn.setBi(1, i);
			
			try {
				b11eqn.solveEqn();
			} catch (IpssNumericException e) {
				e.printStackTrace();
			}
			
			for (int j=0; j<noBus; ++j)
				this.b11r[j][i] = b11eqn.getXi(j);
		}
		
		maxQGenLimit = new double[noBus];
		minQGenLimit = new double[noBus];
		EList<AclfBus> busList = refNet.getBusList();
		for (int i=0; i<noBus; ++i) {
			AclfBus bus = busList.get(i);
			if (busType[i] == RefInfo.ONLY_PV_BUS_TYPE || busType[i] == RefInfo.PV_PQ_BUS_TYPE/*PV½Úµã*/) {
				maxQGenLimit[i] = bus.getQGenLimit().getMax();
				minQGenLimit[i] = bus.getQGenLimit().getMin();
			}else {
				maxQGenLimit[i] = -1;
				minQGenLimit[i] = -1;
			}
		}
	}

	public int getNoBus() {
		return noBus;
	}

	public int getSwingNo() {
		return swingNo;
	}

	public int[] getBusType() {
		return busType;
	}

	public double[][] getB() {
		return b;
	}

	public double[][] getB1() {
		return b1;
	}

	public double[][] getBr() {
		return br;
	}

	public double[][] getB1r() {
		return b1r;
	}

	public double[][] getB11() {
		return b11;
	}

	public double[][] getB11r() {
		return b11r;
	}

	public String[] getBusCode() {
		return busCode;
	}

	public Complex[][] getY() {
		return y;
	}

	public Complex[][] getYr() {
		return yr;
	}

	public double[] getMaxQGenLimit() {
		return maxQGenLimit;
	}

	public double[] getMinQGenLimit() {
		return minQGenLimit;
	}

}
 public class VoltageGenCondition {
	
	private static RefInfo ref = null;
	
	private double[] p = null;

	private double[] v = null;
	
	private Complex[] voltage = null;

	/**
	 * Ö¸Ê¾ÀàÖÐµÄÊý×é´æµÄÊÇÊýÖµ»¹ÊÇÒòÊý
	 */
	private boolean pIsFactor = false;

	private boolean vIsFactor = false;

	/**
	 * ÊÇ·ñÊôÓÚÖ±½Ó¸ø¶¨VthetaµÄ£¬·ñÔòÊôÓÚPV·½·¨¡£
	 */
	private boolean isThVMethod = false;
	
	private int bitState = 0;

	/**
	 * ÊÇ·ñÊÇÎ»ÔËËã·½·¨£¨TraversalVoltageGenerator¶ÀÓÐ£©
	 */
	private boolean isBit = false;
	
	public VoltageGenCondition(boolean isThVMethod) {
		BuildCondition(isThVMethod, null, false, null, false, false, 0, true);
	}
	
	public VoltageGenCondition(boolean isThVMethod, int bitState) {
		BuildCondition(isThVMethod, null, false, null, false, true, bitState, true);
	}

	public VoltageGenCondition(boolean isThVMethod, double[] p, boolean pIsFactor) {
		BuildCondition(isThVMethod, p, pIsFactor, null, false, false, 0, false);
	}
	
	public VoltageGenCondition(boolean isThVMethod, double[] p, boolean pIsFactor, double[] v, boolean vIsFactor, boolean isThV) {
		BuildCondition(isThVMethod, p, pIsFactor, v, vIsFactor, isThV, 0, false);
	}
	
	public VoltageGenCondition(boolean isThVMethod, double[] p, boolean pIsFactor, double[] v, boolean vIsFactor, boolean isThV, int bitState, boolean isBit) {
		BuildCondition(isThVMethod, p, pIsFactor, v, vIsFactor, isThV, bitState, isBit);
	}
	
	private void BuildCondition(boolean isThVMethod, double[] p, boolean pIsFactor, double[] v, boolean vIsFactor, boolean isThV, int bitState, boolean isBit) {
		if (p != null) 
			this.p = p;
		else
			this.p = new double[ref.getNoBus()];
		this.pIsFactor = pIsFactor;
		if (v != null)
			this.v = v;
		else
			this.v = new double[ref.getNoBus()];
		this.voltage = new Complex[ref.getNoBus()];
		this.vIsFactor = vIsFactor;
		this.isThVMethod = isThVMethod;
		this.bitState = bitState;
		this.isBit = isBit;
	}

	public double[] getP() {
		return p;
	}

	public void setP(double[] p) {
		this.p = p;
	}

	public void setPi(double p, int index) {
		this.p[index] = p;
	}
	public double[] getV() {
		return v;
	}

	public void setV(double[] v) {
		this.v = v;
	}
	
	public Complex[] getVoltage() {
		return voltage;
	}

	public void setVoltage(Complex[] voltage) {
		this.voltage = voltage;
	}

	public void setVi(double v, int index) {
		this.v[index] = v;
	}
	public boolean pIsFactor() {
		return pIsFactor;
	}

	public boolean vIsFactor() {
		return vIsFactor;
	}

	public boolean isThVMethod() {
		return isThVMethod;
	}

	public int getBitState() {
		return bitState;
	}
	
	public void setBitState(int bitState) {
		this.bitState = bitState;
	}
	
	public boolean isBit() {
		return isBit;
	}
	
	public static void init(RefInfo ref) {
		VoltageGenCondition.ref = ref;
	}
}
 public class VThSpaceAstringency extends LoadFlowCaseGenerator{

	public static final String NAME = "VThSpaceAstringency";
	public static final String NAME_IN_SHORT = "VTh";
	public static final String PARA_NEEDED = "NONE";
	
	/**
	 * validation
	 */
	private int nCase = 0;
	private int okCase = 0;
	
	public VThSpaceAstringency(String baseCasePath) throws InterpssException {
		super(baseCasePath);
		long startTime = System.currentTimeMillis();
		platformName = NAME;
		nameInShort = NAME_IN_SHORT;
		System.out.print("[REPORT] new "+platformName+"... ...ready.");
		
		System.out.println("[Validation] ON...");
		System.out.println("\tItem 1\tif swing bus V = 1, 0"
				+"\n\tItem 2\tif other v in internal"+LFComparator.V_MIN+", "+LFComparator.V_MAX
				+"\n\tItem 3\tif other th less than LFComparator.TH_ABS_MAX = "+LFComparator.TH_ABS_MAX
				+"\n\tItem 4\tif P less than LFComparator.P_ABS_MAX = "+LFComparator.P_ABS_MAX
				+"\n\tItem 5\tif Q less than LFComparator.Q_ABS_MAX = "+LFComparator.Q_ABS_MAX
				+"\n\tItem 6\tif Q of ONLY_PV bus in internal refInfo.QLimit"
				+"\n\tItem 7\tif PQ of CONNECT bus = 0, 0");
		nCase = 0;
		okCase = 0;
		addInitTime(startTime);
	}
	
	/**
	 * ²îÒì»¯µÄ³õÊ¼»¯·½·¨£¬½ö¹¹Ôìºó±»ÏÔÊ½µ÷ÓÃÖ´ÐÐÒ»´Î
	 * ÐèÒª¼Ì³Ðºó×Ô¼ºÖØÐ´
	 * ÓÃÓÚ×Ô¶¨ÒåÉú³ÉÆ÷¡¢Ð£ÕýÆ÷
	 * ÊäÈëÉú³ÉÆ÷µÄ²ÎÊý
	 */
	@Override
	public void init() {
		long startTime = System.currentTimeMillis();
		//¡°ÆäÓàÕÕ¾É¡±
		super.init();
		//¡°³ýÁËÕâ¸ö¡±
		voltageGenConditionBuilder = new VThScanConditionBuilder(refInfo);
		
		addInitTime(startTime);
	}
	
	@Override
	public void boom() throws InterpssException {
		
		double qbf = 0.95;
		
		((VThScanConditionBuilder)voltageGenConditionBuilder).setVBoundaryFactor(1.0);
		((QChecker)qChecker).setQLimitSparseFactor(qbf);
		this.setMaxIter(10);
		
		double[] vfactor = new double[] {0.9, 1, 0.7, 0.5, 0.9, 0.8, 0.6, 0.95, 0.85, 0.75, 0.65, 0.55};//ÑùÀýÖØÒªÐÔÐòÁÐ
		for (double vf:vfactor) {
			
			this.resetStatistics();
			((VThScanConditionBuilder)voltageGenConditionBuilder).setVBoundaryFactor(vf);
			
			FileOutputStream fs = null;
			SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");//ÉèÖÃÈÕÆÚ¸ñÊ½
			
			try {
				fs = new FileOutputStream(new File("doc/Data/"+NAME_IN_SHORT+"/VTh-vbf-"+vf+"-qbf-"+qbf+"-"+dataFormat.format(new Date())+".txt"));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
			PrintStream f = new PrintStream(fs);
			f.println(getReportTitle());
			
			int i;
			for (i=0; i<(1<<26); ++i) {
				go(voltageGenConditionBuilder.nextCondition());
				//Ã¿1m´ÎÊä³öÒ»´Î£¬´óÔ¼ÊÇ20·ÖÖÓÊä³öÒ»´Î
				if (i % 1000000 == 0) {
					System.out.println("=================================[REPORT] µÚ "+i+"´Î=================================");
					report();
					System.out.println("===================================================================================");
					f.println(getReportStr());
				}
			}
			
			System.out.println("=================================[REPORT] µÚ "+i+"´Î=================================");
			report();
			System.out.println("===================================================================================");
			f.println(getReportStr());
			
			f.close();
		}
	}
	
	@Override
	protected void successGenReaction(AclfCase aclfCase) {
		nCase += 1;
		if (Math.random() > 1-1e-7)
			System.out.println(aclfCase);
		if (LFComparator.checkCase(refInfo, aclfCase)) {
			okCase += 1;
		}
	}
	
	@Override
	public String getReportTitle() {
		return super.getReportTitle()+"\tnSuccessCase\nOKCase";
	}
	
	@Override
	public String getReportStr() {
		return super.getReportStr()+"\t"+nCase+"\t"+okCase;
	}
	
	@Override
	public void report() {
		System.out.println("\n\t==============================================\n"
				+"\t[REPORT] nSuccessCase = "+"\t"+nCase+"\tokCase = "+okCase+"\n"
				+"\t==============================================");
		super.report();
	}

	public static void main(String[] args) throws InterpssException {
		String baseCasePath = "testdata/cases/ieee14.ieee";
		VThSpaceAstringency g = new VThSpaceAstringency(baseCasePath);
		g.init();
		g.boom();
	}
}
 public abstract class LoadFlowCaseGenerator implements ILoadFlowCaseGenerator, IStatistics {

	public static final String NAME = "LoadFlowCaseGenerator";
	public static final String NAME_IN_SHORT = "dLFG";
	public static final String PARA_NEEDED = "NONE";
	public static final double DEFAULT_PU_ERROR = 1e-10;
	
	/**
	 * Îª¶à´Îµ÷ÓÃÉè¼Æ£¬ÓÃÀ´Í³¼Æ×ÜµÄµ÷ÓÃ´ÎÊýºÍ×ÜµÄµü´ú´ÎÊý
	 */
	protected int callTimes = 0;
	protected int totalIterTimes = 0;
	/**
	 * ÓÃÓÚÍ³¼Æµü´úÊýÁ¿,ÔÚinitÖÐ
	 */
	protected int[] iter = null;
	
	/**
	 * µ÷ÓÃÊ±¼äÍ³¼Æ
	 */
	protected long timeUse = 0;
	protected long initTimeUse = 0;
	protected long[] iterTimeUse = null;
	
	
	/*
	 * ¸÷ÖÖÄ£¿éµÄÖ¸Õë
	 * 1. ³õÖµÉú³ÉÆ÷	VoltageGenerator
	 * 2. ºËÐÄÉú³ÉÆ÷	LoadFlowGenerator
	 * 3. ¹¦ÂÊÔ½ÏÞ¼ì²éÆ÷	QChecker
	 * 4. ÁªÂç½Úµã¹¦ÂÊ¼ì²éÆ÷	ConnectBusChecker
	 */
	protected IVoltageGenerator voltageGenerator = null;
	protected ILoadFlowGenerator loadFlowGenerator = null;
	protected IQChecker qChecker = null;
	protected ISpecialBusChecker specialBusChecker = null;
	protected IVgcBuilder voltageGenConditionBuilder = null;

	/**
	 * ÍøÂçÐÅÏ¢Àà£¬Ö»ÒªÍøÂç¶ÔÏóÒ»È·¶¨£¬ÄÚÖÐËùÓÐÁ¿¾ÍÈ·¶¨µÄÒ»¸öÀà
	 */
	protected RefInfo refInfo = null;
	protected String platformName = null;
	protected String nameInShort = null;
	
	/**
	 * ¹¹Ôìº¯Êý£¬¸ù¾Ý»ùÌ¬³±Á÷Éú³ÉrefInfo£¬ÓÃ
	 * @param baseCasePath
	 * @throws InterpssException
	 */
	public LoadFlowCaseGenerator(String baseCasePath) throws InterpssException {
		long startTime = System.currentTimeMillis();
		platformName = NAME;
		nameInShort = NAME_IN_SHORT;
		System.out.print("[REPORT] new "+platformName+"...");
		
		timeUse = 0;
		initTimeUse = 0;
		callTimes = 0;
		totalIterTimes = 0;
		
		IpssCorePlugin.init();
		AclfNetwork refNet = CorePluginFactory
				.getFileAdapter(IpssFileAdapter.FileFormat.IEEECDF)
				.load(baseCasePath)
				.getAclfNet();
		
		gotoLimit(refNet);
		
		refInfo = new RefInfo(refNet);//Ö÷ÒªµÄÊ±¼ä»¨·Ñ
		
		VoltageGenCondition.init(refInfo);
		
		//report
		System.out.println(" ...ready.");
		addInitTime(startTime);
	}
	
	protected void gotoLimit(AclfNetwork net) throws InterpssException {
		
		int busi = 9;
		System.out.println("============ Go to Limit ============");
		LoadflowAlgorithm algo = CoreObjectFactory.createLoadflowAlgorithm(net);
		
		AclfBus bus = net.getBusList().get(9);
		Complex base = bus.getLoadPQ();
		Complex delta = base.multiply(10);
		Complex result = base;

		System.out.println("base = "+base+", delta = "+delta);
		if (bus.getContributeLoadList().size() == 0)
			return;//½öÓÃÓÚcpf39µÄÍ×Ð­
		bus.getContributeLoadList().get(0).setLoadCP(base.add(delta));
		System.out.println("\tbus load pq = "+bus.getLoadPQ());
		
		int iter = 0;
		while(delta.abs() > 1e-10) {
			iter += 1;
			//µ±Ç°µ¥¸ùÇø¼ä
			System.out.println("base = "+base+", delta = "+delta);
			
			//ÊÔÌ½ÖÐµã
			delta = delta.multiply(0.5);
			bus.getContributeLoadList().get(0).setLoadCP(base.add(delta));
			//ÖÐµã×ø±ê
			System.out.println("bus load pq = "+bus.getLoadPQ());
			
			//ÈôÊÔÌ½³É¹¦Ôò...
			if (algo.loadflow()) {
				base = base.add(delta);
				result = base;
				System.out.println("a success bus 9 load PQ = "+bus.getLoadPQ());
			}
//			System.out.println(AclfOutFunc.loadFlowSummary(net));
		}
		
		System.out.println("iter = "+iter);
		bus.getContributeLoadList().get(0).setLoadCP(result);
		System.out.println("after searching, bus 9 load PQ = "+result+", lf result = "+algo.loadflow());
		System.out.println(AclfOutFunc.loadFlowSummary(net));
		
	}

	/**
	 * ³õÊ¼»¯·½·¨£¬ÊÇÕû¸öÆ½Ì¨µÄ²å×ù£¬Í¨¹ýÊµÏÖÀàÖØÐ´´Ë·½·¨À´²åÈë²»Í¬µÄËã·¨
	 * ÐèÒª¼Ì³Ðºó×Ô¼ºÖØÐ´
	 * @param maxIter
	 * @param boundaryFactor
	 * @param qLimitSparseFactor
	 * @throws InterpssException
	 */
	@Override
	public void init(){
		long startTime = System.currentTimeMillis();
		
		//new all the methods' implements
		voltageGenerator = new VoltageGenerator(refInfo);
		
		loadFlowGenerator = new LoadFlowGenerator(refInfo);
		
		qChecker = new QChecker(refInfo);
		
		specialBusChecker = new SpecialBusChecker(refInfo);
		
		voltageGenConditionBuilder = new VThScanConditionBuilder(refInfo);
		
		addInitTime(startTime);
	}
	
	/**
	 * Éú³ÉÌõ¼þ£¬¸ù¾ÝÌõ¼þÉú³Écase
	 * ²»ÐèÒªÐ´¼ÆÊ±µÄ£¡£¡
	 * 1. ¾ö¶¨¸÷¸ö·½·¨µÄ²ÎÊý
	 * 2. µ÷ÓÃ¶àÉÙ´Îgo(c)
	 * 3. ÔõÑùÊä³ö±¨¸æ£¨¸Ð¾õ¸ÉµÄÊÇmain¸ÉµÄ£©
	 * @throws InterpssException 
	 */
	@Override
	public void boom() throws InterpssException {
		int maxIter = 10;
		iter = new int[maxIter+1];
		iterTimeUse = new long[maxIter+1];
		for (int i=0; i<(1<<26); ++i) 
			go(voltageGenConditionBuilder.nextCondition());
	}
	
	protected void setMaxIter(int maxIter) {
		iter = new int[maxIter+1];
		iterTimeUse = new long[maxIter+1];
		System.out.println("[REPORT] "+platformName+" paramter set. maxIter = "+maxIter);
	} 
	
	/**
	 * ´Ë·½·¨²»¶ÔÍâ¿ª·Å£¬ÊÇËã·¨µÄºËÐÄ²½ÖèÀ´µÄ
	 * @param c
	 * @throws InterpssException
	 */
	protected void go(VoltageGenCondition c) throws InterpssException{
		long startTime = System.currentTimeMillis();
		addCallTimes();
		
		Complex[] voltage = voltageGenerator.genVoltage(c);
		AclfCase aclfCase = new AclfCase(voltage);
		
		specialBusChecker.correct(aclfCase);

		int iter = 0;
		boolean successGen = true;
		while (!qChecker.correct(aclfCase)) {
			iter += 1;
			if (iter > this.iter.length - 2) {
				successGen = false;
				break;
			}
			specialBusChecker.correct(aclfCase);
		}
		this.iter[iter] += 1;
		this.totalIterTimes += iter;
		if (successGen) {
			successGenReaction(aclfCase);
		}
		addTimeUse(startTime, iter);
		addTimeUse(startTime);
	}
	
	/**
	 * ´Ë·½·¨ÓÃÓÚÖ´ÐÐ¶ÔÓÚ³É¹¦Éú³É°¸ÀýµÄ·´Ó¦
	 * ²»Í¬ÊµÏÖÖÐ¿ÉÒÔÖØÐ´ÒÔÌí¼ÓÖ´ÐÐ·½·¨¡£
	 * Ä¬ÈÏ²»Ìí¼ÓÄÚÈÝÒÔ¼ÓËÙ
	 * @param onGoNet
	 * @param voltage
	 * @param power
	 */
	protected abstract void successGenReaction(AclfCase aclfCase);
	
	public void report() {
		System.out.println("[REPORT] "+platformName+".report():"
				+"\n ** Time use = "+this.timeUse+"\tSub Cases = "+callTimes+"\t initTime = "+this.initTimeUse+", iterTimes/callTimes = "+(totalIterTimes+0.0)/callTimes);

		((AlgoObject) voltageGenerator).report();
		((AlgoObject) loadFlowGenerator).report();
		((AlgoObject) qChecker).report();
		((AlgoObject) specialBusChecker).report();
		String str = new String("");
		for (int i=0; i<this.iter.length; ++i) {
			str += "\tIter "+i+" case =  "+this.iter[i]+"\t\ttime cost = "+this.iterTimeUse[i]+"\n";
		}
		System.out.println(str);
	}

	public String getReportTitle() {
		String report = new String("");
		
		report += "CallTimes\ttTotal\ttInit\ttVG\ttLFG\ttQC\ttSBC";
		for (int i=0; i<this.iter.length; ++i)
			report += "\t"+i;
		report += "\t"+(this.iter.length-2)+"Rate";
		for (int i=0; i<this.iter.length; ++i)
			report += "\t"+i+"time";
		
		return report;
	}

	/**
	 * ´Ë·½·¨ÏÞÖÆÁËLFCGµÄËùÓÐ·½·¨Ö¸Õë±ØÐëÖ¸Ïò(IDecorator)
	 */
	public String getReportStr() {
		String report = new String("");
		
		report += this.callTimes;
		report += "\t"+this.timeUse;
		report += "\t"+this.initTimeUse;
		report += "\t"+((AlgoObject) voltageGenerator).getTimeUse();
		report += "\t"+((AlgoObject) loadFlowGenerator).getTimeUse();
		report += "\t"+((AlgoObject) qChecker).getTimeUse();
		report += "\t"+((AlgoObject) specialBusChecker).getTimeUse();
		report += "\t"+((AlgoObject) voltageGenConditionBuilder).getTimeUse();
		
		double sum = 0;
		for (int i=0; i<this.iter.length-1; ++i) {
			report += "\t"+this.iter[i];
			sum += this.iter[i];
		}
		report += "\t"+Double.toString(sum/this.callTimes);
		for (int i=0; i<this.iter.length; ++i)
			report += "\t"+this.iterTimeUse[i];
		return report;
	}

	@Override
	public int getCallTimes() {
		return this.callTimes;
	}

	@Override
	public long getInitTimeUse() {
		return this.initTimeUse;
	}

	@Override
	public long getTimeUse() {
		return this.timeUse;
	}

	@Override
	public double getAverageTimeUse() {
		return this.timeUse/this.callTimes;
	}
	
	@Override
	public void resetStatistics() {
		callTimes = 0;
		totalIterTimes = 0;
		iter = new int[iter.length];
		timeUse = 0;
		initTimeUse = 0;
		iterTimeUse = new long[iter.length];
		
		((AlgoObject) voltageGenerator).resetStatistics();
		((AlgoObject) loadFlowGenerator).resetStatistics();
		((AlgoObject) qChecker).resetStatistics();
		((AlgoObject) specialBusChecker).resetStatistics();
		((AlgoObject) voltageGenConditionBuilder).resetStatistics();
		System.out.printf("[REPORT] platform %25s is reset, now called times =  %10d, with time use(s) = %10.0f, in which init time use = %10.3f\n",
				platformName, callTimes, timeUse/1000.0, initTimeUse/1000.0);
	}
	
	protected void addCallTimes() {
		this.callTimes += 1;
	}
	
	protected void addInitTime(long startTime) {
		long timeuse = System.currentTimeMillis() - startTime;
		this.initTimeUse += timeuse;
		this.timeUse += timeuse;
	}

	protected void addTimeUse(long startTime) {
		this.timeUse += System.currentTimeMillis() - startTime;
	}
	protected void addTimeUse(long startTime, int index) {
		this.iterTimeUse[index] += System.currentTimeMillis() - startTime;
	}

	public int getIterTimes() {
		return totalIterTimes;
	}

	public int[] getIter() {
		return iter;
	}

	public IVoltageGenerator getVoltageGenerator() {
		return voltageGenerator;
	}

	public ILoadFlowGenerator getLoadFlowGenerator() {
		return loadFlowGenerator;
	}

	public IQChecker getqChecker() {
		return qChecker;
	}

	public long[] getIterTime() {
		return iterTimeUse;
	}

	public ISpecialBusChecker getSpecialBusChecker() {
		return specialBusChecker;
	}

	public RefInfo getRefInfo() {
		return refInfo;
	}

	public String getPlatformName() {
		return platformName;
	}
}

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.math3.complex.Complex;
import org.interpss.CorePluginFactory;
import org.interpss.IpssCorePlugin;
import org.interpss.display.AclfOutFunc;
import org.interpss.fadapter.IpssFileAdapter;
import com.interpss.CoreObjectFactory;
import com.interpss.common.exp.InterpssException;
import com.interpss.core.aclf.AclfBus;
import com.interpss.core.aclf.AclfLoad;
import com.interpss.core.aclf.AclfNetwork;
import com.interpss.core.aclf.impl.AclfLoadImpl;
import com.interpss.core.algo.LoadflowAlgorithm;
import lfgen.algo.ILoadFlowGenerator;
import lfgen.algo.IQChecker;
import lfgen.algo.ISpecialBusChecker;
import lfgen.algo.IVgcBuilder;
import lfgen.algo.IVoltageGenerator;
import lfgen.algo.impl.LFComparator;
import lfgen.algo.impl.LoadFlowGenerator;
import lfgen.algo.impl.QChecker;
import lfgen.algo.impl.SpecialBusChecker;
import lfgen.algo.impl.VoltageGenerator;
import lfgen.condition_gen.VThScanConditionBuilder;
import lfgen.datatype.AclfCase;
import lfgen.datatype.RefInfo;
import lfgen.datatype.VoltageGenCondition;
import lfgen.output.VThSpaceAstringency;
import lfgen.platform.LoadFlowCaseGenerator;

package lfgen.validate;





/**
* @author JeremyChenlk
* @version 2019Äê3ÔÂ18ÈÕ ÏÂÎç2:48:52
*
* Class description:
*	
*/

public class LfAdjust {
	
	private AclfNetwork net = null;
	
	/*
	 * ¸÷ÖÖÄ£¿éµÄÖ¸Õë
	 * 1. ³õÖµÉú³ÉÆ÷	VoltageGenerator
	 * 2. ºËÐÄÉú³ÉÆ÷	LoadFlowGenerator
	 * 3. ¹¦ÂÊÔ½ÏÞ¼ì²éÆ÷	QChecker
	 * 4. ÁªÂç½Úµã¹¦ÂÊ¼ì²éÆ÷	ConnectBusChecker
	 */
	protected IVoltageGenerator voltageGenerator = null;
	protected ILoadFlowGenerator loadFlowGenerator = null;
	protected IQChecker qChecker = null;
	protected ISpecialBusChecker specialBusChecker = null;
	protected IVgcBuilder voltageGenConditionBuilder = null;
	protected RefInfo refInfo = null;
	
	public LfAdjust(String baseCasePath) throws InterpssException {
		IpssCorePlugin.init();
		AclfNetwork refNet = CorePluginFactory
				.getFileAdapter(IpssFileAdapter.FileFormat.IEEECDF)
				.load(baseCasePath)
				.getAclfNet();
		gotoLimit(refNet);
		
		net = CorePluginFactory
				.getFileAdapter(IpssFileAdapter.FileFormat.IEEECDF)
				.load(baseCasePath)
				.getAclfNet();
		gotoLimit(net);
		LFOut.showlf(net);
		
		refInfo = new RefInfo(refNet);//Ö÷ÒªµÄÊ±¼ä»¨·Ñ
		
		VoltageGenCondition.init(refInfo);
	}

	public void init(){
		long startTime = System.currentTimeMillis();
		
		//new all the methods' implements

		voltageGenerator = new VoltageGenerator(refInfo);
