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}