Tutorial: Converting a C Model
This tutorial provides a step-by-step guide to converting a simulation model written in C into a Functional Mock-up Unit (FMU) using the Jingongo SDK.
The process is very similar to converting a Python model. The SDK packages your local C source files, uploads them to the Jingongo cloud platform, and orchestrates the remote compilation and packaging into a final .fmu
file.
Prerequisites
Before you begin, please ensure you have completed the following steps from our "Getting Started" guide:
- Installed the SDK:
pip install jingongo-framework
- Generated and configured your API Key: The
JINGONGO_API_KEY
environment variable must be set.
The Example C Model
For this tutorial, we will use the sample c_identity_block_model
located in the examples/example_models/
directory of our repository. This is a simple "pass-through" model that demonstrates the required file structure and configuration.
1. The C Source Code
A C-based model for Jingongo typically requires at least two files: a header (.h
) and a source (.c
) file. These files must implement a specific interface that the Jingongo engine can call into.
model.h
(The Header File)
This file defines the data structure that holds your model's state, inputs, outputs, and parameters.
// examples/example_models/c_identity_block_model/model.h
#ifndef MODEL_H
#define MODEL_H
// This struct defines the memory for our model.
// It holds all variables the simulation engine needs to interact with.
typedef struct {
// Inputs
double input_value;
// Outputs
double output_value;
// Parameters
double gain;
} ModelData;
#endif // MODEL_H
model.c (The Source File) This file contains the core logic of your simulation. It implements functions to initialize the model and to perform a "step" in the simulation.
// examples/example_models/c_identity_block_model/model.c
#include "model.h"
// The 'do_step' function is the heart of the simulation.
// It is called at each time step by the Jingongo engine.
void do_step(ModelData* data, double dt) {
// This model's logic is very simple:
// output = input * gain
data->output_value = data->input_value * data->gain;
}
// The 'initialize' function is called once at the beginning.
// It sets the initial state of the model.
void initialize(ModelData* data) {
// Set default starting values
data->input_value = 0.0;
data->output_value = 0.0;
// 'gain' is a parameter, so its value will be set by the
// configuration and does not need to be initialized here.
}
2. The Jingongo Configuration File
The .jingongo.yml file is crucial. It acts as the "manifest" for your model, telling the Jingongo engine everything it needs to know about your C code, including its variables and parameters.
.jingongo.yml
# examples/example_models/c_identity_block_model/.jingongo.yml
model:
# Basic metadata for your model
model_name: "C_Identity_Block"
version: "1.0.1"
description: "A simple pass-through model implemented in C."
language: "c"
# Define the variables the outside world can interact with
inputs:
- name: "input_value"
type: "Real" # Corresponds to 'double' in C
outputs:
- name: "output_value"
type: "Real" # Corresponds to 'double' in C
parameters:
- name: "gain"
type: "Real"
default: 1.0 # The default value if not overridden
The Conversion Script
The Python script below orchestrates the entire conversion process. It points the Jingongo SDK to your local model directory, and the SDK handles the rest.
This script is available at examples/03_convert_c_model.py in the repository.
# examples/03_convert_c_model.py
import os
import sys
import json
import logging
from pathlib import Path
# Make the SDK importable when running from the repo root
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../src')))
from jingongo import Jingongo
# --- Configuration ---
JINGONGO_API_BASE_URL = "https://jingongo-backend-api-723715926581.us-central1.run.app"
def main():
"""
Demonstrates converting a local C-based model into an FMU.
"""
print("--- Tutorial: Converting a C model to an FMU ---")
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
api_key = os.environ.get("JINGONGO_API_KEY")
if not api_key:
print("\n❌ Error: Please set the JINGONGO_API_KEY environment variable.")
return
try:
# 1. Initialize the Jingongo client
client = Jingongo(JINGONGO_API_BASE_URL, api_key, verbose=True)
# 2. Define the path to the local model directory
c_model_path = Path(__file__).parent / "example_models" / "c_identity_block_model"
if not c_model_path.exists():
raise FileNotFoundError(f"❌ Model directory not found: {c_model_path.resolve()}")
print(f"\n🚀 Starting conversion for model at: {c_model_path}")
# 3. Call the core conversion method
# The SDK will zip the directory, upload it, and start the conversion.
# It automatically reads the .jingongo.yml for metadata.
c_job = client.convert_to_fmu(
project_path=c_model_path,
language="c" # We specify the language here
)
print("\n✅ C Conversion Job Finished!")
print("Backend Response:")
print(json.dumps(c_job, indent=2))
except Exception as e:
print(f"\n❌ An error occurred during conversion: {e}")
if __name__ == "__main__":
main()
How to Run It
- Make sure your JINGONGO_API_KEY is set in your terminal.
- Navigate to the root of the repository.
- Run the script:
python -m examples.03_convert_c_model
You will see the SDK log its progress as it packages and uploads your C model. The cloud engine will then compile it and package it into an FMU, with real-time status updates appearing in your console.