Skip to content

Commit

Permalink
Record initial values (#562)
Browse files Browse the repository at this point in the history
  • Loading branch information
t-sommer authored Aug 20, 2024
1 parent 78a6ec5 commit cb4a572
Show file tree
Hide file tree
Showing 24 changed files with 599 additions and 513 deletions.
1 change: 1 addition & 0 deletions fmusim-gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

ModelVariablesTreeModel.h ModelVariablesTreeModel.cpp
AbstractModelVariablesModel.h AbstractModelVariablesModel.cpp
PlotUtil.h PlotUtil.cpp
)

target_include_directories(fmusim-gui PRIVATE
Expand Down
214 changes: 14 additions & 200 deletions fmusim-gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "SimulationThread.h"
#include "BuildPlatformBinaryThread.h"
#include "BuildPlatformBinaryDialog.h"
#include "PlotUtil.h"

extern "C" {
#include "FMIZip.h"
Expand Down Expand Up @@ -411,6 +412,7 @@ void MainWindow::loadFMU(const QString &filename) {
ui->plotWebEngineView->load(QUrl("qrc:/plot.html"));

// enable widgets
ui->dockWidget->show();
ui->showSideBarAction->setEnabled(true);
ui->showSideBarAction->setChecked(true);

Expand Down Expand Up @@ -641,214 +643,26 @@ void MainWindow::updatePlot() {
return;
}

FMIRecorder* recorder = simulationThread->settings->recorder;

QString data;

data += "var time = [";

for (size_t i = 0; i < recorder->nRows; i++) {

Row* row = recorder->rows[i];

if (i > 0) {
data += ", ";
}

data += QString::number(row->time);
}

data += "];\n";

data += "var data = [\n";

size_t k = 0;

for (size_t i = 0; i < recorder->nVariables; i++) {

const FMIModelVariable* variable = recorder->variables[i];

const FMIVariableType type = variable->type;

if (!plotVariables.contains(variable)) {
continue;
}

QString y;

for (size_t j = 0; j < recorder->nRows; j++) {

Row* row = recorder->rows[j];

if (j > 0) {
y += ", ";
}

size_t index;

for (index = 0; index < recorder->variableInfos[type]->nVariables; index++) {
if (recorder->variableInfos[type]->variables[index] == variable) {
break;
}
}

switch (type) {
case FMIFloat32Type:
case FMIDiscreteFloat32Type:
{
const float* values = (float*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIFloat64Type:
case FMIDiscreteFloat64Type:
{
const double* values = (double*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIInt8Type:
{
const int8_t* values = (int8_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIUInt8Type:
{
const uint8_t* values = (uint8_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIInt16Type:
{
const int16_t* values = (int16_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIUInt16Type:
{
const uint16_t* values = (uint16_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIInt32Type:
{
const int32_t* values = (int32_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIUInt32Type:
{
const uint32_t* values = (uint32_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIInt64Type:
{
const int64_t* values = (int64_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIUInt64Type:
{
const uint64_t* values = (uint64_t*)row->values[type];
y += QString::number(values[index]);
}
break;
case FMIBooleanType:
{
const bool* values = (bool*)row->values[type];
y += QString::number(values[index]);
}
break;
default:
y += "0";
break;
}
}

if (k > 0) {
data += ", ";
}

data += "{x: time, y: [" + y + "], type: 'scatter', name: '', line: {color: '#248BD2', width: 1.5";


if (variable->variability == FMIContinuous) {
data += "}";
} else if (type == FMIBooleanType) {
data += ", shape: 'hv'}, fill: 'tozeroy'";
} else {
data += ", shape: 'hv'}";
}

if (k > 0) {
const QString plotIndex = QString::number(k + 1);
data += ", xaxis: 'x" + plotIndex + "', yaxis: 'y" + plotIndex + "'";
}

data += "}\n";

k++;
}

data += "];\n";

QString axes;

k = 0;

for (size_t i = 0; i < recorder->nVariables; i++) {

const FMIModelVariable* variable = recorder->variables[i];

if (!plotVariables.contains(variable)) {
continue;
}

const QString name = QString::fromUtf8(variable->name);

const QString colors = colorScheme == Qt::ColorScheme::Dark ? "color: '#fff', zerolinecolor: '#666'" : "color: '#000', zerolinecolor: '#000'";

const double segment = 1.0 / plotVariables.size();
const double margin = 0.02;

const QString domain = "[" + QString::number(k * segment + (k == 0 ? 0.0 : margin)) + ", " + QString::number((k + 1) * segment - (k == recorder->nVariables ? 0.0 : margin)) + "]";

if (k == 0) {
axes += "xaxis: {" + colors + "},";
axes += "yaxis: {title: '" + name + "', titlefont: {size: 13}, " + colors + ", domain: " + domain + "},";
} else {
axes += "xaxis" + QString::number(k + 1) + ": {" + colors + ", matches: 'x'},";
axes += "yaxis" + QString::number(k + 1) + ": {title: '" + name + "', titlefont: {size: 13}, " + colors + ", domain: " + domain + "},";
}

k++;
}
std::sort(plotVariables.begin(), plotVariables.end(), [](const FMIModelVariable* a, const FMIModelVariable* b) {
return QString(a->name) > QString(b->name);
});

QString plotColors = colorScheme == Qt::ColorScheme::Dark ? "plot_bgcolor: '#1e1e1e', paper_bgcolor: '#1e1e1e'," : "";
const QString javaScript = PlotUtil::createPlot(
simulationThread->settings->initialRecorder,
simulationThread->settings->recorder,
plotVariables,
colorScheme);

QString javaScript =
data +
" var layout = {"
" showlegend: false,"
" autosize: true,"
" font: {family: 'Segoe UI', size: 12},"
+ plotColors +
" grid: {rows: " + QString::number(plotVariables.size()) + ", columns: 1, pattern: 'independent'},"
+ axes +
" margin: { l: 60, r: 20, b: 20, t: 20, pad: 0 }"
"};"
"var config = {"
" 'responsive': true"
"};"
"Plotly.newPlot('gd', data, layout, config);";
// qDebug().noquote() << javaScript;

ui->plotWebEngineView->page()->runJavaScript(javaScript);
}

void MainWindow::unloadFMU() {

variablesListModel->setModelDescription(nullptr);
modelVariablesTreeModel->setModelDescription(nullptr);

if (modelDescription) {
FMIFreeModelDescription(modelDescription);
modelDescription = nullptr;
Expand Down
8 changes: 7 additions & 1 deletion fmusim-gui/ModelVariablesTableModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ ModelVariablesTableModel::ModelVariablesTableModel(QObject *parent)
}

QModelIndex ModelVariablesTableModel::index(int row, int column, const QModelIndex &parent) const {
FMIModelVariable* variable = modelDescription->modelVariables[row];

FMIModelVariable* variable = nullptr;

if (row >= 0 && row < modelDescription->nModelVariables) {
variable = modelDescription->modelVariables[row];
}

return createIndex(row, column, variable);
}

Expand Down
54 changes: 30 additions & 24 deletions fmusim-gui/ModelVariablesTreeModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,43 +72,49 @@ void ModelVariablesTreeModel::setModelDescription(const FMIModelDescription *mod

beginResetModel();

for (size_t i = 0; i < modelDescription->nModelVariables; i++) {
this->modelDescription = modelDescription;

const FMIModelVariable* variable = modelDescription->modelVariables[i];
if (modelDescription) {

QString name = variable->name;
QString prefix;
QString suffix;
for (size_t i = 0; i < modelDescription->nModelVariables; i++) {

if (name.startsWith("der(") && name.endsWith(")")) {
prefix = "der(";
suffix = ")";
name = name.sliced(4, name.length() - 5);
}
const FMIModelVariable* variable = modelDescription->modelVariables[i];

QString name = variable->name;
QString prefix;
QString suffix;

if (name.startsWith("der(") && name.endsWith(")")) {
prefix = "der(";
suffix = ")";
name = name.sliced(4, name.length() - 5);
}

const QStringList segments = QString(name).split('.');
const QStringList segments = QString(name).split('.');

TreeItem* parentItem = rootItem;
TreeItem* parentItem = rootItem;

for (const QString& segment : segments.sliced(0, segments.length() - 1)) {
for (const QString& segment : segments.sliced(0, segments.length() - 1)) {

TreeItem* p = parentItem->find(segment);
TreeItem* p = parentItem->find(segment);

if (!p) {
p = new TreeItem();
p->name = segment;
parentItem->addChild(p);
if (!p) {
p = new TreeItem();
p->name = segment;
parentItem->addChild(p);
}

parentItem = p;
}

parentItem = p;
}
TreeItem* treeItem = new TreeItem();

TreeItem* treeItem = new TreeItem();
treeItem->name = prefix + segments.last() + suffix;
treeItem->modelVariable = variable;

treeItem->name = prefix + segments.last() + suffix;
treeItem->modelVariable = variable;
parentItem->addChild(treeItem);
}

parentItem->addChild(treeItem);
}

endResetModel();
Expand Down
Loading

0 comments on commit cb4a572

Please sign in to comment.