Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions models/prune/prune_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,24 @@ expect_not_present "_test_12_f"
expect_not_present "_test_13_cond"
expect_not_present "_test_13_f"

# Test sparse input setting in `main.c` by running the generated binary with custom
# input values:
# Input 2 (index 1) = 120.123
# Input 1 (index 0) = 110
# Expected:
# Input 1 and 2 Total = 230.123
INPUT_FILE=output/prune_inputs.txt
echo "1:120.123 0:110" > "$INPUT_FILE"
OUTPUT=$(./build/prune "$INPUT_FILE")

# Extract "Input 1 and 2 Total" (column 2) from the t=0 row (line 2)
ACTUAL=$(echo "$OUTPUT" | sed -n '2p' | cut -f2)
EXPECTED="230.123"
if [[ "$ACTUAL" != "$EXPECTED" ]]; then
echo "ERROR: Expected 'Input 1 and 2 Total' at t=0 to be '$EXPECTED' but got '$ACTUAL'"
echo "Output was:"
echo "$OUTPUT"
exit 1
fi

echo "All validation checks passed!"
53 changes: 0 additions & 53 deletions notes/main-perftest.c

This file was deleted.

141 changes: 118 additions & 23 deletions packages/cli/src/c/main.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,82 @@
#include "sde.h"

/**
* Count the number of input pairs in the input string in the format
* "varIndex:value varIndex:value ..." (for example, "0:3.14 6:42").
*/
static size_t countInputs(const char* inputData) {
if (inputData == NULL || *inputData == '\0') {
return 0;
}

// Make a copy since strtok modifies the string
char* inputsCopy = (char*)malloc(strlen(inputData) + 1);
strcpy(inputsCopy, inputData);

size_t count = 0;
char* token = strtok(inputsCopy, " ");
while (token) {
if (strchr(token, ':') != NULL) {
count++;
}
token = strtok(NULL, " ");
}
free(inputsCopy);

return count;
}

/**
* Parse an input data string in the format "varIndex:value varIndex:value ..."
* (for example, "0:3.14 6:42") and populate the inputValues and inputIndices
* arrays for sparse input setting.
*
* @param inputData The input string to parse.
* @param inputValues The array to populate with input values.
* @param inputIndices The array to populate with input indices (first element is count).
*/
static void parseInputs(const char* inputData, double* inputValues, int32_t* inputIndices) {
if (inputData == NULL || *inputData == '\0') {
return;
}

// Make a copy since strtok modifies the string
char* inputsCopy = (char*)malloc(strlen(inputData) + 1);
strcpy(inputsCopy, inputData);

size_t i = 0;
char* token = strtok(inputsCopy, " ");
while (token) {
char* p = strchr(token, ':');
if (p) {
*p = '\0';
int modelVarIndex = atoi(token);
double value = atof(p + 1);
inputIndices[i + 1] = modelVarIndex;
inputValues[i] = value;
i++;
}
token = strtok(NULL, " ");
}
inputIndices[0] = (int32_t)i;
free(inputsCopy);
}

int main(int argc, char** argv) {
// TODO make the input buffer size dynamic
char inputs[500000];
char inputString[500000];
// When true, output data without newlines or a header, suitable for embedding reference data.
bool raw_output = false;
// When true, suppress data output when using PR* macros.
bool suppress_data_output = false;
// Try to read input from a file named in the argument.
if (argc > 1) {
FILE* instream = fopen(argv[1], "r");
if (instream && fgets(inputs, sizeof inputs, instream) != NULL) {
if (instream && fgets(inputString, sizeof inputString, instream) != NULL) {
fclose(instream);
size_t len = strlen(inputs);
if (inputs[len - 1] == '\n') {
inputs[len - 1] = '\0';
size_t len = strlen(inputString);
if (inputString[len - 1] == '\n') {
inputString[len - 1] = '\0';
}
}
if (argc > 2) {
Expand All @@ -24,35 +86,68 @@ int main(int argc, char** argv) {
}
}
} else {
*inputs = '\0';
*inputString = '\0';
}

// Parse input string and create sparse input arrays. Only allocate buffers if there
// are inputs to parse; otherwise pass NULL to runModelWithBuffers so that the model
// uses its default values from initConstants.
double* inputValues = NULL;
int32_t* inputIndices = NULL;
size_t inputCount = countInputs(inputString);
if (inputCount > 0) {
inputValues = (double*)malloc(inputCount * sizeof(double));
inputIndices = (int32_t*)malloc((inputCount + 1) * sizeof(int32_t));
parseInputs(inputString, inputValues, inputIndices);
}
// Run the model and get output for all time steps.
char* outputs = run_model(inputs);

// Calculate the number of save points for the output buffer
double initialTime = getInitialTime();
double finalTime = getFinalTime();
double saveper = getSaveper();
size_t numSavePoints = (size_t)(round((finalTime - initialTime) / saveper)) + 1;

// Allocate output buffer
double* outputBuffer = (double*)malloc(numOutputs * numSavePoints * sizeof(double));

// Run the model with the sparse input arrays and output buffer
runModelWithBuffers(inputValues, inputIndices, outputBuffer, NULL);

if (!suppress_data_output) {
if (raw_output) {
// Write raw output data directly.
fputs(outputs, stdout);
// Write raw output data directly (tab-separated, no newlines)
for (size_t t = 0; t < numSavePoints; t++) {
for (size_t v = 0; v < numOutputs; v++) {
// Output buffer is organized by variable (each variable has numSavePoints values)
double value = outputBuffer[v * numSavePoints + t];
printf("%g\t", value);
}
}
} else {
// Write a header for output data.
printf("%s\n", getHeader());
// Write tab-delimited output data, one line per output time step.
if (outputs != NULL) {
char* p = outputs;
while (*p) {
char* line = p;
for (size_t i = 0; i < numOutputs; i++) {
if (i > 0) {
p++;
}
while (*p && *p != '\t') {
p++;
}
for (size_t t = 0; t < numSavePoints; t++) {
for (size_t v = 0; v < numOutputs; v++) {
// Output buffer is organized by variable (each variable has numSavePoints values)
double value = outputBuffer[v * numSavePoints + t];
if (v > 0) {
printf("\t");
}
*p++ = '\0';
printf("%s\n", line);
printf("%g", value);
}
printf("\n");
}
}
}

// Clean up
if (inputValues != NULL) {
free(inputValues);
}
if (inputIndices != NULL) {
free(inputIndices);
}
free(outputBuffer);
finish();
}
Loading