ScenarioParser.java
- package org.opentrafficsim.road.network.factory.xml.parser;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.function.Supplier;
- import org.djunits.value.vdouble.scalar.Dimensionless;
- import org.djutils.base.Identifiable;
- import org.djutils.eval.Eval;
- import org.djutils.eval.RetrieveValue;
- import org.opentrafficsim.road.network.factory.xml.CircularDependencyException;
- import org.opentrafficsim.xml.bindings.types.ExpressionType;
- import org.opentrafficsim.xml.generated.Demand;
- import org.opentrafficsim.xml.generated.InputParameters;
- import org.opentrafficsim.xml.generated.ModelIdReferralType;
- import org.opentrafficsim.xml.generated.ScenarioType;
- import org.opentrafficsim.xml.generated.Scenarios;
- /**
- * Parser of scenario tags.
- * <p>
- * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
- * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
- * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
- */
- public class ScenarioParser
- {
- /**
- * Parse input parameters for scenario.
- * @param scenarios Scenarios; scenarios tag.
- * @param scenario String; name of scenario tp parse.
- * @return Eval; expression evaluator for all expression in XML.
- */
- public static Eval parseInputParameters(final Scenarios scenarios, final String scenario)
- {
- if (scenarios == null)
- {
- return new Eval();
- }
- ScenariosWrapper scenariosWrapper = new ScenariosWrapper()
- {
- /** {@inheritDoc} */
- @Override
- public Iterable<ParameterWrapper> getDefaultInputParameters()
- {
- return getInputParameterIterator(scenarios.getDefaultInputParameters());
- }
- /** {@inheritDoc} */
- @Override
- public Iterable<ParameterWrapper> getScenarioInputParameters()
- {
- for (ScenarioType scenarioTag : scenarios.getScenario())
- {
- if (scenarioTag.getId().equals(scenario))
- {
- return getInputParameterIterator(scenarioTag.getInputParameters());
- }
- }
- return null;
- }
- };
- return parseInputParameters(scenariosWrapper);
- }
- /**
- * Parse input parameters for scenario.
- * @param scenariosWrapper ScenariosWrapper; scenarios wrapper, from XML or Xsd Tree nodes in editor.
- * @return Eval; expression evaluator for all expression in XML.
- */
- public static Eval parseInputParameters(final ScenariosWrapper scenariosWrapper)
- {
- Map<String, Supplier<?>> defaultsMap = new LinkedHashMap<>();
- ParameterMap defaults = new ParameterMap(defaultsMap);
- Eval eval = new Eval().setRetrieveValue(defaults);
- parseInputParameters(scenariosWrapper.getDefaultInputParameters(), defaultsMap, defaults);
- if (scenariosWrapper.getScenarioInputParameters() != null)
- {
- Map<String, Supplier<?>> inputParametersMap = new LinkedHashMap<>();
- ParameterMap inputParameters = new ParameterMap(inputParametersMap);
- defaults.setScenarioMap(inputParameters);
- parseInputParameters(scenariosWrapper.getScenarioInputParameters(), inputParametersMap, defaults);
- }
- // test whether values can be obtained successfully (might throw CircularDependencyException)
- for (ParameterWrapper parameter : scenariosWrapper.getDefaultInputParameters())
- {
- String id = parameter.getId();
- eval.evaluate(id.substring(1, id.length() - 1));
- }
- if (scenariosWrapper.getScenarioInputParameters() != null)
- {
- for (ParameterWrapper parameter : scenariosWrapper.getScenarioInputParameters())
- {
- String id = parameter.getId();
- eval.evaluate(id.substring(1, id.length() - 1));
- }
- }
- return eval;
- }
- /**
- * Creates parsable parameters from an InputParameters XML tag (default or of a scenario).
- * @param inputParameters InputParameters; parameters XML tag.
- * @return ITerable<ParameterWrapper>; parameters in generic form for parsing.
- */
- private static Iterable<ParameterWrapper> getInputParameterIterator(final InputParameters inputParameters)
- {
- List<ParameterWrapper> parameters = new ArrayList<>();
- if (inputParameters == null)
- {
- return parameters;
- }
- for (Serializable parameter : inputParameters.getDurationOrLengthOrSpeed())
- {
- if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Duration)
- {
- org.opentrafficsim.xml.generated.InputParameters.Duration p =
- (org.opentrafficsim.xml.generated.InputParameters.Duration) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Length)
- {
- org.opentrafficsim.xml.generated.InputParameters.Length p =
- (org.opentrafficsim.xml.generated.InputParameters.Length) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Speed)
- {
- org.opentrafficsim.xml.generated.InputParameters.Speed p =
- (org.opentrafficsim.xml.generated.InputParameters.Speed) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Acceleration)
- {
- org.opentrafficsim.xml.generated.InputParameters.Acceleration p =
- (org.opentrafficsim.xml.generated.InputParameters.Acceleration) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.LinearDensity)
- {
- org.opentrafficsim.xml.generated.InputParameters.LinearDensity p =
- (org.opentrafficsim.xml.generated.InputParameters.LinearDensity) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Frequency)
- {
- org.opentrafficsim.xml.generated.InputParameters.Frequency p =
- (org.opentrafficsim.xml.generated.InputParameters.Frequency) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Double)
- {
- org.opentrafficsim.xml.generated.InputParameters.Double p =
- (org.opentrafficsim.xml.generated.InputParameters.Double) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Fraction)
- {
- org.opentrafficsim.xml.generated.InputParameters.Fraction p =
- (org.opentrafficsim.xml.generated.InputParameters.Fraction) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Integer)
- {
- org.opentrafficsim.xml.generated.InputParameters.Integer p =
- (org.opentrafficsim.xml.generated.InputParameters.Integer) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Boolean)
- {
- org.opentrafficsim.xml.generated.InputParameters.Boolean p =
- (org.opentrafficsim.xml.generated.InputParameters.Boolean) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.String)
- {
- org.opentrafficsim.xml.generated.InputParameters.String p =
- (org.opentrafficsim.xml.generated.InputParameters.String) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- else if (parameter instanceof org.opentrafficsim.xml.generated.InputParameters.Class)
- {
- org.opentrafficsim.xml.generated.InputParameters.Class p =
- (org.opentrafficsim.xml.generated.InputParameters.Class) parameter;
- parameters.add(new ParameterWrapper(p.getId(), p.getValue()));
- }
- }
- return parameters;
- }
- /**
- * Parse input parameters.
- * @param inputParameters Iterable<ParameterWrapper>; xml tag.
- * @param map Map<String, Supplier<?>>; map that underlines inputParameters.
- * @param retrieve ParameterMap; value retrieval.
- */
- private static void parseInputParameters(final Iterable<ParameterWrapper> inputParameters,
- final Map<String, Supplier<?>> map, final ParameterMap retrieve)
- {
- Eval eval = new Eval().setRetrieveValue(retrieve);
- for (ParameterWrapper parameter : inputParameters)
- {
- // need to create a new Eval each time, as input parameters may depend on others
- // NOTE: if Eval has additional user defined functions or unit parsers, that's not included here
- String id = parameter.getId();
- map.put(id.substring(1, id.length() - 1), () -> parameter.get().get(eval));
- }
- }
- /**
- * Parse model ID referrals.
- * @param scenario List<ScenarioType>; scenario
- * @param demand Demand; demand
- * @param eval Eval; expression evaluator.
- * @return map from ID to ID
- */
- public static final Map<String, String> parseModelIdReferral(final List<ScenarioType> scenario, final Demand demand,
- final Eval eval)
- {
- // TODO: use run to select scenario (probably outside this class, and accept a single Scenario
- Map<String, String> map = new LinkedHashMap<>();
- for (ModelIdReferralType modelIdReferral : demand.getModelIdReferral())
- {
- map.put(modelIdReferral.getId(), modelIdReferral.getModelId().get(eval));
- }
- // overwrite with scenario level ID referrals
- if (!scenario.isEmpty())
- {
- for (ModelIdReferralType modelIdReferral : scenario.get(0).getModelIdReferral())
- {
- map.put(modelIdReferral.getId(), modelIdReferral.getModelId().get(eval));
- }
- }
- return map;
- }
- /**
- * Generic scenario form for parsing.
- * <p>
- * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
- * <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
- */
- public static interface ScenariosWrapper
- {
- /**
- * Returns default parameters in generic form for parsing.
- * @return Iterable<ParameterWrapper>; default parameters in generic form for parsing.
- */
- Iterable<ParameterWrapper> getDefaultInputParameters();
- /**
- * Returns scenario parameters in generic form for parsing.
- * @return Iterable<ParameterWrapper>; scenario parameters in generic form for parsing.
- */
- Iterable<ParameterWrapper> getScenarioInputParameters();
- }
- /**
- * Generic parameters for for parsing.
- * <p>
- * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
- * <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
- * @param id String; id.
- * @param value ExpressionType<?>; value expression type.
- */
- public static record ParameterWrapper(String id, ExpressionType<?> value)
- implements Identifiable, Supplier<ExpressionType<?>>
- {
- /** {@inheritDoc} */
- @Override
- public String getId()
- {
- return this.id();
- }
- /** {@inheritDoc} */
- @Override
- public ExpressionType<?> get()
- {
- return this.value();
- }
- }
- /**
- * Wraps parameters to provide for expressions.
- * <p>
- * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
- * <br>
- * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
- * </p>
- * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
- */
- private static class ParameterMap implements RetrieveValue
- {
- /** Map of name to suppliers (constant or distribution). */
- private final Map<String, Supplier<?>> map;
- /** Set of currently looked up values, to detect circular dependency. */
- private final Set<String> lookingUp = new LinkedHashSet<>();
- /** More scenario input parameters. */
- private ParameterMap scenario;
- /**
- * Constructor.
- * @param map Map<String, Supplier<?>>; map that underlines input parameters.
- */
- public ParameterMap(final Map<String, Supplier<?>> map)
- {
- this.map = map;
- }
- /**
- * Set scenario input parameters.
- * @param scenario ParameterMap; parameter map of the scenario.
- */
- public void setScenarioMap(final ParameterMap scenario)
- {
- this.scenario = scenario;
- }
- /** {@inheritDoc} */
- @Override
- public Object lookup(final String name)
- {
- if (!this.lookingUp.add(name))
- {
- throw new CircularDependencyException("Parameter " + name + " is part of a circular dependency.");
- }
- Object value;
- if (this.scenario != null && this.scenario.map.containsKey(name))
- {
- value = this.scenario.map.get(name).get();
- }
- else if (this.map.containsKey(name))
- {
- value = this.map.get(name).get();
- }
- else
- {
- this.lookingUp.remove(name);
- throw new RuntimeException("Parameter " + name + " not available.");
- }
- this.lookingUp.remove(name);
- if (value instanceof Double)
- {
- return Dimensionless.instantiateSI((Double) value);
- }
- return value;
- }
- }
- }