Skip to content
This repository has been archived by the owner on May 18, 2019. It is now read-only.

Commit

Permalink
Added flags for input and output path.
Browse files Browse the repository at this point in the history
Input path flag `-inputPath` is used to read the model_init.xml and model_info.json files. `-f` flag for model_init.xml file gets the preference over `-inputPath`.
Output path flag `-outputPath` is used to write the output files like model_res.mat, model_prof.intdata etc. `-r` flag for model_res.mat file gets preference over `-outputPath` flag.
Fixes ticket:4583 where we need to set a different working directory for simulation executable.

Belonging to [master]:
  - #1970
  • Loading branch information
adeas31 authored and OpenModelica-Hudson committed Nov 7, 2017
1 parent 1a778dd commit 1be2a07
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 48 deletions.
84 changes: 49 additions & 35 deletions SimulationRuntime/c/simulation/modelinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ static void indent(FILE *fout, int n) {
while(n--) fputc(' ', fout);
}

static void convertProfileData(const char *prefix, int numFnsAndBlocks)
static void convertProfileData(const char *outputPath, const char *prefix, int numFnsAndBlocks)
{
size_t len = strlen(prefix);
const char* fullFileName;
if (0 > GC_asprintf((char**)&fullFileName, "%s%s", outputPath, prefix)) {
throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
}
size_t len = strlen(fullFileName);
char *inBinaryInt = (char*)malloc(sizeof(char)*(len + 14));
char *inBinaryReal = (char*)malloc(sizeof(char)*(len + 15));
char *outCsv = (char*)malloc(sizeof(char)*(len + 10));
FILE *finInt, *finReal, *fout;
int fail = 0;
size_t intRowSize = sizeof(uint32_t)*(1+numFnsAndBlocks);
Expand All @@ -81,8 +84,8 @@ static void convertProfileData(const char *prefix, int numFnsAndBlocks)
* But it is not worse than in-memory and may be paged out on low memory. */
omc_mmap_write intMap,realMap;

memcpy(inBinaryInt,prefix,len);
memcpy(inBinaryReal,prefix,len);
memcpy(inBinaryInt,fullFileName,len);
memcpy(inBinaryReal,fullFileName,len);
strcpy(inBinaryInt + len, "_prof.intdata");
strcpy(inBinaryReal + len, "_prof.realdata");

Expand All @@ -100,12 +103,11 @@ static void convertProfileData(const char *prefix, int numFnsAndBlocks)

free(inBinaryInt);
free(inBinaryReal);
free(outCsv);
}

static void printPlotCommand(FILE *plt, const char *plotFormat, const char *title, const char *prefix, int numFnsAndBlocks, int i, int id, const char *idPrefix) {
const char *format = "plot \"%s_prof.realdata\" binary format=\"%%%ddouble\" using 1:($%d>1e-9 ? $%d : 1e-30) w l lw %d\n";
const char *formatCount = "plot \"%s_prof.intdata\" binary format=\"%%%duint32\" using %d w l lw %d\n";
static void printPlotCommand(FILE *plt, const char *plotFormat, const char *title, const char *outputPath, const char *prefix, int numFnsAndBlocks, int i, int id, const char *idPrefix) {
const char *format = "plot \"%s%s_prof.realdata\" binary format=\"%%%ddouble\" using 1:($%d>1e-9 ? $%d : 1e-30) w l lw %d\n";
const char *formatCount = "plot \"%s%s_prof.intdata\" binary format=\"%%%duint32\" using %d w l lw %d\n";
unsigned long nmin = 0, nmax = 0;
double ymin = 0.0, ymax = 0.0;
double ygraphmin = 1e-30, ygraphmax = 0.0;
Expand All @@ -127,7 +129,7 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
fprintf(plt, "unset xtics\n");
fprintf(plt, "unset ytics\n");
fprintf(plt, "unset border\n");
fprintf(plt, "set output \"%s_prof.%s%d.thumb.svg\"\n", prefix, idPrefix, id);
fprintf(plt, "set output \"%s%s_prof.%s%d.thumb.svg\"\n", outputPath, prefix, idPrefix, id);
fprintf(plt, "set title\n");
fprintf(plt, "set xlabel\n");
fprintf(plt, "set ylabel\n");
Expand All @@ -142,7 +144,7 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
fprintf(plt, "set yrange [*:*]\n");
}
/* time */
fprintf(plt, format, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 4);
fprintf(plt, format, outputPath, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 4);
fprintf(plt, "set nolog xy\n");
/* count */
if(i >= 0) {
Expand All @@ -155,8 +157,8 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
{
fprintf(plt, "set yrange [*:*]\n");
}
fprintf(plt, "set output \"%s_prof.%s%d_count.thumb.svg\"\n", prefix, idPrefix, id);
fprintf(plt, formatCount, prefix, 1+numFnsAndBlocks, 2+i, 4);
fprintf(plt, "set output \"%s%s_prof.%s%d_count.thumb.svg\"\n", outputPath, prefix, idPrefix, id);
fprintf(plt, formatCount, outputPath, prefix, 1+numFnsAndBlocks, 2+i, 4);
fprintf(plt, "set ytics\n");
}

Expand All @@ -168,7 +170,7 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
fprintf(plt, "set title \"%s\"\n", title);
fprintf(plt, "set xlabel \"Global step at time\"\n");
fprintf(plt, "set ylabel \"Execution time [s]\"\n");
fprintf(plt, "set output \"%s_prof.%s%d.%s\"\n", prefix, idPrefix, id, plotFormat);
fprintf(plt, "set output \"%s%s_prof.%s%d.%s\"\n", outputPath, prefix, idPrefix, id, plotFormat);
fprintf(plt, "set log y\n");
if(i>=0)
{
Expand All @@ -178,7 +180,7 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
{
fprintf(plt, "set yrange [*:*]\n");
}
fprintf(plt, format, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 2);
fprintf(plt, format, outputPath, prefix, 2+numFnsAndBlocks, 3+i, 3+i, 2);
/* count */
fprintf(plt, "set nolog xy\n");
if(i >= 0)
Expand All @@ -194,7 +196,7 @@ static void printPlotCommand(FILE *plt, const char *plotFormat, const char *titl
fprintf(plt, "set xlabel \"Global step number\"\n");
fprintf(plt, "set ylabel \"Execution count\"\n");
fprintf(plt, "set output \"%s_prof.%s%d_count.%s\"\n", prefix, idPrefix, id, plotFormat);
fprintf(plt, formatCount, prefix, 1+numFnsAndBlocks, 2+i, 2);
fprintf(plt, formatCount, outputPath, prefix, 1+numFnsAndBlocks, 2+i, 2);
}
}

Expand Down Expand Up @@ -234,11 +236,11 @@ static void printVar(FILE *fout, int level, VAR_INFO* info) {
}


static void printFunctions(FILE *fout, FILE *plt, const char *plotFormat, const char *modelFilePrefix, DATA *data) {
static void printFunctions(FILE *fout, FILE *plt, const char *plotFormat, const char *outputPath, const char *modelFilePrefix, DATA *data) {
int i;
for(i=0; i<data->modelData->modelDataXml.nFunctions; i++) {
const struct FUNCTION_INFO func = modelInfoGetFunction(&data->modelData->modelDataXml, i);
printPlotCommand(plt, plotFormat, func.name, modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, func.id, "fun");
printPlotCommand(plt, plotFormat, func.name, outputPath, modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, func.id, "fun");
rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
indent(fout,2);
fprintf(fout, "<function id=\"fun%d\">\n", func.id);
Expand All @@ -252,11 +254,11 @@ static void printFunctions(FILE *fout, FILE *plt, const char *plotFormat, const
}
}

static void printProfileBlocks(FILE *fout, FILE *plt, const char *plotFormat, DATA *data) {
static void printProfileBlocks(FILE *fout, FILE *plt, const char *plotFormat, const char *outputPath, DATA *data) {
int i;
for(i = data->modelData->modelDataXml.nFunctions; i < data->modelData->modelDataXml.nFunctions + data->modelData->modelDataXml.nProfileBlocks; i++) {
const struct EQUATION_INFO eq = modelInfoGetEquationIndexByProfileBlock(&data->modelData->modelDataXml, i-data->modelData->modelDataXml.nFunctions);
printPlotCommand(plt, plotFormat, "equation", data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, eq.id, "eq");
printPlotCommand(plt, plotFormat, "equation", outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, i, eq.id, "eq");
rt_clear(i + SIM_TIMER_FIRST_FUNCTION);
indent(fout,2);fprintf(fout, "<profileblock>\n");
indent(fout,4);fprintf(fout, "<ref refid=\"eq%d\"/>\n", (int) eq.id);
Expand Down Expand Up @@ -314,30 +316,38 @@ static void printProfilingDataHeader(FILE *fout, DATA *data) {
indent(fout, 2); fprintf(fout, "</format>\n");
}

int printModelInfo(DATA *data, threadData_t *threadData, const char *filename, const char *plotfile, const char *plotFormat, const char *method, const char *outputFormat, const char *outputFilename)
int printModelInfo(DATA *data, threadData_t *threadData, const char *outputPath, const char *filename, const char *plotfile, const char *plotFormat, const char *method, const char *outputFormat, const char *outputFilename)
{
static char buf[256];
FILE *fout = fopen(filename, "w");
const char* fullFileName;
if (0 > GC_asprintf((char**)&fullFileName, "%s%s", outputPath, filename)) {
throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
}
FILE *fout = fopen(fullFileName, "w");
FILE *plotCommands;
time_t t;
int i;
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(NO_PIPE)
plotCommands = fopen(plotfile, "w");
const char* fullPlotFile;
if (0 > GC_asprintf((char**)&fullPlotFile, "%s%s", outputPath, plotfile)) {
throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
}
plotCommands = fopen(fullPlotFile, "w");
#else
plotCommands = popen("gnuplot", "w");
#endif
if (!plotCommands) {
warningStreamPrint(LOG_UTIL, 0, "Plots of profiling data were disabled: %s\n", strerror(errno));
}

assertStreamPrint(threadData, 0 != fout, "Failed to open %s: %s\n", filename, strerror(errno));
assertStreamPrint(threadData, 0 != fout, "Failed to open %s%s: %s\n", outputPath, filename, strerror(errno));

if(plotCommands) {
fputs("set terminal svg\n", plotCommands);
fputs("set nokey\n", plotCommands);
fputs("set format y \"%g\"\n", plotCommands);
/* The column containing the time spent to calculate each step */
printPlotCommand(plotCommands, plotFormat, "Execution time of global steps", data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, -1, 999, "");
printPlotCommand(plotCommands, plotFormat, "Execution time of global steps", outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks, -1, 999, "");
}
/* The doctype is needed for id() lookup to work properly */
fprintf(fout, "<!DOCTYPE doc [\
Expand Down Expand Up @@ -425,15 +435,15 @@ int printModelInfo(DATA *data, threadData_t *threadData, const char *filename, c
fprintf(fout, "</variables>\n");

fprintf(fout, "<functions>\n");
printFunctions(fout, plotCommands, plotFormat, data->modelData->modelFilePrefix, data);
printFunctions(fout, plotCommands, plotFormat, outputPath, data->modelData->modelFilePrefix, data);
fprintf(fout, "</functions>\n");

fprintf(fout, "<equations>\n");
printEquations(fout, data->modelData->modelDataXml.nEquations, &data->modelData->modelDataXml);
fprintf(fout, "</equations>\n");

fprintf(fout, "<profileblocks>\n");
printProfileBlocks(fout, plotCommands, plotFormat, data);
printProfileBlocks(fout, plotCommands, plotFormat, outputPath, data);
fprintf(fout, "</profileblocks>\n");

fprintf(fout, "</simulation>\n");
Expand All @@ -448,7 +458,7 @@ int printModelInfo(DATA *data, threadData_t *threadData, const char *filename, c
#if defined(__MINGW32__) || defined(_MSC_VER) || defined(NO_PIPE)
if(omhome) {
#if defined(__MINGW32__) || defined(_MSC_VER)
sprintf(buf, "%s/lib/omc/libexec/gnuplot/binary/gnuplot.exe %s", omhome, plotfile);
sprintf(buf, "%s/lib/omc/libexec/gnuplot/binary/gnuplot.exe %s%s", omhome, outputPath, plotfile);
#else
sprintf(buf, "gnuplot %s", plotfile);
#endif
Expand All @@ -471,7 +481,7 @@ int printModelInfo(DATA *data, threadData_t *threadData, const char *filename, c
#else
const char *xsltproc = "xsltproc";
#endif
sprintf(buf, "%s -o %s_prof.html %s/share/omc/scripts/default_profiling.xsl %s_prof.xml", xsltproc, data->modelData->modelFilePrefix, omhome, data->modelData->modelFilePrefix);
sprintf(buf, "%s -o %s%s_prof.html %s/share/omc/scripts/default_profiling.xsl %s%s_prof.xml", xsltproc, outputPath, data->modelData->modelFilePrefix, omhome, outputPath, data->modelData->modelFilePrefix);
#if defined(__MINGW32__) || defined(_MSC_VER)
free(xsltproc);
#endif
Expand All @@ -487,9 +497,9 @@ int printModelInfo(DATA *data, threadData_t *threadData, const char *filename, c
warningStreamPrint(LOG_STDOUT, 0, "Failed to generate html version of profiling results: %s\n", buf);
}
if (measure_time_flag & 4) {
infoStreamPrint(LOG_STDOUT, 0, "Time measurements are stored in %s_prof.html (human-readable) and %s_prof.xml (for XSL transforms or more details)", data->modelData->modelFilePrefix, data->modelData->modelFilePrefix);
infoStreamPrint(LOG_STDOUT, 0, "Time measurements are stored in %s%s_prof.html (human-readable) and %s%s_prof.xml (for XSL transforms or more details)", outputPath, data->modelData->modelFilePrefix, outputPath, data->modelData->modelFilePrefix);
} else {
infoStreamPrint(LOG_STDOUT, 0, "Time measurements are stored in %s_prof.json", data->modelData->modelFilePrefix);
infoStreamPrint(LOG_STDOUT, 0, "Time measurements are stored in %s%s_prof.json", outputPath, data->modelData->modelFilePrefix);
}
free(buf);
}
Expand Down Expand Up @@ -549,17 +559,21 @@ static void printJSONProfileBlocks(FILE *fout, DATA *data) {
}
}

int printModelInfoJSON(DATA *data, threadData_t *threadData, const char *filename, const char *outputFilename)
int printModelInfoJSON(DATA *data, threadData_t *threadData, const char *outputPath, const char *filename, const char *outputFilename)
{
char buf[256];
FILE *fout = fopen(filename, "wb");
const char* fullFileName;
if (0 > GC_asprintf((char**)&fullFileName, "%s%s", outputPath, filename)) {
throwStreamPrint(NULL, "modelinfo.c: Error: can not allocate memory.");
}
FILE *fout = fopen(fullFileName, "wb");
time_t t;
long i;
double totalTimeEqs = 0;
if (!fout) {
throwStreamPrint(NULL, "Failed to open file %s for writing", filename);
throwStreamPrint(NULL, "Failed to open file %s%s for writing", outputPath, filename);
}
convertProfileData(data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks);
convertProfileData(outputPath, data->modelData->modelFilePrefix, data->modelData->modelDataXml.nFunctions+data->modelData->modelDataXml.nProfileBlocks);
if(time(&t) < 0)
{
fclose(fout);
Expand Down
4 changes: 2 additions & 2 deletions SimulationRuntime/c/simulation/modelinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
extern "C" {
#endif

int printModelInfo(DATA *data, threadData_t *threadData, const char *modelinfo, const char *plotinfo, const char *plotFormat, const char *method, const char *outputFormat, const char *outputFilename);
int printModelInfoJSON(DATA *data, threadData_t *threadData, const char *filename, const char *outputFilename);
int printModelInfo(DATA *data, threadData_t *threadData, const char *outputPath, const char *modelinfo, const char *plotinfo, const char *plotFormat, const char *method, const char *outputFormat, const char *outputFilename);
int printModelInfoJSON(DATA *data, threadData_t *threadData, const char *outputPath, const char *filename, const char *outputFilename);

#ifdef __cplusplus
}
Expand Down
11 changes: 10 additions & 1 deletion SimulationRuntime/c/simulation/simulation_info_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "simulation_info_json.h"
#include "simulation_runtime.h"
#include "options.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
Expand Down Expand Up @@ -377,7 +378,15 @@ void modelInfoInit(MODEL_DATA_XML* xml)
rt_tick(0);
#if !defined(OMC_NO_FILESYSTEM)
if (!xml->infoXMLData) {
mmap_reader = omc_mmap_open_read(xml->fileName);
const char *filename;
if (omc_flag[FLAG_INPUT_PATH]) { /* read the input path from the command line (if any) */
if (0 > GC_asprintf((char**)&filename, "%s/%s", omc_flagValue[FLAG_INPUT_PATH], xml->fileName)) {
throwStreamPrint(NULL, "simulation_info_json.c: Error: can not allocate memory.");
}
mmap_reader = omc_mmap_open_read(filename);
} else {
mmap_reader = omc_mmap_open_read(xml->fileName);
}
xml->infoXMLData = mmap_reader.data;
xml->modelInfoXmlLength = mmap_reader.size;
// fprintf(stderr, "Loaded the JSON (%ld kB)...\n", (long) (s.st_size+1023)/1024);
Expand Down
6 changes: 5 additions & 1 deletion SimulationRuntime/c/simulation/simulation_input_xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,12 @@ void read_input_xml(MODEL_DATA* modelData,
if(NULL == modelData->initXMLData)
{
/* read the filename from the command line (if any) */
if(omc_flag[FLAG_F]) {
if (omc_flag[FLAG_F]) {
filename = omc_flagValue[FLAG_F];
} else if (omc_flag[FLAG_INPUT_PATH]) { /* read the input path from the command line (if any) */
if (0 > GC_asprintf((char**)&filename, "%s/%s_init.xml", omc_flagValue[FLAG_INPUT_PATH], modelData->modelFilePrefix)) {
throwStreamPrint(NULL, "simulation_input_xml.c: Error: can not allocate memory.");
}
} else {
/* no file given on the command line? use the default
* model_name defined in generated code for model.*/
Expand Down
22 changes: 15 additions & 7 deletions SimulationRuntime/c/simulation/simulation_runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,11 +457,16 @@ int startNonInteractiveSimulation(int argc, char**argv, DATA* data, threadData_t
// Create a result file
const char *result_file = omc_flagValue[FLAG_R];
string result_file_cstr;
if(!result_file) {
if (result_file) {
data->modelData->resultFileName = GC_strdup(result_file);
} else if (omc_flag[FLAG_OUTPUT_PATH]) { /* read the output path from the command line (if any) */
if (0 > GC_asprintf((char**)&result_file, "%s/%s_res.%s", omc_flagValue[FLAG_OUTPUT_PATH], data->modelData->modelFilePrefix, data->simulationInfo->outputFormat)) {
throwStreamPrint(NULL, "simulation_runtime.c: Error: can not allocate memory.");
}
data->modelData->resultFileName = GC_strdup(result_file);
} else {
result_file_cstr = string(data->modelData->modelFilePrefix) + string("_res.") + data->simulationInfo->outputFormat;
data->modelData->resultFileName = GC_strdup(result_file_cstr.c_str());
} else {
data->modelData->resultFileName = GC_strdup(result_file);
}

string init_initMethod = "";
Expand Down Expand Up @@ -516,16 +521,19 @@ int startNonInteractiveSimulation(int argc, char**argv, DATA* data, threadData_t
* So before doing the profiling reset the measure_time_flag to measure_time_flag_previous state.
*/
measure_time_flag = measure_time_flag_previous;

if(0 == retVal && measure_time_flag) {
string output_path = "";
if (0 == retVal && measure_time_flag) {
if (omc_flag[FLAG_OUTPUT_PATH]) { /* read the output path from the command line (if any) */
output_path = string(omc_flagValue[FLAG_INPUT_PATH]) + string("/");
}
const string jsonInfo = string(data->modelData->modelFilePrefix) + "_prof.json";
const string modelInfo = string(data->modelData->modelFilePrefix) + "_prof.xml";
const string plotFile = string(data->modelData->modelFilePrefix) + "_prof.plt";
rt_accumulate(SIM_TIMER_TOTAL);
const char* plotFormat = omc_flagValue[FLAG_MEASURETIMEPLOTFORMAT];
retVal = printModelInfo(data, threadData, modelInfo.c_str(), plotFile.c_str(), plotFormat ? plotFormat : "svg",
retVal = printModelInfo(data, threadData, output_path.c_str(), modelInfo.c_str(), plotFile.c_str(), plotFormat ? plotFormat : "svg",
data->simulationInfo->solverMethod, data->simulationInfo->outputFormat, data->modelData->resultFileName) && retVal;
retVal = printModelInfoJSON(data, threadData, jsonInfo.c_str(), data->modelData->resultFileName) && retVal;
retVal = printModelInfoJSON(data, threadData, output_path.c_str(), jsonInfo.c_str(), data->modelData->resultFileName) && retVal;
}

TRACE_POP
Expand Down
12 changes: 10 additions & 2 deletions SimulationRuntime/c/simulation/solver/perform_simulation.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,17 @@ static void fmtInit(DATA* data, MEASURE_TIME* mt)
mt->fmtInt = NULL;
if(measure_time_flag)
{
size_t len = strlen(data->modelData->modelFilePrefix);
const char* fullFileName;
if (omc_flag[FLAG_OUTPUT_PATH]) { /* read the output path from the command line (if any) */
if (0 > GC_asprintf((char**)&fullFileName, "%s/%s", omc_flagValue[FLAG_OUTPUT_PATH], data->modelData->modelFilePrefix)) {
throwStreamPrint(NULL, "perform_simulation.c: Error: can not allocate memory.");
}
} else {
fullFileName = data->modelData->modelFilePrefix;
}
size_t len = strlen(fullFileName);
char* filename = (char*) malloc((len+15) * sizeof(char));
strncpy(filename,data->modelData->modelFilePrefix,len);
strncpy(filename,fullFileName,len);
strncpy(&filename[len],"_prof.realdata",15);
mt->fmtReal = fopen(filename, "wb");
if(!mt->fmtReal)
Expand Down

1 comment on commit 1be2a07

@sjoelund
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remember that there should be an empty line after the commit summary and commit message or things depending on git conventions fail: https://libraries.openmodelica.org/branches/history/master/2017-11-06%2011:14:19..2017-11-08%2002:39:00.html

Please sign in to comment.