1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.numerics.func1d;
39
40 import static ffx.numerics.func1d.QuasiLinearThetaMap.Branch;
41 import static ffx.numerics.func1d.QuasiLinearThetaMap.Branch.A;
42 import static ffx.numerics.func1d.QuasiLinearThetaMap.Branch.B;
43 import static ffx.numerics.func1d.QuasiLinearThetaMap.Branch.C;
44 import static ffx.numerics.func1d.QuasiLinearThetaMap.Branch.D;
45 import static java.lang.String.format;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertTrue;
48
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.OptionalDouble;
52
53 import ffx.utilities.FFXTest;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.junit.runners.Parameterized;
57
58 @RunWith(Parameterized.class)
59 public class QuasiLinearSwitchTest extends FFXTest {
60 private static final double TOL = 1E-11;
61 private final String info;
62 private final QuasiLinearThetaMap mapF;
63 private final double[] expectedConsts;
64 private final double[][] expecteds;
65 private final Branch[] primaryBranch;
66 private final Branch[] secondaryBranch;
67 private final int nVals;
68
69 public QuasiLinearSwitchTest(
70 String info,
71 OptionalDouble theta0,
72 double[] eConsts,
73 double[][] eVals,
74 Branch[] primary,
75 Branch[] secondary) {
76 this.info = info;
77 mapF =
78 theta0.isPresent()
79 ? new QuasiLinearThetaMap(theta0.getAsDouble())
80 : new QuasiLinearThetaMap();
81 expectedConsts = eConsts;
82 expecteds = eVals;
83 primaryBranch = primary;
84 secondaryBranch = secondary;
85 nVals = eVals.length;
86 assertTrue(
87 "Inequal number of arguments for expected vals & branches!",
88 nVals == primary.length && nVals == secondary.length);
89 }
90
91 @Parameterized.Parameters
92 public static Collection<Object[]> data() {
93 return Arrays.asList(
94 new Object[][] {
95 {
96
97 "Default Linear Theta Map",
98 OptionalDouble.empty(),
99
100 new double[] {
101 6.586293806435631, 0.32876610686815605, -0.016424593043157933, -5.586293806435631
102 },
103 new double[][] {
104 {-Math.PI, 1.0, 0.0, -3.2931469032178153},
105 {(0.05 - Math.PI), 0.995884423889855, -0.16458874650913316, -3.28903132710767},
106 {(0.1 - Math.PI), 0.9835479823563423, -0.32876610686815605, -3.2766948855741576},
107 {0.5 * (0.1 - Math.PI), 0.4835616946565922, -0.32876610686815605, 0.0},
108 {-0.1, 0.0164520176436577, -0.32876610686815605, 3.276694885574158},
109 {-0.05, 0.004115576110145532, -0.16458874650913274, 3.28903132710767},
110 {0, 0, 0, 3.2931469032178153},
111 {0.05, 0.004115576110145532, 0.16458874650913274, 3.28903132710767},
112 {0.1, 0.0164520176436577, 0.32876610686815605, 3.276694885574158},
113 {0.5 * (Math.PI - 0.1), 0.48356169465659227, 0.32876610686815605, 0.0},
114 {Math.PI - 0.1, 0.9835479823563427, 0.3287661068681553, -3.2766948855741576},
115 {Math.PI - 0.05, 0.995884423889855, 0.16458874650913316, -3.28903132710767},
116 {Math.PI, 1.0, 0.0, -3.2931469032178153}
117 },
118 new QuasiLinearThetaMap.Branch[] {D, D, D, C, A, A, A, A, A, B, D, D, D},
119 new QuasiLinearThetaMap.Branch[] {D, D, C, C, C, A, A, A, B, B, B, D, D}
120 },
121 {
122 "Linear Theta Map: t0 = 0.1 (manual)",
123 OptionalDouble.of(0.1),
124 new double[] {
125 6.586293806435631, 0.32876610686815605, -0.016424593043157933, -5.586293806435631
126 },
127 new double[][] {
128 {-Math.PI, 1.0, 0.0, -3.2931469032178153},
129 {(0.05 - Math.PI), 0.995884423889855, -0.16458874650913316, -3.28903132710767},
130 {(0.1 - Math.PI), 0.9835479823563423, -0.32876610686815605, -3.2766948855741576},
131 {0.5 * (0.1 - Math.PI), 0.4835616946565922, -0.32876610686815605, 0.0},
132 {-0.1, 0.0164520176436577, -0.32876610686815605, 3.276694885574158},
133 {-0.05, 0.004115576110145532, -0.16458874650913274, 3.28903132710767},
134 {0, 0, 0, 3.2931469032178153},
135 {0.05, 0.004115576110145532, 0.16458874650913274, 3.28903132710767},
136 {0.1, 0.0164520176436577, 0.32876610686815605, 3.276694885574158},
137 {0.5 * (Math.PI - 0.1), 0.48356169465659227, 0.32876610686815605, 0.0},
138 {Math.PI - 0.1, 0.9835479823563427, 0.3287661068681553, -3.2766948855741576},
139 {Math.PI - 0.05, 0.995884423889855, 0.16458874650913316, -3.28903132710767},
140 {Math.PI, 1.0, 0.0, -3.2931469032178153}
141 },
142 new QuasiLinearThetaMap.Branch[] {D, D, D, C, A, A, A, A, A, B, D, D, D},
143 new QuasiLinearThetaMap.Branch[] {D, D, C, C, C, A, A, A, B, B, B, D, D}
144 },
145 });
146 }
147
148 @Test
149 public void testPoints() {
150 for (int i = 0; i < 4; i++) {
151 assertEquals(
152 "Incorrect constant " + i + ": ", mapF.getConstants()[i], expectedConsts[i], TOL);
153 }
154 for (int i = 0; i < nVals; i++) {
155 double[] exp = expecteds[i];
156 Branch prim = primaryBranch[i];
157 Branch secon = secondaryBranch[i];
158 if (prim == secon) {
159 testMidPoint(exp, prim);
160 } else {
161 testJoint(exp, prim, secon);
162 }
163 }
164 }
165
166 @Override
167 public String toString() {
168 return info;
169 }
170
171 private void testMidPoint(double[] expect, Branch br) {
172 double t = expect[0];
173 assertEquals("Incorrect branching!", br, mapF.getBranch(t));
174 double eVal = expect[1];
175 double val = mapF.valueAt(t);
176 assertEquals("A midpoint value was incorrect!", val, eVal, TOL);
177 val = mapF.val(t, br);
178 assertEquals("A midpoint value was incorrect when the branch was specified!", val, eVal, TOL);
179
180 eVal = expect[2];
181 val = mapF.firstDerivative(t);
182 assertEquals("A midpoint first derivative was incorrect!", val, eVal, TOL);
183 val = mapF.fd(t, br);
184 assertEquals(
185 "A midpoint first derivative was incorrect when the branch was specified!", val, eVal, TOL);
186
187 eVal = expect[3];
188 val = mapF.secondDerivative(t);
189 assertEquals("A midpoint second derivative was incorrect!", val, eVal, TOL);
190 val = mapF.sd(t, br);
191 assertEquals(
192 "A midpoint second derivative was incorrect when the branch was specified!",
193 val,
194 eVal,
195 TOL);
196 }
197
198 private void testJoint(double[] expect, Branch prim, Branch second) {
199 double t = expect[0];
200 Branch received = mapF.getBranch(t);
201 boolean rightBranch = (prim == received) || (second == received);
202 assertTrue(
203 format(
204 " Did not find any expected branch! Found: %s. "
205 + "Primary expected: %s. Secondary expected: %s",
206 received, prim, second),
207 rightBranch);
208
209 double eVal = expect[1];
210 double val = mapF.valueAt(t);
211 assertEquals("A joint value was incorrect!", val, eVal, TOL);
212 val = mapF.val(t, prim);
213 assertEquals("A joint value was incorrect when the branch was specified!", val, eVal, TOL);
214 val = mapF.val(t, second);
215 assertEquals("A joint value was incorrect for the alternate branch!", val, eVal, TOL);
216
217 eVal = expect[2];
218 val = mapF.firstDerivative(t);
219 assertEquals("A joint first derivative was incorrect!", val, eVal, TOL);
220 val = mapF.fd(t, prim);
221 assertEquals(
222 "A joint first derivative was incorrect when the branch was specified!", val, eVal, TOL);
223 val = mapF.fd(t, second);
224 assertEquals(
225 "A joint first derivative was incorrect for the alternate branch!", val, eVal, TOL);
226
227 eVal = expect[3];
228 val = mapF.sd(t, prim);
229 assertEquals("A joint second derivative was incorrect!", val, eVal, TOL);
230 }
231 }