| /** |
| ******************************************************************************** |
| * Copyright (c) 2022 Dortmund University of Applied Sciences and Arts and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Dortmund University of Applied Sciences and Arts - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.amalthea.model.util.stimuli; |
| |
| import java.math.BigInteger; |
| |
| import org.eclipse.app4mc.amalthea.model.PeriodicBurstStimulus; |
| import org.eclipse.app4mc.amalthea.model.PeriodicStimulus; |
| import org.eclipse.app4mc.amalthea.model.PeriodicSyntheticStimulus; |
| import org.eclipse.app4mc.amalthea.model.RelativePeriodicStimulus; |
| import org.eclipse.app4mc.amalthea.model.SingleStimulus; |
| import org.eclipse.app4mc.amalthea.model.Stimulus; |
| import org.eclipse.app4mc.amalthea.model.Time; |
| import org.eclipse.app4mc.amalthea.model.VariableRateStimulus; |
| import org.eclipse.app4mc.amalthea.model.util.FactoryUtil; |
| |
| public class EventModelFactory { |
| /** |
| * Constant representing a Time object corresponding to 0ms. |
| */ |
| private static final Time ZEROMS = FactoryUtil.createTime("0ms"); |
| |
| // Suppress default constructor |
| private EventModelFactory() { |
| throw new IllegalStateException("Utility class"); |
| } |
| |
| public static IEventModel of(final Stimulus s) { |
| if (s instanceof PeriodicStimulus) { |
| return ofStimuli((PeriodicStimulus) s); |
| } else if (s instanceof PeriodicSyntheticStimulus) { |
| return ofStimuli((PeriodicSyntheticStimulus) s); |
| } else if (s instanceof RelativePeriodicStimulus) { |
| return ofStimuli((RelativePeriodicStimulus) s); |
| } else if (s instanceof PeriodicBurstStimulus) { |
| return ofStimuli((PeriodicBurstStimulus) s); |
| } else if (s instanceof SingleStimulus) { |
| return ofStimuli((SingleStimulus) s); |
| } else if (s instanceof VariableRateStimulus) { |
| return ofStimuli((VariableRateStimulus) s); |
| } |
| // Stimulus is not supported |
| return null; |
| } |
| |
| /********************************************************* |
| * Factory methods for individual APP4MC stimuli |
| *********************************************************/ |
| |
| private static IEventModel ofStimuli(PeriodicStimulus s) { |
| EMPeriodic em = new EMPeriodic(); |
| em.setRecurrence(s.getRecurrence()); |
| /* |
| * Check if minDistance is set. If not, we are safe to initialize this variable |
| * with a dummy value of zero, as it will only be used as part of max functions |
| * (i.e. to make sure a lower bound on the distance is not exceeded) |
| */ |
| if (s.getMinDistance() == null) { |
| em.setMinDistance(FactoryUtil.createTime("0ms")); |
| } else { |
| em.setMinDistance(s.getMinDistance()); |
| } |
| |
| /** |
| * Check if jitter is is set. If not, we are safe to initialize this variable |
| * with a dummy value of zero, as it will only be used as in additions / |
| * subtractions. |
| */ |
| if (s.getJitter() == null) { |
| em.setJitter(FactoryUtil.createTime("0ms")); |
| } else { |
| em.setJitter(s.getJitter().getUpperBound()); |
| } |
| return em; |
| } |
| |
| private static IEventModel ofStimuli(PeriodicSyntheticStimulus s) { |
| EMPeriodicSynthetic em = new EMPeriodicSynthetic(); |
| em.setOuterPeriod(s.getRecurrence()); |
| em.setEntries(s.getOccurrenceTimes()); |
| return em; |
| } |
| |
| private static IEventModel ofStimuli(RelativePeriodicStimulus periodicRelative) { |
| EMPeriodicRelative em = new EMPeriodicRelative(); |
| em.setLowerBoundDistance(periodicRelative.getNextOccurrence().getLowerBound()); |
| em.setUpperBoundDistance(periodicRelative.getNextOccurrence().getUpperBound()); |
| return em; |
| } |
| |
| private static IEventModel ofStimuli(PeriodicBurstStimulus s) { |
| EMPeriodicBurst em = new EMPeriodicBurst(); |
| |
| // Feasibility check to prevent the creation of an invalid object that would |
| // cause exceptions. |
| if (EventModelFactory.isNullOrZero(s.getRecurrence()) || EventModelFactory.isNullOrZero(s.getBurstLength())) { |
| return null; |
| } |
| |
| // Set Mandatory parameters |
| em.setOuterPeriod(s.getRecurrence()); |
| em.setBurstLength(s.getBurstLength()); |
| |
| /* |
| * From APP4MC Help: The number of occurrences per burst are specified via |
| * occurrenceCount. The occurrenceMinDinstance defines the minimal distance |
| * between them. The burstLength defines the maximum time the burst pattern can |
| * last. If the number of occurrences multiplied with the minimum distance |
| * between activations is bigger than the burstLength only the number of |
| * activations that fit into the burstLength are executed. |
| */ |
| |
| // Check whether or not OccurrenceCount * OccurrenceMinDistance < |
| // BurstLength, and limit the number of events accordingly. |
| // if tMinDistance != 0 && tMinDistance * (occurranceCount - 1) > |
| // tBurstLength |
| if (!EventModelFactory.isNullOrZero(s.getOccurrenceMinDistance()) |
| && !EventModelFactory.isNullOrZero(em.getBurstLength()) && s.getOccurrenceMinDistance() |
| .multiply(s.getOccurrenceCount() - (long) 1).compareTo(em.getBurstLength()) > 0) { |
| // OccurrenceCount * OccurrenceMinDistance > BurstLength, i.e. limit |
| // nb. of occurrences |
| em.setOccurrenceCount((int) Math.ceil(em.getBurstLength().divide(s.getOccurrenceMinDistance()))); |
| } else { |
| // BurstLength is either not set, or does not constrain the nb. of |
| // Occurrences |
| em.setOccurrenceCount(s.getOccurrenceCount()); |
| } |
| |
| // Initialize optional parameter |
| if (s.getOccurrenceMinDistance() != null) { |
| em.setMinDistance(s.getOccurrenceMinDistance()); |
| em.setDeltaBurst(em.getBurstLength().subtract(em.getMinDistance().multiply(em.getOccurrenceCount() - 1))); |
| } else { |
| em.setMinDistance(ZEROMS); |
| em.setDeltaBurst(ZEROMS); |
| } |
| return em; |
| } |
| |
| @java.lang.SuppressWarnings("squid:S1172") |
| private static IEventModel ofStimuli(SingleStimulus singleStimulus) { |
| // Warnings disabled on purpose, since it is intended that neither |
| // singleStimulus nor em are used within this method. |
| @java.lang.SuppressWarnings("squid:S1488") |
| EMSingle em = new EMSingle(); |
| return em; |
| } |
| |
| private static IEventModel ofStimuli(VariableRateStimulus s) { |
| EMVariableRate em = new EMVariableRate(); |
| em.setStep(s.getStep()); |
| em.setLowerBoundOccurrences(s.getOccurrencesPerStep().getLowerBound()); |
| em.setUpperBoundOccurrences(s.getOccurrencesPerStep().getUpperBound()); |
| em.setAverageBoundOccurrences(s.getOccurrencesPerStep().getAverage()); |
| return em; |
| } |
| |
| /********************************************************* |
| * Utility functions used to support arithmetic operations |
| *********************************************************/ |
| |
| /** |
| * Returns the maximum between <a href="#{@link}">{@link Time}</a> a and b |
| * |
| * @param a |
| * @param b |
| * @return |
| */ |
| public static Time max(final Time a, final Time b) { |
| return (a.compareTo(b) > 0) ? a : b; |
| } |
| |
| /** |
| * Returns the minimum between <a href="#{@link}">{@link Time}</a> a and b |
| * |
| * @param a |
| * @param b |
| * @return |
| */ |
| public static Time min(final Time a, final Time b) { |
| return (a.compareTo(b) < 0) ? a : b; |
| } |
| |
| /** |
| * Returns {@code True} if the given {@link Time} is either {@code Null} or 0. |
| * |
| * @param t |
| * @return |
| */ |
| public static boolean isNullOrZero(final Time t) { |
| return (t == null || t.getValue().compareTo(BigInteger.ZERO) == 0); |
| } |
| } |