Commit 864948ae authored by Malte Heithoff's avatar Malte Heithoff
Browse files

EquationSystem Generator and DAECPP Implementation

parent 847f06e4
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.lang.monticar.generator.cpp.loopSolver;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAPortInstanceSymbol;
import de.monticore.lang.monticar.generator.cmake.CMakeFindModule;
import de.monticore.lang.monticar.semantics.helper.NameHelper;
import org.apache.commons.lang3.SystemUtils;
import java.util.*;
public class CPPEquationSystemHelper {
public static String getNameOfPortOfComponent(EMAPortInstanceSymbol port) {
String componentName = getNameOfComponent(port.getComponentInstance());
return String.join(".", componentName, port.getName());
}
public static String getNameOfPort(EMAPortInstanceSymbol port) {
return NameHelper.replaceWithUnderScore(NameHelper.calculateFullQualifiedNameOf(port));
}
public static String getNameOfComponent(EMAComponentInstanceSymbol component) {
return NameHelper.replaceWithUnderScore(NameHelper.calculateFullQualifiedNameOf(component));
}
}
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.lang.monticar.generator.cpp.loopSolver;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAComponentInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.instanceStructure.EMAPortInstanceSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarcmath._symboltable.math.symbols.*;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarcmath._symboltable.math.visitor.CopyEMAMMathExpressionSymbol;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarcmath._symboltable.math.visitor.EMAMMathExpressionSymbolParentAwareVisitor;
import de.monticore.lang.math._symboltable.expression.MathArithmeticExpressionSymbol;
import de.monticore.lang.math._symboltable.expression.MathExpressionSymbol;
import de.monticore.lang.math._symboltable.expression.MathNameExpressionSymbol;
import de.monticore.lang.math._symboltable.expression.MathParenthesisExpressionSymbol;
import de.monticore.lang.math._symboltable.matrix.MathMatrixNameExpressionSymbol;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ViewModelBase;
import de.monticore.lang.monticar.semantics.helper.NameHelper;
import de.monticore.lang.monticar.semantics.loops.analyze.SpecificationConverter;
import de.monticore.lang.monticar.semantics.loops.detection.EMAEquationSystem;
import de.monticore.lang.monticar.semantics.resolve.SymbolTableHelper;
import de.monticore.lang.monticar.semantics.util.math.NameReplacer;
import de.se_rwth.commons.logging.Log;
import javafx.beans.binding.MapExpression;
import java.util.*;
public class EquationSystemViewModel extends ViewModelBase {
private String name;
private List<String> variables = new ArrayList<>();
private List<String> initialValues = new ArrayList<>();
private List<String> massMatrixDiag = new ArrayList<>();
private List<String> function = new ArrayList<>();
private List<String> inports = new ArrayList<>();
private List<EMAComponentInstanceSymbol> algebraicComponents = new ArrayList<>();
public String getName() {
return name;
}
public List<String> getVariables() {
return variables;
}
public List<String> getInitialValues() {
return initialValues;
}
public List<String> getMassMatrixDiag() {
return massMatrixDiag;
}
public List<String> getFunction() {
return function;
}
public List<String> getInports() {
return inports;
}
public List<EMAComponentInstanceSymbol> getAlgebraicComponents() {
return algebraicComponents;
}
public EquationSystemViewModel (EMAEquationSystem eqs) {
this.name = eqs.getName();
Map<String, String> inportMapping = new HashMap<>();
for (EMAPortInstanceSymbol inport : eqs.getInports()) {
Optional<EMAPortInstanceSymbol> source = eqs.getAtomicSourceOf(inport);
String nameOfPort = CPPEquationSystemHelper.getNameOfPort(source.get());
inports.add(nameOfPort);
inportMapping.put(NameHelper.calculateFullQualifiedNameOf(source.get()), nameOfPort);
}
Map<String, Integer> variableIndex = new HashMap<>();
Integer currentIndex = 0;
for (EMAComponentInstanceSymbol component : eqs.getComponentInstanceSymbols()) {
Collection<EMAMInitialValueSymbol> initialValues = SpecificationConverter.getInitialValues(eqs, component);
Collection<EMAMInitialGuessSymbol> initialGuesses = SpecificationConverter.getInitialGuesses(eqs, component);
// getVariables adds only ports, if there is no specification available, consider renaming getVariables
for (EMAMSymbolicVariableSymbol variable : SpecificationConverter.getVariables(eqs, component)) {
variableIndex.put(variable.getName(), currentIndex++);
this.variables.add(NameHelper.replaceWithUnderScore(variable.getName()));
Optional<EMAMInitialValueSymbol> initialValue = initialValues.stream()
.filter(i -> i.getNameToAccess().equals(variable.getName()))
.findFirst();
Optional<EMAMInitialGuessSymbol> initialGuess = initialGuesses.stream()
.filter(i -> i.getNameToAccess().equals(variable.getName()))
.findFirst();
if (initialValue.isPresent()) {
this.initialValues.add(initialValue.get().getValue().getTextualRepresentation());
} else if (initialGuess.isPresent()) {
this.initialValues.add(initialGuess.get().getValue().getTextualRepresentation());
} else {
this.initialValues.add("0");
}
}
}
massMatrixDiag = new ArrayList<>(variables.size());
function = new ArrayList<>(variables.size());
for (int i = 0; i < variables.size(); i++) {
massMatrixDiag.add(null);
function.add(null);
}
Set<Integer> usedIndeces = new HashSet<>();
List<EMAMEquationSymbol> algebraicEquations = new ArrayList<>();
for (EMAComponentInstanceSymbol component : eqs.getComponentInstanceSymbols()) {
Collection<EMAMEquationSymbol> equations = SpecificationConverter.getEquations(eqs, component);
if (!equations.isEmpty()) {
for (EMAMEquationSymbol equation : equations) {
Optional<String> differentialVariable = CalculateDifferentialVariable.getDifferentialVariable(equation);
if (differentialVariable.isPresent()) {
Integer index = variableIndex.get(differentialVariable.get());
massMatrixDiag.set(index, "1");
function.set(index, getFunction(equation.getRightExpression(), variableIndex, inportMapping));
} else
algebraicEquations.add(equation);
}
} else {
algebraicComponents.add(component); // Integrate and Derivative should have been caclulated equations
}
}
currentIndex = 0;
for (EMAMEquationSymbol algebraicEquation : algebraicEquations) {
currentIndex = nextIndex(usedIndeces, currentIndex);
MathArithmeticExpressionSymbol minus = new MathArithmeticExpressionSymbol();
minus.setOperator("-");
minus.setLeftExpression(algebraicEquation.getLeftExpression());
minus.setRightExpression(new MathParenthesisExpressionSymbol(algebraicEquation.getRightExpression()));
massMatrixDiag.set(currentIndex, "0");
function.set(currentIndex, getFunction(minus, variableIndex, inportMapping));
}
for (EMAComponentInstanceSymbol algebraicComponent : algebraicComponents) {
Collection<EMAMSymbolicVariableSymbol> portVariables = SpecificationConverter.getVariables(eqs, algebraicComponent);
for (EMAMSymbolicVariableSymbol portVariable : portVariables) {
currentIndex = nextIndex(usedIndeces, currentIndex);
massMatrixDiag.set(currentIndex, "0");
function.set(currentIndex,
String.join("-", getFunction(portVariable, variableIndex, inportMapping),
CPPEquationSystemHelper.getNameOfPortOfComponent(portVariable.getPort().get())));
}
}
}
private String getFunction(MathExpressionSymbol symbol,
Map<String, Integer> variableIndex, Map<String, String> inportMapping) {
MathExpressionSymbol copy = CopyEMAMMathExpressionSymbol.copy(symbol);
NameReplacer.replaceNames(copy, s -> {
if (variableIndex.containsKey(s)) return String.format("x[%s]", variableIndex.get(s));
if (inportMapping.containsKey(s)) return inportMapping.get(s);
return s;
});
return copy.getTextualRepresentation();
}
private static Integer nextIndex(Set<Integer> usedIndeces, Integer currentIndex) {
while (usedIndeces.contains(currentIndex))
currentIndex++;
usedIndeces.add(currentIndex);
return currentIndex;
}
private static class CalculateDifferentialVariable implements EMAMMathExpressionSymbolParentAwareVisitor {
private Optional<String> differentialVariable = Optional.empty();
public static Optional<String> getDifferentialVariable(EMAMEquationSymbol equation) {
CalculateDifferentialVariable calc = new CalculateDifferentialVariable();
calc.handle(equation);
return calc.differentialVariable;
}
@Override
public void visit(MathMatrixNameExpressionSymbol node) {
if (node.getNameToAccess().equals(de.monticore.lang.monticar.semantics.Options.derivativeOperatorName)) {
if(! (getParents().peek() instanceof EMAMEquationSymbol))
Log.error("Not supported diff operator: should stand alone to the lift side of an equation");
if (! ((EMAMEquationSymbol) getParents().peek()).getLeftExpression().equals(node))
Log.error("Not supported diff operator: should stand alone to the lift side of an equation");
else if (node.getMathMatrixAccessOperatorSymbol().getMathMatrixAccessSymbols().size() != 1)
Log.error("Not supported diff operator: wrong number of arguments");
else if (!(node.getMathMatrixAccessOperatorSymbol().getMathMatrixAccessSymbol(0).get()
instanceof MathNameExpressionSymbol))
Log.error("Not supported diff operator: argument should be Name");
else
this.differentialVariable = Optional.ofNullable(
((MathNameExpressionSymbol) node.getMathMatrixAccessOperatorSymbol()
.getMathMatrixAccessSymbol(0).get())
.getNameToAccess());
}
}
private Stack<MathExpressionSymbol> parents = new Stack<>();
@Override
public Stack<MathExpressionSymbol> getParents() {
return this.parents;
}
private Set<MathExpressionSymbol> visitedSymbols = new HashSet<>();
@Override
public Set<MathExpressionSymbol> getVisitedSymbols() {
return this.visitedSymbols;
}
}
}
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.lang.monticar.generator.cpp.loopSolver.daecpp;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.cpp.loopSolver.EquationSystemViewModel;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.template.TemplateHelper;
import de.monticore.lang.monticar.semantics.loops.detection.EMAEquationSystem;
import de.se_rwth.commons.logging.Log;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
public class DAECPPEquationSystemGenerator {
private static final Template EQUATIONSYSTEM_TEMPLATE;
private static final Template MASSMATRIX_TEMPLATE;
private static final Template RHS_TEMPLATE;
static {
Configuration conf = new Configuration(Configuration.VERSION_2_3_23);
conf.setDefaultEncoding("UTF-8");
conf.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
conf.setLogTemplateExceptions(false);
conf.setClassForTemplateLoading(AllTemplates.class, "/template/loopSolver/daecpp/");
try {
EQUATIONSYSTEM_TEMPLATE = conf.getTemplate("EquationSystem.ftl");
MASSMATRIX_TEMPLATE = conf.getTemplate("MassMatrix.ftl");
RHS_TEMPLATE = conf.getTemplate("RHS.ftl");
} catch (IOException e) {
String msg = "could not load cmake templates";
Log.error(msg, e);
throw new RuntimeException(msg, e);
}
}
public static Collection<FileContent> generateEquationSystem(EMAEquationSystem eqs) {
Collection<FileContent> result = new HashSet<>();
EquationSystemViewModel viewModel = new EquationSystemViewModel(eqs);
// map data
Map<String, Object> dataForTemplate = TemplateHelper.getDataForTemplate(viewModel);
// try generate file content
try {
StringWriter sw = new StringWriter();
EQUATIONSYSTEM_TEMPLATE.process(dataForTemplate, sw);
result.add(new FileContent(sw.toString(), String.format("/%s.h", eqs.getName())));
sw = new StringWriter();
MASSMATRIX_TEMPLATE.process(dataForTemplate, sw);
result.add(new FileContent(sw.toString(), String.format("/%s_MassMatrix.h", eqs.getName())));
sw = new StringWriter();
RHS_TEMPLATE.process(dataForTemplate, sw);
result.add(new FileContent(sw.toString(), String.format("/%s_RHS.h", eqs.getName())));
} catch (TemplateException | IOException e) {
Log.error("EquationSystem template generation failed. ", e);
}
return result;
}
}
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.lang.monticar.generator.cpp.loopSolver.daecpp;
import de.monticore.lang.monticar.generator.cmake.CMakeFindModule;
import org.apache.commons.lang3.SystemUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class DAECPPOptions {
private static Collection<CMakeFindModule> dependencies = null;
public static Collection<CMakeFindModule> getDependencies() {
if (dependencies == null) {
boolean is64bit = false;
if (System.getProperty("os.name").contains("Windows")) {
is64bit = (System.getenv("ProgramFiles(x86)") != null);
} else {
is64bit = (System.getProperty("os.arch").indexOf("64") != -1);
}
dependencies = new ArrayList<>();
CMakeFindModule DAECPP = new CMakeFindModule("DAECPP",
"solver.h", "daecpp_static",
new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(),
true, true, true);
List<String> mkllibSuffix = Arrays.asList("lib/intel64_win", "lib/ia32_win", "lib/intel64");
List<String> intellibSuffix = Arrays.asList("../compiler/lib/intel64_win", "../compiler/lib/ia32_win", "../lib/intel64", "../lib");
CMakeFindModule MKL_INCLUDE = new CMakeFindModule("MKL",
"mkl.h", "",
new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(),
true, false, true);
CMakeFindModule LIB_MKL_INTEL_LP64 = new CMakeFindModule("MKL_INTEL_LP64",
"", "mkl_intel_lp64 mkl_intel_c mkl_intel_ilp64 mkl_intel_lp64",
new ArrayList(),
new ArrayList(),
new ArrayList(),
mkllibSuffix,
Arrays.asList("MKL_HOME"),
false, true, true);
CMakeFindModule LIB_MKL_THREAD = new CMakeFindModule("MKL_THREAD",
"", "mkl_intel_thread",
new ArrayList(),
new ArrayList(),
new ArrayList(),
mkllibSuffix,
Arrays.asList("MKL_HOME"),
false, true, true);
CMakeFindModule LIB_MKL_CORE = new CMakeFindModule("MKL_CORE",
"", "mkl_core",
new ArrayList(),
new ArrayList(),
new ArrayList(),
mkllibSuffix,
Arrays.asList("MKL_HOME"),
false, true, true);
CMakeFindModule LIB_INTEL_OPENMP = new CMakeFindModule("INTEL_OPENMP",
"", "libiomp5md iomp5",
new ArrayList(),
new ArrayList(),
new ArrayList(),
intellibSuffix,
Arrays.asList("MKL_HOME"),
false, true, true);
dependencies.addAll(Arrays.asList(DAECPP, MKL_INCLUDE, LIB_MKL_INTEL_LP64, LIB_MKL_THREAD, LIB_MKL_CORE, LIB_INTEL_OPENMP));
if (!SystemUtils.IS_OS_WINDOWS) {
CMakeFindModule LIB_PTHREAD = new CMakeFindModule("PTHREAD",
"", "pthread",
new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(),
false, true, false);
CMakeFindModule LIB_MATH = new CMakeFindModule("MATH",
"", "m",
new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(),
false, true, false);
CMakeFindModule LIB_DL = new CMakeFindModule("DL",
"", "dl",
new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(),
false, true, false);
dependencies.addAll(Arrays.asList(LIB_PTHREAD, LIB_MATH, LIB_DL));
}
}
return dependencies;
}
}
<#-- (c) https://github.com/MontiCore/monticore -->
#ifndef __${viewModel.name?upper_case}_H__
#define __${viewModel.name?upper_case}_H__
#include "solver.h"
#include "${viewModel.name}_MassMatrix.h"
#include "${viewModel.name}_RHS.h"
#include "ExecutionStepper.h"
class ${viewModel.name} {
private:
daecpp::state_type x;
${viewModel.name}_MassMatrix mass;
${viewModel.name}_RHS rhs;
daecpp::Jacobian jac;
daecpp::SolverOptions opt;
daecpp::Solver solver;
static daecpp::SolverOptions initOptions() {
daecpp::SolverOptions res;
res.atol = 1.0e-15;
res.dt_init = 0.01;
res.dt_max = 0.01;
res.verbosity = 0;
return res;
}
public:
<#list viewModel.inports as inport>
double ${inport};
</#list>
<#list viewModel.variables as var>
double ${var};
</#list>
${viewModel.name}() :
x {${viewModel.initialValues?join(", ")}},
mass {},
rhs {},
jac {rhs, 1.0e-15},
opt { initOptions() },
solver {rhs, jac, mass, opt} {
}
void execute() {
<#list viewModel.inports as inport>
rhs.${inport} = ${inport};
</#list>
double t = getCurrentTime();
solver(x, t);
<#list viewModel.variables as var>
${var} = x[${var?index}];
</#list>
}
};
#endif
\ No newline at end of file
<#-- (c) https://github.com/MontiCore/monticore -->
#ifndef __${viewModel.name?upper_case}_MASSMATRIX_H__
#define __${viewModel.name?upper_case}_MASSMATRIX_H__
#include "solver.h"
class ${viewModel.name}_MassMatrix : public daecpp::MassMatrix {
public:
void operator()(daecpp::sparse_matrix_holder &M) {
M.A.resize(${viewModel.massMatrixDiag?size});
<#list viewModel.massMatrixDiag as var>
M.A[${var?index}] = ${var};
</#list>
M.ja.resize(${viewModel.massMatrixDiag?size});
M.ia.resize(${viewModel.massMatrixDiag?size+1});
for(MKL_INT i = 0; i < ${viewModel.massMatrixDiag?size}; i++) {
M.ja[i] = i;
M.ia[i] = i;
}
M.ia[${viewModel.massMatrixDiag?size}] = ${viewModel.massMatrixDiag?size};
}
};
#endif
\ No newline at end of file
<#-- (c) https://github.com/MontiCore/monticore -->
#ifndef __${viewModel.name?upper_case}_RHS_H__
#define __${viewModel.name?upper_case}_RHS_H__
#include "solver.h"
class ${viewModel.name}_RHS : public daecpp::RHS {
public:
<#list viewModel.inports as inport>
double ${inport};
</#list>
<#if viewModel.inports?size gt 0>
</#if>
void operator()(const daecpp::state_type &x, daecpp::state_type &f,
const double t) {
<#list viewModel.function as f>
f[${f?index}] = ${f};
</#list>
}
};
#endif
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment