diff --git a/README.md b/README.md index 859c7976..21dbc3d0 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,12 @@ FMI4j is a software package for dealing with Functional Mock-up Units (FMUs) on the Java Virtual Machine (JVM), written in [Kotlin](https://kotlinlang.org/). FMI4j supports import of both [FMI](http://fmi-standard.org/) 1.0 and 2.0 for **Co-simulation**. For **Model Exchange** version 2.0 is supported.
-For Model Exchange, solvers from [Apache Commons Math](http://commons.apache.org/proper/commons-math/userguide/ode.html) can be used. Export of FMI 2.0 for **Co-simulation** is also supported. Compared to other FMI libraries targeting the JVM, FMI4j is **considerably faster** due to the fact that we use JNI instead of JNA. -Considering FMI-import, a significant speedup (2-5x) compared to other open-source FMI implementations for the JVM should be expected. For FMI-export FMI4j is multiple orders of magnitude faster than any existing open source alternative. +Considering FMI-import, a significant speedup (2-5x) compared to other open-source FMI implementations for the JVM should be expected. +For FMI-export FMI4j is multiple orders of magnitude faster than any existing open source alternative. ### FMI import diff --git a/fmi-import/build.gradle b/fmi-import/build.gradle index 59689420..6a736503 100644 --- a/fmi-import/build.gradle +++ b/fmi-import/build.gradle @@ -17,7 +17,6 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" compile project(':fmi-md') - api group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1' testImplementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5' testImplementation group: 'org.siani.javafmi', name: 'fmu-wrapper', version: '2.25.1' diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/Model.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/Model.kt index 8e690204..93081543 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/Model.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/Model.kt @@ -24,13 +24,19 @@ package no.ntnu.ihb.fmi4j +import no.ntnu.ihb.fmi4j.modeldescription.CoSimulationModelDescription +import no.ntnu.ihb.fmi4j.modeldescription.CommonModelDescription import no.ntnu.ihb.fmi4j.modeldescription.ModelDescription +import no.ntnu.ihb.fmi4j.modeldescription.ModelExchangeModelDescription import java.io.Closeable -interface Model : Closeable { +typealias CosimulationModel = Model +typealias ModelExchangeModel = Model + +interface Model : Closeable { val modelDescription: ModelDescription - fun newInstance(): SlaveInstance + fun newInstance(): ModelInstance } diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/AbstractFmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/AbstractFmu.kt index a147fe08..21f2b6c4 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/AbstractFmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/AbstractFmu.kt @@ -24,7 +24,9 @@ package no.ntnu.ihb.fmi4j.importer +import no.ntnu.ihb.fmi4j.CosimulationModel import no.ntnu.ihb.fmi4j.Model +import no.ntnu.ihb.fmi4j.ModelExchangeModel import no.ntnu.ihb.fmi4j.modeldescription.ModelDescriptionParser import no.ntnu.ihb.fmi4j.modeldescription.ModelDescriptionProvider import no.ntnu.ihb.fmi4j.util.extractContentTo @@ -57,7 +59,6 @@ abstract class AbstractFmu internal constructor( val modelDescriptionXml: String get() = modelDescriptionFile.readText() - /** * Does the FMU support Co-simulation? */ @@ -88,9 +89,9 @@ abstract class AbstractFmu internal constructor( } } - abstract fun asCoSimulationFmu(): Model + abstract fun asCoSimulationFmu(): CosimulationModel - abstract fun asModelExchangeFmu(): Model + abstract fun asModelExchangeFmu(): ModelExchangeModel protected abstract fun terminateInstances() @@ -173,9 +174,7 @@ abstract class AbstractFmu internal constructor( fun from(file: File): AbstractFmu { val extension = file.extension.toLowerCase() - if (extension != FMU_EXTENSION) { - throw IllegalArgumentException("File '${file.absolutePath}' is not an FMU! Invalid extension found: .$extension") - } + require(extension == FMU_EXTENSION) { "File '${file.absolutePath}' is not an FMU! Invalid extension found: .$extension" } if (!file.exists()) { throw FileNotFoundException("No such file: '$file'!") @@ -200,9 +199,7 @@ abstract class AbstractFmu internal constructor( fun from(url: URL): AbstractFmu { val extension = File(url.file).extension - if (extension != FMU_EXTENSION) { - throw IllegalArgumentException("URL '$url' does not point to an FMU! Invalid extension found: .$extension") - } + require(extension == FMU_EXTENSION) { "URL '$url' does not point to an FMU! Invalid extension found: .$extension" } val fmuName = File(url.file).nameWithoutExtension return createTempDir(fmuName).let { temp -> diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/CoSimulationFmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/CoSimulationFmu.kt index 5216e0af..34f018fb 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/CoSimulationFmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/CoSimulationFmu.kt @@ -24,6 +24,7 @@ package no.ntnu.ihb.fmi4j.importer.fmi1 +import no.ntnu.ihb.fmi4j.CosimulationModel import no.ntnu.ihb.fmi4j.Model import no.ntnu.ihb.fmi4j.SlaveInstance import no.ntnu.ihb.fmi4j.importer.fmi1.jni.CoSimulationLibraryWrapper @@ -35,7 +36,7 @@ import java.io.Closeable class CoSimulationFmu( private val fmu: Fmu -) : Model, Closeable by fmu { +) : CosimulationModel, Closeable by fmu { override val modelDescription: CoSimulationModelDescription by lazy { fmu.modelDescription.asCoSimulationModelDescription() @@ -54,7 +55,7 @@ class CoSimulationFmu( modelDescription.guid, fmu.fmuPath, loggingOn) } - override fun newInstance(): SlaveInstance { + override fun newInstance(): CoSimulationSlave { return newInstance(loggingOn = false) } diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/ModelExchangeFmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/ModelExchangeFmu.kt index f8b7e8be..2164ef1c 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/ModelExchangeFmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi1/ModelExchangeFmu.kt @@ -25,6 +25,8 @@ package no.ntnu.ihb.fmi4j.importer.fmi1 import no.ntnu.ihb.fmi4j.Model +import no.ntnu.ihb.fmi4j.ModelExchangeModel +import no.ntnu.ihb.fmi4j.ModelInstance import no.ntnu.ihb.fmi4j.SlaveInstance import no.ntnu.ihb.fmi4j.importer.fmi1.jni.Fmi1ModelExchangeLibrary import no.ntnu.ihb.fmi4j.importer.fmi1.jni.FmiComponent @@ -38,7 +40,7 @@ import java.io.Closeable */ class ModelExchangeFmu( private val fmu: Fmu -) : Model, Closeable by fmu { +) : ModelExchangeModel, Closeable by fmu { override val modelDescription: ModelExchangeModelDescription by lazy { fmu.modelDescription.asModelExchangeModelDescription() @@ -56,7 +58,10 @@ class ModelExchangeFmu( return lib.instantiateModel(modelDescription.attributes.modelIdentifier, modelDescription.guid, loggingOn) } - @JvmOverloads + override fun newInstance(): ModelExchangeInstance { + return newInstance(false) + } + fun newInstance(loggingOn: Boolean = false): ModelExchangeInstance { val c = instantiate(loggingOn) val wrapper = ModelExchangeLibraryWrapper(c, lib) @@ -65,18 +70,4 @@ class ModelExchangeFmu( } } - override fun newInstance(): SlaveInstance { - throw IllegalStateException("Not supported (yet)") - } - -// fun newInstance(solver: Solver): ModelExchangeSlave { -// return newInstance(solver, visible = false, loggingOn = false) -// } -// -// fun newInstance(solver: Solver, visible: Boolean = false, loggingOn: Boolean = false): ModelExchangeSlave { -// return newInstance(visible, loggingOn).let { -// ModelExchangeSlave(it, solver) -// } -// } - } diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/CoSimulationFmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/CoSimulationFmu.kt index 48aee11d..803ca51b 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/CoSimulationFmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/CoSimulationFmu.kt @@ -24,6 +24,7 @@ package no.ntnu.ihb.fmi4j.importer.fmi2 +import no.ntnu.ihb.fmi4j.CosimulationModel import no.ntnu.ihb.fmi4j.Model import no.ntnu.ihb.fmi4j.SlaveInstance import no.ntnu.ihb.fmi4j.importer.fmi2.jni.CoSimulationLibraryWrapper @@ -34,7 +35,7 @@ import java.io.Closeable class CoSimulationFmu( private val fmu: Fmu -) : Model, Closeable by fmu { +) : CosimulationModel, Closeable by fmu { override val modelDescription: CoSimulationModelDescription by lazy { fmu.modelDescription.asCoSimulationModelDescription() @@ -49,7 +50,7 @@ class CoSimulationFmu( } override fun newInstance(): SlaveInstance { - return newInstance(false, false) + return newInstance(visible = false, loggingOn = false) } fun newInstance(visible: Boolean = false, loggingOn: Boolean = false): CoSimulationSlave { diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/Fmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/Fmu.kt index a349d9c2..a1006da6 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/Fmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/Fmu.kt @@ -67,16 +67,12 @@ class Fmu internal constructor( override fun asCoSimulationFmu(): CoSimulationFmu { - if (!supportsCoSimulation) { - throw IllegalStateException("FMU does not support Co-simulation!") - } + check(supportsCoSimulation) { "FMU does not support Co-simulation!" } return coSimulationFmu } override fun asModelExchangeFmu(): ModelExchangeFmu { - if (!supportsModelExchange) { - throw IllegalStateException("FMU does not support Model Exchange!") - } + check(supportsModelExchange) { "FMU does not support Model Exchange!" } return modelExchangeFmu } diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeFmu.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeFmu.kt index 7a87ac04..b69ac7cc 100644 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeFmu.kt +++ b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeFmu.kt @@ -25,20 +25,20 @@ package no.ntnu.ihb.fmi4j.importer.fmi2 import no.ntnu.ihb.fmi4j.Model +import no.ntnu.ihb.fmi4j.ModelExchangeModel +import no.ntnu.ihb.fmi4j.ModelInstance import no.ntnu.ihb.fmi4j.importer.fmi2.jni.Fmi2ModelExchangeLibrary import no.ntnu.ihb.fmi4j.importer.fmi2.jni.ModelExchangeLibraryWrapper import no.ntnu.ihb.fmi4j.modeldescription.ModelExchangeModelDescription -import no.ntnu.ihb.fmi4j.solvers.Solver import java.io.Closeable /** * * @author Lars Ivar Hatledal */ -class ModelExchangeFmu @JvmOverloads constructor( - private val fmu: Fmu, - private val solver: Solver? = null -) : Model, Closeable by fmu { +class ModelExchangeFmu( + private val fmu: Fmu +) : ModelExchangeModel, Closeable by fmu { override val modelDescription: ModelExchangeModelDescription by lazy { fmu.modelDescription.asModelExchangeModelDescription() @@ -52,8 +52,10 @@ class ModelExchangeFmu @JvmOverloads constructor( } } + override fun newInstance(): ModelExchangeInstance { + return newInstance(visible = false, loggingOn = false) + } - @JvmOverloads fun newInstance(visible: Boolean = false, loggingOn: Boolean = false): ModelExchangeInstance { val c = fmu.instantiate(modelDescription, lib, 0, visible, loggingOn) val wrapper = ModelExchangeLibraryWrapper(c, lib) @@ -62,19 +64,4 @@ class ModelExchangeFmu @JvmOverloads constructor( } } - override fun newInstance(): ModelExchangeSlave { - val solver = solver ?: throw IllegalStateException("Class instantiated with no solver!") - return newInstance(solver, visible = false, loggingOn = false) - } - - fun newInstance(solver: Solver): ModelExchangeSlave { - return newInstance(solver, visible = false, loggingOn = false) - } - - fun newInstance(solver: Solver, visible: Boolean = false, loggingOn: Boolean = false): ModelExchangeSlave { - return newInstance(visible, loggingOn).let { - ModelExchangeSlave(it, solver) - } - } - } diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeSlave.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeSlave.kt deleted file mode 100644 index 3ff1bcda..00000000 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/ModelExchangeSlave.kt +++ /dev/null @@ -1,246 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.importer.fmi2 - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.SimpleModelInstance -import no.ntnu.ihb.fmi4j.SlaveInstance -import no.ntnu.ihb.fmi4j.modeldescription.CoSimulationAttributes -import no.ntnu.ihb.fmi4j.modeldescription.CoSimulationModelDescription -import no.ntnu.ihb.fmi4j.modeldescription.CommonModelDescription -import no.ntnu.ihb.fmi4j.modeldescription.ModelExchangeModelDescription -import no.ntnu.ihb.fmi4j.solvers.Solver -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import kotlin.math.min - -/** - * Wraps a Model Exchange instance, turning it into a SlaveInstance - * - * @author Lars Ivar Hatledal - */ -class ModelExchangeSlave( - private val fmuInstance: ModelExchangeInstance, - private val solver: Solver -) : SlaveInstance, SimpleModelInstance by fmuInstance { - - private val x: DoubleArray - - private val z: DoubleArray - private val pz: DoubleArray - - init { - - val numberOfContinuousStates = fmuInstance.modelDescription.numberOfContinuousStates - val numberOfEventIndicators = fmuInstance.modelDescription.numberOfEventIndicators - - this.x = DoubleArray(numberOfContinuousStates) - - this.z = DoubleArray(numberOfEventIndicators) - this.pz = DoubleArray(numberOfEventIndicators) - - this.solver.setEquations(object : no.ntnu.ihb.fmi4j.solvers.Equations { - override val dimension: Int = numberOfContinuousStates - override fun computeDerivatives(time: Double, y: DoubleArray, yDot: DoubleArray) { - fmuInstance.setTime(time) - fmuInstance.setContinuousStates(y) - fmuInstance.getDerivatives(yDot) - } - }) - - } - - override val modelDescription: CoSimulationModelDescription by lazy { - CoSimulationModelDescriptionWrapper(fmuInstance.modelDescription) - } - - override fun simpleSetup(): Boolean { - return simpleSetup(0.0, 0.0, 0.0) - } - - override fun simpleSetup(start: Double, stop: Double, tolerance: Double): Boolean { - return fmuInstance.setup(start, stop, tolerance) && fmuInstance.enterInitializationMode() && exitInitializationMode() - } - - override fun exitInitializationMode(): Boolean { - - if (!fmuInstance.exitInitializationMode()) { - return false - } - - if (eventIteration()) { - LOG.error("EventIteration returned false during initialization!") - return false - } - return true - } - - override fun doStep(stepSize: Double): Boolean { - - if (stepSize <= 0) { - throw IllegalArgumentException("stepSize must be positive and greater than 0! Was: $stepSize") - } - - var time = simulationTime - val stopTime = (time + stepSize) - - while (time < stopTime) { - - var tNext = min(time + stepSize, stopTime) - - val timeEvent = fmuInstance.eventInfo.nextEventTimeDefined && (fmuInstance.eventInfo.nextEventTime <= time) - if (timeEvent) { - tNext = fmuInstance.eventInfo.nextEventTime - } - - var stateEvent = false - if ((tNext - time) > EPS) { - solve(time, tNext).also { result -> - stateEvent = result.first - time = result.second - } - } else { - time = tNext - } - - fmuInstance.setTime(time).also { - it.warnOnStatusNotOK("fmuInstance.setTime()") - } - - var enterEventMode = false - if (!fmuInstance.modelDescription.attributes.completedIntegratorStepNotNeeded) { - val completedIntegratorStep = fmuInstance.completedIntegratorStep() - if (completedIntegratorStep.terminateSimulation) { - LOG.debug("completedIntegratorStep.terminateSimulation returned true. Terminating FMU...") - return false.also { - terminate() - } - } - enterEventMode = completedIntegratorStep.enterEventMode - } - - if (timeEvent || stateEvent || enterEventMode) { - - fmuInstance.enterEventMode().also { - it.warnOnStatusNotOK("fmuInstance.enterEventMode()") - } - - if (eventIteration()) { - return false - } - - } - - } - - return true - - } - - private fun solve(t: Double, tNext: Double): Pair { - - fmuInstance.getContinuousStates(x) - - val integratedTime = solver.integrate(t, x, tNext, x) - - System.arraycopy(z, 0, pz, 0, z.size) - fmuInstance.getEventIndicators(z) - - fun stateEvent(): Boolean { - - for (i in pz.indices) { - if ((pz[i] * z[i]) < 0) { - return true - } - } - return false - } - - return (stateEvent() to integratedTime) - - } - - private fun eventIteration(): Boolean { - - fmuInstance.eventInfo.newDiscreteStatesNeeded = true - fmuInstance.eventInfo.terminateSimulation = false - - while (fmuInstance.eventInfo.newDiscreteStatesNeeded) { - if (!fmuInstance.newDiscreteStates().isOK()) { - LOG.warn("fmuInstance.newDiscreteStates() returned status $lastStatus") - return true - } - if (fmuInstance.eventInfo.terminateSimulation) { - LOG.debug("eventInfo.getTerminateSimulation() returned true. Terminating FMU...") - terminate() - return true - } - } - - fmuInstance.enterContinuousTimeMode().also { - it.warnOnStatusNotOK("fmuInstance.enterContinuousTimeMode()") - } - - return false - } - - - private companion object { - - const val EPS = 1E-13 - - val LOG: Logger = LoggerFactory.getLogger(ModelExchangeSlave::class.java) - - fun FmiStatus.warnOnStatusNotOK(functionName: String) { - if (this != FmiStatus.OK) { - LOG.warn("$functionName returned status: $this") - } - } - - } - -} - -class CoSimulationModelDescriptionWrapper( - private val md: ModelExchangeModelDescription -) : CommonModelDescription by md, CoSimulationModelDescription { - - override val attributes: CoSimulationAttributes - get() = CoSimulationAttributes( - modelIdentifier = md.attributes.modelIdentifier, - needsExecutionTool = md.attributes.needsExecutionTool, - canBeInstantiatedOnlyOncePerProcess = md.attributes.canBeInstantiatedOnlyOncePerProcess, - canNotUseMemoryManagementFunctions = md.attributes.canNotUseMemoryManagementFunctions, - canGetAndSetFMUstate = md.attributes.canGetAndSetFMUstate, - canSerializeFMUstate = md.attributes.canSerializeFMUstate, - providesDirectionalDerivative = md.attributes.providesDirectionalDerivative, - canHandleVariableCommunicationStepSize = true, - canRunAsynchronuously = false, - canInterpolateInputs = false, - maxOutputDerivativeOrder = 0, - sourceFiles = emptyList() - ) - -} diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/Solver.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/Solver.kt deleted file mode 100644 index 5fa24bf5..00000000 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/Solver.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.solvers - -/** - * Interface for solvers - * A solver is used to solve Model Exchange FMUs - * - * @author Lars Ivar Hatledal - */ -interface Solver { - - /** - * Get the name of the method - */ - val name: String - - /** - * differential equations to integrate - */ - fun setEquations(equations: no.ntnu.ihb.fmi4j.solvers.Equations) - - /** - * Integrate the differential equations up to the given time. - * This method solves an Initial Value Problem (IVP). - * - * @param t0 – initial time - * @param x0 – initial value of the state vector at t0 - * @param t – target time for the integration (can be set to a value smaller than t0 for backward integration) - * @param x – placeholder where to put the state vector at each successful step (and hence at the end of integration), can be the same object as y0 - */ - fun integrate(t0: Double, x0: DoubleArray, t: Double, x: DoubleArray): Double - -} - -/** - * @author Lars Ivar Hatledal - */ -interface Equations { - - /** - * Get the dimension of the problem. - */ - val dimension: Int - - /** - * Get the current time derivative of the state vector - * - * @param t – current value of the independent time variable - * @param y – array containing the current value of the state vector - * @param yDot – placeholder array where to put the time derivative of the state vector - */ - fun computeDerivatives(time: Double, y: DoubleArray, yDot: DoubleArray) - -} diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolver.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolver.kt deleted file mode 100644 index 2e13090b..00000000 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolver.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.solvers.apache - -import org.apache.commons.math3.ode.FirstOrderDifferentialEquations -import org.apache.commons.math3.ode.FirstOrderIntegrator - -/** - * Wraps solvers from apache commons math3 to be used by FMI4j - * to solve Model Exchange FMUs - * - * @author Lars Ivar Hatledal - */ -class ApacheSolver( - private val solver: FirstOrderIntegrator -) : no.ntnu.ihb.fmi4j.solvers.Solver { - - override val name: String - get() = solver.name - - lateinit var equations: FirstOrderDifferentialEquations - - override fun setEquations(equations: no.ntnu.ihb.fmi4j.solvers.Equations) { - this.equations = object : FirstOrderDifferentialEquations { - override fun computeDerivatives(t: Double, y: DoubleArray, yDot: DoubleArray) { - return equations.computeDerivatives(t, y, yDot) - } - - override fun getDimension(): Int { - return equations.dimension - } - } - } - - override fun integrate(t0: Double, x0: DoubleArray, t: Double, x: DoubleArray): Double { - return solver.integrate(equations, t0, x0, t, x) - } - -} diff --git a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolvers.kt b/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolvers.kt deleted file mode 100644 index 93709e00..00000000 --- a/fmi-import/src/main/kotlin/no/ntnu/ihb/fmi4j/solvers/apache/ApacheSolvers.kt +++ /dev/null @@ -1,75 +0,0 @@ -package no.ntnu.ihb.fmi4j.solvers.apache - -import org.apache.commons.math3.ode.nonstiff.* - -/** - * - * Factory for creating instances of ApacheSolver - * - * @author Lars Ivar Hatledal - */ -object ApacheSolvers { - - /** - * Build an Euler integrator with the given step. - * @param stepSize integration step - */ - @JvmStatic - fun euler(stepSize: Double): ApacheSolver { - return ApacheSolver(EulerIntegrator(stepSize)) - } - - @JvmStatic - fun rk4(stepSize: Double): ApacheSolver { - return ApacheSolver(ClassicalRungeKuttaIntegrator(stepSize)) - } - - @JvmStatic - fun luther(stepSize: Double): ApacheSolver { - return ApacheSolver(LutherIntegrator(stepSize)) - } - - @JvmStatic - fun gill(stepSize: Double): ApacheSolver { - return ApacheSolver(GillIntegrator(stepSize)) - } - - @JvmStatic - fun midpoint(stepSize: Double): ApacheSolver { - return ApacheSolver(MidpointIntegrator(stepSize)) - } - - /** - * Build an eighth order Dormand-Prince integrator with the given step bounds - * @param minStep minimal step (sign is irrelevant, regardless of - * integration direction, forward or backward), the last step can - * be smaller than this - * @param maxStep maximal step (sign is irrelevant, regardless of - * integration direction, forward or backward), the last step can - * be smaller than this - * @param scalAbsoluteTolerance allowed absolute error - * @param scalRelativeTolerance allowed relative error - */ - @JvmStatic - fun dormandPrince853(minStep: Double, maxStep: Double, scalAbsoluteTolerance: Double, scalRelativeTolerance: Double): ApacheSolver { - return ApacheSolver(DormandPrince853Integrator(minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance)) - } - - /** - * Build an Adams-Bashforth integrator with the given order and step control parameters. - * @param nSteps number of steps of the method excluding the one being computed - * @param minStep minimal step (sign is irrelevant, regardless of - * integration direction, forward or backward), the last step can - * be smaller than this - * @param maxStep maximal step (sign is irrelevant, regardless of - * integration direction, forward or backward), the last step can - * be smaller than this - * @param scalAbsoluteTolerance allowed absolute error - * @param scalRelativeTolerance allowed relative error - */ - @JvmStatic - fun adamsBashforthIntegrator(nSteps: Int, minStep: Double, maxStep: Double, scalAbsoluteTolerance: Double, scalRelativeTolerance: Double): ApacheSolver { - return ApacheSolver(AdamsBashforthIntegrator(nSteps, minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance)) - } - -} diff --git a/fmi-import/src/test/java/no/ntnu/ihb/fmi4j/importer/VanDerPolTestJava.java b/fmi-import/src/test/java/no/ntnu/ihb/fmi4j/importer/VanDerPolTestJava.java deleted file mode 100644 index 51623531..00000000 --- a/fmi-import/src/test/java/no/ntnu/ihb/fmi4j/importer/VanDerPolTestJava.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017. Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.importer; - -import no.ntnu.ihb.fmi4j.Fmi4jVariableUtils; -import no.ntnu.ihb.fmi4j.FmiStatus; -import no.ntnu.ihb.fmi4j.SlaveInstance; -import no.ntnu.ihb.fmi4j.VariableRead; -import no.ntnu.ihb.fmi4j.importer.fmi2.ModelExchangeFmu; -import no.ntnu.ihb.fmi4j.modeldescription.variables.RealVariable; -import no.ntnu.ihb.fmi4j.solvers.Solver; -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers; -import org.junit.jupiter.api.*; -import org.junit.jupiter.api.condition.EnabledOnOs; -import org.junit.jupiter.api.condition.OS; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -/** - * @author Lars Ivar Hatledal - */ - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class VanDerPolTestJava { - - private static final Logger LOG = LoggerFactory.getLogger(VanDerPolTestJava.class); - - private static ModelExchangeFmu fmu; - - @BeforeAll - public static void setup() throws IOException { - fmu = TestFMUs.fmi20().both() - .vendor("Test-FMUs").version("0.0.1") - .name("VanDerPol").fmu().asModelExchangeFmu(); - } - - @AfterAll - public static void tearDown() { - fmu.close(); - } - - @Test - public void testVersion() { - Assertions.assertEquals("2.0", fmu.getModelDescription().getFmiVersion()); - } - - private void runFmu(Solver solver) { - - LOG.info("Using solver: {}", solver.getName()); - - SlaveInstance slave = VanDerPolTestJava.fmu - .newInstance(solver, false, false); - - RealVariable x0 = slave.getModelVariables() - .getByName("x0").asRealVariable(); - - Assertions.assertTrue(slave.simpleSetup()); - - double stop = 1.0; - double macroStep = 1.0 / 10; - while (slave.getSimulationTime() <= stop) { - VariableRead read = Fmi4jVariableUtils.read(x0, slave); - Assertions.assertSame(read.getStatus(), FmiStatus.OK); - LOG.info("t={}, x0={}", slave.getSimulationTime(), read.getValue()); - Assertions.assertTrue(slave.doStep(macroStep)); - } - - Assertions.assertTrue(slave.terminate()); - } - - @Test - @EnabledOnOs(OS.WINDOWS) - public void testEuler() { - runFmu(ApacheSolvers.euler(1E-3)); - } - - @Test - @EnabledOnOs(OS.WINDOWS) - public void testRungeKutta() { - runFmu(ApacheSolvers.rk4(1E-3)); - } - - @Test - @EnabledOnOs(OS.WINDOWS) - public void testLuther() { - runFmu(ApacheSolvers.luther(1E-3)); - } - -} diff --git a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/BouncingBallTest.kt b/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/BouncingBallTest.kt deleted file mode 100644 index 9cb11086..00000000 --- a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/BouncingBallTest.kt +++ /dev/null @@ -1,97 +0,0 @@ -package no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.fmusdk - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.importer.TestFMUs -import no.ntnu.ihb.fmi4j.read -import no.ntnu.ihb.fmi4j.solvers.Solver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers -import org.apache.commons.math3.ode.nonstiff.DormandPrince853Integrator -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.condition.EnabledOnOs -import org.junit.jupiter.api.condition.OS -import org.slf4j.LoggerFactory - -@EnabledOnOs(OS.WINDOWS) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class BouncingBallTest { - - private companion object { - private val LOG = LoggerFactory.getLogger(BouncingBallTest::class.java) - - private val fmu = TestFMUs.fmi20().me() - .vendor("FMUSDK").version("2.0.4") - .name("bouncingBall").fmu().asModelExchangeFmu() - - } - - @AfterAll - fun tearDown() { - fmu.close() - } - - @Test - fun test() { - fmu.modelDescription.modelVariables.getByName("h").asRealVariable().also { - Assertions.assertEquals(1.0, it.start) - } - } - - private fun runFmu(solver: Solver) { - - LOG.info("Using solver: '${solver.name}'") - - fmu.newInstance(solver, loggingOn = false).use { slave -> - - val h = slave.modelVariables - .getByName("h").asRealVariable() - - Assertions.assertTrue(slave.simpleSetup()) - - val macroStep = 1.0 / 10 - while (slave.simulationTime <= 0.1) { - - if (!slave.doStep(macroStep)) { - LOG.error("${slave.lastStatus} @ ${slave.simulationTime}") - break - } - - h.read(slave).also { - Assertions.assertEquals(FmiStatus.OK, it.status) - LOG.info("t=${slave.simulationTime}, h=${it.value}") - } - } - - } - - } - - @Test - fun testEuler() { - runFmu(ApacheSolvers.euler(1E-3)) - } - - @Test - fun testRungeKutta() { - runFmu(ApacheSolvers.rk4(1E-3)) - } - - @Test - fun testLuther() { - runFmu(ApacheSolvers.luther(1E-3)) - } - - @Test - fun testMidpoint() { - runFmu(ApacheSolvers.midpoint(1E-3)) - } - - @Test - fun testDp() { - runFmu(ApacheSolver(DormandPrince853Integrator(0.0, 1E-3, 1E-4, 1E-4))) - } - -} diff --git a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/VanDerPolTest.kt b/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/VanDerPolTest.kt deleted file mode 100644 index f4dd8029..00000000 --- a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/fmusdk/VanDerPolTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.fmusdk - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.importer.TestFMUs -import no.ntnu.ihb.fmi4j.read -import no.ntnu.ihb.fmi4j.solvers.Solver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.condition.EnabledOnOs -import org.junit.jupiter.api.condition.OS -import org.slf4j.LoggerFactory - -@EnabledOnOs(OS.WINDOWS) -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class VanDerPolTest { - - companion object { - - private val LOG = LoggerFactory.getLogger(VanDerPolTest::class.java) - - private const val stop = 1.0 - private const val macroStep = 1.0 / 10 - - private val fmu = TestFMUs.fmi20().me() - .vendor("FMUSDK").version("2.0.4") - .name("vanDerPol").fmu().asModelExchangeFmu() - - } - - @AfterAll - fun tearDown() { - fmu.close() - } - - private fun runFmu(solver: Solver) { - - LOG.info("Using solver: '${solver.name}'") - - fmu.newInstance(solver).use { slave -> - - val variableName = "x0" - val x0 = slave.modelVariables - .getByName(variableName).asRealVariable() - - Assertions.assertTrue(slave.simpleSetup()) - - while (slave.simulationTime <= stop) { - val read = x0.read(slave) - Assertions.assertTrue(read.status === FmiStatus.OK) - LOG.info("t=${slave.simulationTime}, $variableName=${read.value}") - Assertions.assertTrue(slave.doStep(macroStep)) - } - - } - - } - - @Test - fun testEuler() { - runFmu(ApacheSolvers.euler(1E-3)) - } - - @Test - fun testRungeKutta() { - runFmu(ApacheSolvers.rk4(1E-3)) - } - - @Test - fun testLuther() { - runFmu(ApacheSolvers.luther(1E-3)) - } - - @Test - fun testMidpoint() { - runFmu(ApacheSolvers.midpoint(1E-3)) - } - -} \ No newline at end of file diff --git a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/openmodelica/FmuExportCrossCompile.kt b/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/openmodelica/FmuExportCrossCompile.kt deleted file mode 100644 index 1a3e3f41..00000000 --- a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/openmodelica/FmuExportCrossCompile.kt +++ /dev/null @@ -1,100 +0,0 @@ -package no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.openmodelica - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.importer.TestFMUs -import no.ntnu.ihb.fmi4j.read -import no.ntnu.ihb.fmi4j.solvers.Solver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers -import org.apache.commons.math3.ode.nonstiff.DormandPrince853Integrator -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.condition.EnabledOnOs -import org.junit.jupiter.api.condition.OS -import org.slf4j.LoggerFactory - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class FmuExportCrossCompile { - - private companion object { - - private val LOG = LoggerFactory.getLogger(FmuExportCrossCompile::class.java) - - const val stop = 1.0 - const val macroStep = 1.0 / 10 - const val microStep = 1E-3 - - val fmu = TestFMUs.fmi20().cs() - .vendor("OpenModelica").version("v1.11.0") - .name("FmuExportCrossCompile").fmu().asModelExchangeFmu() - - } - - @AfterAll - fun tearDown() { - fmu.close() - } - - @Test - fun test() { - fmu.modelDescription.modelVariables.getByName("h").asRealVariable().also { - Assertions.assertEquals(1.0, it.start) - } - } - - private fun runFmu(solver: Solver) { - - LOG.info("Using solver: '${solver.name}'") - - fmu.newInstance(solver).use { slave -> - - val h = slave.modelVariables - .getByName("h").asRealVariable() - - Assertions.assertTrue(slave.simpleSetup()) - - while (slave.simulationTime <= stop) { - Assertions.assertTrue(slave.doStep(macroStep)) - h.read(slave).also { - Assertions.assertEquals(FmiStatus.OK, it.status) - LOG.info("t=${slave.simulationTime}, h=${it.value}") - } - } - - } - - } - - @Test - @EnabledOnOs(OS.WINDOWS) - fun testEuler() { - runFmu(ApacheSolvers.euler(microStep)) - } - - @Test - @EnabledOnOs(OS.WINDOWS) - fun testRungeKutta() { - runFmu(ApacheSolvers.rk4(microStep)) - } - - @Test - @EnabledOnOs(OS.WINDOWS) - fun testLuther() { - runFmu(ApacheSolvers.luther(microStep)) - } - - @Test - @EnabledOnOs(OS.WINDOWS) - fun testMidpoint() { - runFmu(ApacheSolvers.midpoint(microStep)) - } - - @Test - @EnabledOnOs(OS.WINDOWS) - fun testDp() { - runFmu(ApacheSolver(DormandPrince853Integrator(0.0, microStep, 1E-4, 1E-4))) - } - -} \ No newline at end of file diff --git a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/BouncingBallTest.kt b/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/BouncingBallTest.kt deleted file mode 100644 index 1891f66d..00000000 --- a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/BouncingBallTest.kt +++ /dev/null @@ -1,90 +0,0 @@ -package no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.testfmus - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.importer.TestFMUs -import no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.fmusdk.BouncingBallTest -import no.ntnu.ihb.fmi4j.read -import no.ntnu.ihb.fmi4j.solvers.Solver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers -import org.apache.commons.math3.ode.nonstiff.DormandPrince853Integrator -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.slf4j.LoggerFactory - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class BouncingBallTest { - - private companion object { - private val LOG = LoggerFactory.getLogger(BouncingBallTest::class.java) - - private val fmu = TestFMUs.fmi20().both() - .vendor("Test-FMUs").version("0.0.1") - .name("BouncingBall").fmu().asModelExchangeFmu() - - } - - @AfterAll - fun tearDown() { - fmu.close() - } - - @Test - fun test() { - fmu.modelDescription.modelVariables.getByName("h").asRealVariable().also { - Assertions.assertEquals(1.0, it.start) - } - } - - private fun runFmu(solver: Solver) { - - LOG.info("Using solver: '${solver.name}'") - - fmu.newInstance(solver).use { slave -> - - val h = slave.modelVariables - .getByName("h").asRealVariable() - - Assertions.assertTrue(slave.simpleSetup()) - - val macroStep = 1.0 / 10 - while (slave.simulationTime <= 1) { - Assertions.assertTrue(slave.doStep(macroStep)) - h.read(slave).also { - Assertions.assertEquals(FmiStatus.OK, it.status) - LOG.info("t=${slave.simulationTime}, h=${it.value}") - } - } - - } - - } - - @Test - fun testEuler() { - runFmu(ApacheSolvers.euler(1E-3)) - } - - @Test - fun testRungeKutta() { - runFmu(ApacheSolvers.rk4(1E-3)) - } - - @Test - fun testLuther() { - runFmu(ApacheSolvers.luther(1E-3)) - } - - @Test - fun testMidpoint() { - runFmu(ApacheSolvers.midpoint(1E-3)) - } - - @Test - fun testDp() { - runFmu(ApacheSolver(DormandPrince853Integrator(0.0, 1E-3, 1E-4, 1E-4))) - } - -} diff --git a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/VanDerPolTest.kt b/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/VanDerPolTest.kt deleted file mode 100644 index 45c0392d..00000000 --- a/fmi-import/src/test/kotlin/no/ntnu/ihb/fmi4j/importer/fmi2/me/vendors/testfmus/VanDerPolTest.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017-2018 Norwegian University of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package no.ntnu.ihb.fmi4j.importer.fmi2.me.vendors.testfmus - -import no.ntnu.ihb.fmi4j.FmiStatus -import no.ntnu.ihb.fmi4j.importer.TestFMUs -import no.ntnu.ihb.fmi4j.read -import no.ntnu.ihb.fmi4j.solvers.Solver -import no.ntnu.ihb.fmi4j.solvers.apache.ApacheSolvers -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.slf4j.LoggerFactory - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class VanDerPolTest { - - companion object { - - private val LOG = LoggerFactory.getLogger(VanDerPolTest::class.java) - - private const val stop = 1.0 - private const val macroStep = 1.0 / 10 - - private val fmu = TestFMUs.fmi20().both() - .vendor("Test-FMUs").version("0.0.1") - .name("VanDerPol").fmu().asModelExchangeFmu() - - } - - @AfterAll - fun tearDown() { - fmu.close() - } - - private fun runFmu(solver: Solver) { - - LOG.info("Using solver: '${solver.name}'") - - fmu.newInstance(solver).use { slave -> - - val variableName = "x0" - val x0 = slave.modelVariables - .getByName(variableName).asRealVariable() - - Assertions.assertTrue(slave.simpleSetup()) - - while (slave.simulationTime <= stop) { - val read = x0.read(slave) - Assertions.assertTrue(read.status === FmiStatus.OK) - LOG.info("t=${slave.simulationTime}, $variableName=${read.value}") - Assertions.assertTrue(slave.doStep(macroStep)) - } - - } - - } - - @Test - fun testEuler() { - runFmu(ApacheSolvers.euler(1E-3)) - } - - @Test - fun testRungeKutta() { - runFmu(ApacheSolvers.rk4(1E-3)) - } - - @Test - fun testLuther() { - runFmu(ApacheSolvers.luther(1E-3)) - } - - @Test - fun testMidpoint() { - runFmu(ApacheSolvers.midpoint(1E-3)) - } - -} \ No newline at end of file