Writing a relationship in C++ or Python
Every relationship and source term in this series so far has been a real equation, typed into the math field or built from reference chips. That covers a lot of ground, but not everything: a vendor's tire model, a lookup table, a control law with a branch in it. For exactly that gap, a relationship (or a node's own source term) can be implemented in C++ or Python instead, real code Konjugate compiles or launches locally and runs on the same schedule as an equation.
The example is a variation on "Getting started"'s hot plate and room air: the Cooling relationship now switches between two rate constants depending on how large the temperature gap is, fast above 20 degrees, slow below it. That's a genuine branch, not something a single equation naturally expresses, and it's one line of code.
Two parameters, still an equation for now
The relationship starts out ordinary: two custom parameters, fastRate and slowRate, sitting right next to the usual state references.
Nothing about adding parameters depends on which implementation gets chosen next. They're available as bindings either way.
Switching to C++
Implementation, in the same builder, offers Equation, C++ program or Python program. Choosing C++ swaps the equation field for a provider source panel and generates a starter template on the spot:
Bindings and the output key
Bindings, underneath, is how a value gets from the model into the provider: a key the code will read it by, and a reference (a state on either endpoint, or a parameter) to read it from. Four bindings and an output key later:
The source itself is plain text here, editable directly in this textarea if that's all you need. The full authoring experience lives one click away.
The code editor
Open code editor opens a dedicated window, not a panel bolted onto the builder: a real CodeMirror editor with C++ syntax highlighting, a theme picker and live validation running in the background as you type.
That check is the real compiler, not a lint approximation: C++ source gets clang++ -fsyntax-only against the actual SDK header, Python gets python3 -c "ast.parse(...)". The status line and Apply button track it directly, Apply stays disabled until the last check passed. Applying writes the source back into the same live-edit session the inline equation editors use, so the whole edit, template, bindings, output key and code, collapses into one undo step.
Running it
Create edge, then Run, same as any other model. The first run compiles the provider; every run after that reuses the cached build unless the source changes.
Compiler and interpreter overrides
Konjugate auto-detects a C++ compiler and a Python interpreter per machine. The ⚒ button in the title bar opens Compiler & interpreter, where that detection can be overridden if it finds the wrong one, or none at all:
This is a machine-local preference, not part of the project. Opening the same project on a different computer just re-detects.
The same relationship in Python
Switching Implementation to Python instead generates a different starter template, targeting a small konjugate package rather than a C++ header. The finished provider, doing the identical job:
from konjugate import (
EvaluationContext,
InputView,
OutputCollector,
RelationshipDescription,
RelationshipProvider,
ScalarPort,
)
class Cooling(RelationshipProvider):
def describe(self):
return RelationshipDescription(
"cooling",
"Cooling",
[
ScalarPort("plateTemperature", "plateTemperature", ""),
ScalarPort("roomTemperature", "roomTemperature", ""),
ScalarPort("fastRate", "fastRate", ""),
ScalarPort("slowRate", "slowRate", ""),
],
ScalarPort("roomTemperatureGradient", "roomTemperatureGradient", ""),
)
def evaluate(self, context, inputs, outputs):
gap = inputs["plateTemperature"] - inputs["roomTemperature"]
rate = inputs["fastRate"] if gap > 20.0 else inputs["slowRate"]
outputs.add_gradient(rate * gap)
Same bindings, same output key, same bindings-to-keyword-arguments shape, just Python's own syntax and an inputs["key"] lookup instead of context.inputs.at("key"). Run the identical 40 seconds and Room air lands on 78.4646829548178, the same answer as the C++ version to full precision. Nothing about the model, the bindings or the schedule changes between languages; only the implementation does.
Source terms work the same way
Everything on this page applies just as directly to a node's own source term, not only a relationship. "Tuning a parameter against measured data" already showed a source term with its own tunable parameter; that same source-term editor offers the identical Equation/C++/Python choice, the identical bindings list and the identical code editor. A parameter bound into C++ or Python code is still an ordinary parameter everywhere else in Konjugate: still tunable, still usable as a live control during a run.
Where to go from here
"Exporting a simulation as standalone code" covers what happens to a provider like this one when the whole model gets exported: its source is pasted straight into the generated file, not re-derived. "Installing add-ons and plugins" covers the other way a C++ or Python provider reaches a project, installed as a reusable .kjp plugin rather than authored inline.
Follow Konjugate on LinkedIn for updates, or subscribe via RSS.
Comments
Post a Comment