From: Jussi Koskela Date: Wed, 1 Feb 2017 08:33:03 +0000 (+0200) Subject: Re-enable adding time variable to configuration X-Git-Tag: v1.29.0~7 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=a4fe01fb1b0c39afbf6eda87495c5e919ffed957;p=simantics%2Fsysdyn.git Re-enable adding time variable to configuration Missing time variable caused failure to run game experiments. Removal of time variable was committed accidentally. refs #7006 Change-Id: Ie927f63b016e8cc31708eba1a6305cce90dfc04b --- diff --git a/bundles/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java b/bundles/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java index 31e679ad..97d84943 100644 --- a/bundles/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java +++ b/bundles/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java @@ -1,586 +1,586 @@ -/******************************************************************************* - * Copyright (c) 2007, 2012, 2014 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.modelica; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; - -import org.simantics.sysdyn.representation.Book; -import org.simantics.sysdyn.representation.Configuration; -import org.simantics.sysdyn.representation.Dependency; -import org.simantics.sysdyn.representation.Enumeration; -import org.simantics.sysdyn.representation.IElement; -import org.simantics.sysdyn.representation.IndependentVariable; -import org.simantics.sysdyn.representation.Input; -import org.simantics.sysdyn.representation.Module; -import org.simantics.sysdyn.representation.ModuleType; -import org.simantics.sysdyn.representation.Sheet; -import org.simantics.sysdyn.representation.Stock; -import org.simantics.sysdyn.representation.Variable; -import org.simantics.sysdyn.representation.expressions.DelayExpression; -import org.simantics.sysdyn.representation.expressions.IExpression; - -/** - * ModelicaWriter writes Sysdyn model representations (objmap) into Modelica code. - * - * @author Teemu Lempinen - * @author Tuomas Miettinen - * - */ -public class ModelicaWriter { - - public static final String VAR_TIME = "time"; - public static final String VAR_START = "startTime"; - public static final String VAR_STOP = "stopTime"; - public static final String VAR_STEP = "timeStep"; - - /** - * Write a collection of configurations into a single Modelica code - * @param isGame - * - * @param Configurations Configurations, one main configuration and possible modules - * @return Complete Modelica code of a model - */ - public static String write(Collection _configurations, double startTime, double stopTime, double timeStep, boolean isGame, String omVersion) { - - ArrayList configurations = new ArrayList(_configurations); - Collections.sort(configurations, new Comparator() { - - boolean uses(Configuration o1, Configuration o2) { - ModuleType type = o2.getModuleType(); - if(type == null) return false; - for(IElement e : o1.getElements()) { - if(e instanceof Module) { - Module m = (Module)e; - if(m.getType().equals(type)) { - return true; - } - } - } - return false; - } - - @Override - public int compare(Configuration o1, Configuration o2) { - if(uses(o1, o2)) return 1; - else if(uses(o2, o1)) return -1; - else return 0; - } - - }); - - Configuration modelConf = null; - for(Configuration conf : configurations) { - if(conf.getModel() != null) { - modelConf = conf; - } - } - StringBuilder b = new StringBuilder(); - - int spreadsheetlocation = b.length(); - - String modelName = modelConf.getLabel().replace(" ", ""); - b.append("model " + modelName + "\n"); - - // Super class for enumerations - b.append("partial class Enumeration_class\n"); - b.append(" parameter Integer size;\n"); - b.append(" parameter Integer elements[:];\n"); - b.append("end Enumeration_class;\n\n"); - - // find out which delays are used in the model and create the - // necessary classes - List generated = new ArrayList(); - for (Configuration configuration : configurations) { - for (IElement element : configuration.getElements()) { - if (element instanceof IndependentVariable) { - IndependentVariable variable = (IndependentVariable)element; - for (IExpression expression : variable.getExpressions()) { - if (expression instanceof DelayExpression) { - DelayExpression delay = (DelayExpression)expression; - - int order = delay.getOrder(); - int[] dimensions = null; - - // TODO: is it cool to assume an expression is in the array - // shorthand form if the expression does not have an array range - // even though the variable has array indices? (if this - // assumption does not hold DelayExpression must be updated as well) - - if (expression.getArrayRange() == null) { - dimensions = variable.getDimensionArray(); - } - - // create the appropriate delay class if it has not - // been created already - - if (!generated.contains(getDelayName(order, dimensions))) { - b.append(getDelayClass(order, dimensions)); - b.append("\n"); - generated.add(getDelayName(order, dimensions)); - } - } - } - } - } - } - - HashSet sheetNames = new HashSet(); - for(Sheet sheet : getSpreadSheets(configurations)) - sheetNames.add(sheet.getModelicaName()); - - // write global time parameters (could be moved to writeConfiguration()) - b.append("// Simulation parameters\n"); - b.append("inner parameter Real ").append(VAR_START).append(" = ").append(startTime).append(";\n"); - b.append("inner parameter Real ").append(VAR_STOP).append(" = ").append(stopTime).append(";\n"); - b.append("inner parameter Real ").append(VAR_STEP).append(" = ").append(timeStep).append(";\n"); - b.append('\n'); - - // Write all module configurations to the declarations part (first) - for(Configuration conf : configurations) { - conf.setIsGameConfiguration(isGame); - if(!conf.equals(modelConf)) - writeConfiguration(conf, sheetNames, startTime, b); - } - - // Write model configuration last, so that equations-part does not contain module definitions - modelConf.setIsGameConfiguration(isGame); - writeConfiguration(modelConf, sheetNames, startTime, b); - - b.append("end " + modelName + ";\n\n"); - - // Insert spreadsheets - if(omVersion != null && omVersion.startsWith("1.9")) { - b.insert(spreadsheetlocation, getGlobalSpreadSheets(configurations)); - } else { - b.append(getGlobalSpreadSheets(configurations)); - } - - return b.toString(); - } - - /** - * Get all spreadsheets that are found in the model - * @param configurations - * @return - */ - private static List getSpreadSheets(Collection configurations) { - for(Configuration conf : configurations) { - if(conf.getModel() != null) { - for(IElement e : conf.getElements()) { - if(e instanceof Book) { - return ((Book)e).getSheets(); - } - } - } - } - return Collections.emptyList(); - } - - /** - * - */ - private static String getGlobalSpreadSheets(Collection configurations) { - StringBuilder sheets = new StringBuilder(); - for(Configuration conf : configurations) { - if(conf.getModel() != null) { - for(IElement e : conf.getElements()) { - if(e instanceof Book) { - return ((Book)e).getBook(); - } - } - } - } - - return sheets.toString(); - } - - /** - * Write a single configuration to a given string builder - * - * @param configuration Model or module configuration - * @param b String builder - */ - private static void writeConfiguration(Configuration configuration, HashSet sheetNames, double startTime, StringBuilder b) { - boolean defTime = false; - String app; - - // Lists for storing different configuration elements - ArrayList variables = new ArrayList(); - ArrayList inputs = new ArrayList(); - ArrayList modules = new ArrayList(); - ArrayList stocks = new ArrayList(); - ArrayList enumerations = new ArrayList(); - ArrayList inputDependencies = new ArrayList(); - ArrayList outputDependencies = new ArrayList(); - HashMap> moduleInputs = new HashMap>(); - - // Initialize lists - for(IElement element : configuration.getElements()) { - if(element instanceof IndependentVariable) { - // Normal variable - variables.add((IndependentVariable)element); - if(element instanceof Stock) - // Stock - stocks.add((Stock)element); - } else if (element instanceof Module) { - // Module - Module m = (Module)element; - modules.add(m); - moduleInputs.put(m.getModelicaName(), new ArrayList()); - for(IElement e : m.getType().getConfiguration().getElements()) - // Inputs inside the module - if(e instanceof Input && !((Input)e).isHeadOfDependency()) { - moduleInputs.get(m.getModelicaName()).add((Input)e); - } - } else if (element instanceof Input) { - // Input variables - inputs.add((Input)element); - } else if (element instanceof Enumeration) { - // Enumerations - enumerations.add((Enumeration)element); - } else if (element instanceof Dependency) { - Dependency dependency = (Dependency)element; - if(dependency.getHead() instanceof Module) { - // References given to child modules - outputDependencies.add(dependency); - } else if(dependency.getTail() instanceof Module){ - // References from child modules - inputDependencies.add(dependency); - } - } - } - - // Setup input references. (Input, String reference to another variable) - HashMap inputReferences = new HashMap(); - setupInputReferences(inputReferences, inputDependencies); - - - // If the configuration is model configuration, use model name. Otherwise, use configuration name. - ModuleType mt = configuration.getModuleType(); - - // className == null, if this is a model configuration. model configuration start and end are written in ModelicaWriter.write - String className = mt != null ? (mt.getModelicaName()) : null; - - if(className != null) - b.append("class "+className+"\n"); - - // Add spreadsheets to all modules and model. Model is "inner" and modules "outer" - String globalStatus = mt != null ? "outer" : "inner"; - for(String sheetName : sheetNames) - b.append(" " + globalStatus + " " + sheetName + "_class" + " "+ sheetName + ";\n"); - - if(!enumerations.isEmpty()) { - b.append("// Enumeration definitions\n"); - for(Enumeration e : enumerations) { - b.append(e.getDeclaration()); - } - } - - if (mt != null) { - b.append("// References to simulation parameters\n"); - b.append(" outer Real ").append(VAR_START).append(";\n"); - b.append(" outer Real ").append(VAR_STOP).append(";\n"); - b.append(" outer Real ").append(VAR_STEP).append(";\n"); - } - - b.append("// Variable definitions\n"); - for(IndependentVariable variable : variables) { - app = variable.getDeclaration(); - if (app != null) { - b.append(app); - } - } - - if(defTime) { - // Time variable for FMU (game) simulations - if(configuration.isGameConfiguration()) { - if(configuration.getModel() != null) - // Parameter for model root. Values changed in FMU simulator - b.append(" parameter Real time = " + startTime + ";\n"); - else - // Continuous variable for module instances - b.append(" Real time;\n"); - - } - } - - if(!modules.isEmpty()) { - b.append("// Module definitions\n"); - for(Module m : modules) { - b.append(m.getDeclaration()); - } - } - - - // Input definitions - inputDefinitions(b, configuration, inputs, inputReferences); - - boolean initialEquations = false; - for(Stock stock : stocks) { - app = stock.getInitialEquation(); - if (app != null) { - if(initialEquations == false) { - initialEquations = true; - b.append("// Initial Equations\n"); - b.append("initial equation\n"); - } - b.append(app); - } - } - - boolean equation = false; - b.append("// Equations\n"); - for(IndependentVariable variable : variables) { - app = variable.getEquation(); - if (app != null) { - if(!equation) { - b.append("equation\n"); - equation = true; - } - - b.append(app); - } - } - - // If "equation" has not been added but there are still equations to be defined, add "equation" - if(!equation && (!inputReferences.isEmpty() || !outputDependencies.isEmpty() || - !moduleInputs.isEmpty() || !modules.isEmpty())) - b.append("equation\n"); - - // Continuous input references - continuousInputReferences(b, inputReferences); - - b.append("// Outputs\n"); - for(Dependency dependency : outputDependencies) { - Variable variable = (Variable)dependency.getTail(); - Module module = (Module)dependency.getHead(); - Input reference = (Input)dependency.refersTo(); - if(reference != null && reference.getName() != null && (reference.getVariability() == null || reference.getVariability().isEmpty())) { - b.append(" " + module.getModelicaName() + "." + reference.getModelicaName() + " = " + variable.getModelicaName() + ";\n"); - moduleInputs.get(module.getModelicaName()).remove(reference); - } - } - - b.append("// Default values for inputs in modules\n"); - for(String moduleLabel : moduleInputs.keySet()) { - for(Input input : moduleInputs.get(moduleLabel)) { - if(input.getVariability() == null || input.getVariability().isEmpty()) - b.append(" " + moduleLabel + "." + input.getModelicaName() + " = " + input.getDefaultInputValue(moduleLabel) + ";\n"); - } - } - - if(defTime) { - if(configuration.isGameConfiguration() && !modules.isEmpty()) { - b.append("// Time values for module\n"); - for(Module m : modules) { - b.append(" " + m.getModelicaName() + ".time = time;\n"); - } - } - } - - if(className != null) - b.append("end ").append(className).append(";\n\n"); - - } - - /** - * Define continuous input references - * @param b String builder - * @param inputReferences Input references - */ - private static void continuousInputReferences(StringBuilder b, HashMap inputReferences) { - b.append("// Inputs\n"); - for(Input i : inputReferences.keySet()) { - if(i.getVariability() == null || i.getVariability().isEmpty()) { - // Define only continuous variables here - b.append(" " + i.getModelicaName() + " = " + inputReferences.get(i)); - } - } - } - - /** - * Setup input references for all inputs that are defined in child modules - * - * @param inputReferences Map containing the references - * @param inputDependencies List of input dependencies - */ - private static void setupInputReferences(HashMap inputReferences, ArrayList inputDependencies) { - for(Dependency dependency : inputDependencies) { - Input input = (Input)dependency.getHead(); - Module module = (Module)dependency.getTail(); - Variable reference = (Variable)dependency.refersTo(); - String expression; - // If reference exists, use reference name. Otherwise, use default value. - if(reference != null && reference.getName() != null) - expression = module.getModelicaName() + "." + reference.getModelicaName() + ";\n"; - - else - expression = input.getDefaultInputValue() + ";\n"; - - inputReferences.put(input, expression); - } - } - - /** - * Build input definitions - * - * @param b String builder - * @param configuration Module configuration - * @param inputs All inputs of this module - * @param inputReferences - */ - private static void inputDefinitions(StringBuilder b, Configuration configuration, ArrayList inputs, HashMap inputReferences) { - if(inputs.isEmpty()) - return; - - b.append("// Input definitions\n"); - for(Input i : inputs) { - if(i.getVariability() != null && !i.getVariability().isEmpty()) { - // Input is NOT continuous - if(inputReferences.containsKey(i)) { - // Input is defined in a child module - String declaration = i.getDeclaration(); - declaration = declaration.substring(0, declaration.length() - 2); // remove ";\n" from the end - b.append(declaration + " = " + inputReferences.get(i)); - } else { - // Input is not defined in a child module, use default value - b.append(i.getDeclarationWithValue()); - } - } else if(configuration.getModel() != null && !i.isHeadOfDependency()) { - /* - * Input is in the top of the hierarchy, - * and it does not get value from anywhere else. - * => Declare it wit its default value - */ - b.append(i.getDeclarationWithValue()); - } else { - // Continuous => Parent module takes care of declaring a value for the input - b.append(i.getDeclaration()); - } - } - } - - public String escape(String name) { - return name.replace(' ', '_'); - } - - public static final String DELAY_TIME = "delayTime"; - public static final String DELAY_INITIAL = "initialValue"; - - private static String getDelayClass(int order, int...dimensions) { - boolean array = dimensions != null && dimensions.length > 0; - - StringBuilder buffer = new StringBuilder(); - - buffer.append("class ").append(getDelayName(order, dimensions)).append("\n"); - - // variable block - - // (possibly) continuous auxiliary variable - buffer.append('\t') - .append(getReal("DL")).append(";\n"); - // (possibly) continuous delay time - buffer.append('\t') - .append(getReal(DELAY_TIME)).append(";\n"); - // (possibly) continuous initial value - buffer.append('\t') - .append(getReal(DELAY_INITIAL, dimensions)).append(";\n"); - - // first valve - buffer.append('\t') - .append(getReal(getDelayValve(0), dimensions)).append(";\n"); - - // stocks and valves, valves are delayed values of the variable - for (int i = 1; i <= order; i++) { - buffer.append('\t') - .append(getReal("LV"+i, dimensions)).append(' ') - .append("(" + (array ? "each " : "") + "fixed=false)").append(";\n"); - buffer.append('\t') - .append(getReal(getDelayValve(i), dimensions)).append(";\n"); - } - - // initial equation block - buffer.append("initial equation\n"); - - // Each stock gets the same initial value - for (int i = 1; i <= order; i++) { - buffer.append('\t') - .append("LV"+i) - .append(" = ") - .append("DL" + (array ? " .* " : " * ") + DELAY_INITIAL) - .append(";\n"); - } - - // equation block - buffer.append("equation\n"); - - buffer.append('\t') - .append("DL") - .append(" = ") - .append(DELAY_TIME +" / " + order) - .append(";\n"); - - // valves and stocks - for (int i = 1; i <= order; i++) { - buffer.append('\t') - .append("der(LV"+i + ")") - .append(" = ") - .append("-" + getDelayValve(i) + (array ? " .+ " : " + ") + getDelayValve(i-1)) - .append(";\n"); - buffer.append('\t') - .append(getDelayValve(i)) - .append(" = ") - .append("LV"+i + (array ? " ./ " : " / ") + "DL") - .append(";\n"); - } - - buffer.append("end ").append(getDelayName(order, dimensions)).append(";\n"); - - return buffer.toString(); - } - - private static String getReal(String name, int...dims) { - StringBuilder buffer = new StringBuilder(); - buffer.append("Real ").append(name); - if (dims != null && dims.length > 0) { - buffer.append('['); - for (int i = 0; i < dims.length; i++) { - if (i > 0) buffer.append(','); - buffer.append(dims[i]); - } - buffer.append(']'); - } - return buffer.toString(); - } - - public static String getDelayName(int order, int...dims) { - StringBuilder buffer = new StringBuilder(); - buffer.append("o_").append(order).append('_'); - if (dims != null && dims.length > 0) { - buffer.append("d_"); - for (int dim : dims) buffer.append(dim).append('_'); - } - buffer.append("delay"); - return buffer.toString(); - } - - public static String getDelayValve(int order) { - return "delay"+order; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2012, 2014 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.modelica; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import org.simantics.sysdyn.representation.Book; +import org.simantics.sysdyn.representation.Configuration; +import org.simantics.sysdyn.representation.Dependency; +import org.simantics.sysdyn.representation.Enumeration; +import org.simantics.sysdyn.representation.IElement; +import org.simantics.sysdyn.representation.IndependentVariable; +import org.simantics.sysdyn.representation.Input; +import org.simantics.sysdyn.representation.Module; +import org.simantics.sysdyn.representation.ModuleType; +import org.simantics.sysdyn.representation.Sheet; +import org.simantics.sysdyn.representation.Stock; +import org.simantics.sysdyn.representation.Variable; +import org.simantics.sysdyn.representation.expressions.DelayExpression; +import org.simantics.sysdyn.representation.expressions.IExpression; + +/** + * ModelicaWriter writes Sysdyn model representations (objmap) into Modelica code. + * + * @author Teemu Lempinen + * @author Tuomas Miettinen + * + */ +public class ModelicaWriter { + + public static final String VAR_TIME = "time"; + public static final String VAR_START = "startTime"; + public static final String VAR_STOP = "stopTime"; + public static final String VAR_STEP = "timeStep"; + + /** + * Write a collection of configurations into a single Modelica code + * @param isGame + * + * @param Configurations Configurations, one main configuration and possible modules + * @return Complete Modelica code of a model + */ + public static String write(Collection _configurations, double startTime, double stopTime, double timeStep, boolean isGame, String omVersion) { + + ArrayList configurations = new ArrayList(_configurations); + Collections.sort(configurations, new Comparator() { + + boolean uses(Configuration o1, Configuration o2) { + ModuleType type = o2.getModuleType(); + if(type == null) return false; + for(IElement e : o1.getElements()) { + if(e instanceof Module) { + Module m = (Module)e; + if(m.getType().equals(type)) { + return true; + } + } + } + return false; + } + + @Override + public int compare(Configuration o1, Configuration o2) { + if(uses(o1, o2)) return 1; + else if(uses(o2, o1)) return -1; + else return 0; + } + + }); + + Configuration modelConf = null; + for(Configuration conf : configurations) { + if(conf.getModel() != null) { + modelConf = conf; + } + } + StringBuilder b = new StringBuilder(); + + int spreadsheetlocation = b.length(); + + String modelName = modelConf.getLabel().replace(" ", ""); + b.append("model " + modelName + "\n"); + + // Super class for enumerations + b.append("partial class Enumeration_class\n"); + b.append(" parameter Integer size;\n"); + b.append(" parameter Integer elements[:];\n"); + b.append("end Enumeration_class;\n\n"); + + // find out which delays are used in the model and create the + // necessary classes + List generated = new ArrayList(); + for (Configuration configuration : configurations) { + for (IElement element : configuration.getElements()) { + if (element instanceof IndependentVariable) { + IndependentVariable variable = (IndependentVariable)element; + for (IExpression expression : variable.getExpressions()) { + if (expression instanceof DelayExpression) { + DelayExpression delay = (DelayExpression)expression; + + int order = delay.getOrder(); + int[] dimensions = null; + + // TODO: is it cool to assume an expression is in the array + // shorthand form if the expression does not have an array range + // even though the variable has array indices? (if this + // assumption does not hold DelayExpression must be updated as well) + + if (expression.getArrayRange() == null) { + dimensions = variable.getDimensionArray(); + } + + // create the appropriate delay class if it has not + // been created already + + if (!generated.contains(getDelayName(order, dimensions))) { + b.append(getDelayClass(order, dimensions)); + b.append("\n"); + generated.add(getDelayName(order, dimensions)); + } + } + } + } + } + } + + HashSet sheetNames = new HashSet(); + for(Sheet sheet : getSpreadSheets(configurations)) + sheetNames.add(sheet.getModelicaName()); + + // write global time parameters (could be moved to writeConfiguration()) + b.append("// Simulation parameters\n"); + b.append("inner parameter Real ").append(VAR_START).append(" = ").append(startTime).append(";\n"); + b.append("inner parameter Real ").append(VAR_STOP).append(" = ").append(stopTime).append(";\n"); + b.append("inner parameter Real ").append(VAR_STEP).append(" = ").append(timeStep).append(";\n"); + b.append('\n'); + + // Write all module configurations to the declarations part (first) + for(Configuration conf : configurations) { + conf.setIsGameConfiguration(isGame); + if(!conf.equals(modelConf)) + writeConfiguration(conf, sheetNames, startTime, b); + } + + // Write model configuration last, so that equations-part does not contain module definitions + modelConf.setIsGameConfiguration(isGame); + writeConfiguration(modelConf, sheetNames, startTime, b); + + b.append("end " + modelName + ";\n\n"); + + // Insert spreadsheets + if(omVersion != null && omVersion.startsWith("1.9")) { + b.insert(spreadsheetlocation, getGlobalSpreadSheets(configurations)); + } else { + b.append(getGlobalSpreadSheets(configurations)); + } + + return b.toString(); + } + + /** + * Get all spreadsheets that are found in the model + * @param configurations + * @return + */ + private static List getSpreadSheets(Collection configurations) { + for(Configuration conf : configurations) { + if(conf.getModel() != null) { + for(IElement e : conf.getElements()) { + if(e instanceof Book) { + return ((Book)e).getSheets(); + } + } + } + } + return Collections.emptyList(); + } + + /** + * + */ + private static String getGlobalSpreadSheets(Collection configurations) { + StringBuilder sheets = new StringBuilder(); + for(Configuration conf : configurations) { + if(conf.getModel() != null) { + for(IElement e : conf.getElements()) { + if(e instanceof Book) { + return ((Book)e).getBook(); + } + } + } + } + + return sheets.toString(); + } + + /** + * Write a single configuration to a given string builder + * + * @param configuration Model or module configuration + * @param b String builder + */ + private static void writeConfiguration(Configuration configuration, HashSet sheetNames, double startTime, StringBuilder b) { + boolean defTime = true; + String app; + + // Lists for storing different configuration elements + ArrayList variables = new ArrayList(); + ArrayList inputs = new ArrayList(); + ArrayList modules = new ArrayList(); + ArrayList stocks = new ArrayList(); + ArrayList enumerations = new ArrayList(); + ArrayList inputDependencies = new ArrayList(); + ArrayList outputDependencies = new ArrayList(); + HashMap> moduleInputs = new HashMap>(); + + // Initialize lists + for(IElement element : configuration.getElements()) { + if(element instanceof IndependentVariable) { + // Normal variable + variables.add((IndependentVariable)element); + if(element instanceof Stock) + // Stock + stocks.add((Stock)element); + } else if (element instanceof Module) { + // Module + Module m = (Module)element; + modules.add(m); + moduleInputs.put(m.getModelicaName(), new ArrayList()); + for(IElement e : m.getType().getConfiguration().getElements()) + // Inputs inside the module + if(e instanceof Input && !((Input)e).isHeadOfDependency()) { + moduleInputs.get(m.getModelicaName()).add((Input)e); + } + } else if (element instanceof Input) { + // Input variables + inputs.add((Input)element); + } else if (element instanceof Enumeration) { + // Enumerations + enumerations.add((Enumeration)element); + } else if (element instanceof Dependency) { + Dependency dependency = (Dependency)element; + if(dependency.getHead() instanceof Module) { + // References given to child modules + outputDependencies.add(dependency); + } else if(dependency.getTail() instanceof Module){ + // References from child modules + inputDependencies.add(dependency); + } + } + } + + // Setup input references. (Input, String reference to another variable) + HashMap inputReferences = new HashMap(); + setupInputReferences(inputReferences, inputDependencies); + + + // If the configuration is model configuration, use model name. Otherwise, use configuration name. + ModuleType mt = configuration.getModuleType(); + + // className == null, if this is a model configuration. model configuration start and end are written in ModelicaWriter.write + String className = mt != null ? (mt.getModelicaName()) : null; + + if(className != null) + b.append("class "+className+"\n"); + + // Add spreadsheets to all modules and model. Model is "inner" and modules "outer" + String globalStatus = mt != null ? "outer" : "inner"; + for(String sheetName : sheetNames) + b.append(" " + globalStatus + " " + sheetName + "_class" + " "+ sheetName + ";\n"); + + if(!enumerations.isEmpty()) { + b.append("// Enumeration definitions\n"); + for(Enumeration e : enumerations) { + b.append(e.getDeclaration()); + } + } + + if (mt != null) { + b.append("// References to simulation parameters\n"); + b.append(" outer Real ").append(VAR_START).append(";\n"); + b.append(" outer Real ").append(VAR_STOP).append(";\n"); + b.append(" outer Real ").append(VAR_STEP).append(";\n"); + } + + b.append("// Variable definitions\n"); + for(IndependentVariable variable : variables) { + app = variable.getDeclaration(); + if (app != null) { + b.append(app); + } + } + + if(defTime) { + // Time variable for FMU (game) simulations + if(configuration.isGameConfiguration()) { + if(configuration.getModel() != null) + // Parameter for model root. Values changed in FMU simulator + b.append(" parameter Real time = " + startTime + ";\n"); + else + // Continuous variable for module instances + b.append(" Real time;\n"); + + } + } + + if(!modules.isEmpty()) { + b.append("// Module definitions\n"); + for(Module m : modules) { + b.append(m.getDeclaration()); + } + } + + + // Input definitions + inputDefinitions(b, configuration, inputs, inputReferences); + + boolean initialEquations = false; + for(Stock stock : stocks) { + app = stock.getInitialEquation(); + if (app != null) { + if(initialEquations == false) { + initialEquations = true; + b.append("// Initial Equations\n"); + b.append("initial equation\n"); + } + b.append(app); + } + } + + boolean equation = false; + b.append("// Equations\n"); + for(IndependentVariable variable : variables) { + app = variable.getEquation(); + if (app != null) { + if(!equation) { + b.append("equation\n"); + equation = true; + } + + b.append(app); + } + } + + // If "equation" has not been added but there are still equations to be defined, add "equation" + if(!equation && (!inputReferences.isEmpty() || !outputDependencies.isEmpty() || + !moduleInputs.isEmpty() || !modules.isEmpty())) + b.append("equation\n"); + + // Continuous input references + continuousInputReferences(b, inputReferences); + + b.append("// Outputs\n"); + for(Dependency dependency : outputDependencies) { + Variable variable = (Variable)dependency.getTail(); + Module module = (Module)dependency.getHead(); + Input reference = (Input)dependency.refersTo(); + if(reference != null && reference.getName() != null && (reference.getVariability() == null || reference.getVariability().isEmpty())) { + b.append(" " + module.getModelicaName() + "." + reference.getModelicaName() + " = " + variable.getModelicaName() + ";\n"); + moduleInputs.get(module.getModelicaName()).remove(reference); + } + } + + b.append("// Default values for inputs in modules\n"); + for(String moduleLabel : moduleInputs.keySet()) { + for(Input input : moduleInputs.get(moduleLabel)) { + if(input.getVariability() == null || input.getVariability().isEmpty()) + b.append(" " + moduleLabel + "." + input.getModelicaName() + " = " + input.getDefaultInputValue(moduleLabel) + ";\n"); + } + } + + if(defTime) { + if(configuration.isGameConfiguration() && !modules.isEmpty()) { + b.append("// Time values for module\n"); + for(Module m : modules) { + b.append(" " + m.getModelicaName() + ".time = time;\n"); + } + } + } + + if(className != null) + b.append("end ").append(className).append(";\n\n"); + + } + + /** + * Define continuous input references + * @param b String builder + * @param inputReferences Input references + */ + private static void continuousInputReferences(StringBuilder b, HashMap inputReferences) { + b.append("// Inputs\n"); + for(Input i : inputReferences.keySet()) { + if(i.getVariability() == null || i.getVariability().isEmpty()) { + // Define only continuous variables here + b.append(" " + i.getModelicaName() + " = " + inputReferences.get(i)); + } + } + } + + /** + * Setup input references for all inputs that are defined in child modules + * + * @param inputReferences Map containing the references + * @param inputDependencies List of input dependencies + */ + private static void setupInputReferences(HashMap inputReferences, ArrayList inputDependencies) { + for(Dependency dependency : inputDependencies) { + Input input = (Input)dependency.getHead(); + Module module = (Module)dependency.getTail(); + Variable reference = (Variable)dependency.refersTo(); + String expression; + // If reference exists, use reference name. Otherwise, use default value. + if(reference != null && reference.getName() != null) + expression = module.getModelicaName() + "." + reference.getModelicaName() + ";\n"; + + else + expression = input.getDefaultInputValue() + ";\n"; + + inputReferences.put(input, expression); + } + } + + /** + * Build input definitions + * + * @param b String builder + * @param configuration Module configuration + * @param inputs All inputs of this module + * @param inputReferences + */ + private static void inputDefinitions(StringBuilder b, Configuration configuration, ArrayList inputs, HashMap inputReferences) { + if(inputs.isEmpty()) + return; + + b.append("// Input definitions\n"); + for(Input i : inputs) { + if(i.getVariability() != null && !i.getVariability().isEmpty()) { + // Input is NOT continuous + if(inputReferences.containsKey(i)) { + // Input is defined in a child module + String declaration = i.getDeclaration(); + declaration = declaration.substring(0, declaration.length() - 2); // remove ";\n" from the end + b.append(declaration + " = " + inputReferences.get(i)); + } else { + // Input is not defined in a child module, use default value + b.append(i.getDeclarationWithValue()); + } + } else if(configuration.getModel() != null && !i.isHeadOfDependency()) { + /* + * Input is in the top of the hierarchy, + * and it does not get value from anywhere else. + * => Declare it wit its default value + */ + b.append(i.getDeclarationWithValue()); + } else { + // Continuous => Parent module takes care of declaring a value for the input + b.append(i.getDeclaration()); + } + } + } + + public String escape(String name) { + return name.replace(' ', '_'); + } + + public static final String DELAY_TIME = "delayTime"; + public static final String DELAY_INITIAL = "initialValue"; + + private static String getDelayClass(int order, int...dimensions) { + boolean array = dimensions != null && dimensions.length > 0; + + StringBuilder buffer = new StringBuilder(); + + buffer.append("class ").append(getDelayName(order, dimensions)).append("\n"); + + // variable block + + // (possibly) continuous auxiliary variable + buffer.append('\t') + .append(getReal("DL")).append(";\n"); + // (possibly) continuous delay time + buffer.append('\t') + .append(getReal(DELAY_TIME)).append(";\n"); + // (possibly) continuous initial value + buffer.append('\t') + .append(getReal(DELAY_INITIAL, dimensions)).append(";\n"); + + // first valve + buffer.append('\t') + .append(getReal(getDelayValve(0), dimensions)).append(";\n"); + + // stocks and valves, valves are delayed values of the variable + for (int i = 1; i <= order; i++) { + buffer.append('\t') + .append(getReal("LV"+i, dimensions)).append(' ') + .append("(" + (array ? "each " : "") + "fixed=false)").append(";\n"); + buffer.append('\t') + .append(getReal(getDelayValve(i), dimensions)).append(";\n"); + } + + // initial equation block + buffer.append("initial equation\n"); + + // Each stock gets the same initial value + for (int i = 1; i <= order; i++) { + buffer.append('\t') + .append("LV"+i) + .append(" = ") + .append("DL" + (array ? " .* " : " * ") + DELAY_INITIAL) + .append(";\n"); + } + + // equation block + buffer.append("equation\n"); + + buffer.append('\t') + .append("DL") + .append(" = ") + .append(DELAY_TIME +" / " + order) + .append(";\n"); + + // valves and stocks + for (int i = 1; i <= order; i++) { + buffer.append('\t') + .append("der(LV"+i + ")") + .append(" = ") + .append("-" + getDelayValve(i) + (array ? " .+ " : " + ") + getDelayValve(i-1)) + .append(";\n"); + buffer.append('\t') + .append(getDelayValve(i)) + .append(" = ") + .append("LV"+i + (array ? " ./ " : " / ") + "DL") + .append(";\n"); + } + + buffer.append("end ").append(getDelayName(order, dimensions)).append(";\n"); + + return buffer.toString(); + } + + private static String getReal(String name, int...dims) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Real ").append(name); + if (dims != null && dims.length > 0) { + buffer.append('['); + for (int i = 0; i < dims.length; i++) { + if (i > 0) buffer.append(','); + buffer.append(dims[i]); + } + buffer.append(']'); + } + return buffer.toString(); + } + + public static String getDelayName(int order, int...dims) { + StringBuilder buffer = new StringBuilder(); + buffer.append("o_").append(order).append('_'); + if (dims != null && dims.length > 0) { + buffer.append("d_"); + for (int dim : dims) buffer.append(dim).append('_'); + } + buffer.append("delay"); + return buffer.toString(); + } + + public static String getDelayValve(int order) { + return "delay"+order; + } + +}