001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.math3.ode.events; 019 020import org.apache.commons.math3.exception.MathInternalError; 021 022/** Enumerate for {@link EventFilter filtering events}. 023 * 024 * @since 3.2 025 */ 026 027public enum FilterType { 028 029 /** Constant for triggering only decreasing events. 030 * <p>When this filter is used, the wrapped {@link EventHandler 031 * event handler} {@link EventHandler#eventOccurred(double, double[], 032 * boolean) eventOccurred} method will be called <em>only</em> with 033 * its {@code increasing} argument set to false.</p> 034 */ 035 TRIGGER_ONLY_DECREASING_EVENTS { 036 037 /** {@inheritDoc} */ 038 @Override 039 protected boolean getTriggeredIncreasing() { 040 return false; 041 } 042 043 /** {@inheritDoc} 044 * <p> 045 * states scheduling for computing h(t,y) as an altered version of g(t, y) 046 * <ul> 047 * <li>0 are triggered events for which a zero is produced (here decreasing events)</li> 048 * <li>X are ignored events for which zero is masked (here increasing events)</li> 049 * </ul> 050 * </p> 051 * <pre> 052 * g(t) 053 * ___ ___ ___ 054 * / \ / \ / \ 055 * / \ / \ / \ 056 * / g>0 \ / g>0 \ / g>0 \ 057 * / \ / \ / \ 058 * ----- X --------- 0 --------- X --------- 0 --------- X --------- 0 --- 059 * / \ / \ / \ 060 * / \ g<0 / \ g<0 / \ g<0 061 * / \ / \ / \ / 062 * ___/ \___/ \___/ \___/ 063 * </pre> 064 * <pre> 065 * h(t,y)) as an alteration of g(t,y) 066 * ___ ___ ___ 067 * \ / \ / \ / \ 068 * \ / \ h=+g / \ / \ 069 * \ / \ h=min(-s,-g,+g) / \ / \ 070 * \_/ \ / \_/ \ 071 * ------ ---------- 0 ----------_---------- 0 --------------------- 0 --- 072 * \ / \ / \ 073 * h=max(+s,-g,+g) \ / \ / h=max(+s,-g,+g) \ 074 * \ / \ / h=-g \ / 075 * \___/ \___/ \___/ 076 * </pre> 077 * <p> 078 * As shown by the figure above, several expressions are used to compute h, 079 * depending on the current state: 080 * <ul> 081 * <li>h = max(+s,-g,+g)</li> 082 * <li>h = +g</li> 083 * <li>h = min(-s,-g,+g)</li> 084 * <li>h = -g</li> 085 * </ul> 086 * where s is a tiny positive value: {@link org.apache.commons.math3.util.Precision#SAFE_MIN}. 087 * </p> 088 */ 089 @Override 090 protected Transformer selectTransformer(final Transformer previous, 091 final double g, final boolean forward) { 092 if (forward) { 093 switch (previous) { 094 case UNINITIALIZED : 095 // we are initializing the first point 096 if (g > 0) { 097 // initialize as if previous root (i.e. backward one) was an ignored increasing event 098 return Transformer.MAX; 099 } else if (g < 0) { 100 // initialize as if previous root (i.e. backward one) was a triggered decreasing event 101 return Transformer.PLUS; 102 } else { 103 // we are exactly at a root, we don't know if it is an increasing 104 // or a decreasing event, we remain in uninitialized state 105 return Transformer.UNINITIALIZED; 106 } 107 case PLUS : 108 if (g >= 0) { 109 // we have crossed the zero line on an ignored increasing event, 110 // we must change the transformer 111 return Transformer.MIN; 112 } else { 113 // we are still in the same status 114 return previous; 115 } 116 case MINUS : 117 if (g >= 0) { 118 // we have crossed the zero line on an ignored increasing event, 119 // we must change the transformer 120 return Transformer.MAX; 121 } else { 122 // we are still in the same status 123 return previous; 124 } 125 case MIN : 126 if (g <= 0) { 127 // we have crossed the zero line on a triggered decreasing event, 128 // we must change the transformer 129 return Transformer.MINUS; 130 } else { 131 // we are still in the same status 132 return previous; 133 } 134 case MAX : 135 if (g <= 0) { 136 // we have crossed the zero line on a triggered decreasing event, 137 // we must change the transformer 138 return Transformer.PLUS; 139 } else { 140 // we are still in the same status 141 return previous; 142 } 143 default : 144 // this should never happen 145 throw new MathInternalError(); 146 } 147 } else { 148 switch (previous) { 149 case UNINITIALIZED : 150 // we are initializing the first point 151 if (g > 0) { 152 // initialize as if previous root (i.e. forward one) was a triggered decreasing event 153 return Transformer.MINUS; 154 } else if (g < 0) { 155 // initialize as if previous root (i.e. forward one) was an ignored increasing event 156 return Transformer.MIN; 157 } else { 158 // we are exactly at a root, we don't know if it is an increasing 159 // or a decreasing event, we remain in uninitialized state 160 return Transformer.UNINITIALIZED; 161 } 162 case PLUS : 163 if (g <= 0) { 164 // we have crossed the zero line on an ignored increasing event, 165 // we must change the transformer 166 return Transformer.MAX; 167 } else { 168 // we are still in the same status 169 return previous; 170 } 171 case MINUS : 172 if (g <= 0) { 173 // we have crossed the zero line on an ignored increasing event, 174 // we must change the transformer 175 return Transformer.MIN; 176 } else { 177 // we are still in the same status 178 return previous; 179 } 180 case MIN : 181 if (g >= 0) { 182 // we have crossed the zero line on a triggered decreasing event, 183 // we must change the transformer 184 return Transformer.PLUS; 185 } else { 186 // we are still in the same status 187 return previous; 188 } 189 case MAX : 190 if (g >= 0) { 191 // we have crossed the zero line on a triggered decreasing event, 192 // we must change the transformer 193 return Transformer.MINUS; 194 } else { 195 // we are still in the same status 196 return previous; 197 } 198 default : 199 // this should never happen 200 throw new MathInternalError(); 201 } 202 } 203 } 204 205 }, 206 207 /** Constant for triggering only increasing events. 208 * <p>When this filter is used, the wrapped {@link EventHandler 209 * event handler} {@link EventHandler#eventOccurred(double, double[], 210 * boolean) eventOccurred} method will be called <em>only</em> with 211 * its {@code increasing} argument set to true.</p> 212 */ 213 TRIGGER_ONLY_INCREASING_EVENTS { 214 215 /** {@inheritDoc} */ 216 @Override 217 protected boolean getTriggeredIncreasing() { 218 return true; 219 } 220 221 /** {@inheritDoc} 222 * <p> 223 * states scheduling for computing h(t,y) as an altered version of g(t, y) 224 * <ul> 225 * <li>0 are triggered events for which a zero is produced (here increasing events)</li> 226 * <li>X are ignored events for which zero is masked (here decreasing events)</li> 227 * </ul> 228 * </p> 229 * <pre> 230 * g(t) 231 * ___ ___ ___ 232 * / \ / \ / \ 233 * / \ / \ / \ 234 * / g>0 \ / g>0 \ / g>0 \ 235 * / \ / \ / \ 236 * ----- 0 --------- X --------- 0 --------- X --------- 0 --------- X --- 237 * / \ / \ / \ 238 * / \ g<0 / \ g<0 / \ g<0 239 * / \ / \ / \ / 240 * ___/ \___/ \___/ \___/ 241 * </pre> 242 * <pre> 243 * h(t,y)) as an alteration of g(t,y) 244 * ___ ___ 245 * \ / \ / \ 246 * \ h=-g / \ / \ h=-g 247 * \ h=min(-s,-g,+g) / \ / \ h=min(-s,-g,+g) 248 * \ / \_/ \ 249 * ------0 ----------_---------- 0 --------------------- 0 --------- _ --- 250 * \ / \ / \ / \ 251 * \ / \ / h=max(+s,-g,+g) \ / \ 252 * \ / \ / h=+g \ / \ / 253 * \___/ \___/ \___/ \___/ 254 * </pre> 255 * <p> 256 * As shown by the figure above, several expressions are used to compute h, 257 * depending on the current state: 258 * <ul> 259 * <li>h = max(+s,-g,+g)</li> 260 * <li>h = +g</li> 261 * <li>h = min(-s,-g,+g)</li> 262 * <li>h = -g</li> 263 * </ul> 264 * where s is a tiny positive value: {@link org.apache.commons.math3.util.Precision#SAFE_MIN}. 265 * </p> 266 */ 267 @Override 268 protected Transformer selectTransformer(final Transformer previous, 269 final double g, final boolean forward) { 270 if (forward) { 271 switch (previous) { 272 case UNINITIALIZED : 273 // we are initializing the first point 274 if (g > 0) { 275 // initialize as if previous root (i.e. backward one) was a triggered increasing event 276 return Transformer.PLUS; 277 } else if (g < 0) { 278 // initialize as if previous root (i.e. backward one) was an ignored decreasing event 279 return Transformer.MIN; 280 } else { 281 // we are exactly at a root, we don't know if it is an increasing 282 // or a decreasing event, we remain in uninitialized state 283 return Transformer.UNINITIALIZED; 284 } 285 case PLUS : 286 if (g <= 0) { 287 // we have crossed the zero line on an ignored decreasing event, 288 // we must change the transformer 289 return Transformer.MAX; 290 } else { 291 // we are still in the same status 292 return previous; 293 } 294 case MINUS : 295 if (g <= 0) { 296 // we have crossed the zero line on an ignored decreasing event, 297 // we must change the transformer 298 return Transformer.MIN; 299 } else { 300 // we are still in the same status 301 return previous; 302 } 303 case MIN : 304 if (g >= 0) { 305 // we have crossed the zero line on a triggered increasing event, 306 // we must change the transformer 307 return Transformer.PLUS; 308 } else { 309 // we are still in the same status 310 return previous; 311 } 312 case MAX : 313 if (g >= 0) { 314 // we have crossed the zero line on a triggered increasing event, 315 // we must change the transformer 316 return Transformer.MINUS; 317 } else { 318 // we are still in the same status 319 return previous; 320 } 321 default : 322 // this should never happen 323 throw new MathInternalError(); 324 } 325 } else { 326 switch (previous) { 327 case UNINITIALIZED : 328 // we are initializing the first point 329 if (g > 0) { 330 // initialize as if previous root (i.e. forward one) was an ignored decreasing event 331 return Transformer.MAX; 332 } else if (g < 0) { 333 // initialize as if previous root (i.e. forward one) was a triggered increasing event 334 return Transformer.MINUS; 335 } else { 336 // we are exactly at a root, we don't know if it is an increasing 337 // or a decreasing event, we remain in uninitialized state 338 return Transformer.UNINITIALIZED; 339 } 340 case PLUS : 341 if (g >= 0) { 342 // we have crossed the zero line on an ignored decreasing event, 343 // we must change the transformer 344 return Transformer.MIN; 345 } else { 346 // we are still in the same status 347 return previous; 348 } 349 case MINUS : 350 if (g >= 0) { 351 // we have crossed the zero line on an ignored decreasing event, 352 // we must change the transformer 353 return Transformer.MAX; 354 } else { 355 // we are still in the same status 356 return previous; 357 } 358 case MIN : 359 if (g <= 0) { 360 // we have crossed the zero line on a triggered increasing event, 361 // we must change the transformer 362 return Transformer.MINUS; 363 } else { 364 // we are still in the same status 365 return previous; 366 } 367 case MAX : 368 if (g <= 0) { 369 // we have crossed the zero line on a triggered increasing event, 370 // we must change the transformer 371 return Transformer.PLUS; 372 } else { 373 // we are still in the same status 374 return previous; 375 } 376 default : 377 // this should never happen 378 throw new MathInternalError(); 379 } 380 } 381 } 382 383 }; 384 385 /** Get the increasing status of triggered events. 386 * @return true if triggered events are increasing events 387 */ 388 protected abstract boolean getTriggeredIncreasing(); 389 390 /** Get next function transformer in the specified direction. 391 * @param previous transformer active on the previous point with respect 392 * to integration direction (may be null if no previous point is known) 393 * @param g current value of the g function 394 * @param forward true if integration goes forward 395 * @return next transformer transformer 396 */ 397 protected abstract Transformer selectTransformer(Transformer previous, 398 double g, boolean forward); 399 400}