From 8a6203d01e6be948bf6f71fc7c131fbefe39659a Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Wed, 22 Jul 2026 19:16:56 +0200 Subject: [PATCH] Fixed some bugs --- BEdit/m_Test.mo | 21 --- BEdit/src/bedit/core/bond_graph.py | 50 +++-- BEdit/src/bedit/core/simulation/composer.py | 92 ++++++++-- .../src/bedit/core/simulation/openmodelica.py | 97 ++++++++-- BEdit/src/bedit/core/simulation/service.py | 31 +++- BEdit/src/bedit/data/libraries/bondgraph.beb | Bin 1210 -> 1228 bytes BEdit/untitled.bedit.json | 173 ++---------------- 7 files changed, 243 insertions(+), 221 deletions(-) delete mode 100644 BEdit/m_Test.mo diff --git a/BEdit/m_Test.mo b/BEdit/m_Test.mo deleted file mode 100644 index 340f2fb..0000000 --- a/BEdit/m_Test.mo +++ /dev/null @@ -1,21 +0,0 @@ -model m_Test - model m_Constant0 - output Real y(quantity="Length", unit="m"); - parameter Real v = 2; - equation - y = v; - end m_Constant0; - model m_Gain0 - input Real u; - output Real y; - parameter Real k(quantity="Current", unit="A") = 2.5; - equation - y = k*u; - end m_Gain0; - m_Constant0 Constant0; - m_Gain0 Gain0; -equation - Gain0.u = Constant0.y; -annotation( - experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-06, Interval = 0.002)); -end m_Test; \ No newline at end of file diff --git a/BEdit/src/bedit/core/bond_graph.py b/BEdit/src/bedit/core/bond_graph.py index 7003319..bee7af4 100644 --- a/BEdit/src/bedit/core/bond_graph.py +++ b/BEdit/src/bedit/core/bond_graph.py @@ -25,8 +25,6 @@ def infer_causality(component: dict[str, Any], toplevel: bool = True) -> dict[st """ if toplevel: - log.info("Causality inference") - # Reset causalities reset_causality(component) @@ -61,20 +59,40 @@ def infer_causality(component: dict[str, Any], toplevel: bool = True) -> dict[st - # Soft choices - for block in graph.get("blocks", []): - for port in block.get('interface', {}).get('ports', []): - if port.get('type', '') != 'power': - continue - if is_port_fully_assigned(block, port, graph): - continue - if port.get('causality', 'indifferent') == 'likes effort out': - propagate_from_port(block, port, 'effort out', graph, id_list) - elif port.get('causality', 'indifferent') == 'likes flow out': - propagate_from_port(block, port, 'flow out', graph, id_list) - elif port.get('causality', 'indifferent') in ['indifferent', 'single flow in', 'single effort in']: - # Force an arbitrary assignment on the first unassigned bond connected to this port - propagate_from_port(block, port, 'effort out', graph, id_list) + # Soft choices may need several passes when a junction has multiple + # unresolved bonds. Stop as soon as a pass makes no further progress. + while True: + unresolved_before = sum( + con.get('type') == 'power' and con.get('causality', 'none') == 'none' + for con in graph.get('connections', []) + ) + for block in graph.get("blocks", []): + for port in block.get('interface', {}).get('ports', []): + if port.get('type', '') != 'power': + continue + if is_port_fully_assigned(block, port, graph): + continue + if port.get('causality', 'indifferent') == 'likes effort out': + propagate_from_port(block, port, 'effort out', graph, id_list) + elif port.get('causality', 'indifferent') == 'likes flow out': + propagate_from_port(block, port, 'flow out', graph, id_list) + elif port.get('causality', 'indifferent') == 'single effort in': + evaluate_junction_constraints(block, port, graph, id_list) + if not is_port_fully_assigned(block, port, graph): + propagate_from_port(block, port, 'flow out', graph, id_list) + elif port.get('causality', 'indifferent') == 'single flow in': + evaluate_junction_constraints(block, port, graph, id_list) + if not is_port_fully_assigned(block, port, graph): + propagate_from_port(block, port, 'effort out', graph, id_list) + elif port.get('causality', 'indifferent') == 'indifferent': + # Force an arbitrary assignment on the first unassigned bond connected to this port + propagate_from_port(block, port, 'effort out', graph, id_list) + unresolved_after = sum( + con.get('type') == 'power' and con.get('causality', 'none') == 'none' + for con in graph.get('connections', []) + ) + if unresolved_after == 0 or unresolved_after >= unresolved_before: + break # Last check for con in graph.get('connections', []): diff --git a/BEdit/src/bedit/core/simulation/composer.py b/BEdit/src/bedit/core/simulation/composer.py index 1e1acd3..68e4451 100644 --- a/BEdit/src/bedit/core/simulation/composer.py +++ b/BEdit/src/bedit/core/simulation/composer.py @@ -80,6 +80,7 @@ def emit_model( id_list: dict[str, Any], indent: int = 0, connection_counts: dict[str, int] | None = None, + connection_signs: dict[str, list[float]] | None = None, ) -> str: """Emit a component and its nested definitions as Modelica source.""" @@ -92,16 +93,31 @@ def emit_model( implementation_kind = implementation.get("kind") nested_graph = implementation.get("graph", {}) port_counts = connection_counts or _interface_connection_counts(graph) - macros = _port_count_macros(graph, port_counts) + port_signs = connection_signs or _interface_connection_signs(graph) + macros = _port_connection_macros(graph, port_counts, port_signs) + + if indent == 0 and _contains_power_port(graph): + lines.extend( + ( + f"{body_indent}connector BondPort \"Bond graph power port\"", + f"{body_indent}\tReal e \"Effort variable\";", + f"{body_indent}\tflow Real f \"Flow variable\";", + f"{body_indent}end BondPort;", + ) + ) if implementation_kind == "graph": for block in nested_graph.get("blocks", []): + block_counts, block_signs = _block_connection_data( + nested_graph, block["id"] + ) lines.extend( emit_model( block, {}, indent + 1, - _block_connection_counts(nested_graph, block["id"]), + block_counts, + block_signs, ) .rstrip() .splitlines() @@ -157,8 +173,10 @@ def emit_model( target = _endpoint_expression( connection["target"], graph, blocks, junctions, endpoint_indices ) - # Connector types may require different equations in future. - lines.append(f"{body_indent}{target} = {source};") + if connection.get("type") == "power": + lines.append(f"{body_indent}connect({source}, {target});") + else: + lines.append(f"{body_indent}{target} = {source};") else: initial_equations = str( implementation.get("source", {}).get("initialEquations", "") @@ -213,10 +231,14 @@ def cleanup_graph(graph: dict[str, Any]) -> dict[str, Any]: def _port_declaration( port: dict[str, Any], direction: str, indent: int, macros: dict[str, str] ) -> str: - port_type = modelica_type(port.get("valueType", "real")) indentation = "\t" * indent port_name = identifier(port["name"]) dimensions = _port_dimensions(port, port_name) + if port.get("type") == "power": + return expand_bevalues( + f"{indentation}BondPort {port_name}{dimensions};", macros + ) + port_type = modelica_type(port.get("valueType", "real")) attributes = _quantity_unit_attributes(port) declaration = ( f"{indentation}{direction} {port_type} {port_name}{dimensions}{attributes};" @@ -299,16 +321,21 @@ def _index_array_endpoint( return f"{expression}[{endpoint_indices[key]}]" -def _block_connection_counts( +def _block_connection_data( graph: dict[str, Any], block_id: str -) -> dict[str, int]: +) -> tuple[dict[str, int], dict[str, list[float]]]: counts: dict[str, int] = {} + signs: dict[str, list[float]] = {} for connection in graph.get("connections", []): - for endpoint in (connection.get("source", {}), connection.get("target", {})): + for endpoint, sign in ( + (connection.get("source", {}), -1.0), + (connection.get("target", {}), 1.0), + ): if endpoint.get("block") == block_id and endpoint.get("port"): port_id = endpoint["port"] counts[port_id] = counts.get(port_id, 0) + 1 - return counts + signs.setdefault(port_id, []).append(sign) + return counts, signs def _interface_connection_counts(component: dict[str, Any]) -> dict[str, int]: @@ -324,19 +351,56 @@ def _interface_connection_counts(component: dict[str, Any]) -> dict[str, int]: return counts -def _port_count_macros( - component: dict[str, Any], connection_counts: dict[str, int] +def _interface_connection_signs(component: dict[str, Any]) -> dict[str, list[float]]: + implementation = component.get("implementation", {}) + if implementation.get("kind") != "graph": + return {} + signs: dict[str, list[float]] = {} + for connection in implementation.get("graph", {}).get("connections", []): + for endpoint, sign in ( + (connection.get("source", {}), -1.0), + (connection.get("target", {}), 1.0), + ): + port_id = endpoint.get("interface") + if port_id: + signs.setdefault(port_id, []).append(sign) + return signs + + +def _port_connection_macros( + component: dict[str, Any], + connection_counts: dict[str, int], + connection_signs: dict[str, list[float]], ) -> dict[str, str]: macros: dict[str, str] = {} interface = component.get("interface", {}) for port in interface.get("ports", []): if port.get("multipleConnections", False): - macros[f"{identifier(port['name'])}_N"] = str( - connection_counts.get(port["id"], 0) - ) + macro_name = identifier(port["name"]) + port_id = port["id"] + macros[f"{macro_name}_N"] = str(connection_counts.get(port_id, 0)) + signs = connection_signs.get(port_id, []) + macros[f"{macro_name}_S"] = "{" + ", ".join( + f"{sign:.1f}" for sign in signs + ) + "}" return macros +def _contains_power_port(component: dict[str, Any]) -> bool: + if any( + port.get("type") == "power" + for port in component.get("interface", {}).get("ports", []) + ): + return True + implementation = component.get("implementation", {}) + if implementation.get("kind") != "graph": + return False + return any( + _contains_power_port(block) + for block in implementation.get("graph", {}).get("blocks", []) + ) + + def expand_bevalues(text: str, values: dict[str, str]) -> str: """Replace BEdit ``$name$`` macros and reject unresolved composer values.""" diff --git a/BEdit/src/bedit/core/simulation/openmodelica.py b/BEdit/src/bedit/core/simulation/openmodelica.py index e8c0226..4f30591 100644 --- a/BEdit/src/bedit/core/simulation/openmodelica.py +++ b/BEdit/src/bedit/core/simulation/openmodelica.py @@ -1,5 +1,7 @@ import json +import logging import os +import re import shlex import shutil import socket @@ -54,6 +56,7 @@ class ModelBuildResult: check_summary: str build_result: Any + diagnostics: str = "" class OpenModelicaInterface: @@ -100,21 +103,42 @@ class OpenModelicaInterface: """Load and build one composed model as an ordered worker operation.""" def operation(omc, _temp_dir: Path): - unit_checking = omc.sendExpression( - 'setCommandLineOptions("--unitChecking")' - ) - if unit_checking is not True: - raise RuntimeError("OpenModelica could not enable unit checking") - loaded = omc.sendExpression(f"loadString({json.dumps(model)})") - if loaded is not True: - raise RuntimeError("OpenModelica could not load the composed model") - check_summary = omc.sendExpression(f"checkModel({model_name})") - if not isinstance(check_summary, str) or not check_summary.strip(): - raise RuntimeError( - "OpenModelica did not return a model-check summary" + capture = _LogCapture() + ompython_logger = logging.getLogger("OMPython") + previous_propagate = ompython_logger.propagate + ompython_logger.addHandler(capture) + ompython_logger.propagate = False + try: + unit_checking = omc.sendExpression( + 'setCommandLineOptions("--unitChecking")' ) - build_result = omc.sendExpression(f"buildModel({model_name})") - return ModelBuildResult(check_summary, build_result) + if unit_checking is not True: + raise RuntimeError("OpenModelica could not enable unit checking") + loaded = omc.sendExpression(f"loadString({json.dumps(model)})") + if loaded is not True: + raise RuntimeError("OpenModelica could not load the composed model") + diagnostics = [_read_omc_diagnostics(omc)] + check_summary = omc.sendExpression(f"checkModel({model_name})") + diagnostics.append(_read_omc_diagnostics(omc)) + if not isinstance(check_summary, str) or not check_summary.strip(): + raise RuntimeError( + "OpenModelica did not return a model-check summary" + ) + raw_build_result = omc.sendExpression( + f"buildModel({model_name})", parsed=False + ) + build_result = _parse_modelica_string_array(raw_build_result) + diagnostics.append(_read_omc_diagnostics(omc)) + diagnostics.extend(capture.messages) + diagnostic_text = "\n".join( + item.strip() + for item in diagnostics + if isinstance(item, str) and item.strip() + ) + return ModelBuildResult(check_summary, build_result, diagnostic_text) + finally: + ompython_logger.removeHandler(capture) + ompython_logger.propagate = previous_propagate self._submit("build model", operation, callback, error_callback) @@ -266,6 +290,51 @@ class OpenModelicaInterface: shutil.rmtree(temp_dir, ignore_errors=True) +def _read_omc_diagnostics(omc) -> str: + """Read OMC diagnostics without sending multiline text through OMPython's parser.""" + + raw = omc.sendExpression("getErrorString()", parsed=False) + if isinstance(raw, bytes): + raw = raw.decode("utf-8", errors="replace") + if not isinstance(raw, str): + return "" + text = raw.strip() + if not text: + return "" + try: + decoded = json.loads(text) + except json.JSONDecodeError: + return text + return decoded if isinstance(decoded, str) else text + + +class _LogCapture(logging.Handler): + """Collect dependency log messages for forwarding through BEdit's logger.""" + + def __init__(self) -> None: + super().__init__(level=logging.WARNING) + self.messages: list[str] = [] + + def emit(self, record: logging.LogRecord) -> None: + self.messages.append(record.getMessage()) + + +def _parse_modelica_string_array(raw: Any) -> tuple[str, ...]: + """Parse the string array returned by ``buildModel`` in raw mode.""" + + if isinstance(raw, bytes): + raw = raw.decode("utf-8", errors="replace") + if not isinstance(raw, str): + raise RuntimeError(f"OpenModelica returned an invalid build result: {raw!r}") + values = tuple( + json.loads(token) + for token in re.findall(r'"(?:\\.|[^"\\])*"', raw) + ) + if not values: + raise RuntimeError(f"OpenModelica returned an invalid build result: {raw!r}") + return values + + def _deliver_callback(callback: Callable[[Any], None], value: Any) -> None: try: callback(value) diff --git a/BEdit/src/bedit/core/simulation/service.py b/BEdit/src/bedit/core/simulation/service.py index fa7b76d..a0f9f90 100644 --- a/BEdit/src/bedit/core/simulation/service.py +++ b/BEdit/src/bedit/core/simulation/service.py @@ -45,11 +45,10 @@ class Simulation: graph: dict[str, Any], callback: Callable[[str], None] | None = None, error_callback: ErrorCallback | None = None, + message_callback: Callable[[SimulationMessage], None] | None = None, ) -> None: """Compose and retain the active graph's Modelica representation.""" - return - self.model_path = None self.compose_source(graph) @@ -64,6 +63,24 @@ class Simulation: log.error("%s", failure) return log.info("%s", result.check_summary.strip()) + if message_callback is not None: + message_callback( + SimulationMessage( + stream="build", + type="info", + text=result.check_summary.strip(), + ) + ) + if result.diagnostics: + log.warning("OpenModelica build diagnostics:\n%s", result.diagnostics) + if message_callback is not None: + message_callback( + SimulationMessage( + stream="build", + type="warning", + text=result.diagnostics, + ) + ) log.info("Compiling OK: %s", result.build_result) try: self.model_path = str(result.build_result[0]) @@ -77,6 +94,14 @@ class Simulation: else: log.error("%s", failure) return + if message_callback is not None: + message_callback( + SimulationMessage( + stream="build", + type="info", + text=f"Compiling OK: {result.build_result}", + ) + ) if callback is not None: callback(self.model_path) @@ -134,7 +159,7 @@ class Simulation: error_callback, ) - self.compose(graph, run_model, error_callback) + self.compose(graph, run_model, error_callback, message_callback) def get_progress(self) -> SimulationProgress | None: """Return the most recently received simulation status.""" diff --git a/BEdit/src/bedit/data/libraries/bondgraph.beb b/BEdit/src/bedit/data/libraries/bondgraph.beb index b829835640a90180f7e4a453c41b2068b906469d..42b931d53617d3e38e028b27481be765b307271b 100644 GIT binary patch literal 1228 zcmV;-1T*_WMM3}pc-rllTW=gS6vvy_e2S5phfrzC+%H6kh_<4AsiLF;q$mQ<_&95I zc071IO~P9OLI@#5c;Pjv_Ld7#Y54$A`{}J_;khs04H=D-E}OiJ1&m(zz!naj3X-sGs2$hl$LgH^)i-IAqUyoT|YVg z@>==qZk!zRs@UU9Aocsnwf?h5QvsZy7&hA(<0Aj<7dhx3s;FCF;vjHHWjs4)yzVcJ z*TwyevkbVPkZ&H+n57Ft?dKN;?dxJoY-At@T?78CStNpH3EX073bE>xKi_+Vk^&yc zMlB8~>3vh6R8X<8(<)LbcJ?uqzEU2|w_2R7EH#QGc)lv}&4)EfLHnVDVWu&)S4`npVX?Ai}@EE?^0~wbxwN5qZ!`U*c zKhQqbvYTXXI=cz7Sk`?Q&mCfj6B+Tc`OXt6!$?tbr#7%tZB~X4z7c|@dvP4-4hcYy zz>jp#_52VbCmdwS;yHS1_o&SZkG)xKU)s&;LSXVs4Cdm5f_Yd`$Zsel$73+|Jj*~X z(rr7mrC_kJj$DFt0M9~U;9%dZ1jFN{^GDcmas}ZV9gj~4T|Xxm#zqm|2Ncit?7CQ6 zT6oFQ!Vrow>n4=NKPwhtZkqJZ$a6q;7iBaxGB=7#OXi7(JPO31(VY=4`f1S0p?#C>oVf(aeu#vajyXD6$Nx0qSb2 zs@4+5vT02|WxvW8)hlz5VrA!5f&oSfhRC+e5aUR99c=23XS;fYZ6)bteHa*a?1mL6 z=12g8DoC^7o?Y)h& z)32_S*WTvYDX)q>&ID5L&#v^Z1DXop1jVq`$ru;;uRqI={;rC;1ttyxhg8P1G2?ZA zX}m5TW}Icf1%-U;n8qw!9%rprrS0fl@)m=5D)4sn|WlRQgJJG~aG>ww}-J$1EvYX+C#^A&)uDl%3rp#;Npa zIqeQjvqE$+YayCepFW6Dk)uS~{UhT*fOEha5E(+Du|f>J5hLF>J?xg==;YEMyq!nB z7<%N!h)23PT}x5&U%8|!CppNHhNUzA|hZ*8>>M~vOogbuIo(-OLY`9(&TYi-( zaXF82gq?E0d**pZ+E!kB+{v3Lg99$zfYP-D+Jq*_{#D|ryBjf%f$v|n4RyB#Y>4(< z^^?=@V7s$Uv1pz(zNuW?Z310uiotUa`pE74RE=77SJAogkLc8vZoOvdRvkRmbEzZe z!3Lx05tfQoIgYbNqYqp{Q&<(7iOeCEP+UHLSz7+|ufFA6aP|NOGwRQ_yhc;1mp9q^ z9qI8G`w5LW;+tDXs%o`}1P6F|LR(oiyE4+-?FTZNBDPf zR)3&a$h z9)Ta}p6mG`L{2!!l9e%fYWJwc3QxUQ?OfQ!>Re#*3k>GUjDmSwQOG}3NKVIK?0J@f zT%_A}XiLFhV;#8!=>VRE!ob14SqX+GtK(bPX>tkS8*PtI3Edcz3)7<5t-8DqJPsG` zx>#FUe$CSI2#+%LW)#RjD78} zUk_1i$RF$=-yoL*8zzpQ05!zmekQv!kmKYQNgJ_&bQP|+x5eba{XQ_Jm4#*s3 zZ<4IYsp6s56*L`T^p}}q$Cy=intlIEZtj`)6*_s*x|ZFe_a#B{jYef?H1p$y?CU!V z3NJ&-fx6nNsCxvEM&zlgq>Q+lbba>abl)_-S=(TXnd|2W>LD Y2W^FDN#Fc%E0!DQo9vf=1L>@&x^Wd-MF0Q* diff --git a/BEdit/untitled.bedit.json b/BEdit/untitled.bedit.json index a2ff80d..2c51d23 100644 --- a/BEdit/untitled.bedit.json +++ b/BEdit/untitled.bedit.json @@ -177,13 +177,13 @@ "source": { "equations": "der(state) = p.f;\np.e = state/c;", "declarations": "", - "initialEquations": "" + "initialEquations": "state = 0;" } } }, { "id": "bfa506d8-ee41-4bab-ae19-a97fd67bfcf6", - "name": "1", + "name": "j1", "position": { "x": -96.0, "y": -160.0 @@ -256,8 +256,8 @@ "implementation": { "kind": "text", "source": { - "equations": "flow = p[1].f;\nsum(p[i].e for i in 1:$p_N$) = 0;\nfor i in 2:$p_N$ loop\n p[i].f = p[i-1].f;\nend for;", - "declarations": "Real flow;", + "equations": "f = s[1] * p[1].f;\nsum(s[i] * p[i].e for i in 1:$p_N$) = 0;\nfor i in 2:$p_N$ loop\n s[i] * p[i].f = s[i-1] * p[i-1].f;\nend for;", + "declarations": "parameter Real s[$p_N$] = $p_S$;\nReal f;", "initialEquations": "" } } @@ -399,7 +399,7 @@ "parameters": [ { "id": "parameter-d056bc27", - "name": "effort", + "name": "e", "type": "real", "value": "1", "quantity": "", @@ -446,15 +446,15 @@ "implementation": { "kind": "text", "source": { - "equations": "p.e = effort;\nflow = p.f;", - "declarations": "Real flow;", + "equations": "p.e = e;\nf = p.f;", + "declarations": "Real f;", "initialEquations": "" } } }, { "id": "140ae14b-9dbb-4756-aa25-29101ef2a99e", - "name": "0", + "name": "j0", "position": { "x": -96.0, "y": -32.0 @@ -527,130 +527,8 @@ "implementation": { "kind": "text", "source": { - "equations": "effort = p[1].e;\nsum(p[i].f for i in 1:$p_N$) = 0;\nfor i in 2:$p_N$ loop\n p[i].e = p[i-1].e;\nend for;", - "declarations": "Real effort;", - "initialEquations": "" - } - } - }, - { - "id": "6a6fbadd-28ec-4d10-b854-876752a6b287", - "name": "C0", - "position": { - "x": -96.0, - "y": 96.0 - }, - "rotation": 0.0, - "interface": { - "ports": [ - { - "id": "port-2e1d884f", - "name": "p", - "position": { - "x": 0.0, - "y": 0.0 - }, - "properties": { - "iconPosition": { - "x": 64.0, - "y": 64.0 - } - }, - "type": "power", - "multipleConnections": false, - "valueType": "real", - "quantity": "", - "unit": "", - "dimensions": { - "rows": 1, - "columns": 1 - }, - "description": "", - "orientation": "input", - "domain": "power", - "causality": "preferred effort out" - }, - { - "id": "port-ca7716d5", - "name": "state", - "position": { - "x": 0.0, - "y": 0.0 - }, - "properties": { - "iconPosition": { - "x": 88.0, - "y": 40.0 - } - }, - "type": "signal", - "multipleConnections": false, - "valueType": "real", - "quantity": "", - "unit": "", - "dimensions": { - "rows": 1, - "columns": 1 - }, - "description": "", - "orientation": "output", - "domain": "power", - "causality": "indifferent" - } - ] - }, - "parameters": [ - { - "id": "parameter-d056bc27", - "name": "c", - "type": "real", - "value": "1", - "quantity": "", - "unit": "", - "dimensions": { - "rows": 1, - "columns": 1 - }, - "description": "" - } - ], - "icon": { - "shape": "rectangle", - "fill": "#f4f4f4", - "border": "#303030", - "text": "Text", - "size": { - "width": 128.0, - "height": 128.0 - }, - "elements": [ - { - "type": "text", - "x": 40.0, - "y": 40.0, - "width": 48.0, - "height": 48.0, - "text": "C", - "color": "#303030", - "fontSize": 32.0, - "lineStyle": "solid", - "lineWidth": 1.5, - "stroke": "#303030", - "fill": "#ffffff" - } - ] - }, - "properties": { - "showName": false - }, - "library": { - "showSubtree": true - }, - "implementation": { - "kind": "text", - "source": { - "equations": "der(state) = p.f;\np.e = state/c;", - "declarations": "", + "equations": "e = p[1].e;\nsum(p[i].f for i in 1:$p_N$) = 0;\nfor i in 2:$p_N$ loop\n p[i].e = p[i-1].e;\nend for;", + "declarations": "Real e;", "initialEquations": "" } } @@ -699,7 +577,7 @@ "id": "parameter-d056bc27", "name": "r", "type": "real", - "value": "1", + "value": "10", "quantity": "", "unit": "", "dimensions": { @@ -868,7 +746,7 @@ "source": { "equations": "der(state) = p.e;\np.f = state/i;", "declarations": "", - "initialEquations": "" + "initialEquations": "state = 0;" } } } @@ -906,23 +784,6 @@ "waypoints": [] }, "type": "power", - "causality": "target" - }, - { - "id": "ae95fbfc-c771-47f2-8f9e-1c823daaf6b8", - "source": { - "block": "140ae14b-9dbb-4756-aa25-29101ef2a99e", - "port": "port-3e53bf80" - }, - "target": { - "block": "6a6fbadd-28ec-4d10-b854-876752a6b287", - "port": "port-2e1d884f" - }, - "name": "", - "properties": { - "waypoints": [] - }, - "type": "power", "causality": "source" }, { @@ -977,7 +838,7 @@ "causality": "target" }, { - "id": "d6940de3-5b4c-42be-a247-639b3803d85e", + "id": "e67f412c-39ae-404d-a513-d4a0c389ef40", "source": { "block": "bfa506d8-ee41-4bab-ae19-a97fd67bfcf6", "port": "port-3e53bf80" @@ -996,7 +857,13 @@ ], "annotations": [], "junctions": [], - "simulation": {} + "simulation": { + "startTime": 0.0, + "stopTime": 10.0, + "intervalMode": "numberOfIntervals", + "numberOfIntervals": 500, + "intervalTime": 0.002 + } } } }