public void TestSensitivityGenerator() { PerturbAndObserveRunner<Complex> runner = new PerturbAndObserveRunner<Complex>(new OpenDSSSimulator()); runner.NetworkFilename = AppDomain.CurrentDomain.BaseDirectory + @"\TestNetworks\Ex9_5_nogen.dss"; runner.PerturbCommands = new String[] { "new Generator.{0} bus1={1} phases=3 model=1 status=fixed kV={2} Vminpu=0.9 Vmaxpu=1.1 kW={3} kvAR=0" }; runner.PerturbElementSelector = network => network.Buses.Values; runner.PerturbElementValuesSelector = elem => { Bus b = (Bus)elem; return new Object[] { "gg-" + b.ID, b.ID, b.BaseVoltage * Math.Sqrt(3) / 1000, 3260 }; }; runner.PerturbValuesToRecord = x => x[3]; runner.ObserveElementSelector = network => network.Buses.Values; runner.ObserveElementValuesSelector = elem => ((Bus)elem).Voltage; runner.RunPerturbAndObserve(); SensitivityGenerator<Complex> generator = new SensitivityGenerator<Complex>(); generator.RecordedPerturbationSelector = x => x; generator.ResultSelector = x => x.Magnitude; var sensitivities = generator.GenerateSensitivities(runner); AssertEqualByPercent(0.018510852, sensitivities.MapX["b2"]["b2"], 0.1); AssertEqualByPercent(0.007367939, sensitivities.MapX["b2"]["b3"], 0.1); AssertEqualByPercent(0.015043472, sensitivities.MapX["b2"]["b4"], 0.1); AssertEqualByPercent(0.006543352, sensitivities.MapX["b3"]["b2"], 0.1); AssertEqualByPercent(0.013438371, sensitivities.MapX["b3"]["b3"], 0.1); AssertEqualByPercent(0.009204037, sensitivities.MapX["b3"]["b4"], 0.1); AssertEqualByPercent(0.018171524, sensitivities.MapX["b4"]["b2"], 0.1); AssertEqualByPercent(0.012616745, sensitivities.MapX["b4"]["b3"], 0.1); AssertEqualByPercent(0.025445765, sensitivities.MapX["b4"]["b4"], 0.1); }
public void TestSensitivityGenerator() { PerturbAndObserveRunner <Complex> runner = new PerturbAndObserveRunner <Complex>(new OpenDSSSimulator()); runner.NetworkFilename = AppDomain.CurrentDomain.BaseDirectory + @"\TestNetworks\Ex9_5_nogen.dss"; runner.PerturbCommands = new String[] { "new Generator.{0} bus1={1} phases=3 model=1 status=fixed kV={2} Vminpu=0.9 Vmaxpu=1.1 kW={3} kvAR=0" }; runner.PerturbElementSelector = network => network.Buses.Values; runner.PerturbElementValuesSelector = elem => { Bus b = (Bus)elem; return(new Object[] { "gg-" + b.ID, b.ID, b.BaseVoltage *Math.Sqrt(3) / 1000, 3260 }); }; runner.PerturbValuesToRecord = x => x[3]; runner.ObserveElementSelector = network => network.Buses.Values; runner.ObserveElementValuesSelector = elem => ((Bus)elem).Voltage; runner.RunPerturbAndObserve(); SensitivityGenerator <Complex> generator = new SensitivityGenerator <Complex>(); generator.RecordedPerturbationSelector = x => x; generator.ResultSelector = x => x.Magnitude; var sensitivities = generator.GenerateSensitivities(runner); AssertEqualByPercent(0.018510852, sensitivities.MapX["b2"]["b2"], 0.1); AssertEqualByPercent(0.007367939, sensitivities.MapX["b2"]["b3"], 0.1); AssertEqualByPercent(0.015043472, sensitivities.MapX["b2"]["b4"], 0.1); AssertEqualByPercent(0.006543352, sensitivities.MapX["b3"]["b2"], 0.1); AssertEqualByPercent(0.013438371, sensitivities.MapX["b3"]["b3"], 0.1); AssertEqualByPercent(0.009204037, sensitivities.MapX["b3"]["b4"], 0.1); AssertEqualByPercent(0.018171524, sensitivities.MapX["b4"]["b2"], 0.1); AssertEqualByPercent(0.012616745, sensitivities.MapX["b4"]["b3"], 0.1); AssertEqualByPercent(0.025445765, sensitivities.MapX["b4"]["b4"], 0.1); }
/// <summary> /// Generates Voltage Sensitivities to changes in P and Q at each load bus on /// the network. /// </summary> /// <remarks> /// This is a convenience class that uses the functionality supplied by /// <see cref="SensitivityGenerator{T}"/> and <see cref="PerturbAndObserveRunner{T}"/>. /// For other kinds of sensitivities, you may wish to use these classes directly.</remarks> /// <param name="Simulator">The simulator to use for the generation of sensitivities.</param> /// <param name="NetworkMasterFile">The file path of the Network to calculate sensitivities for.</param> /// <param name="CommandString">A command for issuing perturbations. The command should be /// compatible with <see cref="String.Format(String,Object[])"/>-style format strings, and should /// use <c>{0}</c> to represent a random ID, <c>{1}</c> to represent the bus that perturbation should occur /// on, <c>{2}</c> to represent a kW quantity to perturb by and <c>{3}</c> to represent a kVAr quantity to /// perturb by. /// <example> /// As an example, the following string specifies a new generator for perturbation in OpenDSS syntax: /// <code> /// "new Generator.{0} bus1={1} phases=3 model=1 status=fixed kV=11 Vminpu=0.9 Vmaxpu=1.1 kW={2} kvAR={3}"</code></example></param> /// <param name="PerturbationFrac">The fraction of average load size to perturb by.</param> /// <returns>A 2-axis dictionary, in which the X-axis represents the source bus, the Y-axis represents the affected bus, /// and the values are an index of sensitivity information.</returns> public static TwinKeyDictionary<String, String, VoltageSensitivityToPQDataSet> GetVoltageSensitivityToComplexPower(ISimulator Simulator, String NetworkMasterFile, String CommandString, double PerturbationFrac) { PerturbAndObserveRunner<Complex> perturbAndObserve = new PerturbAndObserveRunner<Complex>(Simulator); NetworkController controller = new NetworkController(Simulator); controller.NetworkFilename = NetworkMasterFile; controller.Execute(); var avgLoad = controller.Network.Loads.Select(load=>load.ActualKVA).Aggregate((seed,elem) => seed+elem); avgLoad /= controller.Network.Loads.Count; perturbAndObserve.NetworkFilename = NetworkMasterFile; perturbAndObserve.ObserveElementSelector = network => network.Buses.Values.Where(bus => bus.ConnectedTo.OfType<Load>().Any()); perturbAndObserve.PerturbElementSelector = perturbAndObserve.ObserveElementSelector; perturbAndObserve.PerturbCommands = new []{CommandString}; perturbAndObserve.ObserveElementValuesSelector = elem => ((Bus)elem).Voltage; SensitivityGenerator<Complex> generator = new SensitivityGenerator<Complex>(); //real perturbAndObserve.PerturbElementValuesSelector = bus => new Object[] {"inject-"+bus.ID,bus.ID,PerturbationFrac * avgLoad.Real, 0}; perturbAndObserve.PerturbValuesToRecord = vars => vars[2]; perturbAndObserve.RunPerturbAndObserve(); generator.RecordedPerturbationSelector = x => x; generator.ResultSelector = x => x.Magnitude; var MagnitudeDictionaryReal = generator.GenerateSensitivities(perturbAndObserve); generator.ResultSelector = x => x.Phase; var PhaseDictionaryReal = generator.GenerateSensitivities(perturbAndObserve); //imaginary perturbAndObserve.PerturbElementValuesSelector = bus => new Object[] { "inject-" + bus.ID, bus.ID, 0, PerturbationFrac * avgLoad.Imaginary }; perturbAndObserve.PerturbValuesToRecord = vars => vars[3]; perturbAndObserve.RunPerturbAndObserve(); generator.RecordedPerturbationSelector = x => x; generator.ResultSelector = x => x.Magnitude; var MagnitudeDictionaryImag = generator.GenerateSensitivities(perturbAndObserve); generator.ResultSelector = x => x.Phase; var PhaseDictionaryImag = generator.GenerateSensitivities(perturbAndObserve); // now merge all the dictionaries. return TwinKeyDictionaryMerge(MagnitudeDictionaryReal, MagnitudeDictionaryImag, PhaseDictionaryReal, PhaseDictionaryImag); }