%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%                                                                  %%%%%
%%%%    IEEE PES Power Grid Library - Optimal Power Flow - v21.07     %%%%%
%%%%          (https://github.com/power-grid-lib/pglib-opf)           %%%%%
%%%%             Benchmark Group - Active Power Increase              %%%%%
%%%%                         29 - July - 2021                         %%%%%
%%%%                                                                  %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function mpc = pglib_opf_case24_ieee_rts__api
mpc.version = '2';
mpc.baseMVA = 100.0;

%% area data
%	area	refbus
mpc.areas = [
	1	 1;
	2	 3;
	3	 8;
	4	 6;
];

%% bus data
%	bus_i	type	Pd	Qd	Gs	Bs	area	Vm	Va	baseKV	zone	Vmax	Vmin
mpc.bus = [
	1	 2	 207.30	 22.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	2	 2	 186.19	 20.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	3	 1	 345.50	 37.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	4	 1	 142.04	 15.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	5	 1	 136.28	 14.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	6	 1	 261.04	 28.00	 0.0	 -100.0	 2	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	7	 2	 239.93	 25.00	 0.0	 0.0	 2	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	8	 1	 328.23	 35.00	 0.0	 0.0	 2	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	9	 1	 335.90	 36.00	 0.0	 0.0	 1	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	10	 1	 374.29	 40.00	 0.0	 0.0	 2	    1.00000	    0.00000	 138.0	 1	    1.05000	    0.95000;
	11	 1	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	12	 1	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	13	 3	 508.65	 54.00	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	14	 2	 372.37	 39.00	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	15	 2	 608.47	 64.00	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	16	 2	 191.94	 20.00	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	17	 1	 0.0	 0.0	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	18	 2	 639.18	 68.00	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	19	 1	 347.42	 37.00	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	20	 1	 245.69	 26.00	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	21	 2	 0.0	 0.0	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	22	 2	 0.0	 0.0	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	23	 2	 0.0	 0.0	 0.0	 0.0	 3	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
	24	 1	 0.0	 0.0	 0.0	 0.0	 4	    1.00000	    0.00000	 230.0	 1	    1.05000	    0.95000;
];

%% generator data
%	bus	Pg	Qg	Qmax	Qmin	Vg	mBase	status	Pmax	Pmin
mpc.gen = [
	1	 43.5	 0.0	 40.0	 -40.0	 1.0	 100.0	 1	 79	 8.0; % PEL
	1	 109.5	 0.0	 106.0	 -106.0	 1.0	 100.0	 1	 211	 8.0; % PEL
	1	 41.3	 0.0	 38.0	 -38.0	 1.0	 100.0	 1	 75	 7.6; % PEL
	1	 42.8	 0.0	 39.0	 -39.0	 1.0	 100.0	 1	 78	 7.6; % NG
	2	 98.0	 0.0	 94.0	 -94.0	 1.0	 100.0	 1	 188	 8.0; % NG
	2	 95.0	 0.0	 91.0	 -91.0	 1.0	 100.0	 1	 182	 8.0; % PEL
	2	 91.8	 0.0	 88.0	 -88.0	 1.0	 100.0	 1	 176	 7.6; % NG
	2	 335.3	 0.0	 332.0	 -332.0	 1.0	 100.0	 1	 663	 7.6; % COW
	7	 221.25	 0.0	 215.0	 -215.0	 1.0	 100.0	 1	 430	 12.5; % NG
	7	 82.75	 0.0	 77.0	 -77.0	 1.0	 100.0	 1	 153	 12.5; % NG
	7	 303.75	 0.0	 298.0	 -298.0	 1.0	 100.0	 1	 595	 12.5; % COW
	13	 289.25	 0.0	 272.0	 -272.0	 1.0	 100.0	 1	 544	 34.5; % NG
	13	 288.25	 0.0	 271.0	 -271.0	 1.0	 100.0	 1	 542	 34.5; % NG
	13	 321.75	 0.0	 305.0	 -305.0	 1.0	 100.0	 1	 609	 34.5; % COW
	14	 0.0	 0.0	 252.0	 -252.0	 1.0	 100.0	 1	 0	 0.0; % SYNC
	15	 80.1	 0.0	 94.8	 -94.8	 1.0	 100.0	 1	 159	 1.2; % NG
	15	 103.6	 0.0	 103.0	 -103.0	 1.0	 100.0	 1	 206	 1.2; % COW
	15	 98.1	 0.0	 98.0	 -98.0	 1.0	 100.0	 1	 195	 1.2; % NG
	15	 81.6	 0.0	 94.8	 -94.8	 1.0	 100.0	 1	 162	 1.2; % NG
	15	 70.1	 0.0	 94.8	 -94.8	 1.0	 100.0	 1	 139	 1.2; % NG
	15	 116.575	 0.0	 103.0	 -103.0	 1.0	 100.0	 1	 206	 27.15; % NG
	16	 308.075	 0.0	 295.0	 -295.0	 1.0	 100.0	 1	 589	 27.15; % NG
	18	 216.0	 4.5	 200.0	 -191.0	 1.0	 100.0	 1	 382	 50.0; % NG
	21	 362.5	 0.0	 338.0	 -338.0	 1.0	 100.0	 1	 675	 50.0; % COW
	22	 113.5	 0.0	 111.0	 -111.0	 1.0	 100.0	 1	 222	 5.0; % NG
	22	 94.5	 0.0	 92.0	 -92.0	 1.0	 100.0	 1	 184	 5.0; % NG
	22	 75.5	 0.0	 73.0	 -73.0	 1.0	 100.0	 1	 146	 5.0; % NG
	22	 119.0	 0.0	 117.0	 -117.0	 1.0	 100.0	 1	 233	 5.0; % COW
	22	 110.5	 0.0	 108.0	 -108.0	 1.0	 100.0	 1	 216	 5.0; % NG
	22	 44.0	 0.0	 42.0	 -42.0	 1.0	 100.0	 1	 83	 5.0; % NG
	23	 224.075	 0.0	 211.0	 -211.0	 1.0	 100.0	 1	 421	 27.15; % NG
	23	 159.575	 0.0	 146.0	 -146.0	 1.0	 100.0	 1	 292	 27.15; % COW
	23	 226.0	 0.0	 191.0	 -191.0	 1.0	 100.0	 1	 382	 70.0; % NG
];

%% generator cost data
%	2	startup	shutdown	n	c(n-1)	...	c0
mpc.gencost = [
	2	 1500.0	 0.0	 3	   0.000000	 130.000000	 400.684900; % PEL
	2	 1500.0	 0.0	 3	   0.000000	 130.000000	 400.684900; % PEL
	2	 1500.0	 0.0	 3	   0.014142	  16.081100	 212.307600; % PEL
	2	 1500.0	 0.0	 3	   0.014142	  16.081100	 212.307600; % NG
	2	 1500.0	 0.0	 3	   0.000000	 130.000000	 400.684900; % NG
	2	 1500.0	 0.0	 3	   0.000000	 130.000000	 400.684900; % PEL
	2	 1500.0	 0.0	 3	   0.014142	  16.081100	 212.307600; % NG
	2	 1500.0	 0.0	 3	   0.014142	  16.081100	 212.307600; % COW
	2	 1500.0	 0.0	 3	   0.052672	  43.661500	 781.521000; % NG
	2	 1500.0	 0.0	 3	   0.052672	  43.661500	 781.521000; % NG
	2	 1500.0	 0.0	 3	   0.052672	  43.661500	 781.521000; % COW
	2	 1500.0	 0.0	 3	   0.007170	  48.580400	 832.757500; % NG
	2	 1500.0	 0.0	 3	   0.007170	  48.580400	 832.757500; % NG
	2	 1500.0	 0.0	 3	   0.007170	  48.580400	 832.757500; % COW
	2	 1500.0	 0.0	 3	   0.000000	   0.000000	   0.000000; % SYNC
	2	 1500.0	 0.0	 3	   0.328412	  56.564000	  86.385200; % NG
	2	 1500.0	 0.0	 3	   0.328412	  56.564000	  86.385200; % COW
	2	 1500.0	 0.0	 3	   0.328412	  56.564000	  86.385200; % NG
	2	 1500.0	 0.0	 3	   0.328412	  56.564000	  86.385200; % NG
	2	 1500.0	 0.0	 3	   0.328412	  56.564000	  86.385200; % NG
	2	 1500.0	 0.0	 3	   0.008342	  12.388300	 382.239100; % NG
	2	 1500.0	 0.0	 3	   0.008342	  12.388300	 382.239100; % NG
	2	 1500.0	 0.0	 3	   0.000213	   4.423100	 395.374900; % NG
	2	 1500.0	 0.0	 3	   0.000213	   4.423100	 395.374900; % COW
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % NG
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % NG
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % NG
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % COW
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % NG
	2	 1500.0	 0.0	 3	   0.000000	   0.001000	   0.001000; % NG
	2	 1500.0	 0.0	 3	   0.008342	  12.388300	 382.239100; % NG
	2	 1500.0	 0.0	 3	   0.008342	  12.388300	 382.239100; % COW
	2	 1500.0	 0.0	 3	   0.004895	  11.849500	 665.109400; % NG
];

%% branch data
%	fbus	tbus	r	x	b	rateA	rateB	rateC	ratio	angle	status	angmin	angmax
mpc.branch = [
	1	 2	 0.0026	 0.0139	 0.4611	 175.0	 193.0	 200.0	 0.0	 0.0	 1	 -30.0	 30.0;
	1	 3	 0.0546	 0.2112	 0.0572	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	1	 5	 0.0218	 0.0845	 0.0229	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	2	 4	 0.0328	 0.1267	 0.0343	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	2	 6	 0.0497	 0.192	 0.052	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	3	 9	 0.0308	 0.119	 0.0322	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	3	 24	 0.0023	 0.0839	 0.0	 400.0	 510.0	 600.0	 1.03	 0.0	 1	 -30.0	 30.0;
	4	 9	 0.0268	 0.1037	 0.0281	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	5	 10	 0.0228	 0.0883	 0.0239	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	6	 10	 0.0139	 0.0605	 2.459	 175.0	 193.0	 200.0	 0.0	 0.0	 1	 -30.0	 30.0;
	7	 8	 0.0159	 0.0614	 0.0166	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	8	 9	 0.0427	 0.1651	 0.0447	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	8	 10	 0.0427	 0.1651	 0.0447	 175.0	 208.0	 220.0	 0.0	 0.0	 1	 -30.0	 30.0;
	9	 11	 0.0023	 0.0839	 0.0	 400.0	 510.0	 600.0	 1.03	 0.0	 1	 -30.0	 30.0;
	9	 12	 0.0023	 0.0839	 0.0	 400.0	 510.0	 600.0	 1.03	 0.0	 1	 -30.0	 30.0;
	10	 11	 0.0023	 0.0839	 0.0	 400.0	 510.0	 600.0	 1.02	 0.0	 1	 -30.0	 30.0;
	10	 12	 0.0023	 0.0839	 0.0	 400.0	 510.0	 600.0	 1.02	 0.0	 1	 -30.0	 30.0;
	11	 13	 0.0061	 0.0476	 0.0999	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	11	 14	 0.0054	 0.0418	 0.0879	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	12	 13	 0.0061	 0.0476	 0.0999	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	12	 23	 0.0124	 0.0966	 0.203	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	13	 23	 0.0111	 0.0865	 0.1818	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	14	 16	 0.005	 0.0389	 0.0818	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	15	 16	 0.0022	 0.0173	 0.0364	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	15	 21	 0.0063	 0.049	 0.103	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	15	 21	 0.0063	 0.049	 0.103	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	15	 24	 0.0067	 0.0519	 0.1091	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 17	 0.0033	 0.0259	 0.0545	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	16	 19	 0.003	 0.0231	 0.0485	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	17	 18	 0.0018	 0.0144	 0.0303	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	17	 22	 0.0135	 0.1053	 0.2212	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	18	 21	 0.0033	 0.0259	 0.0545	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	18	 21	 0.0033	 0.0259	 0.0545	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	19	 20	 0.0051	 0.0396	 0.0833	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	19	 20	 0.0051	 0.0396	 0.0833	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	20	 23	 0.0028	 0.0216	 0.0455	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	20	 23	 0.0028	 0.0216	 0.0455	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
	21	 22	 0.0087	 0.0678	 0.1424	 500.0	 600.0	 625.0	 0.0	 0.0	 1	 -30.0	 30.0;
];

% INFO    : === Translation Options ===
% INFO    : Load Model:                  from file ./pglib_opf_case24_ieee_rts.m.api.sol
% INFO    : Gen Active Capacity Model:   stat
% INFO    : Gen Reactive Capacity Model: al50ag
% INFO    : Gen Active Cost Model:       stat
% INFO    :
% INFO    : === Load Replacement Notes ===
% INFO    : Bus 1	: Pd=108.0, Qd=22.0 -> Pd=207.30, Qd=22.00
% INFO    : Bus 2	: Pd=97.0, Qd=20.0 -> Pd=186.19, Qd=20.00
% INFO    : Bus 3	: Pd=180.0, Qd=37.0 -> Pd=345.50, Qd=37.00
% INFO    : Bus 4	: Pd=74.0, Qd=15.0 -> Pd=142.04, Qd=15.00
% INFO    : Bus 5	: Pd=71.0, Qd=14.0 -> Pd=136.28, Qd=14.00
% INFO    : Bus 6	: Pd=136.0, Qd=28.0 -> Pd=261.04, Qd=28.00
% INFO    : Bus 7	: Pd=125.0, Qd=25.0 -> Pd=239.93, Qd=25.00
% INFO    : Bus 8	: Pd=171.0, Qd=35.0 -> Pd=328.23, Qd=35.00
% INFO    : Bus 9	: Pd=175.0, Qd=36.0 -> Pd=335.90, Qd=36.00
% INFO    : Bus 10	: Pd=195.0, Qd=40.0 -> Pd=374.29, Qd=40.00
% INFO    : Bus 13	: Pd=265.0, Qd=54.0 -> Pd=508.65, Qd=54.00
% INFO    : Bus 14	: Pd=194.0, Qd=39.0 -> Pd=372.37, Qd=39.00
% INFO    : Bus 15	: Pd=317.0, Qd=64.0 -> Pd=608.47, Qd=64.00
% INFO    : Bus 16	: Pd=100.0, Qd=20.0 -> Pd=191.94, Qd=20.00
% INFO    : Bus 18	: Pd=333.0, Qd=68.0 -> Pd=639.18, Qd=68.00
% INFO    : Bus 19	: Pd=181.0, Qd=37.0 -> Pd=347.42, Qd=37.00
% INFO    : Bus 20	: Pd=128.0, Qd=26.0 -> Pd=245.69, Qd=26.00
% INFO    :
% INFO    : === Generator Setpoint Replacement Notes ===
% INFO    : Gen at bus 1	: Pg=18.0, Qg=5.0 -> Pg=73.0, Qg=1.0
% INFO    : Gen at bus 1	: Pg=18.0, Qg=5.0 -> Pg=73.0, Qg=1.0
% INFO    : Gen at bus 1	: Pg=45.6, Qg=2.5 -> Pg=72.0, Qg=1.0
% INFO    : Gen at bus 1	: Pg=45.6, Qg=2.5 -> Pg=72.0, Qg=1.0
% INFO    : Gen at bus 2	: Pg=18.0, Qg=5.0 -> Pg=157.0, Qg=31.0
% INFO    : Gen at bus 2	: Pg=18.0, Qg=5.0 -> Pg=157.0, Qg=31.0
% INFO    : Gen at bus 2	: Pg=45.6, Qg=2.5 -> Pg=156.0, Qg=31.0
% INFO    : Gen at bus 2	: Pg=45.6, Qg=2.5 -> Pg=156.0, Qg=31.0
% INFO    : Gen at bus 7	: Pg=62.5, Qg=30.0 -> Pg=126.0, Qg=42.0
% INFO    : Gen at bus 7	: Pg=62.5, Qg=30.0 -> Pg=126.0, Qg=42.0
% INFO    : Gen at bus 7	: Pg=62.5, Qg=30.0 -> Pg=126.0, Qg=42.0
% INFO    : Gen at bus 13	: Pg=133.0, Qg=40.0 -> Pg=410.0, Qg=105.0
% INFO    : Gen at bus 13	: Pg=133.0, Qg=40.0 -> Pg=410.0, Qg=105.0
% INFO    : Gen at bus 13	: Pg=133.0, Qg=40.0 -> Pg=410.0, Qg=105.0
% INFO    : Gen at bus 14	: Pg=0.0, Qg=75.0 -> Pg=0.0, Qg=210.0
% INFO    : Gen at bus 15	: Pg=7.2, Qg=3.0 -> Pg=132.0, Qg=79.0
% INFO    : Gen at bus 15	: Pg=7.2, Qg=3.0 -> Pg=132.0, Qg=79.0
% INFO    : Gen at bus 15	: Pg=7.2, Qg=3.0 -> Pg=132.0, Qg=79.0
% INFO    : Gen at bus 15	: Pg=7.2, Qg=3.0 -> Pg=132.0, Qg=79.0
% INFO    : Gen at bus 15	: Pg=7.2, Qg=3.0 -> Pg=132.0, Qg=79.0
% INFO    : Gen at bus 15	: Pg=104.65, Qg=15.0 -> Pg=184.0, Qg=79.0
% INFO    : Gen at bus 16	: Pg=104.65, Qg=15.0 -> Pg=522.0, Qg=-34.0
% INFO    : Gen at bus 18	: Pg=250.0, Qg=75.0 -> Pg=301.0, Qg=32.0
% INFO    : Gen at bus 21	: Pg=250.0, Qg=75.0 -> Pg=203.0, Qg=-118.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 22	: Pg=30.0, Qg=3.0 -> Pg=68.0, Qg=-9.0
% INFO    : Gen at bus 23	: Pg=104.65, Qg=15.0 -> Pg=237.0, Qg=15.0
% INFO    : Gen at bus 23	: Pg=104.65, Qg=15.0 -> Pg=237.0, Qg=15.0
% INFO    : Gen at bus 23	: Pg=245.0, Qg=62.5 -> Pg=323.0, Qg=15.0
% INFO    :
% INFO    : === Generator Reactive Capacity Atleast Setpoint Value Notes ===
% INFO    : Gen at bus 1	: Qg 1.0, Qmin 0.0, Qmax 10.0 -> Qmin -1.2, Qmax 10.0
% INFO    : Gen at bus 1	: Qg 1.0, Qmin 0.0, Qmax 10.0 -> Qmin -1.2, Qmax 10.0
% INFO    : Gen at bus 2	: Qg 31.0, Qmin 0.0, Qmax 10.0 -> Qmin -37.2, Qmax 37.2
% INFO    : Gen at bus 2	: Qg 31.0, Qmin 0.0, Qmax 10.0 -> Qmin -37.2, Qmax 37.2
% INFO    : Gen at bus 2	: Qg 31.0, Qmin -25.0, Qmax 30.0 -> Qmin -37.2, Qmax 37.2
% INFO    : Gen at bus 2	: Qg 31.0, Qmin -25.0, Qmax 30.0 -> Qmin -37.2, Qmax 37.2
% INFO    : Gen at bus 7	: Qg 42.0, Qmin 0.0, Qmax 60.0 -> Qmin -50.4, Qmax 60.0
% INFO    : Gen at bus 7	: Qg 42.0, Qmin 0.0, Qmax 60.0 -> Qmin -50.4, Qmax 60.0
% INFO    : Gen at bus 7	: Qg 42.0, Qmin 0.0, Qmax 60.0 -> Qmin -50.4, Qmax 60.0
% INFO    : Gen at bus 13	: Qg 105.0, Qmin 0.0, Qmax 80.0 -> Qmin -126.0, Qmax 126.0
% INFO    : Gen at bus 13	: Qg 105.0, Qmin 0.0, Qmax 80.0 -> Qmin -126.0, Qmax 126.0
% INFO    : Gen at bus 13	: Qg 105.0, Qmin 0.0, Qmax 80.0 -> Qmin -126.0, Qmax 126.0
% INFO    : Gen at bus 14	: Qg 210.0, Qmin -50.0, Qmax 200.0 -> Qmin -252.0, Qmax 252.0
% INFO    : Gen at bus 15	: Qg 79.0, Qmin 0.0, Qmax 6.0 -> Qmin -94.8, Qmax 94.8
% INFO    : Gen at bus 15	: Qg 79.0, Qmin 0.0, Qmax 6.0 -> Qmin -94.8, Qmax 94.8
% INFO    : Gen at bus 15	: Qg 79.0, Qmin 0.0, Qmax 6.0 -> Qmin -94.8, Qmax 94.8
% INFO    : Gen at bus 15	: Qg 79.0, Qmin 0.0, Qmax 6.0 -> Qmin -94.8, Qmax 94.8
% INFO    : Gen at bus 15	: Qg 79.0, Qmin 0.0, Qmax 6.0 -> Qmin -94.8, Qmax 94.8
% INFO    : Gen at bus 15	: Qg 79.0, Qmin -50.0, Qmax 80.0 -> Qmin -94.8, Qmax 80.0
% INFO    : Gen at bus 21	: Qg -118.0, Qmin -50.0, Qmax 200.0 -> Qmin -141.6, Qmax 200.0
% INFO    :
% INFO    : === Generator Classification Notes ===
% INFO    : PEL    4   -     6.70
% INFO    : SYNC   1   -     0.00
% INFO    : COW    7   -    23.79
% INFO    : NG     21  -    69.51
% INFO    :
% INFO    : === Generator Active Capacity Stat Model Notes ===
% INFO    : Gen at bus 1 - PEL	: Pg=73.0, Pmax=20.0 -> Pmax=79   samples: 7
% INFO    : Gen at bus 1 - PEL	: Pg=73.0, Pmax=20.0 -> Pmax=211   samples: 1
% INFO    : Gen at bus 1 - PEL	: Pg=72.0, Pmax=76.0 -> Pmax=75   samples: 9
% INFO    : Gen at bus 1 - NG	: Pg=72.0, Pmax=76.0 -> Pmax=78   samples: 2
% INFO    : Gen at bus 2 - NG	: Pg=157.0, Pmax=20.0 -> Pmax=188   samples: 1
% WARNING : Failed to find a generator capacity within (157.0-785.0) after 100 samples, using percent increase model
% INFO    : Gen at bus 2 - PEL	: Pg=157.0, Pmax=20.0 -> Pmax=182   samples: 100
% INFO    : Gen at bus 2 - NG	: Pg=156.0, Pmax=76.0 -> Pmax=176   samples: 1
% INFO    : Gen at bus 2 - COW	: Pg=156.0, Pmax=76.0 -> Pmax=663   samples: 3
% INFO    : Gen at bus 7 - NG	: Pg=126.0, Pmax=100.0 -> Pmax=430   samples: 2
% INFO    : Gen at bus 7 - NG	: Pg=126.0, Pmax=100.0 -> Pmax=153   samples: 1
% INFO    : Gen at bus 7 - COW	: Pg=126.0, Pmax=100.0 -> Pmax=595   samples: 1
% INFO    : Gen at bus 13 - NG	: Pg=410.0, Pmax=197.0 -> Pmax=544   samples: 18
% INFO    : Gen at bus 13 - NG	: Pg=410.0, Pmax=197.0 -> Pmax=542   samples: 17
% INFO    : Gen at bus 13 - COW	: Pg=410.0, Pmax=197.0 -> Pmax=609   samples: 2
% INFO    : Gen at bus 14 - SYNC	: Pg=0.0, Pmax=0.0 -> Pmax=0   samples: 0
% INFO    : Gen at bus 15 - NG	: Pg=132.0, Pmax=12.0 -> Pmax=159   samples: 4
% INFO    : Gen at bus 15 - COW	: Pg=132.0, Pmax=12.0 -> Pmax=206   samples: 2
% INFO    : Gen at bus 15 - NG	: Pg=132.0, Pmax=12.0 -> Pmax=195   samples: 3
% INFO    : Gen at bus 15 - NG	: Pg=132.0, Pmax=12.0 -> Pmax=162   samples: 10
% INFO    : Gen at bus 15 - NG	: Pg=132.0, Pmax=12.0 -> Pmax=139   samples: 1
% INFO    : Gen at bus 15 - NG	: Pg=184.0, Pmax=155.0 -> Pmax=206   samples: 1
% WARNING : Failed to find a generator capacity within (522.0-2610.0) after 100 samples, using percent increase model
% INFO    : Gen at bus 16 - NG	: Pg=522.0, Pmax=155.0 -> Pmax=589   samples: 100
% INFO    : Gen at bus 18 - NG	: Pg=301.0, Pmax=400.0 -> Pmax=382   samples: 10
% INFO    : Gen at bus 21 - COW	: Pg=203.0, Pmax=400.0 -> Pmax=675   samples: 2
% INFO    : Gen at bus 22 - NG	: Pg=68.0, Pmax=50.0 -> Pmax=222   samples: 2
% INFO    : Gen at bus 22 - NG	: Pg=68.0, Pmax=50.0 -> Pmax=184   samples: 1
% INFO    : Gen at bus 22 - NG	: Pg=68.0, Pmax=50.0 -> Pmax=146   samples: 2
% INFO    : Gen at bus 22 - COW	: Pg=68.0, Pmax=50.0 -> Pmax=233   samples: 1
% INFO    : Gen at bus 22 - NG	: Pg=68.0, Pmax=50.0 -> Pmax=216   samples: 1
% INFO    : Gen at bus 22 - NG	: Pg=68.0, Pmax=50.0 -> Pmax=83   samples: 1
% INFO    : Gen at bus 23 - NG	: Pg=237.0, Pmax=155.0 -> Pmax=421   samples: 2
% INFO    : Gen at bus 23 - COW	: Pg=237.0, Pmax=155.0 -> Pmax=292   samples: 3
% INFO    : Gen at bus 23 - NG	: Pg=323.0, Pmax=350.0 -> Pmax=382   samples: 35
% INFO    :
% INFO    : === Generator Active Capacity LB Model Notes ===
% INFO    : Gen at bus 1	: Pmin=16.0 -> Pmin=8.0
% INFO    : Gen at bus 1	: Pmin=16.0 -> Pmin=8.0
% INFO    : Gen at bus 1	: Pmin=15.2 -> Pmin=7.6
% INFO    : Gen at bus 1	: Pmin=15.2 -> Pmin=7.6
% INFO    : Gen at bus 2	: Pmin=16.0 -> Pmin=8.0
% INFO    : Gen at bus 2	: Pmin=16.0 -> Pmin=8.0
% INFO    : Gen at bus 2	: Pmin=15.2 -> Pmin=7.6
% INFO    : Gen at bus 2	: Pmin=15.2 -> Pmin=7.6
% INFO    : Gen at bus 7	: Pmin=25.0 -> Pmin=12.5
% INFO    : Gen at bus 7	: Pmin=25.0 -> Pmin=12.5
% INFO    : Gen at bus 7	: Pmin=25.0 -> Pmin=12.5
% INFO    : Gen at bus 13	: Pmin=69.0 -> Pmin=34.5
% INFO    : Gen at bus 13	: Pmin=69.0 -> Pmin=34.5
% INFO    : Gen at bus 13	: Pmin=69.0 -> Pmin=34.5
% INFO    : Gen at bus 15	: Pmin=2.4 -> Pmin=1.2
% INFO    : Gen at bus 15	: Pmin=2.4 -> Pmin=1.2
% INFO    : Gen at bus 15	: Pmin=2.4 -> Pmin=1.2
% INFO    : Gen at bus 15	: Pmin=2.4 -> Pmin=1.2
% INFO    : Gen at bus 15	: Pmin=2.4 -> Pmin=1.2
% INFO    : Gen at bus 15	: Pmin=54.3 -> Pmin=27.15
% INFO    : Gen at bus 16	: Pmin=54.3 -> Pmin=27.15
% INFO    : Gen at bus 18	: Pmin=100.0 -> Pmin=50.0
% INFO    : Gen at bus 21	: Pmin=100.0 -> Pmin=50.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 22	: Pmin=10.0 -> Pmin=5.0
% INFO    : Gen at bus 23	: Pmin=54.3 -> Pmin=27.15
% INFO    : Gen at bus 23	: Pmin=54.3 -> Pmin=27.15
% INFO    : Gen at bus 23	: Pmin=140.0 -> Pmin=70.0
% INFO    :
% INFO    : === Generator Reactive Capacity Atleast Max 50 Percent Active Model Notes ===
% INFO    : Gen at bus 1 - PEL	: Pmax 79.0, Qmin -1.2, Qmax 10.0 -> Qmin -40.0, Qmax 40.0
% INFO    : Gen at bus 1 - PEL	: Pmax 211.0, Qmin -1.2, Qmax 10.0 -> Qmin -106.0, Qmax 106.0
% INFO    : Gen at bus 1 - PEL	: Pmax 75.0, Qmin -25.0, Qmax 30.0 -> Qmin -38.0, Qmax 38.0
% INFO    : Gen at bus 1 - NG	: Pmax 78.0, Qmin -25.0, Qmax 30.0 -> Qmin -39.0, Qmax 39.0
% INFO    : Gen at bus 2 - NG	: Pmax 188.0, Qmin -37.2, Qmax 37.2 -> Qmin -94.0, Qmax 94.0
% INFO    : Gen at bus 2 - PEL	: Pmax 182.0, Qmin -37.2, Qmax 37.2 -> Qmin -91.0, Qmax 91.0
% INFO    : Gen at bus 2 - NG	: Pmax 176.0, Qmin -37.2, Qmax 37.2 -> Qmin -88.0, Qmax 88.0
% INFO    : Gen at bus 2 - COW	: Pmax 663.0, Qmin -37.2, Qmax 37.2 -> Qmin -332.0, Qmax 332.0
% INFO    : Gen at bus 7 - NG	: Pmax 430.0, Qmin -50.4, Qmax 60.0 -> Qmin -215.0, Qmax 215.0
% INFO    : Gen at bus 7 - NG	: Pmax 153.0, Qmin -50.4, Qmax 60.0 -> Qmin -77.0, Qmax 77.0
% INFO    : Gen at bus 7 - COW	: Pmax 595.0, Qmin -50.4, Qmax 60.0 -> Qmin -298.0, Qmax 298.0
% INFO    : Gen at bus 13 - NG	: Pmax 544.0, Qmin -126.0, Qmax 126.0 -> Qmin -272.0, Qmax 272.0
% INFO    : Gen at bus 13 - NG	: Pmax 542.0, Qmin -126.0, Qmax 126.0 -> Qmin -271.0, Qmax 271.0
% INFO    : Gen at bus 13 - COW	: Pmax 609.0, Qmin -126.0, Qmax 126.0 -> Qmin -305.0, Qmax 305.0
% INFO    : Gen at bus 15 - COW	: Pmax 206.0, Qmin -94.8, Qmax 94.8 -> Qmin -103.0, Qmax 103.0
% INFO    : Gen at bus 15 - NG	: Pmax 195.0, Qmin -94.8, Qmax 94.8 -> Qmin -98.0, Qmax 98.0
% INFO    : Gen at bus 15 - NG	: Pmax 206.0, Qmin -94.8, Qmax 80.0 -> Qmin -103.0, Qmax 103.0
% INFO    : Gen at bus 16 - NG	: Pmax 589.0, Qmin -50.0, Qmax 80.0 -> Qmin -295.0, Qmax 295.0
% INFO    : Gen at bus 18 - NG	: Pmax 382.0, Qmin -50.0, Qmax 200.0 -> Qmin -191.0, Qmax 200.0
% INFO    : Gen at bus 21 - COW	: Pmax 675.0, Qmin -141.6, Qmax 200.0 -> Qmin -338.0, Qmax 338.0
% INFO    : Gen at bus 22 - NG	: Pmax 222.0, Qmin -10.0, Qmax 16.0 -> Qmin -111.0, Qmax 111.0
% INFO    : Gen at bus 22 - NG	: Pmax 184.0, Qmin -10.0, Qmax 16.0 -> Qmin -92.0, Qmax 92.0
% INFO    : Gen at bus 22 - NG	: Pmax 146.0, Qmin -10.0, Qmax 16.0 -> Qmin -73.0, Qmax 73.0
% INFO    : Gen at bus 22 - COW	: Pmax 233.0, Qmin -10.0, Qmax 16.0 -> Qmin -117.0, Qmax 117.0
% INFO    : Gen at bus 22 - NG	: Pmax 216.0, Qmin -10.0, Qmax 16.0 -> Qmin -108.0, Qmax 108.0
% INFO    : Gen at bus 22 - NG	: Pmax 83.0, Qmin -10.0, Qmax 16.0 -> Qmin -42.0, Qmax 42.0
% INFO    : Gen at bus 23 - NG	: Pmax 421.0, Qmin -50.0, Qmax 80.0 -> Qmin -211.0, Qmax 211.0
% INFO    : Gen at bus 23 - COW	: Pmax 292.0, Qmin -50.0, Qmax 80.0 -> Qmin -146.0, Qmax 146.0
% INFO    : Gen at bus 23 - NG	: Pmax 382.0, Qmin -25.0, Qmax 150.0 -> Qmin -191.0, Qmax 191.0
% INFO    :
% INFO    : === Generator Setpoint Replacement Notes ===
% INFO    : Gen at bus 1	: Pg=73.0, Qg=1.0 -> Pg=43.5, Qg=0.0
% INFO    : Gen at bus 1	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 1	: Pg=73.0, Qg=1.0 -> Pg=109.5, Qg=0.0
% INFO    : Gen at bus 1	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 1	: Pg=72.0, Qg=1.0 -> Pg=41.3, Qg=0.0
% INFO    : Gen at bus 1	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 1	: Pg=72.0, Qg=1.0 -> Pg=42.8, Qg=0.0
% INFO    : Gen at bus 1	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 2	: Pg=157.0, Qg=31.0 -> Pg=98.0, Qg=0.0
% INFO    : Gen at bus 2	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 2	: Pg=157.0, Qg=31.0 -> Pg=95.0, Qg=0.0
% INFO    : Gen at bus 2	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 2	: Pg=156.0, Qg=31.0 -> Pg=91.8, Qg=0.0
% INFO    : Gen at bus 2	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 2	: Pg=156.0, Qg=31.0 -> Pg=335.3, Qg=0.0
% INFO    : Gen at bus 2	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 7	: Pg=126.0, Qg=42.0 -> Pg=221.25, Qg=0.0
% INFO    : Gen at bus 7	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 7	: Pg=126.0, Qg=42.0 -> Pg=82.75, Qg=0.0
% INFO    : Gen at bus 7	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 7	: Pg=126.0, Qg=42.0 -> Pg=303.75, Qg=0.0
% INFO    : Gen at bus 7	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 13	: Pg=410.0, Qg=105.0 -> Pg=289.25, Qg=0.0
% INFO    : Gen at bus 13	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 13	: Pg=410.0, Qg=105.0 -> Pg=288.25, Qg=0.0
% INFO    : Gen at bus 13	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 13	: Pg=410.0, Qg=105.0 -> Pg=321.75, Qg=0.0
% INFO    : Gen at bus 13	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 14	: Pg=0.0, Qg=210.0 -> Pg=0.0, Qg=0.0
% INFO    : Gen at bus 14	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=132.0, Qg=79.0 -> Pg=80.1, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=132.0, Qg=79.0 -> Pg=103.6, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=132.0, Qg=79.0 -> Pg=98.1, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=132.0, Qg=79.0 -> Pg=81.6, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=132.0, Qg=79.0 -> Pg=70.1, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 15	: Pg=184.0, Qg=79.0 -> Pg=116.575, Qg=0.0
% INFO    : Gen at bus 15	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 16	: Pg=522.0, Qg=-34.0 -> Pg=308.075, Qg=0.0
% INFO    : Gen at bus 16	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 18	: Pg=301.0, Qg=32.0 -> Pg=216.0, Qg=4.5
% INFO    : Gen at bus 18	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 21	: Pg=203.0, Qg=-118.0 -> Pg=362.5, Qg=0.0
% INFO    : Gen at bus 21	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=113.5, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=94.5, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=75.5, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=119.0, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=110.5, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 22	: Pg=68.0, Qg=-9.0 -> Pg=44.0, Qg=0.0
% INFO    : Gen at bus 22	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 23	: Pg=237.0, Qg=15.0 -> Pg=224.075, Qg=0.0
% INFO    : Gen at bus 23	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 23	: Pg=237.0, Qg=15.0 -> Pg=159.575, Qg=0.0
% INFO    : Gen at bus 23	: Vg=1.0 -> Vg=1.0
% INFO    : Gen at bus 23	: Pg=323.0, Qg=15.0 -> Pg=226.0, Qg=0.0
% INFO    : Gen at bus 23	: Vg=1.0 -> Vg=1.0
% INFO    :
% INFO    : === Writing Matpower Case File Notes ===


function alpha_filter = getAlphaFilter(kgrid, medium, filter_cutoff, taper_ratio)
%GETALPHAFILTER Create filter for medium.alpha_filter.
%
% DESCRIPTION:
%       getAlphaFilter uses getWin to create a Tukey window via rotation to
%       pass to the medium.alpha_filter input field of the first order
%       simulation functions (kspaceFirstOrder1D, kspaceFirstOrder2D, and
%       kspaceFirstOrder3D). This parameter is used to regularise time
%       reversal image reconstruction when absorption compensation is
%       included.
%
% USAGE:
%       alpha_filter = getAlphaFilter(kgrid, medium, filter_cutoff)
%       alpha_filter = getAlphaFilter(kgrid, medium, filter_cutoff, taper_ratio)
%
% INPUTS:
%       kgrid           - k-Wave grid structure returned by makeGrid
%       medium          - k-Wave medium structure
%       filter_cutoff   - alpha_filter cutoff frequency [Hz], where
%                         filter_cutoff = [f_all] in 1D
%                         filter_cutoff = [f_all] or [f_x, f_y] in 2D
%                         filter_cutoff = [f_all] or [f_x, f_y, f_z] in 3D
%
%                         Any of the filter_cutoff inputs may be set to
%                         'max' to set the cutoff frequency to the maximum
%                         frequency supported by the grid
%
% OPTIONAL INPUTS
%       taper_ratio     - taper ratio for Tukey Window (default = 0.5)
%
% OUTPUTS:
%       alpha_filter    - filter
%
% ABOUT:
%       author          - Bradley Treeby
%       date            - 6th May 2010
%       last update     - 28th October 2011
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox
%
% See also getWin

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

% update the command line status
disp('Creating absorption filter...');

% check to see if the taper ratio is given
if nargin == 3
    taper_ratio = 0.5;
elseif nargin ~= 4
    error('incorrect number of inputs');
end

% update command line status
disp(['  taper ratio: ' num2str(taper_ratio)]);

% extract the dimensions
dim = numDim(kgrid.k);

% extract the alpha_filter cutoff frequencies
if numel(filter_cutoff) == 1
    filter_cutoff_x = filter_cutoff;
    if dim > 2
        filter_cutoff_z = filter_cutoff;
    end
    if dim > 1
        filter_cutoff_y = filter_cutoff;
    end
elseif numel(filter_cutoff) ~= dim
    error(['input filter_cutoff must have 1 or ' num2str(dim) ' elements for a ' num2str(dim) 'D grid']);
else
    if dim == 1
        filter_cutoff_x = filter_cutoff{1};
    end
    if dim == 2
        filter_cutoff_x = filter_cutoff{1};
        filter_cutoff_y = filter_cutoff{2};
    end
    if dim == 3
        filter_cutoff_x = filter_cutoff{1};
        filter_cutoff_y = filter_cutoff{2};
        filter_cutoff_z = filter_cutoff{3};
    end
end

% extract the maximium sound speed
c = max(medium.sound_speed(:));

% calculate the alpha_filter size in the z direction for 3D data
if dim > 2
    if strcmp(filter_cutoff_z, 'max')
        % set the alpha_filter size to be the same as the grid size
        filter_size_z = kgrid.Nz;
        filter_cutoff_z = kgrid.kz_max*c/(2*pi);
    else
        % convert the cutoff frequency to a wavenumber
        k_cutoff_z = 2*pi*filter_cutoff_z ./ c;

        % set the alpha_filter size
        filter_size_z = round(kgrid.Nz*k_cutoff_z/kgrid.kz(end));

        % check the alpha_filter size
        if filter_size_z > kgrid.Nz
            % set the alpha_filter size to be the same as the grid size
            filter_size_z = kgrid.Nz;
            filter_cutoff_z = kgrid.kz_max*c/(2*pi);
        end
    end
end

% calculate the alpha_filter size in the y direction for 2 and 3D data
if dim > 1
    if strcmp(filter_cutoff_y, 'max')
        % set the alpha_filter size to be the same as the grid size
        filter_size_y = kgrid.Ny;
        filter_cutoff_y = kgrid.ky_max*c/(2*pi);
    else
        % convert the cutoff frequency to a wavenumber
        k_cutoff_y = 2*pi*filter_cutoff_y ./ c;

        % set the alpha_filter size
        filter_size_y = round(kgrid.Ny*k_cutoff_y/kgrid.ky(end));

        % check the alpha_filter size
        if filter_size_y > kgrid.Ny
            % set the alpha_filter size to be the same as the grid size
            filter_size_y = kgrid.Ny;
            filter_cutoff_y = kgrid.ky_max*c/(2*pi);
        end
    end
end

% calculate the alpha_filter size in the x direction for 1, 2, and 3D data
if strcmp(filter_cutoff_x, 'max')
    % set the alpha_filter size to be the same as the grid size
    filter_size_x = kgrid.Nx;
    filter_cutoff_x = kgrid.kx_max*c/(2*pi);
else
    % convert the cutoff frequency to a wavenumber
    k_cutoff_x = 2*pi*filter_cutoff_x ./ c;

    % set the alpha_filter size
    filter_size_x = round(kgrid.Nx*k_cutoff_x/kgrid.kx(end));

    % check the alpha_filter size
    if filter_size_x > kgrid.Nx
        % set the alpha_filter size to be the same as the grid size
        filter_size_x = kgrid.Nx;
        filter_cutoff_x = kgrid.kx_max*c/(2*pi);
    end
end

% create the alpha_filter using getWin
switch dim
    case 1
        % create the alpha_filter
        filter_sec = getWin(filter_size_x, 'Tukey', 'Param', taper_ratio, 'Rotation', true);

        % enlarge the alpha_filter to the size of the grid
        alpha_filter  = zeros(kgrid.Nx, 1);
        x_index = round((kgrid.Nx - filter_size_x)/2) + 1;
        alpha_filter(x_index:x_index + filter_size_x - 1) = filter_sec;

        % update the command line status
        disp(['  filter cutoff: ' scaleSI(filter_cutoff_x) 'Hz']);
    case 2
        % create the alpha_filter
        filter_sec = getWin([filter_size_x, filter_size_y], 'Tukey', 'Param', taper_ratio, 'Rotation', true);

        % enlarge the alpha_filter to the size of the grid
        alpha_filter  = zeros(kgrid.Nx, kgrid.Ny);
        x_index = round((kgrid.Nx - filter_size_x)/2) + 1;
        y_index = round((kgrid.Ny - filter_size_y)/2) + 1;
        alpha_filter(x_index:x_index + filter_size_x - 1, y_index:y_index + filter_size_y - 1) = filter_sec;

        % update the command line status
        disp(['  filter cutoff: ' scaleSI(filter_cutoff_x) 'Hz by ' scaleSI(filter_cutoff_y) 'Hz']);
    case 3
        % create the alpha_filter
        filter_sec = getWin([filter_size_x, filter_size_y, filter_size_z], 'Tukey', 'Param', taper_ratio, 'Rotation', true);

        % enlarge the alpha_filter to the size of the grid
        alpha_filter  = zeros(kgrid.Nx, kgrid.Ny, kgrid.Nz);
        x_index = round((kgrid.Nx - filter_size_x)/2) + 1;
        y_index = round((kgrid.Ny - filter_size_y)/2) + 1;
        z_index = round((kgrid.Nz - filter_size_z)/2) + 1;
        alpha_filter(x_index:x_index + filter_size_x - 1, y_index:y_index + filter_size_y - 1, z_index:z_index + filter_size_z - 1) = filter_sec;

        % update the command line status
        disp(['  filter cutoff: ' scaleSI(filter_cutoff_x) 'Hz by ' scaleSI(filter_cutoff_y) 'Hz by ' scaleSI(filter_cutoff_z) 'Hz']);
end


% LIONSIMBA example script
% Multiple cells scenario: simulates three cells in serial connection.

%   This file is part of the LIONSIMBA Toolbox
%
%	Official web-site: 	http://sisdin.unipv.it/labsisdin/lionsimba.php
% 	Official GitHUB: 	https://github.com/lionsimbatoolbox/LIONSIMBA
%
%   LIONSIMBA: A Matlab framework based on a finite volume model suitable for Li-ion battery design, simulation, and control
%   Copyright (C) 2016-2018 :Marcello Torchio, Lalo Magni, Davide Raimondo,
%                            University of Pavia, 27100, Pavia, Italy
%                            Bhushan Gopaluni, Univ. of British Columbia,
%                            Vancouver, BC V6T 1Z3, Canada
%                            Richard D. Braatz,
%                            Massachusetts Institute of Technology,
%                            Cambridge, Massachusetts 02142, USA
%
%   Main code contributors to LIONSIMBA 2.0:
%                           Ian Campbell, Krishnakumar Gopalakrishnan,
%                           Imperial college London, London, UK
%
%   LIONSIMBA is a free Matlab-based software distributed with an MIT
%   license.

% Clear the workspace
clear

% Define the integration times.
t0 = 0;
tf = 10^4;
% Define the parameters structure.
param{1} = Parameters_init;
param{2} = Parameters_init;
param{3} = Parameters_init;

% Modify the initial SOC of cell #1
param{1}.cs_n_init = 0.95*param{1}.cs_n_init;

% Double the length of the positive electrode of cell #2
param{2}.len_p=2*param{2}.len_p;

% Simulate the battery of 3 cells
results = startSimulation(t0,tf,[],-30,param);

ncells = length(param);

v_tot = 0;
for i=1:ncells
    v_tot = v_tot + results.Phis{i}(:,1)-results.Phis{i}(:,end);
end
%% Plot the results

figure(1)
subplot(2,ncells,(1:ncells))
plot(results.time{1},v_tot,'LineWidth',6)
grid on
box on
xlabel('Time [s]')
ylabel('Pack Voltage [V]')
hold on
xlim([0 results.time{1}(end)])
ylim([2.5*length(param) 4.2*length(param)])

figure_index = ncells+1;
for i=1:ncells
    subplot(2,ncells,figure_index)
    plot(results.time{i},results.Voltage{i},'--','LineWidth',3)
    grid on
    box on
    xlabel('Time [s]')
    ylabel(['Cell #',num2str(i),' Voltage [V]'])
    figure_index = figure_index+1;
    ylim([2.5 4.2])
    xlim([0 results.time{1}(end)])
end

n_plots = 1;
figure_index = 1;
figure(2)
for i=1:ncells
    subplot(ncells,n_plots,figure_index)
    ce_indices = [1 results.parameters{i}.Np+1 results.parameters{i}.Np+results.parameters{i}.Ns results.parameters{i}.Np+results.parameters{i}.Ns+results.parameters{i}.Nn];
    plot(results.time{i},results.ce{i}(:,ce_indices),'LineWidth',3)
    grid on
    box on
    if(figure_index==ncells)
        xlabel('Time [s]')
    else
%         set(gca,'xtick',[])
        set(gca,'xticklabel',[])
    end
    ylabel(['Cell #',num2str(i),' - c_{e} [mol/m^3}'])
    xlim([0 results.time{1}(end)])
    ylim([0 2200])
    figure_index = figure_index+1;
end

n_plots = 1;
figure_index = 1;
figure(3)
for i=1:ncells
    subplot(ncells,n_plots,figure_index)
    phie_indices = [1 results.parameters{i}.Np+1 results.parameters{i}.Np+results.parameters{i}.Ns results.parameters{i}.Np+results.parameters{i}.Ns+results.parameters{i}.Nn];
    plot(results.time{i},results.Phie{i}(:,phie_indices),'LineWidth',3)
    grid on
    box on
    if(figure_index==ncells)
        xlabel('Time [s]')
    else
%         set(gca,'xtick',[])
        set(gca,'xticklabel',[])
    end
    ylabel(['Cell #',num2str(i)])
    xlim([0 results.time{1}(end)])
    ylim([-0.3 0])
    figure_index = figure_index+1;
end

n_plots = 1;
figure_index = 1;
figure(4)
for i=1:ncells
    subplot(ncells,n_plots,figure_index)
    cs_indices = [1 results.parameters{i}.Np results.parameters{i}.Np+1 results.parameters{i}.Np+results.parameters{i}.Nn];
    plot(results.time{i},results.cs_surface{i}(:,cs_indices),'LineWidth',3)
    grid on
    box on
    if(figure_index==ncells)
        xlabel('Time [s]')
    else
%         set(gca,'xtick',[])
        set(gca,'xticklabel',[])
    end
    ylabel(['Cell #',num2str(i)])
    xlim([0 results.time{1}(end)])
    ylim([100 51554])
    figure_index = figure_index+1;
end

n_plots = 1;
figure_index = 1;
figure(5)
for i=1:ncells
    subplot(ncells,n_plots,figure_index)
    cs_indices = [1 results.parameters{i}.Np results.parameters{i}.Np+1 results.parameters{i}.Np+results.parameters{i}.Nn];
    plot(results.time{i},results.Temperature{i}(:,end),'LineWidth',3)
    grid on
    box on
    if(figure_index==ncells)
        xlabel('Time [s]')
    else
%         set(gca,'xtick',[])
        set(gca,'xticklabel',[])
    end
    ylabel(['Cell #',num2str(i),' - Temp [K]'])
    xlim([0 results.time{1}(end)])
    ylim([296 315])
    figure_index = figure_index+1;
end


function [Flux, FBAsolution, model] = testPathway(model, MetIn, MetOut, AdditionalMetsInorOut, ObjectiveOption)
% Allows the user to see if given one metabolite `A`,
% downstream metabolite `B` can be made made. Additional sinks can be added
% for co-factors if needed
% `A -->-->-->-->--> B`
%
% USAGE:
%
%    [Flux, FBAsolution, model] = testPathway(model, MetIn, MetOut, AdditionalMetsInorOut, ObjectiveOption)
%
% INPUTS:
%    model:                    COBRA model structure
%    MetIn:                    The input metabolite(s) (`A`)
%    MetOut:                   The output metabolite (`B`)
%
% OPTIONAL INPUTS:
%    AdditionalMetsInorOut:    Additional metabolites for which sinks will be added
%    ObjectiveOption:          Boolean:
%
%                                * 1 = objective will be production of `B` (default)
%                                * 0 = use objective in model
%
% OUTPUTS:
%    Flux:                     The rate of `B` production
%    FBAsolution:              Solution to the FBA problem
%    model:                    COBRA model with sinks in it
%
% .. Author: Nathan Lewis, Feb 16 2009

if ~iscell(MetIn)
    Met = MetIn; clear MetIn; MetIn{1} = Met;
end
if ~iscell(MetOut)
    Met = MetOut; clear MetOut; MetOut{1} = Met;
end
if nargin > 3
    if ~iscell(AdditionalMetsInorOut)
        Met = AdditionalMetsInorOut; clear AdditionalMetsInorOut; AdditionalMetsInorOut{1} = Met;
    end
    % add sink rxns for all AdditionalMetsInorOut
    for i = 1:length(AdditionalMetsInorOut)
        model = addReaction(model,cat(2,'Tempsink_',AdditionalMetsInorOut{i}),{AdditionalMetsInorOut{i} },-1 ,true);
    end
end
if nargin <5,ObjectiveOption=1;end

for i = 1:length(MetIn) % add inputs
    model = addReaction(model,cat(2,'TempInput_',MetIn{i}),{MetIn{i} },1 ,false);
end
[model, rxnExists] = addReaction(model,cat(2,'TempOutput_',MetOut{1}),{MetOut{1} },-1 ,false);
if (ObjectiveOption==1 && isempty(rxnExists))
	model = changeObjective(model,cat(2,'TempOutput_',MetOut{1}));
elseif (ObjectiveOption == 1 && ~isempty(rxnExists))
	model = changeObjective(model,model.rxns(rxnExists));
end
FBAsolution = optimizeCbModel(model,'max');
Flux = FBAsolution.f;
if ~isempty(FBAsolution.x)
%printFluxVector(model,FBAsolution.x);
else display('zero flux in network')
end


% Monopole Point Source In A Homogeneous Propagation Medium Example
%
% This example provides a simple demonstration of using k-Wave for the
% simulation and detection of a time varying pressure source within a
% two-dimensional homogeneous propagation medium.  It builds on the
% Homogeneous Propagation Medium and Recording The Particle Velocity
% examples.
%
% author: Bradley Treeby
% date: 2nd December 2009
% last update: 2nd September 2012
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

clear all;

% =========================================================================
% SIMULATION
% =========================================================================

% create the computational grid
Nx = 128;           % number of grid points in the x (row) direction
Ny = 128;           % number of grid points in the y (column) direction
dx = 50e-3/Nx;    	% grid point spacing in the x direction [m]
dy = dx;            % grid point spacing in the y direction [m]
kgrid = makeGrid(Nx, dx, Ny, dy);

% define the properties of the propagation medium
medium.sound_speed = 1500;  % [m/s]
medium.alpha_coeff = 0.75;  % [dB/(MHz^y cm)]
medium.alpha_power = 1.5;

% create the time array
[kgrid.t_array, dt] = makeTime(kgrid, medium.sound_speed);

% define a single source point
source.p_mask = zeros(Nx, Ny);
source.p_mask(end - Nx/4, Ny/2) = 1;

% define a time varying sinusoidal source
source_freq = 0.25e6;   % [Hz]
source_mag = 2;         % [Pa]
source.p = source_mag*sin(2*pi*source_freq*kgrid.t_array);

% filter the source to remove high frequencies not supported by the grid
source.p = filterTimeSeries(kgrid, medium, source.p);

% define a single sensor point
sensor.mask = zeros(Nx, Ny);
sensor.mask(Nx/4, Ny/2) = 1;

% define the acoustic parameters to record
sensor.record = {'p', 'p_final'};

% run the simulation
sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor);

% =========================================================================
% VISUALISATION
% =========================================================================

% plot the final wave-field
figure;
imagesc(kgrid.y_vec*1e3, kgrid.x_vec*1e3, sensor_data.p_final + source.p_mask + sensor.mask, [-1 1]);
colormap(getColorMap);
ylabel('x-position [mm]');
xlabel('y-position [mm]');
axis image;

% plot the simulated sensor data
figure;
[t_sc, scale, prefix] = scaleSI(max(kgrid.t_array(:)));

subplot(2, 1, 1), plot(kgrid.t_array*scale, source.p, 'k-');
xlabel(['Time [' prefix 's]']);
ylabel('Signal Amplitude');
axis tight;
title('Input Pressure Signal');

subplot(2, 1, 2), plot(kgrid.t_array*scale, sensor_data.p, 'r-');
xlabel(['Time [' prefix 's]']);
ylabel('Signal Amplitude');
axis tight;
title('Sensor Pressure Signal');


function p = prior_loggaussian(varargin)
%PRIOR_LOGGAUSSIAN  Log-Gaussian prior structure
%
%  Description
%    P = PRIOR_LOGGAUSSIAN('PARAM1', VALUE1, 'PARAM2', VALUE2, ...)
%    creates Log-Gaussian prior structure in which the named
%    parameters have the specified values. Any unspecified
%    parameters are set to default values.
%
%    P = PRIOR_LOGGAUSSIAN(P, 'PARAM1', VALUE1, 'PARAM2', VALUE2, ...)
%    modify a prior structure with the named parameters altered
%    with the specified values.
%
%    Parameters for Log-Gaussian prior [default]
%      mu       - location [0]
%      s2       - scale squared (variance) [1]
%      mu_prior - prior for mu [prior_fixed]
%      s2_prior - prior for s2 [prior_fixed]
%
%  See also
%    PRIOR_*
%
% Copyright (c) 2000-2001,2010 Aki Vehtari
% Copyright (c) 2010 Jaakko Riihimäki

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  ip=inputParser;
  ip.FunctionName = 'PRIOR_LOGGAUSSIAN';
  ip.addOptional('p', [], @isstruct);
  ip.addParamValue('mu',0, @(x) isscalar(x));
  ip.addParamValue('mu_prior',[], @(x) isstruct(x) || isempty(x));
  ip.addParamValue('s2',1, @(x) isscalar(x) && x>0);
  ip.addParamValue('s2_prior',[], @(x) isstruct(x) || isempty(x));
  ip.parse(varargin{:});
  p=ip.Results.p;

  if isempty(p)
    init=true;
    p.type = 'Log-Gaussian';
  else
    if ~isfield(p,'type') && ~isequal(p.type,'Log-Gaussian')
      error('First argument does not seem to be a valid prior structure')
    end
    init=false;
  end

  % Initialize parameters
  if init || ~ismember('mu',ip.UsingDefaults)
    p.mu = ip.Results.mu;
  end
  if init || ~ismember('s2',ip.UsingDefaults)
    p.s2 = ip.Results.s2;
  end
  % Initialize prior structure
  if init
    p.p=[];
  end
  if init || ~ismember('mu_prior',ip.UsingDefaults)
    p.p.mu=ip.Results.mu_prior;
  end
  if init || ~ismember('s2_prior',ip.UsingDefaults)
    p.p.s2=ip.Results.s2_prior;
  end

  if init
    % set functions
    p.fh.pak = @prior_loggaussian_pak;
    p.fh.unpak = @prior_loggaussian_unpak;
    p.fh.lp = @prior_loggaussian_lp;
    p.fh.lpg = @prior_loggaussian_lpg;
    p.fh.recappend = @prior_loggaussian_recappend;
  end

end

function [w, s, h] = prior_loggaussian_pak(p)

  w=[];
  s={};
  h=[];
  if ~isempty(p.p.mu)
    w = p.mu;
    s=[s; 'Log-Gaussian.mu'];
    h = 1;
  end
  if ~isempty(p.p.s2)
    w = [w log(p.s2)];
    s=[s; 'log(Log-Gaussian.s2)'];
    h = [h 1];
  end
end

function [p, w] = prior_loggaussian_unpak(p, w)

  if ~isempty(p.p.mu)
    i1=1;
    p.mu = w(i1);
    w = w(i1+1:end);
  end
  if ~isempty(p.p.s2)
    i1=1;
    p.s2 = exp(w(i1));
    w = w(i1+1:end);
  end
end

function lp = prior_loggaussian_lp(x, p)

  lJ = -log(x);    % =log(1/x)=log(|J|) of transformation
  xt  = log(x);    % transformed x
  lp = 0.5*sum(-log(2*pi) -log(p.s2)- 1./p.s2 .* sum((xt-p.mu).^2,1)) +sum(lJ);

  if ~isempty(p.p.mu)
    lp = lp + p.p.mu.fh.lp(p.mu, p.p.mu);
  end
  if ~isempty(p.p.s2)
    lp = lp + p.p.s2.fh.lp(p.s2, p.p.s2) + log(p.s2);
  end
end

function lpg = prior_loggaussian_lpg(x, p)

  lJg = -1./x;     % gradient of log(|J|) of transformation
  xt   = log(x);   % transformed x
  xtg  = 1./x;     % derivative of transformation
  lpg = xtg.*(1./p.s2).*(p.mu-xt) + lJg;

  if ~isempty(p.p.mu)
    lpgmu = sum((1./p.s2).*(xt-p.mu)) + p.p.mu.fh.lpg(p.mu, p.p.mu);
    lpg = [lpg lpgmu];
  end
  if ~isempty(p.p.s2)
    lpgs2 = (sum(-0.5*(1./p.s2-1./p.s2.^2.*(xt-p.mu).^2 )) + p.p.s2.fh.lpg(p.s2, p.p.s2)).*p.s2 + 1;
    lpg = [lpg lpgs2];
  end
end

function rec = prior_loggaussian_recappend(rec, ri, p)
% The parameters are not sampled in any case.
  rec = rec;
  if ~isempty(p.p.mu)
    rec.mu(ri,:) = p.mu;
  end
  if ~isempty(p.p.s2)
    rec.s2(ri,:) = p.s2;
  end
end


%
%
% DIFFERENTIAL SEARCH ALGORITHM (DSA) (in MATLAB)
% STANDARD VERSION of DSA (16.July.2013)
%
%
% usage : > ds(method,fnc,mydata,popsize,dim,low,up,maxcycle)
%
% method
%--------------------------------------------------------------
% 1: Bijective DSA (B-DSA)
% 2: Surjective DSA (S-DSA)
% 3: Elitist DSA (strategy 1) (E1-DSA)
% 4: Elitist DSA (strategy 2) (E2-DSA)
% if method=[. . . ...],   Hybrid-DSA (H-DSA)
%--------------------------------------------------------------
% example :
% ds(1,'circlefit',mydata,10,3,-10,10,2000) ; % B-DSA
% ds(2,'circlefit',mydata,10,3,-10,10,2000) ; % S-DSA
% ds(3,'circlefit',mydata,10,3,-10,10,2000) ; % E1-DSA
% ds(4,'circlefit',mydata,10,3,-10,10,2000) ; % E2-DSA
% ds([1 2],'circlefit',mydata,10,3,-10,10,2000) ; % Hybrid-DSA, in this case B-DSA and S-DSA are hybridized.
%--------------------------------------------------------------
% Please cite this article as;
% P.Civicioglu, "Transforming geocentric cartesian coordinates to geodetic coordinates by using differential search algorithm",  Computers & Geosciences, 46 (2012), 229-247.
% P.Civicioglu, "Understanding the nature of evolutionary search algorithms", Additional technical report for the project of 110Y309-Tubitak,2013, Ankara, Turkey.
%
%
%
%
%--------------------------------------------------------------
%{
19.March.2013
Copyright Notice
Copyright (c) 2012, Pinar Civicioglu
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%}

function ds(method,fnc,mydata,size_of_superorganism,size_of_one_clan,low_habitat_limit,up_habitat_limit,epoch)

% size_of_superorganism ; size of population.
% size_of_one_clan ; size of problem dimension (1,2,3,...,d), where each clan (i.e. sub-superorganism) includes d-individuals.
% mydata ; additional parameters for objective function, use mydata=[], if it is not needed. See Best-Fit Circle example (circlefit.m) for usage of mydata.

%Initialization

% control of habitat limits
if numel(low_habitat_limit)==1,
    low_habitat_limit=low_habitat_limit*ones(1,size_of_one_clan);
    up_habitat_limit=up_habitat_limit*ones(1,size_of_one_clan);
end

% generate initial individuals, clans and superorganism.
superorganism=genpop(size_of_superorganism,size_of_one_clan,low_habitat_limit,up_habitat_limit);
% success of clans/superorganism
fit_superorganism=feval(fnc,superorganism,mydata);

for epk=1:epoch

    % SETTING OF ALGORITHMIC CONTROL PARAMETERS
    % Trial-pattern generation strategy for morphogenesis; 'one-by-one morphogenesis'.
    % p1=0.0*rand;  % i.e.,  0.0 <= p1 <= 0.0
    % p2=0.0*rand;  % i.e.,  0.0 <= p2 <= 0.0

    % Trial-pattern generation strategy for morphogenesis; 'one-or-more morphogenesis'. (DEFAULT)
    p1=0.3*rand;  % i.e.,  0.0 <= p1 <= 0.3
    p2=0.3*rand;  % i.e.,  0.0 <= p2 <= 0.3

    %-------------------------------------------------------------------

   [direction,msg]=generate_direction(method(randi(numel(method))),superorganism,size_of_superorganism,fit_superorganism);

   map=generate_map_of_active_individuals(size_of_superorganism,size_of_one_clan,p1,p2);

  %-------------------------------------------------------------------
    % Recommended Methods for generation of Scale-Factor; R
    % R=4*randn;  % brownian walk
    % R=4*randg;  % brownian walk
    % R=lognrnd(rand,5*rand);  % brownian walk
     R=1./gamrnd(1,0.5);   % pseudo-stable walk
    % R=1/normrnd(0,5);    % pseudo-stable walk

    %-------------------------------------------------------------------

    % bio-interaction (morphogenesis)
    stopover=superorganism+(R.*map).*(direction-superorganism);

   % Boundary Control
    stopover=update(stopover,low_habitat_limit,up_habitat_limit);

    % Selection-II
    fit_stopover=feval(fnc,stopover,mydata);
    ind=fit_stopover<fit_superorganism;
    fit_superorganism(ind)=fit_stopover(ind);
    superorganism(ind,:)=stopover(ind,:);

   % update results
    [globalminimum,indexbest]=min(fit_superorganism);
    globalminimizer=superorganism(indexbest,:);

    % export results
    assignin('base','globalminimum',globalminimum);
    assignin('base','globalminimizer',globalminimizer);
    fprintf('%s  | %5.0f   --->   %10.16f\n',msg,epk,globalminimum)

end

function pop=genpop(a,b,low,up)
pop=ones(a,b);
for i=1:a
    for j=1:b
        pop(i,j)=rand*(up(j)-low(j))+low(j);
    end
end

function p=update(p,low,up)
[popsize,dim]=size(p);
for i=1:popsize
    for j=1:dim
        % first (standard)-method
        if p(i,j)<low(j), if rand<rand, p(i,j)=rand*(up(j)-low(j))+low(j); else p(i,j)=low(j); end, end
        if p(i,j)>up(j),  if rand<rand, p(i,j)=rand*(up(j)-low(j))+low(j); else p(i,j)=up(j); end, end

        %{
       %  second-method
        if rand<rand,
            if p(i,j)<low(j) || p(i,j)>up(j), p(i,j)=rand*(up(j)-low(j))+low(j); end
        else
            if p(i,j)<low(j), p(i,j)=low(j); end
            if p(i,j)>up(j),  p(i,j)=up(j); end
        end
        %}
    end
end

function [direction,msg]=generate_direction(method,superorganism,size_of_superorganism,fit_superorganism);
 switch method
        case 1,
            % BIJECTIVE DSA  (B-DSA) (i.e., go-to-rnd DSA);
            % philosophy: evolve the superorganism (i.e.,population) towards to "permuted-superorganism (i.e., random directions)"
            direction=superorganism(randperm(size_of_superorganism),:); msg=' B-DSA';
        case 2,
            % SURJECTIVE DSA (S-DSA) (i.e., go-to-good DSA)
            % philosophy: evolve the superorganism (i.e.,population) towards to "some of the random top-best" solutions
            ind=ones(size_of_superorganism,1);
            [null_,B]=sort(fit_superorganism);
            for i=1:size_of_superorganism, ind(i)=B(randi(ceil(rand*size_of_superorganism),1)); end;
            direction=superorganism(ind,:);  msg=' S-DSA';
        case 3,
            % ELITIST DSA #1 (E1-DSA) (i.e., go-to-best DSA)
            % philosophy: evolve the superorganism (i.e.,population) towards to "one of the random top-best" solution
            [null,jind]=sort(fit_superorganism); ibest=jind(ceil(rand*size_of_superorganism)); msg='E1-DSA';
            direction=repmat(superorganism(ibest,:),[size_of_superorganism 1]);
        case 4,
            % ELITIST DSA #2 (E2-DSA) (i.e., go-to-best DSA)
            % philosophy: evolve the superorganism (i.e.,population) towards to "the best" solution
            [null_,ibest]=min(fit_superorganism); msg='E2-DSA';
            direction=repmat(superorganism(ibest,:),[size_of_superorganism 1]);
 end
return

function map=generate_map_of_active_individuals(size_of_superorganism,size_of_one_clan,p1,p2);
    % strategy-selection of active/passive individuals
    map=zeros(size_of_superorganism,size_of_one_clan);
        if rand<rand,
            if rand<p1,
                % Random-mutation #1 strategy
                for i=1:size_of_superorganism
                    map(i,:)=rand(1,size_of_one_clan) < rand;
                end
            else
                % Differential-mutation strategy
                for i=1:size_of_superorganism
                    map(i,randi(size_of_one_clan))=1;
                end
            end
        else
             % Random-mutation #2 strategy
            for i=1:size_of_superorganism
                map(i,randi(size_of_one_clan,1,ceil(p2*size_of_one_clan)))=1;
            end
        end
return


%%*****************************************************************
%% NTrhsfun: compute the right-hand side vector of the
%%           Schur complement equation for the NT direction.
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

    function [rhs,EinvRc,hRd] = NTrhsfun(blk,At,par,X,Z,rp,Rd,sigmu,hRd,dX,dZ);

    spdensity = par.spdensity;
    m = length(rp);
    if (nargin > 8)
       corrector = 1;
    else
       corrector = 0;
       hRd = zeros(m,1);
    end
    hEinvRc = zeros(m,1);
    EinvRc  = cell(size(blk,1),1);
    rhsfree = [];
%%
    for p = 1:size(blk,1)
        pblk = blk(p,:);
        n = sum(pblk{2});  numblk = length(pblk{2});
        if strcmp(pblk{1},'l')
	   if iscell(sigmu)
              EinvRc{p} = sigmu{p}./Z{p} -X{p};
	   else
              EinvRc{p} = sigmu./Z{p} -X{p};
           end
           Rq = sparse(n,1);
           if (corrector) & (norm(par.parbarrier{p})==0)
              Rq = dX{p}.*dZ{p}./Z{p};
           else
              tmp  = par.dd{p}.*Rd{p};
              tmp2 = mexMatvec(At{p},tmp,1);
              hRd = hRd + tmp2;
           end
	   EinvRc{p} = EinvRc{p} - Rq;
           tmp2 = mexMatvec(At{p},EinvRc{p},1);
           hEinvRc = hEinvRc + tmp2;
	elseif strcmp(pblk{1},'q')
	   if iscell(sigmu)
              EinvRc{p} = qops(pblk,-sigmu{p}./(par.gamz{p}.*par.gamz{p}),Z{p},4) -X{p};
	   else
              EinvRc{p} = qops(pblk,-sigmu./(par.gamz{p}.*par.gamz{p}),Z{p},4) -X{p};
           end
           Rq = sparse(n,1);
   	   if (corrector) & (norm(par.parbarrier{p})==0)
              w = sqrt(par.gamz{p}./par.gamx{p});
              hdx = qops(pblk,w,par.ff{p},5,dX{p});
              hdz = qops(pblk,w,par.ff{p},6,dZ{p});
              hdxdz = Arrow(pblk,hdx,hdz);
              vv = qops(pblk,w,par.ff{p},5,X{p});
              Vihdxdz = Arrow(pblk,vv,hdxdz,1);
              Rq = qops(pblk,w,par.ff{p},6,Vihdxdz);
           else
              tmp  = par.dd{p}.*Rd{p} + qops(pblk,qops(pblk,Rd{p},par.ee{p},1),par.ee{p},3);
              tmp2 = mexMatvec(At{p},tmp,1);
              hRd = hRd + tmp2;
           end
	   EinvRc{p} = EinvRc{p} - Rq;
           tmp2 = mexMatvec(At{p},EinvRc{p},1);
           hEinvRc = hEinvRc + tmp2;
        elseif strcmp(pblk{1},'s')
           n2 = pblk{2}.*(pblk{2}+1)/2;
	   if iscell(sigmu)
     	      %%ss = [0,cumsum(pblk{2})];
              %%sigmuvec = zeros(n,1);
              %%for k = 1:length(pblk{2});
              %%   sigmuvec(ss(k)+1:ss(k+1)) = sigmu{p}(k)*ones(pblk{2}(k),1);
              %%end
              sigmuvec = mexexpand(pblk{2},sigmu{p});
              tmp = spdiags(sigmuvec./par.sv{p} -par.sv{p},0,n,n);
           else
              tmp = spdiags(sigmu./par.sv{p} -par.sv{p},0,n,n);
           end
           EinvRc{p} = Prod3(pblk,par.G{p}',tmp,par.G{p},1);
           Rq = sparse(n,n);
           if (corrector) & (norm(par.parbarrier{p})==0)
              hdZ = Prod3(pblk,par.G{p},dZ{p},par.G{p}',1);
              hdX = spdiags(qops(pblk,par.parbarrier{p}',1./par.sv{p},3)-par.sv{p},0,n,n)-hdZ;
              tmp = Prod2(pblk,hdX,hdZ,0);
              tmp = 0.5*(tmp+tmp');
              if (numblk == 1)
                 d = par.sv{p};
                 e = ones(pblk{2},1);
                 Rq = 2*tmp./(d*e'+e*d');
                 if (nnz(Rq) <= spdensity*n2); Rq = sparse(Rq); end
              else
                 Rq = sparse(n,n);
                 ss = [0, cumsum(pblk{2})];
                 for i = 1:numblk
                    pos = [ss(i)+1 : ss(i+1)];
                    d = par.sv{p}(pos); e = ones(length(pos),1);
                    Rq(pos,pos) = 2*tmp(pos,pos)./(d*e' + e*d');
                 end
              end
              Rq = Prod3(pblk,par.G{p}',Rq,par.G{p},1);
           else
              tmp = Prod3(pblk,par.W{p},Rd{p},par.W{p},1,par.nzlistAy{p});
              tmp2 = AXfun(pblk,At(p,:),par.permA(p,:),{tmp});
              hRd = hRd + tmp2;
           end
           EinvRc{p} = EinvRc{p} - Rq;
           tmp2 = AXfun(pblk,At(p,:),par.permA(p,:),EinvRc(p));
           hEinvRc = hEinvRc + tmp2;
        elseif strcmp(pblk{1},'u')
           rhsfree = [rhsfree; Rd{p}];
        end
    end
%%
    rhs = rp + hRd - hEinvRc;
    rhs = full([rhs; rhsfree]);
%%*******************************************************************


%% pathRRT
%%  - create a path from a start node to an end node
%%    using the RRT algorithm.
%%  - RRT = Rapidly-exploring Random Tree
%%
%% Last Modified - 6/8/2006 - R. Beard
%%               - 4/15/2010 - R. Beard

function path_out=planRRT(wpp_start, wpp_end, map)

    % standard length of path segments
    segmentLength = 100;

    % desired down position is down position of end node
    pd = wpp_end(3);
    chi = -9999;

    % specify start and end nodes from wpp_start and wpp_end
    start_node = [wpp_start(1), wpp_start(2), pd, chi, 0, 0, 0];
    end_node = [wpp_end(1), wpp_end(2), pd, chi, 0, 0, 0];
    % format:  [N, E, D, chi, cost, parent_idx, flag_connect_to_goal]

    % establish tree starting with the start node
    tree = start_node;

    % check to see if start_node connects directly to end_node
    if ( (norm(start_node(1:3)-end_node(1:3))<segmentLength )...
            &(collision(start_node,end_node,map)==0) )
        path = [start_node; end_node];
    else
        numPaths = 0;
        while numPaths<3,
            [tree,flag] = extendTree(tree,end_node,segmentLength,map,pd,chi);
            numPaths = numPaths + flag;
        end
    end

    % find path with minimum cost to end_node
    path = findMinimumPath(tree,end_node);
    path_out = smoothPath(path,map);
    plotmap(map,path,path_out,tree);

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% generateRandomNode
%%   create a random node (initialize)
function node=generateRandomNode(map,pd,chi)

    % randomly pick configuration
    pn       = map.width*rand;
    pe       = map.width*rand;
    pd       = pd; % constant altitute paths
    cost     = 0;
    node     = [pn, pe, pd, chi, cost, 0, 0];
    % format:  [N, E, D, chi, cost, parent_idx, flag_connect_to_goal]

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% collision
%%   check to see if a node is in collsion with obstacles
function collision_flag = collision(start_node, end_node, map)

    collision_flag = 0;

    [X,Y,Z] = pointsAlongPath(start_node, end_node, 0.1);

    for i = 1:length(X),
        if Z(i) >= downAtNE(map, X(i), Y(i)),
            collision_flag = 1;
        end
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% pointsAlongPath
%%   Find points along straight-line path separted by Del (to be used in
%%   collision detection)
function [X,Y,Z] = pointsAlongPath(start_node, end_node, Del)

    X = [start_node(1)];
    Y = [start_node(2)];
    Z = [start_node(3)];

    q = [end_node(1:3)-start_node(1:3)];
    L = norm(q);
    q = q/L;

    w = start_node(1:3);
    for i=2:floor(L/Del),
        w = w + Del*q;
        X = [X, w(1)];
        Y = [Y, w(2)];
        Z = [Z, w(3)];
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% downAtNE
%%   find the world down coordinate at a specified (n,e) location
function down = downAtNE(map, n, e)

      [d_n,idx_n] = min(abs(n - map.buildings_n));
      [d_e,idx_e] = min(abs(e - map.buildings_e));

      if (d_n<=map.BuildingWidth) && (d_e<=map.BuildingWidth),
          down = -map.heights(idx_e,idx_n);
      else
          down = 0;
      end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% extendTree
%%   extend tree by randomly selecting point and growing tree toward that
%%   point
function [new_tree,flag] = extendTree(tree,end_node,segmentLength,map,pd,chi)

  flag1 = 0;
  loop_count = 0;
  while flag1==0,
    % select a random point
    randomNode=generateRandomNode(map,pd,chi);

    % find leaf on node that is closest to randomPoint
    tmp = tree(:,1:3)-ones(size(tree,1),1)*randomNode(1:3);
    [dist,idx] = min(diag(tmp*tmp'));
    L = min(sqrt(dist), segmentLength);
    cost     = tree(idx,5) + L;
    tmp = randomNode(1:3)-tree(idx,1:3);
    new_point = tree(idx,1:3)+L*(tmp/norm(tmp));
    new_node = [new_point, chi, cost, idx, 0];
    loop_count = loop_count+1
    if collision(tree(idx,:), new_node, map)==0,
      new_tree = [tree; new_node];
      flag1=1;
    end
  end

  % check to see if new node connects directly to end_node
  if ( (norm(new_node(1:3)-end_node(1:3))<segmentLength )...
      &&(collision(new_node,end_node,map)==0) )
    flag = 1;
    new_tree(end,7)=1;  % mark node as connecting to end.
  else
    flag = 0;
  end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% findMinimumPath
%%   find the lowest cost path to the end node
function path = findMinimumPath(tree,end_node)

    % find nodes that connect to end_node
    connectingNodes = [];
    for i=1:size(tree,1),
        if tree(i,7)==1,
            connectingNodes = [connectingNodes; tree(i,:)];
        end
    end

    % find minimum cost last node
    [tmp,idx] = min(connectingNodes(:,5));

    % construct lowest cost path
    path = [connectingNodes(idx,:); end_node];
    parent_node = connectingNodes(idx,6);
    while parent_node>1,
        parent_node = tree(parent_node,6);
        path = [tree(parent_node,:); path];
    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% smoothPath
%%   smooth the waypoint path
function newPath = smoothPath(path,map)

    newPath = path(1,:); % add the start node
    ptr =2;  % pointer into the path
    while ptr <= size(path,1)-1,
        if collision(newPath(end,:), path(ptr+1,:), map)~=0, % if there is a collision
            newPath = [newPath; path(ptr,:)];  % add previous node
        end
        ptr=ptr+1;
    end
    newPath = [newPath; path(end,:)];

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% plotmap
%%   plot obstacles and path
function plotmap(map,path,smoothedPath,tree)

    % setup plot
    figure(3), clf
    axis([0,map.width,0,map.width,0,2*map.MaxHeight]);
    xlabel('E')
    ylabel('N')
    zlabel('h')
    hold on

    % plot buildings
    V = [];
    F = [];
    patchcolors = [];
    count = 0;
    for i=1:map.NumBlocks,
        for j=1:map.NumBlocks,
            [Vtemp,Ftemp,patchcolorstemp] = buildingVertFace(map.buildings_n(i),...
                map.buildings_e(j),map.BuildingWidth,map.heights(j,i));
            V = [V; Vtemp];
            Ftemp = Ftemp + count;
            F = [F; Ftemp];
            count = count + 8;
            patchcolors = [patchcolors;patchcolorstemp];
        end
    end

    patch('Vertices', V, 'Faces', F,...
                     'FaceVertexCData',patchcolors,...
                     'FaceColor','flat');

    % draw tree
    for i=2:size(tree,1),
        X = [tree(i,1), tree(tree(i,6),1)];
        Y = [tree(i,2), tree(tree(i,6),2)];
        Z = [tree(i,3), tree(tree(i,6),3)];
        plot3(Y,X,-Z,'g')
    end

    % draw path
    X = path(:,1);
    Y = path(:,2);
    Z = path(:,3);
    plot3(Y,X,-Z,'r','linewidth',2);

    % draw smooth path
    X = smoothedPath(:,1);
    Y = smoothedPath(:,2);
    Z = smoothedPath(:,3);
    plot3(Y,X,-Z,'k','linewidth',2);

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% buildingVertFace(x,y,width,height)
%%   define patches for a building located at (x,y)
function [V,F,patchcolors] = buildingVertFace(n,e,width,height)

  % vertices of the building
  V = [...
        e+width/2, n+width/2, 0;...
        e+width/2, n-width/2, 0;...
        e-width/2, n-width/2, 0;...
        e-width/2, n+width/2, 0;...
        e+width/2, n+width/2, height;...
        e+width/2, n-width/2, height;...
        e-width/2, n-width/2, height;...
        e-width/2, n+width/2, height;...
        ];
  % define faces of fuselage
  F = [...
        1, 4, 8, 5;... % North Side
        1, 2, 6, 5;... % East Side
        2, 3, 7, 6;... % South Side
        3, 4, 8, 7;... % West Side
        5, 6, 7, 8;... % Top
        ];

  myred = [1, 0, 0];
  mygreen = [0, 1, 0];
  myblue = [0, 0, 1];
  myyellow = [1,1,0];
  mymagenta   = [0, 1, 1];

  patchcolors = [...
    mygreen;... % North
    mygreen;... % East
    mygreen;... % South
    mygreen;... % West
    myyellow;...  % Top
    ];

end


function CPD = update_ess(CPD, fmarginal, evidence, ns, cnodes, hidden_bitv)
% UPDATE_ESS Update the Expected Sufficient Statistics of a hhmmF node.
% function CPD = update_ess(CPD, fmarginal, evidence, ns, cnodes, hidden_bitv)

% Figure out the node numbers associated with each parent
% so we extract evidence from the right place
dom = fmarginal.domain; % Q(1) .. Q(d) F(d+1) F(d)
Qps = fmarginal.domain(1:end-2);
Q = Qps(end);
Qps = Qps(1:end-1);

Qsz = CPD.Qsizes(CPD.Q);
Qpsz = prod(CPD.Qsizes(CPD.Qps)); % may be 1

% We assume the F node are always hidden, but allow some of the Q nodes
% to be observed. We do case analysis for speed.
%We only extract prob from fmarginal.T when F(d+1)=2 i.e., model below has finished.
% wrong -> % We sum over the possibilities that F(d+1) = 1 or 2

obs_self = ~hidden_bitv(Q);
if obs_self
  self_val = evidence{Q};
end

if isempty(Qps) % independent of parent context
  counts = zeros(Qsz, 2);
  %fmarginal.T(Q(d), F(d+1), F(d))
  if obs_self
    marg = myreshape(fmarginal.T, [1 2 2]);
    counts(self_val,:) = marg(1,2,:);
    %counts(self_val,:) = marg(1,1,:) + marg(1,2,:);
  else
    marg = myreshape(fmarginal.T, [Qsz 2 2]);
    counts = squeeze(marg(:,2,:));
    %counts = squeeze(marg(:,2,:)) + squeeze(marg(:,1,:));
  end
else
  counts = zeros(Qpsz, Qsz, 2);
  %fmarginal.T(Q(1:d-1), Q(d), F(d+1), F(d))
  obs_Qps = ~any(hidden_bitv(Qps));  % we assume that all or none of the Q  parents are observed
  if obs_Qps
    Qps_val = subv2ind(Qpsz, cat(1, evidence{Qps}));
  end
  if obs_self & obs_Qps
    marg = myreshape(fmarginal.T, [1 1 2 2]);
    counts(Qps_val, self_val, :) = squeeze(marg(1,1,2,:));
    %counts(Qps_val, self_val, :) = squeeze(marg(1,1,2,:)) + squeeze(marg(1,1,1,:));
  elseif ~obs_self & obs_Qps
    marg = myreshape(fmarginal.T, [1 Qsz 2 2]);
    counts(Qps_val, :, :) = squeeze(marg(1,:,2,:));
    %counts(Qps_val, :, :) = squeeze(marg(1,:,2,:)) + squeeze(marg(1,:,1,:));
  elseif obs_self & ~obs_Qps
    error('not yet implemented')
  else
    marg = myreshape(fmarginal.T, [Qpsz Qsz 2 2]);
    counts(:, :, :) = squeeze(marg(:,:,2,:));
    %counts(:, :, :) = squeeze(marg(:,:,2,:)) + squeeze(marg(:,:,1,:));
  end
end

CPD.sub_CPD_term = update_ess_simple(CPD.sub_CPD_term, counts);


function TCP = jeongLungTCPmodel(paramS,doseBinsV,volHistV)
% Usage: TCP = jeongLungTCPmodel(paramS);
% Lung TCP model
% Based on code by Jeho Jeong jeongj@mskcc.org
%------------------------------------------------------------------------------------
% INPUTS:
% paramS : Parameter dictionary with fields
%          -frxSize (Fraction size (Gy)),
%          -treatmentSchedule(Vector indicating treatment days)
% Example:
% paramS.frxSize.val = 2;
% paramS.treatmentSchedule.val = [ 1  2  3  4  5 ...
%                           8  9 10 11 12 ...
%                           15 16 17 18 19 ...
%                           22 23 24 25 26];
%
%----------------------------------------------------------------------------
% AI 8/30/18

%% Get fractionation
fx_in = paramS.frxSize.val;
nFrx = paramS.numFractions.val;

%% Get treatment days
schedule_in = paramS.treatmentSchedule.val;
if  isfield(paramS,'scheduleType')
    scheduleType = paramS.scheduleType;
else
    scheduleType = 'weekday';
end
%Check for numeric input
if ~isnumeric(schedule_in)
    scheduleV = str2num(schedule_in);
else
    scheduleV = schedule_in;
end
%Otherwise, assume function specified
if isempty(scheduleV)
    scheduleV = eval([schedule_in,'(',num2str(nFrx),',scheduleType)']);
    %scheduleV = getTreatmentSchedule(nFrx); %every weekday with weekend
                                             %breaks
end

%% Input variables for the analysis
alpha_p_ori=0.305;
a_over_b=2.8;
oer_i=1.7;
rho_t=10^6;
v_t_ref=3e4;
f_s=0.01;
t_c=2;
f_p_pro_in=0.5;
ht_loss=2;
k_m=0.3;
ht_lys=3;
oer_h=1.37;
F_p_cyc=[0.56;0.24;0.2];
Alpha_ratio_p_cyc=[2;3];

d_t=15;
clf_in=0.92;
gf_in=0.25;

beta_p_ori=alpha_p_ori/a_over_b;

%% EQD2 estimation for each cohort

EQD2=[];
n_pt=[];
v_t=3e4;
alpha_p=alpha_p_ori;
beta_p=beta_p_ori;
n_t=rho_t*v_t;                %No. cells
n_t_ref=rho_t*v_t_ref;
total_clono_cell=n_t*f_s;
delta_t=d_t/(60*24);          %dt in days
t_start=0;

IC=[];
GF=[];
TCP=[];
TD50=[];
BED=[];
Reox_time=[];
Reox_time2=[];
Treat_duration=[];
vec_leng=[];
comp_size(1)=0;       %Compartment size (P)
comp_size(2)=0;       %Compartment size (H)
comp_size(3)=0;       %Compartment size (I)
comp_size_ref(1)=0;
comp_size_ref(2)=0;
comp_size_ref(3)=0;
p_pre=[];
i_pre=[];
h_pre=[];
T_end=[];

clf=clf_in;
gf=gf_in;

%% Run sub-routine for specific CLF and GF
%---Variables for the initial st-st distribution--%
f_p_pro=f_p_pro_in;

comp_size(1)=gf/f_p_pro*n_t;
comp_size(2)=(1-gf*(1/f_p_pro_in+clf*ht_loss/t_c))*n_t;
comp_size(3)=clf*gf*ht_loss/t_c*n_t;

comp_size_ref(1)=gf/f_p_pro*n_t_ref;
comp_size_ref(2)=(1-gf*(1/f_p_pro_in+clf*ht_loss/t_c))*n_t_ref;
comp_size_ref(3)=clf*gf*ht_loss/t_c*n_t_ref;
%--- end ----%

%Record  number of cells
f_p=comp_size(1)/sum(comp_size);
f_i=comp_size(2)/sum(comp_size);
f_h=comp_size(3)/sum(comp_size);

for d=fx_in
    Treat_day=scheduleV;

    %Cell cycle and dose-dependent radiosensitivity
    f = @(alpha_s)F_p_cyc(1)*exp(-Alpha_ratio_p_cyc(1)*alpha_s*2-...
        Alpha_ratio_p_cyc(1)*(alpha_s/a_over_b)*4)+F_p_cyc(2)*...
        exp(-alpha_s*2-(alpha_s/a_over_b)*4)+F_p_cyc(3)*...
        exp(-Alpha_ratio_p_cyc(2)*alpha_s*2-...
        Alpha_ratio_p_cyc(2)*(alpha_s/a_over_b)*4)-exp(-alpha_p*2-...
        (alpha_p/a_over_b)*4);

    alpha_s=0.3; grid=0.1; pre_f=f(alpha_s);
    while abs(f(alpha_s)) >= eps
        if pre_f*f(alpha_s)<0
            grid=grid*0.1;
        end
        pre_f = f(alpha_s);
        if f(alpha_s)>0
            alpha_s=alpha_s+grid;
        else
            alpha_s=alpha_s-grid;
        end
    end
    Alpha_p_cyc(2)= alpha_s;

    Alpha_p_cyc(1)=Alpha_p_cyc(2)*Alpha_ratio_p_cyc(1);
    Alpha_p_cyc(3)=Alpha_p_cyc(2)*Alpha_ratio_p_cyc(2);

    %Effective alpha, beta from survival fractions
    Su_p=F_p_cyc(1)*exp(-Alpha_p_cyc(1)*d-(Alpha_p_cyc(1)/a_over_b)*d^2)...
        +F_p_cyc(2)*exp(-Alpha_p_cyc(2)*d-(Alpha_p_cyc(2)/a_over_b)*d^2)...
        +F_p_cyc(3)*exp(-Alpha_p_cyc(3)*d-(Alpha_p_cyc(3)/a_over_b)*d^2);
    alpha_p_eff=-log(Su_p)/(d*(1+(d/a_over_b)));
    beta_p_eff=(alpha_p_eff/a_over_b);

    Su_i_2gy=exp(-alpha_p/oer_i*2-(alpha_p/a_over_b)/(oer_i^2)*2^2);
    oer_i_g1=(-(Alpha_p_cyc(1)*2)-sqrt((Alpha_p_cyc(1)*2)^2-...
        4*log(Su_i_2gy)*(Alpha_p_cyc(1)/a_over_b)*2^2))/(2*log(Su_i_2gy));
    Su_h_2gy=exp(-alpha_p/oer_h*2-(alpha_p/a_over_b)/(oer_h^2)*2^2);
    oer_h_g1=(-(Alpha_p_cyc(1)*2)-sqrt((Alpha_p_cyc(1)*2)^2-...
        4*log(Su_h_2gy)*(Alpha_p_cyc(1)/a_over_b)*2^2))/(2*log(Su_h_2gy));
    alpha_i=Alpha_p_cyc(1)/oer_i_g1;
    beta_i=(Alpha_p_cyc(1)/a_over_b)/(oer_i_g1^2);
    alpha_h=Alpha_p_cyc(1)/oer_h_g1;
    beta_h=(Alpha_p_cyc(1)/a_over_b)/(oer_h_g1^2);

    alpha_p=alpha_p_eff;
    beta_p=beta_p_eff;

    % Run sub-routine for a specific CLF and GF
    %--- RT fractional dose for SBRT schedule ---%

    % Assign proliferating fraction to the initial value
    f_p_pro=f_p_pro_in;

    % Cell distribution in each compartment
    % (1:Pv, 2:Pd, 3:Iv, 4:Id, 5:Hv, 6:Hd, 7:lysis)
    % Initially all compartments are fully filled with viable cells
    % "comp_size" is the size of each compartment (1:P, 2:I, 3:H)

    cell_dist=[];
    cell_dist(1)=comp_size(1);
    cell_dist(2)=0;
    cell_dist(3)=comp_size(2);
    cell_dist(4)=0;
    cell_dist(5)=comp_size(3);
    cell_dist(6)=0;
    cell_dist(7)=0;

    % variables (t:time(day), j:# of fraction, add_time:additional time for
    %           weekend break, cum_cell_dist: cumulative cell distribution for
    %           each time increment)
    t=0;
    j=0;
    cum_cell_dist_sbrt=[];

    % Treat for specific SBRT schedule
    while t<t_start+(max(Treat_day)-1)+delta_t/2

        % Change in f_p_pro (k_p) as blood supply improves
        f_p_pro=1-0.5*(cell_dist(1)+cell_dist(2))/comp_size(1);

        % RT fraction
        if  t>(t_start+(Treat_day(j+1)-1)-delta_t/2) &&...
                t<(t_start+(Treat_day(j+1)-1)+delta_t/2)

            cell_dist(2)=cell_dist(2)+cell_dist(1)*(1-exp(-alpha_p*d-beta_p*d^2));
            cell_dist(1)=cell_dist(1)*exp(-alpha_p*d-beta_p*d^2);
            cell_dist(4)=cell_dist(4)+cell_dist(3)*(1-exp(-alpha_i*d-beta_i*d^2));
            cell_dist(3)=cell_dist(3)*exp(-alpha_i*d-beta_i*d^2);
            cell_dist(6)=cell_dist(6)+cell_dist(5)*(1-exp(-alpha_h*d-beta_h*d^2));
            cell_dist(5)=cell_dist(5)*exp(-alpha_h*d-beta_h*d^2);

            j=j+1;
        end

        % Cell Proliferation & Death
        cell_dist(1)=cell_dist(1)*(2)^(f_p_pro*delta_t/t_c);
        h_pre=cell_dist(5)+cell_dist(6);
        cell_dist(5)=cell_dist(5)*(0.5)^(delta_t/ht_loss);
        cell_dist(6)=cell_dist(6)*(0.5)^(delta_t/ht_loss);
        p_d_pre=cell_dist(2);
        cell_dist(2)=cell_dist(2)*(2)^(f_p_pro*(2*k_m-1)*delta_t/t_c);

        % Mitotically dead cell in 1 time step
        md=p_d_pre-cell_dist(2)+(h_pre-cell_dist(5)-cell_dist(6));
        cell_dist(7)=cell_dist(7)+md;
        cell_dist(7)=cell_dist(7)*(0.5)^(delta_t/ht_lys);

        % Recompartmentalization of the cell
        if cell_dist(1)+cell_dist(2)>=comp_size(1)
            p_ex=(cell_dist(1)+cell_dist(2))-comp_size(1);
            p_ratio=cell_dist(1)/(cell_dist(1)+cell_dist(2));
            cell_dist(1)=comp_size(1)*p_ratio;
            cell_dist(2)=comp_size(1)*(1-p_ratio);
            cell_dist(3)=cell_dist(3)+p_ex*p_ratio;
            cell_dist(4)=cell_dist(4)+p_ex*(1-p_ratio);
        else
            if cell_dist(3)+cell_dist(4)>0
                if cell_dist(3)+cell_dist(4)>comp_size(1)-...
                        (cell_dist(1)+cell_dist(2))
                    p_def=comp_size(1)-(cell_dist(1)+cell_dist(2));
                    i_ratio=cell_dist(3)/(cell_dist(3)+cell_dist(4));
                    cell_dist(1)=cell_dist(1)+p_def*i_ratio;
                    cell_dist(2)=cell_dist(2)+p_def*(1-i_ratio);
                    cell_dist(3)=cell_dist(3)-p_def*i_ratio;
                    cell_dist(4)=cell_dist(4)-p_def*(1-i_ratio);
                else
                    cell_dist(1)=cell_dist(1)+cell_dist(3);
                    cell_dist(2)=cell_dist(2)+cell_dist(4);
                    cell_dist(3)=0; cell_dist(4)=0;
                    if cell_dist(5)+cell_dist(6)>0
                        if cell_dist(5)+cell_dist(6)>comp_size(1)-...
                                (cell_dist(1)+cell_dist(2))
                            p_def=comp_size(1)-(cell_dist(1)+cell_dist(2));
                            h_ratio=cell_dist(5)/(cell_dist(5)+cell_dist(6));
                            cell_dist(1)=cell_dist(1)+p_def*h_ratio;
                            cell_dist(2)=cell_dist(2)+p_def*(1-h_ratio);
                            cell_dist(5)=cell_dist(5)-p_def*h_ratio;
                            cell_dist(6)=cell_dist(6)-p_def*(1-h_ratio);
                        else
                            cell_dist(1)=cell_dist(1)+cell_dist(5);
                            cell_dist(2)=cell_dist(2)+cell_dist(6);
                            cell_dist(5)=0; cell_dist(6)=0;
                        end
                    end
                end
            end
        end
        if cell_dist(3)+cell_dist(4)>=comp_size(2)
            i_ex=(cell_dist(3)+cell_dist(4))-comp_size(2);
            i_ratio=cell_dist(3)/(cell_dist(3)+cell_dist(4));
            cell_dist(3)=comp_size(2)*i_ratio;
            cell_dist(4)=comp_size(2)*(1-i_ratio);
            cell_dist(5)=cell_dist(5)+i_ex*i_ratio;
            cell_dist(6)=cell_dist(6)+i_ex*(1-i_ratio);
        else
            if cell_dist(5)+cell_dist(6)>0
                if cell_dist(5)+cell_dist(6)>comp_size(2)-...
                        (cell_dist(3)+cell_dist(4))
                    i_def=comp_size(2)-(cell_dist(3)+cell_dist(4));
                    h_ratio=cell_dist(5)/(cell_dist(5)+cell_dist(6));
                    cell_dist(3)=cell_dist(3)+i_def*h_ratio;
                    cell_dist(4)=cell_dist(4)+i_def*(1-h_ratio);
                    cell_dist(5)=cell_dist(5)-i_def*h_ratio;
                    cell_dist(6)=cell_dist(6)-i_def*(1-h_ratio);
                else
                    cell_dist(3)=cell_dist(3)+cell_dist(5);
                    cell_dist(4)=cell_dist(4)+cell_dist(6);
                    cell_dist(5)=0; cell_dist(6)=0;
                end
            end
        end

        % time step increase and store the number of cells in each compartment
        t=t+delta_t;
        cum_cell_dist_sbrt=[cum_cell_dist_sbrt cell_dist'];

    end

    s_sbrt=cell_dist(1)+cell_dist(3)+cell_dist(5);
    sf_sbrt=s_sbrt/sum(comp_size);
    ntd2=length(Treat_day)*d*(1+(d/a_over_b))/(1+(2/a_over_b));
    d_sbrt=d;
    n_frac_sbrt=length(Treat_day);
    duration_sbrt=max(Treat_day);
    t_sbrt=t;
    %-------------------------------------------------------------------------------%

    %% EQD2 calculation
    d=2;
    alpha_p=alpha_p_ori;            beta_p=beta_p_ori;
    alpha_i=alpha_p_ori/oer_i;      beta_i=beta_p_ori/(oer_i^2);
    alpha_h=alpha_p_ori/oer_h;      beta_h=beta_p_ori/(oer_h^2);
    s_eqd2=0;       sf_eqd2=0;      eqd2=0;

    %----- RT fractional dose for EQD2 estimation ----%

    % Assign proliferating fraction to the initial value

    f_p_pro=f_p_pro_in;

    % Cell distribution in each compartment
    % (1:Pv, 2:Pd, 3:Iv, 4:Id, 5:Hv, 6:Hd, 7:lysis)
    % Initially all compartments are fully filled with viable cells
    % "comp_size" is the size of each compartment (1:P, 2:I, 3:H)

    cell_dist=[];
    cell_dist(1)=comp_size_ref(1);
    cell_dist(2)=0;
    cell_dist(3)=comp_size_ref(2);
    cell_dist(4)=0;
    cell_dist(5)=comp_size_ref(3);
    cell_dist(6)=0;
    cell_dist(7)=0;

    % variables (t:time(day), j:# of fraction, add_time:additional time for
    %           weekend break, cum_cell_dist: cumulative cell distribution for
    %           each time increment)
    t=0;
    j=0;
    add_time=0;
    cum_cell_dist=[];

    % Treat until the SF becomes equivalent to SBRT regime
    while (cell_dist(1)+cell_dist(3)+cell_dist(5))>s_sbrt

        % Change in f_p_pro (k_p) as blood supply improves
        f_p_pro=1-0.5*(cell_dist(1)+cell_dist(2))/comp_size(1);

        % RT fraction
        if  t>(t_start+j+add_time-delta_t/2) && t<(t_start+j+add_time+delta_t/2)

            cell_dist(2)=cell_dist(2)+cell_dist(1)*(1-exp(-alpha_p*d-beta_p*d^2));
            cell_dist(1)=cell_dist(1)*exp(-alpha_p*d-beta_p*d^2);
            cell_dist(4)=cell_dist(4)+cell_dist(3)*(1-exp(-alpha_i*d-beta_i*d^2));
            cell_dist(3)=cell_dist(3)*exp(-alpha_i*d-beta_i*d^2);
            cell_dist(6)=cell_dist(6)+cell_dist(5)*(1-exp(-alpha_h*d-beta_h*d^2));
            cell_dist(5)=cell_dist(5)*exp(-alpha_h*d-beta_h*d^2);

            j=j+1;

            % Week-end break
            if rem(j,5)==0
                add_time=add_time+2;
            end

        end

        % Cell Proliferation & Death
        cell_dist(1)=cell_dist(1)*(2)^(f_p_pro*delta_t/t_c);
        h_pre=cell_dist(5)+cell_dist(6);
        cell_dist(5)=cell_dist(5)*(0.5)^(delta_t/ht_loss);
        cell_dist(6)=cell_dist(6)*(0.5)^(delta_t/ht_loss);
        p_d_pre=cell_dist(2);
        cell_dist(2)=cell_dist(2)*(2)^(f_p_pro*(2*k_m-1)*delta_t/t_c);

        % Mitotically dead cell in 1 time step
        md=p_d_pre-cell_dist(2)+(h_pre-cell_dist(5)-cell_dist(6));
        cell_dist(7)=cell_dist(7)+md;
        cell_dist(7)=cell_dist(7)*(0.5)^(delta_t/ht_lys);

        % Recompartmentalization of the cell
        if cell_dist(1)+cell_dist(2)>=comp_size(1)
            p_ex=(cell_dist(1)+cell_dist(2))-comp_size(1);
            p_ratio=cell_dist(1)/(cell_dist(1)+cell_dist(2));
            cell_dist(1)=comp_size(1)*p_ratio;
            cell_dist(2)=comp_size(1)*(1-p_ratio);
            cell_dist(3)=cell_dist(3)+p_ex*p_ratio;
            cell_dist(4)=cell_dist(4)+p_ex*(1-p_ratio);
        else
            if cell_dist(3)+cell_dist(4)>0
                if cell_dist(3)+cell_dist(4)>comp_size(1)-...
                        (cell_dist(1)+cell_dist(2))
                    p_def=comp_size(1)-(cell_dist(1)+cell_dist(2));
                    i_ratio=cell_dist(3)/(cell_dist(3)+cell_dist(4));
                    cell_dist(1)=cell_dist(1)+p_def*i_ratio;
                    cell_dist(2)=cell_dist(2)+p_def*(1-i_ratio);
                    cell_dist(3)=cell_dist(3)-p_def*i_ratio;
                    cell_dist(4)=cell_dist(4)-p_def*(1-i_ratio);
                else
                    cell_dist(1)=cell_dist(1)+cell_dist(3);
                    cell_dist(2)=cell_dist(2)+cell_dist(4);
                    cell_dist(3)=0; cell_dist(4)=0;
                    if cell_dist(5)+cell_dist(6)>0
                        if cell_dist(5)+cell_dist(6)>comp_size(1)-...
                                (cell_dist(1)+cell_dist(2))
                            p_def=comp_size(1)-(cell_dist(1)+cell_dist(2));
                            h_ratio=cell_dist(5)/(cell_dist(5)+cell_dist(6));
                            cell_dist(1)=cell_dist(1)+p_def*h_ratio;
                            cell_dist(2)=cell_dist(2)+p_def*(1-h_ratio);
                            cell_dist(5)=cell_dist(5)-p_def*h_ratio;
                            cell_dist(6)=cell_dist(6)-p_def*(1-h_ratio);
                        else
                            cell_dist(1)=cell_dist(1)+cell_dist(5);
                            cell_dist(2)=cell_dist(2)+cell_dist(6);
                            cell_dist(5)=0; cell_dist(6)=0;
                        end
                    end
                end
            end
        end
        if cell_dist(3)+cell_dist(4)>=comp_size(2)
            i_ex=(cell_dist(3)+cell_dist(4))-comp_size(2);
            i_ratio=cell_dist(3)/(cell_dist(3)+cell_dist(4));
            cell_dist(3)=comp_size(2)*i_ratio;
            cell_dist(4)=comp_size(2)*(1-i_ratio);
            cell_dist(5)=cell_dist(5)+i_ex*i_ratio;
            cell_dist(6)=cell_dist(6)+i_ex*(1-i_ratio);
        else
            if cell_dist(5)+cell_dist(6)>0
                if cell_dist(5)+cell_dist(6)>comp_size(2)-...
                        (cell_dist(3)+cell_dist(4))
                    i_def=comp_size(2)-(cell_dist(3)+cell_dist(4));
                    h_ratio=cell_dist(5)/(cell_dist(5)+cell_dist(6));
                    cell_dist(3)=cell_dist(3)+i_def*h_ratio;
                    cell_dist(4)=cell_dist(4)+i_def*(1-h_ratio);
                    cell_dist(5)=cell_dist(5)-i_def*h_ratio;
                    cell_dist(6)=cell_dist(6)-i_def*(1-h_ratio);
                else
                    cell_dist(3)=cell_dist(3)+cell_dist(5);
                    cell_dist(4)=cell_dist(4)+cell_dist(6);
                    cell_dist(5)=0; cell_dist(6)=0;
                end
            end
        end

        % time step increase and store the number of cells in each compartment
        t=t+delta_t;
        cum_cell_dist=[cum_cell_dist cell_dist'];

        s_eqd2_pre=s_eqd2;
        sf_eqd2_pre=sf_eqd2;
        eqd2_pre=eqd2;

        s_eqd2=cell_dist(1)+cell_dist(3)+cell_dist(5);
        sf_eqd2=s_eqd2/sum(comp_size);
        tcp=exp(-s_eqd2*f_s);
        eqd2=j*d;

    end

    %----------------------------------------------------------------------%

    eqd2=eqd2_pre+((eqd2-eqd2_pre)/(s_eqd2_pre-s_eqd2))*(s_eqd2_pre-s_sbrt);

end

%% Compute TCP
TD_50 = 62.1;
gamma_50 = 1.5;
TCP_upper_bound = 0.95;

TCP=TCP_upper_bound/(1+(TD_50/eqd2)^(4*gamma_50));


function yp = p00_fun ( test, neqn, t, y )

%*****************************************************************************80
%
%% P00_FUN evaluates the right hand side of any test problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer TEST, the test problem index.
%
%    Input, integer NEQN, the number of equations.
%
%    Input, real T, the value of the independent variable.
%
%    Input, real Y(NEQN,1), the value of the dependent variables.
%
%    Output, real YP(NEQN,1), the value of the derivative of the
%    dependent variables, as specified by the ODE.
%
  yp = zeros ( neqn, 1 );

  if ( test == 1 )
    yp = p01_fun ( neqn, t, y );
  elseif ( test == 2 )
    yp = p02_fun ( neqn, t, y );
  elseif ( test == 3 )
    yp = p03_fun ( neqn, t, y );
  elseif ( test == 4 )
    yp = p04_fun ( neqn, t, y );
  elseif ( test == 5 )
    yp = p05_fun ( neqn, t, y );
  elseif ( test == 6 )
    yp = p06_fun ( neqn, t, y );
  elseif ( test == 7 )
    yp = p07_fun ( neqn, t, y );
  elseif ( test == 8 )
    yp = p08_fun ( neqn, t, y );
  elseif ( test == 9 )
    yp = p09_fun ( neqn, t, y );
  elseif ( test == 10 )
    yp = p10_fun ( neqn, t, y );
  elseif ( test == 11 )
    yp = p11_fun ( neqn, t, y );
  elseif ( test == 12 )
    yp = p12_fun ( neqn, t, y );
  elseif ( test == 13 )
    yp = p13_fun ( neqn, t, y );
  elseif ( test == 14 )
    yp = p14_fun ( neqn, t, y );
  elseif ( test == 15 )
    yp = p15_fun ( neqn, t, y );
  elseif ( test == 16 )
    yp = p16_fun ( neqn, t, y );
  elseif ( test == 17 )
    yp = p17_fun ( neqn, t, y );
  elseif ( test == 18 )
    yp = p18_fun ( neqn, t, y );
  elseif ( test == 19 )
    yp = p19_fun ( neqn, t, y );
  elseif ( test == 20 )
    yp = p20_fun ( neqn, t, y );
  elseif ( test == 21 )
    yp = p21_fun ( neqn, t, y );
  elseif ( test == 22 )
    yp = p22_fun ( neqn, t, y );
  elseif ( test == 23 )
    yp = p23_fun ( neqn, t, y );
  elseif ( test == 24 )
    yp = p24_fun ( neqn, t, y );
  elseif ( test == 25 )
    yp = p25_fun ( neqn, t, y );
  elseif ( test == 26 )
    yp = p26_fun ( neqn, t, y );
  elseif ( test == 27 )
    yp = p27_fun ( neqn, t, y );
  elseif ( test == 28 )
    yp = p28_fun ( neqn, t, y );
  elseif ( test == 29 )
    yp = p29_fun ( neqn, t, y );
  elseif ( test == 30 )
    yp = p30_fun ( neqn, t, y );
  elseif ( test == 31 )
    yp = p31_fun ( neqn, t, y );
  elseif ( test == 32 )
    yp = p32_fun ( neqn, t, y );
  elseif ( test == 33 )
    yp = p33_fun ( neqn, t, y );
  elseif ( test == 34 )
    yp = p34_fun ( neqn, t, y );
  elseif ( test == 35 )
    yp = p35_fun ( neqn, t, y );
  elseif ( test == 36 )
    yp = p36_fun ( neqn, t, y );
  elseif ( test == 37 )
    yp = p37_fun ( neqn, t, y );
  elseif ( test == 38 )
    yp = p38_fun ( neqn, t, y );
  elseif ( test == 39 )
    yp = p39_fun ( neqn, t, y );
  elseif ( test == 40 )
    yp = p40_fun ( neqn, t, y );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_FUN - Fatal error!\n' );
    fprintf ( 1, '  Illegal problem index TEST = %d\n', test );
    error ( 'P00_FUN - Fatal error!' );
  end

  return
end


function [poly,poly_idx,max_index,max_size] = extdom_polygon(bnde,pts,order,line,min_size)
% DESCRIPTION: Given a set of boundary edges of a singly- or multi-
%              polygonal region, organize them in a winding order.
%
% INPUTS:
%         bnde: the indices of each boundary edge as a nbnde x 2 matrix
%         pts:  the x,y locations of all the points in the region
%               stored as an np x 2 matrix.
%         order:the order in which the traversal takes place
%               counter-clockwise (0) or clockwise (1) or add a negative
%               sign to append NaNs in each cell.
%          line:if desired output will be polylines
%       min_size: if the lenght of the polygon is less than min_size
%                  points, throw it out. zero by default.
% OUTPUTS:
%          poly: the boundary of each enclosing polygon sorted in winding-order
%                poly is returned as a cell-array of length number of polys.
%      poly_idx: indices of the polygon coordinates in the same format as
%                poly
%     max_index: is the index into poly that is the largest
%      max_size: is the size of the largest poly
%
% Last Edited:
% kjr,UND,CHL,2017
%   kjr,UND,CHL -->revised for massive speed improvements March 2018.
%
%                                           TRAVERSAL METHOD
% Pick any unvisited edge segment [v_start,v_next] and add these vertices to the polygon loop.
% Find the unvisited edge segment [v_i,v_j] that has either v_i = v_next or v_j = v_next and add the other vertex (the one not equal to v_next) to the polygon loop.
% Reset v_next as this newly added vertex, mark the edge as visited and continue from 2.
% Traversal is done when we get back to v_start.
% NOTE: that the signed area will be positive if the vertices are
% oriented counterclockwise, and will be negative if it is oriented clockwise

% NOTE: By flipping the edges left-to-right, we can easily see the nodal
% connectivity of the triangulation. However, since we are effectively
% adding new "edges", we must also quickly locate and flag the "flipped" edge
% in addition to the current edge under consideration. This is accomplished with the invmap
% array which allows one, given a vertex gid, to quickly find it's linear
% index inside the array bnde((boundary edges). This localizes the search to find
% the connectivity to continue the "walk" on the boundary making the
% calculation massively more efficient than compared to searching the entire bnde
% array with edge under consideration.

% if storing lines
if(nargin < 4); line = 0; end
if(nargin < 5); min_size = 1; end

bnde = [bnde; fliplr(bnde)];
bnde = sortrows(bnde,1);
ned = length(bnde);
an  = sign(order);
active = true(ned,1);

p = 0 ;
% given a vertex with num gid, return where it exists last lid.
for lid = 1 : ned
    gid = bnde(lid,1);
    invmap(gid) = lid ;
end

while any(active)
    p = p + 1;

    rn = find(active,1);

    temp  = pts(bnde(rn,:)',:);
    temp2 = bnde(rn,:)';

    v_start= bnde(rn,1);
    v_next = bnde(rn,2);

    active(rn) = false;

    % flag flipped edge too
    flipped = fliplr(bnde(rn,:));
    idx = invmap(flipped(1));
    st   = max((idx - 1),1);
    ed   = min(idx,ned);
    rn = find(flipped(2)==bnde(st:ed,2),1);

    active(rn+st-1) = false;

    k = 2 ;
    while v_next~=v_start

        % form local set to search for continuation of boundary walk.
        idx  = invmap(v_next);
        st   = max((idx - 1),1);
        ed   = min(idx,ned);

        r = find(v_next==bnde(st:ed,1) & active(st:ed),1);
        tsel = bnde(st+r-1,:); tsel_inv = fliplr(tsel) ;
        sel=tsel(tsel~=v_next);

        if(line)
            if(isempty(sel))
                break
            end
        end
        % store points.
        k = k + 1;
        temp(k,:) = pts(sel,:);
        temp2(k,:)= sel;

        active(r+st-1) = false;

        % flag flipped edge too
        idx = invmap(tsel_inv(1));
        st   = max((idx - 1),1);
        ed   = min(idx,ned);
        r = find(tsel_inv(2)==bnde(st:ed,2),1);
        active(r+st-1) = false;

        v_next = sel;

    end

    if length(temp > min_size)
        poly{p}     = temp;
        poly_idx{p} = temp2;
    else
        continue
    end
    if an < 0
        poly{p}(end+1,:) = [NaN NaN];
        poly_idx{p}(end+1,:) = NaN;
    end
    [area]=parea(poly{p}(:,1),poly{p}(:,2));
    if order==0 % ccw
        if sign(area)<0
            poly{p} = flipud(poly{p});
            poly_idx{p} = flipud(poly_idx{p});
        end
    else % cw
        if sign(area)>0
            poly{p} = flipud(poly{p});
            poly_idx{p} = flipud(poly_idx{p});
        end
    end
end
[max_size, max_index] = max(cellfun('size', poly, 1));
end
% helper function, computes area of polygon
function [area]=parea(x,y)
n    = length(x);
xp   = [x; x(1)];
yp   = [y; y(1)];
area = 0;
for i = 1:n
    area = area + det([xp(i), xp(i+1); yp(i), yp(i+1)]);
end
area = 1/2*area;
end