Code generator mapping#
The code generator mapping API allows to explore and query the relationship between Swan model elements and their generated C code counterparts.
This API can be used after executing a Code Generation job in Scade One.
It needs the generated JSON mapping data file named cg_map.json.
The latter file contains three sections:
model: Elements from the Swan language (operators, types, constants, sensors, etc.)
code: Generated C code elements (functions, types, variables, etc.)
mapping: Associations between model and code items with optional roles
Modules of interest#
Getting started#
Loading mapping data#
The main entry point is the CGMapping class. You can load mapping data from
a JSON file or dictionary:
from ansys.scadeone.core.svc.cgmapping import CGMapping
# Load from JSON file
mapping = CGMapping.from_file("path/to/cg_map.json")
Basic information#
Once loaded, you can get basic information about the mapping:
# Get statistics about loaded data
stats = mapping.get_statistics()
print(f"Model items: {stats['model_items']}")
print(f"Code items: {stats['code_items']}")
print(f"Mappings: {stats['mappings']}")
# Get format version
print(f"Format version: {mapping.version}")
Querying model elements#
Finding model elements#
You can search for model elements using various methods:
# Find model elements by their path
operators = mapping.get_model_by_path("MyPackage::MyOperator")
# Find model elements by name
items = mapping.get_model_by_name("MyOperator")
Specialized model queries#
The API provides specialized methods for common model element types:
# Get all operators
all_operators = mapping.get_all_operators()
# Get only root operators
root_operators = mapping.get_root_operators()
# Get all constants
constants = mapping.get_all_constants()
# Get all sensors
sensors = mapping.get_all_sensors()
# Get all types
types = mapping.get_all_types()
Working with operators#
operators = mapping.get_model_by_name("FlightController")
for operator in operators:
# Operator attributes
print(f"Operator path: {operator.path}")
print(f"Is root: {operator.root}")
print(f"Is expanded: {operator.expanded}")
for input in operator.inputs:
print(f" Input: {input.name}")
# Specialized method access
cycle_method = operator.get_cycle()
init_method = operator.get_init()
reset_method = operator.get_reset()
# Access to operator metadata
function_name = operator.get_function_name()
header_file = operator.get_header_name()
# Context and structure access
context_type = operator.get_context_type()
global_context = operator.get_global_context()
input_struct = operator.get_input_struct_type()
obs_struct = operator.get_obs_struct_type()
Using model elements#
All model elements inherit from ModelElement, which provides
the get_generated_element() method to access their generated code counterpart:
# Get all generated code elements for an operator
code_items = operator.get_generated_element()
print(f"Operator generates {len(code_items)} code elements")
# Get specific code elements using specialized helpers
cycle_fn = operator.get_cycle()
if cycle_fn:
print(f"Cycle method: {cycle_fn.name}")
reset_fn = operator.get_reset()
if reset_fn:
print(f"Reset method: {reset_fn.name}")
Querying code elements#
Finding code elements#
Similar to model elements, you can search for code elements:
# Find code elements by name
functions = mapping.get_code_by_name("FlightController_cycle")
# Get all code containers (files)
containers = mapping.get_all_code_containers()
for container in containers:
print(f"Interface file: {container.interface_file}")
if container.implementation_file:
print(f"Implementation file: {container.implementation_file}")
Note
See Code Container for more details on code containers.
Working with code elements#
Code elements represent various C constructs:
# Example with a C function
functions = mapping.get_code_by_name("my_function")
if functions:
function = functions[0]
print(f"Function name: {function.name}")
print(f"Return type ID: {function.return_type}")
print(f"Parameters: {len(function.parameters)}")
for param in function.parameters:
print(f" - {param.name}: type {param.type}")
Using code elements#
All code elements inherit from CodeElement, which provides
the get_model_element() method to access the associated model element that generated them:
# Get the model element that generated this code
model_item = function.get_model_element()
print(f"Generated from: {type(model_item).__name__}")
if hasattr(model_item, 'path'):
print(f" Path: {model_item.path}")
Bidirectional mapping#
Forward mapping (model → code)#
Get generated code from model elements:
code_items = model_element.get_generated_element()
cycle_function = model_element.get_cycle()
Reverse mapping (code → model)#
Find which model element generated specific code:
model_item = code_element.get_model_element()
Use cases#
Complete working example#
For a comprehensive use case demonstrating the mapping API, here is a complete working example:
1from pathlib import Path
2from ansys.scadeone.core.common.logger import LOGGER, LoggerLevel
3from ansys.scadeone.core.svc.cgmapping import (
4 CGMapping,
5 ModelMonoOperator,
6 ModelPredefinedType,
7 ModelNamedType,
8 ModelArray,
9 ModelGroup,
10)
11
12
13def demonstrate_model_element_usage():
14 # Load a test mapping file from its path
15 test_file = Path("cg_map.json")
16
17 if not test_file.exists():
18 print(f"Test file not found: {test_file}")
19 return
20
21 # Load the mapping
22 mapping = CGMapping.from_file(test_file)
23 print(f"Mapping loaded - version: {mapping.version}")
24
25 # Root operators
26 root_ops = mapping.get_root_operators()
27 print(f"\nFound {len(root_ops)} root operators:")
28 for op in root_ops:
29 print(f" Root operator: {op.path}")
30
31 # Print statistics
32 stats = mapping.get_statistics()
33 print(f"\nTotal model items: {stats['model_items']}")
34 print(f"Total code items: {stats['code_items']}")
35 print(f"Total mappings: {stats['mappings']}")
36
37 # Demonstration with operators
38 print("\n=== Operators ===")
39 operators = mapping.get_all_operators()
40 print(f"Number of operators found: {len(operators)}")
41
42 for operator in operators:
43 print(f"\nOperator: {operator.path}")
44
45 # Skip mono operators for this demo as they have different characteristics
46 if isinstance(operator, ModelMonoOperator):
47 print(f" Mono operator - Source : {operator.get_src_operator().path}")
48 continue
49
50 # Display operator inputs
51 print(f" Inputs ({len(operator.inputs)}):")
52 for input in operator.inputs:
53 if isinstance(input, ModelGroup):
54 print(f" - {input.name} (Group):")
55 for projection in input.projections:
56 generated_code = projection.get_generated_element()
57 c_type = projection.get_c_type()
58 model_type = projection.get_model_type()
59 type_name = c_type.name if c_type else "unknown"
60 model_type_name = "unknown"
61 if model_type:
62 if isinstance(model_type, ModelPredefinedType):
63 model_type_name = model_type.name
64 elif isinstance(model_type, (ModelNamedType, ModelArray)):
65 model_type_name = model_type.path
66 print(
67 f" - Proj {projection.projection} : {generated_code.name}: C Type = {type_name}, Model Type = {model_type_name}"
68 )
69 else:
70 generated_code = input.get_generated_element()
71 c_type = input.get_c_type()
72 model_type = input.get_model_type()
73 type_name = c_type.name if c_type else "unknown"
74 model_type_name = "unknown"
75 if model_type:
76 if isinstance(model_type, ModelPredefinedType):
77 model_type_name = model_type.name
78 elif isinstance(model_type, (ModelNamedType, ModelArray)):
79 model_type_name = model_type.path
80 print(f" - {input.name}: C Type = {type_name}, Model Type = {model_type_name}")
81
82 # Specialized methods for operators
83 cycle_method = operator.get_cycle()
84 print(f" Cycle method: {cycle_method.name if cycle_method else 'none'}")
85
86 init_method = operator.get_init()
87 print(f" Init method: {init_method.name if init_method else 'none'}")
88
89 reset_method = operator.get_reset()
90 print(f" Reset method: {reset_method.name if reset_method else 'none'}")
91
92 monos = operator.get_mono_operators()
93 if monos:
94 print(f" Mono operators: {len(monos)}")
95 for mono in monos:
96 print(f" - {mono.path}")
97
98 # Demonstration with constants
99 print("\n=== Constants ===")
100 constants = mapping.get_all_constants()
101 print(f"Number of constants found: {len(constants)}")
102
103 for i, constant in enumerate(constants, 1):
104 print(f"\n{i}. Constant: {constant.path}")
105 code_item = constant.get_generated_element()
106 if code_item:
107 print(f" Generated code element: {type(code_item).__name__} (ID: {code_item.id})")
108 print(f" Name: {code_item.name}")
109 else:
110 print(" No generated code element")
111
112 # Demonstration with sensors
113 print("\n=== Sensors ===")
114 sensors = mapping.get_all_sensors()
115 print(f"Number of sensors found: {len(sensors)}")
116
117 for i, sensor in enumerate(sensors, 1):
118 print(f"\n{i}. Sensor: {sensor.path}")
119 code_item = sensor.get_generated_element()
120 if code_item:
121 print(f" Generated code element: {type(code_item).__name__} (ID: {code_item.id})")
122 print(f" Name: {code_item.name}")
123 else:
124 print(" No generated code element")
125
126 # Demonstration with types
127 print("\n=== Types ===")
128 types = mapping.get_all_types()
129 print(f"Number of types found: {len(types)}")
130
131 # Group types by category for better presentation
132 predefined_types = [t for t in types if isinstance(t, ModelPredefinedType)]
133 named_types = [t for t in types if isinstance(t, ModelNamedType)]
134 other_types = [t for t in types if not isinstance(t, (ModelPredefinedType, ModelNamedType))]
135
136 print(f"\nPredefined types: {len(predefined_types)}")
137 for i, type_elem in enumerate(predefined_types, 1):
138 type_name = type_elem.name
139 print(f" {i}. {type(type_elem).__name__} - {type_name}")
140 code_item = type_elem.get_generated_element()
141 if code_item:
142 print(f" -> {type(code_item).__name__} : {code_item.name}")
143
144 print(f"\nNamed types: {len(named_types)}")
145 for i, type_elem in enumerate(named_types, 1):
146 type_name = type_elem.path
147 print(f" {i}. {type(type_elem).__name__} - {type_name}")
148 code_item = type_elem.get_generated_element()
149 if code_item:
150 print(f" -> {type(code_item).__name__} : {code_item.name}")
151
152 if other_types:
153 print(f"\nOther types: {len(other_types)}")
154 for i, type_elem in enumerate(other_types, 1):
155 type_ID = type_elem.id
156 print(f" {i}. {type(type_elem).__name__} - ID {type_ID}")
157 code_item = type_elem.get_generated_element()
158 if code_item:
159 print(f" -> {type(code_item).__name__} : {code_item.name}")
160 else:
161 print(" (No generated code element)")
162
163
164if __name__ == "__main__":
165 log_dir = Path.cwd() / "logs"
166 LOGGER.log_to_file(folder_path=log_dir, level=LoggerLevel.DEBUG)
167
168 print("Demonstration of CG mapping API.")
169 print("=" * 60)
170 demonstrate_model_element_usage()
171 print("\n" + "=" * 60)
172 print("Demonstration completed.")
173 print(f"LOGGER output file: {log_dir / 'pyscadeone.log'}")