from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from types import SimpleNamespace from PythonModels.core.base import Component from PythonModels.core.network import SimulationNetwork from PythonModels.core.solver import SolveIVPConfig, integrate_ode MODEL_NAME = "test_mql" AMESIM_ARCHIVE_RELATIVE_PATH = Path("AmesimModels/test_mql.ame") # Extracted from AmesimModels/test_mql.ame on the model-development branch. # This is a structural Python port scaffold: it preserves the AMESim component # inventory, parameters, and connection topology without changing the existing # Testmodel implementation. The detailed AMESim submodel equations should be # replaced incrementally per submodel family. MODEL_INFO = {'num_states': 132, 'num_discrete_states': 24, 'is_explicit': 1} SIMULATION_SETTINGS = {'raw': '0 10 0.01 1e+30 1e-07 0.001 1 0.1\r\n0 0 0 0 8 0 0 0 0 0', 't_start': 0.0, 't_stop': 10.0, 'print_interval': 0.01, 'max_step': 0.001, 'sample_step': 0.1} GLOBAL_PARAMETERS = {'D2': '20', 'D1': '20', 'D3': '14', 'Pdq': '1', 'P0': '153', 'V': '15', 'cf': '0.45'} SUBMODEL_COUNTS = {'PNRP17': 8, 'F000': 16, 'MECMAS21': 10, 'LMECHN1': 2, 'LSTP00A': 8, 'PNCH012': 8, 'PNPL01': 16, 'FORC': 2, 'PNCH023': 4, 'PNOR001': 8, 'PN3NODE2': 8, 'P4NODE2': 8, 'PNVO001': 8, 'STEP0': 8, 'UD00': 2, 'PNGD00': 1} LINE_SUBMODEL_COUNTS = {'DIRECT': 44, 'PNL0001': 20, 'PNL0003': 8, 'PNL0002': 8, 'PNL00R': 4} COMPONENT_SPECS = [{'index': 0, 'alias': 'pn_brp2_8', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 1, 'alias': 'pn_brp2_9', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 2, 'alias': 'pn_brp2_10', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 3, 'alias': 'pn_brp2_11', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 4, 'alias': 'pn_brp2_12', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 5, 'alias': 'pn_brp2_13', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 6, 'alias': 'pn_brp2_14', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 7, 'alias': 'pn_brp2_15', 'component_name': 'pn_brp2', 'library_id': 'pcd.pn_brp2', 'submodel': 'PNRP17', 'label': 'pneumatic piston with moving body', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'dp', 'title': 'piston diameter', 'value': '2.00000000000000e+02', 'units': 'mm'}, {'name': 'dr', 'title': 'rod diameter', 'value': '1.00000000000000e+00', 'units': 'mm'}, {'name': 'x0', 'title': 'chamber length at zero relative displacement', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 8, 'alias': 'zeroforcesource_17', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 9, 'alias': 'mass_friction_endstops_10', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 10, 'alias': 'zeroforcesource_18', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 11, 'alias': 'mass_friction_endstops_11', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 12, 'alias': 'zeroforcesource_19', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 13, 'alias': 'mass_friction_endstops_12', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 14, 'alias': 'zeroforcesource_20', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 15, 'alias': 'mass_friction_endstops_13', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 16, 'alias': 'zeroforcesource_21', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 17, 'alias': 'mass_friction_endstops_14', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 18, 'alias': 'zeroforcesource_22', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 19, 'alias': 'mass_friction_endstops_15', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 20, 'alias': 'zeroforcesource_23', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 21, 'alias': 'mass_friction_endstops_16', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 22, 'alias': 'zeroforcesource_24', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 23, 'alias': 'mass_friction_endstops_17', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '5.00000000000000e+01', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-1.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '8.00000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '4', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 24, 'alias': 'dynamic_mechanical_node_alternative_2', 'component_name': 'dynamic_mechanical_node_alternative', 'library_id': 'meca.dynamic_mechanical_node_alternative', 'submodel': 'LMECHN1', 'label': 'dynamic linear mechanical node (velocity and displacement)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}, {'name': 'port_3', 'type': 'lshaft', 'face': '2'}, {'name': 'port_4', 'type': 'lshaft', 'face': '2'}, {'name': 'port_5', 'type': 'lshaft', 'face': '2'}, {'name': 'port_6', 'type': 'lshaft', 'face': '2'}, {'name': 'port_7', 'type': 'lshaft', 'face': '2'}, {'name': 'port_8', 'type': 'lshaft', 'face': '2'}, {'name': 'port_9', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'v1', 'title': 'number of ports at right', 'value': '8', 'units': ''}, {'name': 'sum', 'title': 'node sum', 'value': '1', 'units': ''}]}, {'index': 25, 'alias': 'mass_friction_endstops_18', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '1.70000000000000e+05', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '0.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '3.70000000000000e-01', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 26, 'alias': 'elasticendstop_8', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 27, 'alias': 'elasticendstop_9', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 28, 'alias': 'elasticendstop_10', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 29, 'alias': 'elasticendstop_11', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 30, 'alias': 'elasticendstop_12', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 31, 'alias': 'elasticendstop_13', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 32, 'alias': 'elasticendstop_14', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 33, 'alias': 'elasticendstop_15', 'component_name': 'elasticendstop', 'library_id': 'meca.elasticendstop', 'submodel': 'LSTP00A', 'label': 'elastic contact (no states)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': [{'name': 'na', 'title': 'number of active coils', 'value': '1.00000000000000e+01', 'units': 'null'}, {'name': 'gap0', 'title': 'gap or clearance with both displacements zero', 'value': '0.00000000000000e+00', 'units': 'mm'}, {'name': 'kcont', 'title': 'contact stiffness', 'value': '1.00000000000000e+11', 'units': 'N/m'}, {'name': 'G', 'title': 'material shear modulus', 'value': '8.57000000000000e+10', 'units': 'N/m**2'}, {'name': 'sdiam', 'title': 'spring diameter', 'value': '2.00000000000000e+01', 'units': 'mm'}, {'name': 'wdiam', 'title': 'wire diameter', 'value': '2.00000000000000e+00', 'units': 'mm'}, {'name': 'rcont', 'title': 'contact damping', 'value': '1.00000000000000e+11', 'units': 'N/(m/s)'}, {'name': 'Pdis', 'title': 'penetration for full damping', 'value': '1.00000000000000e-04', 'units': 'mm'}, {'name': 'stiffmode', 'title': 'spring stiffness mode', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}]}, {'index': 34, 'alias': 'dynamic_mechanical_node_alternative_3', 'component_name': 'dynamic_mechanical_node_alternative', 'library_id': 'meca.dynamic_mechanical_node_alternative', 'submodel': 'LMECHN1', 'label': 'dynamic linear mechanical node (velocity and displacement)', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}, {'name': 'port_3', 'type': 'lshaft', 'face': '3'}, {'name': 'port_4', 'type': 'lshaft', 'face': '3'}, {'name': 'port_5', 'type': 'lshaft', 'face': '3'}, {'name': 'port_6', 'type': 'lshaft', 'face': '3'}, {'name': 'port_7', 'type': 'lshaft', 'face': '3'}, {'name': 'port_8', 'type': 'lshaft', 'face': '3'}, {'name': 'port_9', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'v1', 'title': 'number of ports at right', 'value': '8', 'units': ''}, {'name': 'sum', 'title': 'node sum', 'value': '1', 'units': ''}]}, {'index': 35, 'alias': 'mass_friction_endstops_19', 'component_name': 'mass_friction_endstops', 'library_id': 'meca.mass_friction_endstops', 'submodel': 'MECMAS21', 'label': '1D translation mass', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': [{'name': 'mass', 'title': 'mass', 'value': '9.00000000000000e+04', 'units': 'kg'}, {'name': 'fstick', 'title': 'stiction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'fcoul', 'title': 'Coulomb friction force', 'value': '0.00000000000000e+00', 'units': 'N'}, {'name': 'rvisc', 'title': 'coefficient of viscous friction', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)'}, {'name': 'wind', 'title': 'coefficient of windage', 'value': '0.00000000000000e+00', 'units': 'N/(m/s)**2'}, {'name': 'dvel', 'title': 'stick velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restdvel', 'title': 'velocity threshold', 'value': '1.00000000000000e-06', 'units': 'm/s'}, {'name': 'restcoeff', 'title': 'restitution coefficient', 'value': '6.50000000000000e-01', 'units': 'null'}, {'name': 'astrib', 'title': 'Stribeck constant', 'value': '1.00000000000000e-03', 'units': 'm/s'}, {'name': 'xmin', 'title': 'lower displacement limit', 'value': '-7.20000000000000e-01', 'units': 'm'}, {'name': 'Kbmin', 'title': 'lower limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmin', 'title': 'lower limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmin', 'title': 'lower limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'xmax', 'title': 'higher displacement limit', 'value': '0.00000000000000e+00', 'units': 'm'}, {'name': 'Kbmax', 'title': 'higher limit stiffness', 'value': '1.00000000000000e+06', 'units': 'N/mm'}, {'name': 'Dbmax', 'title': 'higher limit contact damping coefficient', 'value': '1.00000000000000e+01', 'units': 'N/(mm/s)'}, {'name': 'Pdmax', 'title': 'higher limit penetration for full damping', 'value': '1.00000000000000e-01', 'units': 'mm'}, {'name': 'theta', 'title': 'inclination (+90 port 1 lowest, -90 port 1 highest)', 'value': '0.00000000000000e+00', 'units': 'degree'}, {'name': 'useFriction', 'title': 'use friction', 'value': '1', 'units': ''}, {'name': 'stoptype', 'title': 'endstop type', 'value': '1', 'units': ''}, {'name': 'discContactOption', 'title': 'negative contact force', 'value': '1', 'units': ''}, {'name': 'strib', 'title': 'Stribeck effect', 'value': '1', 'units': ''}, {'name': 'frictionType', 'title': 'friction type', 'value': '1', 'units': ''}]}, {'index': 36, 'alias': 'pn_c1_8', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 37, 'alias': 'pn_plug_16', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 38, 'alias': 'pn_plug_17', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 39, 'alias': 'pn_c1_9', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 40, 'alias': 'pn_plug_18', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 41, 'alias': 'pn_plug_19', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 42, 'alias': 'pn_c1_10', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 43, 'alias': 'pn_plug_20', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 44, 'alias': 'pn_plug_21', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 45, 'alias': 'pn_c1_11', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 46, 'alias': 'pn_plug_22', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 47, 'alias': 'pn_plug_23', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 48, 'alias': 'pn_c1_12', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 49, 'alias': 'pn_plug_24', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 50, 'alias': 'pn_plug_25', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 51, 'alias': 'pn_c1_13', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 52, 'alias': 'pn_plug_26', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 53, 'alias': 'pn_plug_27', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 54, 'alias': 'pn_c1_14', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 55, 'alias': 'pn_plug_28', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 56, 'alias': 'pn_plug_29', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 57, 'alias': 'pn_c1_15', 'component_name': 'pn_c1', 'library_id': 'pcd.pn_c1', 'submodel': 'PNCH012', 'label': 'variable volume pneumatic chamber with heat exchange (preferred)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '2'}, {'name': 'port_2', 'type': 'pflow', 'face': '1'}, {'name': 'port_3', 'type': 'pflow', 'face': '3'}, {'name': 'port_4', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol0', 'title': 'dead volume', 'value': 'V', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '1.50000000000000e+03', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '7.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 58, 'alias': 'pn_plug_30', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}], 'parameters': []}, {'index': 59, 'alias': 'pn_plug_31', 'component_name': 'pn_plug', 'library_id': 'pn.pn_plug', 'submodel': 'PNPL01', 'label': 'zero pneumatic flow source', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 60, 'alias': 'zeroforcesource_26', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 61, 'alias': 'zeroforcesource_27', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 62, 'alias': 'zeroforcesource_28', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 63, 'alias': 'zeroforcesource_29', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 64, 'alias': 'zeroforcesource_30', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 65, 'alias': 'zeroforcesource_31', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 66, 'alias': 'zeroforcesource_32', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 67, 'alias': 'zeroforcesource_33', 'component_name': 'zeroforcesource', 'library_id': 'meca.zeroforcesource', 'submodel': 'F000', 'label': 'zero force source', 'ports': [{'name': 'port_1', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 68, 'alias': 'forcecon_1', 'component_name': 'forcecon', 'library_id': 'meca.forcecon', 'submodel': 'FORC', 'label': 'conversion of signal input into a force in N', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '2'}, {'name': 'port_2', 'type': 'lshaft', 'face': '3'}], 'parameters': []}, {'index': 69, 'alias': 'pn_general_chamber', 'component_name': 'pn_general_chamber', 'library_id': 'pn.pn_general_chamber', 'submodel': 'PNCH023', 'label': 'simple pneumatic chamber with heat exchange', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol', 'title': 'volume', 'value': '5.70000000000000e+01', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '0.00000000000000e+00', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '1.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 70, 'alias': 'pn_orifice_18', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 71, 'alias': 'pn_orifice_19', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 72, 'alias': 'pn_node3_8', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 73, 'alias': 'pn_node3_9', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 74, 'alias': 'pn_general_chamber_2', 'component_name': 'pn_general_chamber', 'library_id': 'pn.pn_general_chamber', 'submodel': 'PNCH023', 'label': 'simple pneumatic chamber with heat exchange', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol', 'title': 'volume', 'value': '5.70000000000000e+01', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '0.00000000000000e+00', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '1.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 75, 'alias': 'pn_orifice_20', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 76, 'alias': 'pn_orifice_21', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 77, 'alias': 'pn_node3_10', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 78, 'alias': 'pn_node3_11', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 79, 'alias': 'pn_general_chamber_4', 'component_name': 'pn_general_chamber', 'library_id': 'pn.pn_general_chamber', 'submodel': 'PNCH023', 'label': 'simple pneumatic chamber with heat exchange', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol', 'title': 'volume', 'value': '5.70000000000000e+01', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '0.00000000000000e+00', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '1.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 80, 'alias': 'pn_orifice_22', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 81, 'alias': 'pn_orifice_23', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 82, 'alias': 'pn_node3_12', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 83, 'alias': 'pn_node3_13', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 84, 'alias': 'pn_general_chamber_5', 'component_name': 'pn_general_chamber', 'library_id': 'pn.pn_general_chamber', 'submodel': 'PNCH023', 'label': 'simple pneumatic chamber with heat exchange', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cvol', 'title': 'volume', 'value': '5.70000000000000e+01', 'units': 'L'}, {'name': 'kth', 'title': 'thermal exchange coefficient', 'value': '0.00000000000000e+00', 'units': 'J/m**2/K/s'}, {'name': 'sth', 'title': 'thermal exchange area', 'value': '1.00000000000000e-01', 'units': 'm**2'}, {'name': 'extemp', 'title': 'external temperature', 'value': '2.93150000000000e+02', 'units': 'K'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}]}, {'index': 85, 'alias': 'pn_orifice_24', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 86, 'alias': 'pn_orifice_25', 'component_name': 'pn_orifice', 'library_id': 'pn.pn_orifice', 'submodel': 'PNOR001', 'label': 'pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '0'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': '9.00000000000000e-01', 'units': 'null'}, {'name': 'area', 'title': 'orifice area', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 87, 'alias': 'pn_node3_14', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 88, 'alias': 'pn_node3_15', 'component_name': 'pn_node3', 'library_id': 'pn.pn_node3', 'submodel': 'PN3NODE2', 'label': 'pneumatic junction 3 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}], 'parameters': []}, {'index': 89, 'alias': 'pnnode4_16', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 90, 'alias': 'pnnode4_17', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 91, 'alias': 'pnnode4_18', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 92, 'alias': 'pnnode4_19', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 93, 'alias': 'pnnode4_20', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 94, 'alias': 'pnnode4_21', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 95, 'alias': 'pnnode4_22', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 96, 'alias': 'pnnode4_23', 'component_name': 'pnnode4', 'library_id': 'pn.pnnode4', 'submodel': 'P4NODE2', 'label': 'pneumatic junction 4 ports (temperature and pressure fixed by port 2)', 'ports': [{'name': 'port_1', 'type': 'pflow', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '0'}, {'name': 'port_4', 'type': 'pflow', 'face': '2'}], 'parameters': []}, {'index': 97, 'alias': 'pn_morifice_11', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 98, 'alias': 'step_8', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 99, 'alias': 'pn_morifice_12', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 100, 'alias': 'step_9', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 101, 'alias': 'pn_morifice_13', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 102, 'alias': 'step_10', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 103, 'alias': 'pn_morifice_14', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 104, 'alias': 'step_11', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 105, 'alias': 'forcecon_2', 'component_name': 'forcecon', 'library_id': 'meca.forcecon', 'submodel': 'FORC', 'label': 'conversion of signal input into a force in N', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}, {'name': 'port_2', 'type': 'lshaft', 'face': '2'}], 'parameters': []}, {'index': 106, 'alias': 'piecewiselinear', 'component_name': 'piecewiselinear', 'library_id': 'sig.piecewiselinear', 'submodel': 'UD00', 'label': 'piecewise linear signal source', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'tstart', 'title': 'time at which duty cycle starts', 'value': '0.00000000000000e+00', 'units': 's'}, {'name': 'start1', 'title': 'output at start of stage 1', 'value': '1.00000000000000e+17', 'units': 'null'}, {'name': 'end1', 'title': 'output at end of stage 1', 'value': '1.00000000000000e+17', 'units': 'null'}, {'name': 't1', 'title': 'duration of stage 1', 'value': '8.00000000000000e-01', 'units': 's'}, {'name': 'start2', 'title': 'output at start of stage 2', 'value': '4.90000000000000e+04', 'units': 'null'}, {'name': 'end2', 'title': 'output at end of stage 2', 'value': '4.90000000000000e+04', 'units': 'null'}, {'name': 't2', 'title': 'duration of stage 2', 'value': '1.00000000000000e+01', 'units': 's'}, {'name': 'start3', 'title': 'output at start of stage 3', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end3', 'title': 'output at end of stage 3', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't3', 'title': 'duration of stage 3', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start4', 'title': 'output at start of stage 4', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end4', 'title': 'output at end of stage 4', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't4', 'title': 'duration of stage 4', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start5', 'title': 'output at start of stage 5', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end5', 'title': 'output at end of stage 5', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't5', 'title': 'duration of stage 5', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start6', 'title': 'output at start of stage 6', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end6', 'title': 'output at end of stage 6', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't6', 'title': 'duration of stage 6', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start7', 'title': 'output at start of stage 7', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end7', 'title': 'output at end of stage 7', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't7', 'title': 'duration of stage 7', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start8', 'title': 'output at start of stage 8', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end8', 'title': 'output at end of stage 8', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't8', 'title': 'duration of stage 8', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'nstages', 'title': 'number of stages', 'value': '2', 'units': ''}, {'name': 'iscyclic', 'title': 'cyclic', 'value': '1', 'units': ''}]}, {'index': 107, 'alias': 'piecewiselinear_1', 'component_name': 'piecewiselinear', 'library_id': 'sig.piecewiselinear', 'submodel': 'UD00', 'label': 'piecewise linear signal source', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '2'}], 'parameters': [{'name': 'tstart', 'title': 'time at which duty cycle starts', 'value': '0.00000000000000e+00', 'units': 's'}, {'name': 'start1', 'title': 'output at start of stage 1', 'value': '1.00000000000000e+12', 'units': 'null'}, {'name': 'end1', 'title': 'output at end of stage 1', 'value': '1.00000000000000e+12', 'units': 'null'}, {'name': 't1', 'title': 'duration of stage 1', 'value': '8.00000000000000e-01', 'units': 's'}, {'name': 'start2', 'title': 'output at start of stage 2', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end2', 'title': 'output at end of stage 2', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't2', 'title': 'duration of stage 2', 'value': '1.00000000000000e+01', 'units': 's'}, {'name': 'start3', 'title': 'output at start of stage 3', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end3', 'title': 'output at end of stage 3', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't3', 'title': 'duration of stage 3', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start4', 'title': 'output at start of stage 4', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end4', 'title': 'output at end of stage 4', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't4', 'title': 'duration of stage 4', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start5', 'title': 'output at start of stage 5', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end5', 'title': 'output at end of stage 5', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't5', 'title': 'duration of stage 5', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start6', 'title': 'output at start of stage 6', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end6', 'title': 'output at end of stage 6', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't6', 'title': 'duration of stage 6', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start7', 'title': 'output at start of stage 7', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end7', 'title': 'output at end of stage 7', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't7', 'title': 'duration of stage 7', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'start8', 'title': 'output at start of stage 8', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'end8', 'title': 'output at end of stage 8', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 't8', 'title': 'duration of stage 8', 'value': '3.00000000000000e+00', 'units': 's'}, {'name': 'nstages', 'title': 'number of stages', 'value': '2', 'units': ''}, {'name': 'iscyclic', 'title': 'cyclic', 'value': '1', 'units': ''}]}, {'index': 108, 'alias': 'pn_morifice_1', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 109, 'alias': 'step_12', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 110, 'alias': 'pn_morifice_9', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 111, 'alias': 'step_13', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 112, 'alias': 'pn_morifice_10', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 113, 'alias': 'step_14', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 114, 'alias': 'pn_morifice_15', 'component_name': 'pn_morifice', 'library_id': 'pn.pn_morifice', 'submodel': 'PNVO001', 'label': 'modulated pneumatic orifice (constant flow coefficient)', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '1'}, {'name': 'port_2', 'type': 'pflow', 'face': '3'}, {'name': 'port_3', 'type': 'pflow', 'face': '2'}], 'parameters': [{'name': 'cq', 'title': 'flow coefficient (Cq)', 'value': 'cf', 'units': 'null'}, {'name': 'area0', 'title': 'orifice area at maximum opening', 'value': '3.14*10^2/4', 'units': 'mm**2'}, {'name': 'Cv', 'title': 'maximum flow coefficient (Cv)', 'value': '5.00000000000000e-01', 'units': 'null'}, {'name': 'Kv', 'title': 'maximum flow coefficient (Kv)', 'value': '4.00000000000000e-01', 'units': 'null'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'flowset', 'title': 'flow coefficient setting', 'value': '1', 'units': ''}]}, {'index': 115, 'alias': 'step_15', 'component_name': 'step', 'library_id': 'sig.step', 'submodel': 'STEP0', 'label': 'step function', 'ports': [{'name': 'port_1', 'type': 'signal', 'face': '3'}], 'parameters': [{'name': 'out0', 'title': 'value before step', 'value': '0.00000000000000e+00', 'units': 'null'}, {'name': 'out1', 'title': 'value after step', 'value': '1.00000000000000e+00', 'units': 'null'}, {'name': 't0', 'title': 'step time', 'value': '4.00000000000000e-02', 'units': 's'}, {'name': 'td', 'title': 'transition duration', 'value': '1.00000000000000e-01', 'units': 's'}, {'name': 'transitionType', 'title': 'transition type', 'value': '1', 'units': ''}]}, {'index': 116, 'alias': 'pn_gas_data', 'component_name': 'pn_gas_data', 'library_id': 'pn.pn_gas_data', 'submodel': 'PNGD00', 'label': 'gas definition for helium (He)', 'ports': [], 'parameters': [{'name': 'cp', 'title': 'constant-pressure specific heat (Cp)', 'value': '1.00520000000000e+03', 'units': 'J/kg/K'}, {'name': 'cv', 'title': 'constant-volume specific heat (Cv)', 'value': '7.18000000000000e+02', 'units': 'J/kg/K'}, {'name': 'gamma', 'title': 'specific heat ratio (gamma)', 'value': '1.40000000000000e+00', 'units': 'null'}, {'name': 'rGas', 'title': 'specific gas constant (r)', 'value': '2.87200000000000e+02', 'units': 'J/kg/K'}, {'name': 'mu', 'title': 'absolute viscosity (mu)', 'value': '1.82000000000000e-02', 'units': 'cP'}, {'name': 'lam', 'title': 'thermal conductivity', 'value': '2.64000000000000e-02', 'units': 'W/m/K'}, {'name': 'M', 'title': 'molar mass', 'value': '2.89651300000000e+01', 'units': 'g/mol'}, {'name': 'operatingTempK', 'title': 'operating temperature', 'value': '2.98150000000000e+02', 'units': 'K'}, {'name': 'enthForm', 'title': 'enthalpy of formation', 'value': '-1.25530000000000e+02', 'units': 'J/mol'}, {'name': 'gi', 'title': 'gas type index', 'value': '1', 'units': ''}, {'name': 'fluidType', 'title': 'fluid definition', 'value': '12', 'units': ''}, {'name': 'eosType', 'title': 'properties definition', 'value': '6', 'units': ''}, {'name': 'gasSetting', 'title': 'setting properties through', 'value': '1', 'units': ''}]}] CONNECTION_SPECS = [{'index': 0, 'alias': 'linear_24', 'source_component': 'pn_brp2_8', 'source_port': 'port_5', 'target_component': 'elasticendstop_8', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 1, 'alias': 'linear_25', 'source_component': 'elasticendstop_8', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 2, 'alias': 'linear_26', 'source_component': 'pn_brp2_9', 'source_port': 'port_5', 'target_component': 'elasticendstop_9', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 3, 'alias': 'linear_27', 'source_component': 'elasticendstop_9', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_2', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 4, 'alias': 'linear_28', 'source_component': 'pn_brp2_10', 'source_port': 'port_5', 'target_component': 'elasticendstop_10', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 5, 'alias': 'linear_29', 'source_component': 'pn_brp2_11', 'source_port': 'port_5', 'target_component': 'elasticendstop_11', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 6, 'alias': 'linear_30', 'source_component': 'pn_brp2_12', 'source_port': 'port_5', 'target_component': 'elasticendstop_12', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 7, 'alias': 'linear_31', 'source_component': 'pn_brp2_13', 'source_port': 'port_5', 'target_component': 'elasticendstop_13', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 8, 'alias': 'linear_32', 'source_component': 'pn_brp2_14', 'source_port': 'port_5', 'target_component': 'elasticendstop_14', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 9, 'alias': 'linear_33', 'source_component': 'pn_brp2_15', 'source_port': 'port_5', 'target_component': 'elasticendstop_15', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 10, 'alias': 'linear_34', 'source_component': 'elasticendstop_10', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 11, 'alias': 'linear_35', 'source_component': 'elasticendstop_11', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_4', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 12, 'alias': 'linear_36', 'source_component': 'elasticendstop_12', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_5', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 13, 'alias': 'linear_37', 'source_component': 'elasticendstop_13', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_6', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 14, 'alias': 'linear_38', 'source_component': 'elasticendstop_14', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_7', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 15, 'alias': 'linear_39', 'source_component': 'elasticendstop_15', 'source_port': 'port_2', 'target_component': 'dynamic_mechanical_node_alternative_2', 'target_port': 'port_8', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 16, 'alias': 'linear_40', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_8', 'target_component': 'pn_brp2_8', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 17, 'alias': 'linear_41', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_7', 'target_component': 'pn_brp2_9', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 18, 'alias': 'linear_42', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_6', 'target_component': 'pn_brp2_10', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 19, 'alias': 'linear_43', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_5', 'target_component': 'pn_brp2_11', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 20, 'alias': 'linear_44', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_4', 'target_component': 'pn_brp2_12', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 21, 'alias': 'linear_45', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_3', 'target_component': 'pn_brp2_13', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 22, 'alias': 'linear_46', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_2', 'target_component': 'pn_brp2_14', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 23, 'alias': 'linear_47', 'source_component': 'dynamic_mechanical_node_alternative_3', 'source_port': 'port_1', 'target_component': 'pn_brp2_15', 'target_port': 'port_3', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 24, 'alias': 'pneumatic_56', 'source_component': 'pn_c1_8', 'source_port': 'port_3', 'target_component': 'pn_brp2_8', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 25, 'alias': 'pneumatic_57', 'source_component': 'pn_c1_9', 'source_port': 'port_3', 'target_component': 'pn_brp2_9', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 26, 'alias': 'pneumatic_58', 'source_component': 'pn_c1_10', 'source_port': 'port_3', 'target_component': 'pn_brp2_10', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 27, 'alias': 'pneumatic_59', 'source_component': 'pn_c1_11', 'source_port': 'port_3', 'target_component': 'pn_brp2_11', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 28, 'alias': 'pneumatic_60', 'source_component': 'pn_c1_12', 'source_port': 'port_3', 'target_component': 'pn_brp2_12', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 29, 'alias': 'pneumatic_61', 'source_component': 'pn_c1_13', 'source_port': 'port_3', 'target_component': 'pn_brp2_13', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 30, 'alias': 'pneumatic_62', 'source_component': 'pn_c1_14', 'source_port': 'port_3', 'target_component': 'pn_brp2_14', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 31, 'alias': 'pneumatic_63', 'source_component': 'pn_c1_15', 'source_port': 'port_3', 'target_component': 'pn_brp2_15', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 32, 'alias': 'pneumatic_64', 'source_component': 'pn_morifice_15', 'source_port': 'port_2', 'target_component': 'pnnode4_19', 'target_port': 'port_4', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 33, 'alias': 'pneumatic_65', 'source_component': 'pnnode4_19', 'source_port': 'port_2', 'target_component': 'pn_c1_11', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 34, 'alias': 'pneumatic_66', 'source_component': 'pnnode4_18', 'source_port': 'port_2', 'target_component': 'pn_c1_10', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 35, 'alias': 'pneumatic_67', 'source_component': 'pn_morifice_10', 'source_port': 'port_2', 'target_component': 'pnnode4_18', 'target_port': 'port_4', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 36, 'alias': 'pneumatic_68', 'source_component': 'pnnode4_17', 'source_port': 'port_2', 'target_component': 'pn_c1_9', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 37, 'alias': 'pneumatic_69', 'source_component': 'pnnode4_16', 'source_port': 'port_2', 'target_component': 'pn_c1_8', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 38, 'alias': 'pneumatic_70', 'source_component': 'pn_morifice_12', 'source_port': 'port_2', 'target_component': 'pnnode4_20', 'target_port': 'port_4', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 39, 'alias': 'pneumatic_71', 'source_component': 'pnnode4_23', 'source_port': 'port_2', 'target_component': 'pn_c1_12', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 40, 'alias': 'pneumatic_72', 'source_component': 'pnnode4_20', 'source_port': 'port_2', 'target_component': 'pn_c1_13', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 41, 'alias': 'pneumatic_73', 'source_component': 'pnnode4_21', 'source_port': 'port_2', 'target_component': 'pn_c1_14', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 42, 'alias': 'pneumatic_74', 'source_component': 'pnnode4_22', 'source_port': 'port_2', 'target_component': 'pn_c1_15', 'target_port': 'port_1', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 43, 'alias': 'pneumatic_75', 'source_component': 'pn_node3_10', 'source_port': 'port_2', 'target_component': 'pn_morifice_10', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 44, 'alias': 'pneumatic_76', 'source_component': 'pn_node3_11', 'source_port': 'port_2', 'target_component': 'pn_morifice_15', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 45, 'alias': 'pneumatic_77', 'source_component': 'pn_node3_12', 'source_port': 'port_2', 'target_component': 'pn_morifice_11', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 46, 'alias': 'pneumatic_78', 'source_component': 'pn_node3_13', 'source_port': 'port_2', 'target_component': 'pn_morifice_12', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 47, 'alias': 'pneumatic_79', 'source_component': 'pnnode4_23', 'source_port': 'port_4', 'target_component': 'pn_morifice_11', 'target_port': 'port_2', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 48, 'alias': 'pneumatic_80', 'source_component': 'pnnode4_18', 'source_port': 'port_1', 'target_component': 'pnnode4_19', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 49, 'alias': 'pneumatic_81', 'source_component': 'pnnode4_23', 'source_port': 'port_1', 'target_component': 'pnnode4_20', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 50, 'alias': 'pneumatic_82', 'source_component': 'pnnode4_21', 'source_port': 'port_1', 'target_component': 'pnnode4_22', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 51, 'alias': 'pneumatic_83', 'source_component': 'pnnode4_16', 'source_port': 'port_1', 'target_component': 'pnnode4_17', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 52, 'alias': 'pneumatic_84', 'source_component': 'pnnode4_20', 'source_port': 'port_1', 'target_component': 'pnnode4_21', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 53, 'alias': 'pneumatic_85', 'source_component': 'pnnode4_19', 'source_port': 'port_1', 'target_component': 'pnnode4_23', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 54, 'alias': 'pneumatic_86', 'source_component': 'pnnode4_17', 'source_port': 'port_1', 'target_component': 'pnnode4_18', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 55, 'alias': 'pneumatic_87', 'source_component': 'pn_node3_8', 'source_port': 'port_2', 'target_component': 'pn_morifice_1', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 56, 'alias': 'pneumatic_88', 'source_component': 'pn_node3_9', 'source_port': 'port_2', 'target_component': 'pn_morifice_9', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 57, 'alias': 'pneumatic_89', 'source_component': 'pn_morifice_1', 'source_port': 'port_2', 'target_component': 'pnnode4_16', 'target_port': 'port_4', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 58, 'alias': 'pneumatic_90', 'source_component': 'pn_morifice_9', 'source_port': 'port_2', 'target_component': 'pnnode4_17', 'target_port': 'port_4', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 59, 'alias': 'pneumatic_91', 'source_component': 'pn_node3_14', 'source_port': 'port_2', 'target_component': 'pn_morifice_13', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 60, 'alias': 'pneumatic_92', 'source_component': 'pn_node3_15', 'source_port': 'port_2', 'target_component': 'pn_morifice_14', 'target_port': 'port_3', 'submodel': 'PNL0003', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R-C)'}, {'index': 61, 'alias': 'pneumatic_93', 'source_component': 'pn_morifice_13', 'source_port': 'port_2', 'target_component': 'pnnode4_21', 'target_port': 'port_4', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 62, 'alias': 'pneumatic_94', 'source_component': 'pn_morifice_14', 'source_port': 'port_2', 'target_component': 'pnnode4_22', 'target_port': 'port_4', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 63, 'alias': 'pneumatic_95', 'source_component': 'pnnode4_22', 'source_port': 'port_1', 'target_component': 'pnnode4_16', 'target_port': 'port_3', 'submodel': 'PNL0002', 'label': 'Compressibility + friction submodel of pneumatic pipe (R-C-R)'}, {'index': 64, 'alias': 'pneumatic_96', 'source_component': 'pn_node3_8', 'source_port': 'port_1', 'target_component': 'pn_orifice_18', 'target_port': 'port_2', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 65, 'alias': 'pneumatic_97', 'source_component': 'pn_orifice_19', 'source_port': 'port_1', 'target_component': 'pn_node3_9', 'target_port': 'port_3', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 66, 'alias': 'pneumatic_98', 'source_component': 'pn_node3_10', 'source_port': 'port_1', 'target_component': 'pn_orifice_20', 'target_port': 'port_2', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 67, 'alias': 'pneumatic_99', 'source_component': 'pn_orifice_21', 'source_port': 'port_1', 'target_component': 'pn_node3_11', 'target_port': 'port_3', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 68, 'alias': 'pneumatic_100', 'source_component': 'pn_node3_9', 'source_port': 'port_1', 'target_component': 'pn_node3_10', 'target_port': 'port_3', 'submodel': 'PNL00R', 'label': 'Friction submodel of pneumatic pipe (R)'}, {'index': 69, 'alias': 'pneumatic_101', 'source_component': 'pn_node3_12', 'source_port': 'port_1', 'target_component': 'pn_orifice_22', 'target_port': 'port_2', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 70, 'alias': 'pneumatic_102', 'source_component': 'pn_orifice_23', 'source_port': 'port_1', 'target_component': 'pn_node3_13', 'target_port': 'port_3', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 71, 'alias': 'pneumatic_103', 'source_component': 'pn_node3_14', 'source_port': 'port_1', 'target_component': 'pn_orifice_24', 'target_port': 'port_2', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 72, 'alias': 'pneumatic_104', 'source_component': 'pn_orifice_25', 'source_port': 'port_1', 'target_component': 'pn_node3_15', 'target_port': 'port_3', 'submodel': 'PNL0001', 'label': 'Compressibility + friction submodel of pneumatic pipe (C-R)'}, {'index': 73, 'alias': 'pneumatic_105', 'source_component': 'pn_node3_8', 'source_port': 'port_3', 'target_component': 'pn_node3_15', 'target_port': 'port_1', 'submodel': 'PNL00R', 'label': 'Friction submodel of pneumatic pipe (R)'}, {'index': 74, 'alias': 'pneumatic_106', 'source_component': 'pn_node3_13', 'source_port': 'port_1', 'target_component': 'pn_node3_14', 'target_port': 'port_3', 'submodel': 'PNL00R', 'label': 'Friction submodel of pneumatic pipe (R)'}, {'index': 75, 'alias': 'pneumatic_107', 'source_component': 'pn_node3_11', 'source_port': 'port_1', 'target_component': 'pn_node3_12', 'target_port': 'port_3', 'submodel': 'PNL00R', 'label': 'Friction submodel of pneumatic pipe (R)'}, {'index': 76, 'alias': 'control_8', 'source_component': 'step_8', 'source_port': 'port_1', 'target_component': 'pn_morifice_11', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 77, 'alias': 'control_9', 'source_component': 'step_9', 'source_port': 'port_1', 'target_component': 'pn_morifice_12', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 78, 'alias': 'control_10', 'source_component': 'step_10', 'source_port': 'port_1', 'target_component': 'pn_morifice_13', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 79, 'alias': 'control_11', 'source_component': 'step_11', 'source_port': 'port_1', 'target_component': 'pn_morifice_14', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 80, 'alias': 'control_12', 'source_component': 'step_12', 'source_port': 'port_1', 'target_component': 'pn_morifice_1', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 81, 'alias': 'control_13', 'source_component': 'step_13', 'source_port': 'port_1', 'target_component': 'pn_morifice_9', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 82, 'alias': 'control_14', 'source_component': 'step_14', 'source_port': 'port_1', 'target_component': 'pn_morifice_10', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}, {'index': 83, 'alias': 'control_15', 'source_component': 'step_15', 'source_port': 'port_1', 'target_component': 'pn_morifice_15', 'target_port': 'port_1', 'submodel': 'DIRECT', 'label': 'Direct connection'}] @dataclass(frozen=True) class TestMqlRunConfig: t_start: float = SIMULATION_SETTINGS["t_start"] t_stop: float = SIMULATION_SETTINGS["t_stop"] sample_step: float = SIMULATION_SETTINGS["sample_step"] def sample_times(self) -> list[float]: if self.sample_step <= 0.0: raise ValueError("sample_step must be positive") point_count = int(round((self.t_stop - self.t_start) / self.sample_step)) return [self.t_start + index * self.sample_step for index in range(point_count + 1)] @dataclass(frozen=True) class TestMqlSnapshot: model_name: str component_count: int connection_count: int continuous_state_count: int discrete_state_count: int global_parameters: dict[str, str] submodel_counts: dict[str, int] @dataclass(frozen=True) class TestMqlSimulationResult: t: list[float] y: list[list[float]] series: dict[str, list[float]] @dataclass(frozen=True) class TestMqlFullStateSnapshot: pneumatic: object mechanical: object mechanical_node_total_force_by_alias: dict[str, float] @property def state_count(self) -> int: return self.pneumatic_state_count + self.mechanical_state_count @property def pneumatic_state_count(self) -> int: return 112 @property def mechanical_state_count(self) -> int: return self.mechanical.state_count @dataclass(frozen=True) class TestMqlVariableChamberRhsDiagnostic: chamber_alias: str piston_alias: str chamber_pressure_pa: float chamber_temperature_k: float chamber_volume_m3: float chamber_volume_rate_m3_s: float port_a_mass_flow_kg_s: float port_b_mass_flow_kg_s: float mass_derivative_kg_s: float port_a_energy_flow_w: float port_b_energy_flow_w: float boundary_work_w: float thermal_energy_flow_w: float energy_derivative_w: float @dataclass(frozen=True) class TestMqlPnl0001LineRhsDiagnostic: line_alias: str chamber_alias: str line_pressure_pa: float line_temperature_k: float chamber_pressure_pa: float chamber_temperature_k: float chamber_to_line_flow_kg_s: float node_to_line_flow_kg_s: float mass_derivative_kg_s: float port_1_energy_flow_w: float port_2_energy_flow_w: float thermal_energy_flow_w: float energy_derivative_w: float _PISTON_FORCE_BINDINGS = ( ("mass_friction_endstops_10", "pn_brp2_8", "p4_port3_remote_primary_chamber"), ("mass_friction_endstops_11", "pn_brp2_9", "p4_primary_chamber"), ("mass_friction_endstops_12", "pn_brp2_10", "p4_port1_remote_primary_chamber"), ("mass_friction_endstops_13", "pn_brp2_11", "p4_port1_far_primary_chamber"), ("mass_friction_endstops_14", "pn_brp2_12", "p4_port1_next_primary_chamber"), ("mass_friction_endstops_15", "pn_brp2_13", "p4_bridge_primary_chamber"), ("mass_friction_endstops_16", "pn_brp2_14", "p4_port3_next_primary_chamber"), ("mass_friction_endstops_17", "pn_brp2_15", "p4_port3_far_primary_chamber"), ) _ELASTIC_ENDSTOP_FORCE_BINDINGS = ( ("mass_friction_endstops_10", "mass_friction_endstops_18", "elasticendstop_8"), ("mass_friction_endstops_11", "mass_friction_endstops_18", "elasticendstop_9"), ("mass_friction_endstops_12", "mass_friction_endstops_18", "elasticendstop_10"), ("mass_friction_endstops_13", "mass_friction_endstops_18", "elasticendstop_11"), ("mass_friction_endstops_14", "mass_friction_endstops_18", "elasticendstop_12"), ("mass_friction_endstops_15", "mass_friction_endstops_18", "elasticendstop_13"), ("mass_friction_endstops_16", "mass_friction_endstops_18", "elasticendstop_14"), ("mass_friction_endstops_17", "mass_friction_endstops_18", "elasticendstop_15"), ) def _default_full_state_data_paths() -> tuple[str, ...]: chamber_paths: list[str] = [] piston_paths: list[str] = [] for _mass_alias, piston_alias, chamber_field in _PISTON_FORCE_BINDINGS: chamber_alias = _PNCH012_ALIAS_BY_SNAPSHOT_FIELD[chamber_field] chamber_paths.extend([f"press@{chamber_alias}", f"vol@{chamber_alias}"]) piston_paths.extend([f"vol1@{piston_alias}", f"vvol1@{piston_alias}"]) mass_paths = [ f"{signal}@mass_friction_endstops_{index}" for index in range(10, 20) for signal in ("x1", "v1", "acc1") ] return tuple( [ *chamber_paths, *piston_paths, *mass_paths, "dm1@pneumatic_69", "xv@pn_morifice_1", "dm2@pn_morifice_1", ] ) _PNCH012_ALIAS_BY_SNAPSHOT_FIELD = { "p4_port3_remote_primary_chamber": "pn_c1_8", "p4_primary_chamber": "pn_c1_9", "p4_port1_remote_primary_chamber": "pn_c1_10", "p4_port1_far_primary_chamber": "pn_c1_11", "p4_port1_next_primary_chamber": "pn_c1_12", "p4_bridge_primary_chamber": "pn_c1_13", "p4_port3_next_primary_chamber": "pn_c1_14", "p4_port3_far_primary_chamber": "pn_c1_15", } _PRIMARY_CHAMBER_DIAGNOSTIC_FIELDS = { "pn_c1_8": ( "p4_port3_remote_primary_chamber", "p4_port3_remote_primary_line", "p4_port3_remote_chamber_to_line_flow", ), "pn_c1_9": ( "p4_primary_chamber", "p4_primary_line", "p4_primary_chamber_to_line_flow", ), "pn_c1_10": ( "p4_port1_remote_primary_chamber", "p4_port1_remote_primary_line", "p4_port1_remote_chamber_to_line_flow", ), "pn_c1_11": ( "p4_port1_far_primary_chamber", "p4_port1_far_primary_line", "p4_port1_far_chamber_to_line_flow", ), "pn_c1_12": ( "p4_port1_next_primary_chamber", "p4_port1_next_primary_line", "p4_port1_next_chamber_to_line_flow", ), "pn_c1_13": ( "p4_bridge_primary_chamber", "p4_bridge_primary_line", "p4_bridge_chamber_to_line_flow", ), "pn_c1_14": ( "p4_port3_next_primary_chamber", "p4_port3_next_primary_line", "p4_port3_next_chamber_to_line_flow", ), "pn_c1_15": ( "p4_port3_far_primary_chamber", "p4_port3_far_primary_line", "p4_port3_far_chamber_to_line_flow", ), } _PNL0001_LINE_DIAGNOSTIC_FIELDS = { "pneumatic_69": ( "p4_port3_remote_primary_line", "p4_port3_remote_primary_chamber", "p4_port3_remote_chamber_to_line_flow", "p4_port3_remote_node_to_primary_line_flow", ), } _VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS = { "pn_morifice_1": "p4_port3_remote_orifice_to_node_flow", } class TestMqlFullStateClosure: def __init__( self, *, pneumatic_closure: object, mechanical_closure: object, pneumatic_assembly: object, ) -> None: self.pneumatic_closure = pneumatic_closure self.mechanical_closure = mechanical_closure self.pneumatic_assembly = pneumatic_assembly self.pneumatic_state_count = len(pneumatic_closure.initial_state_vector()) self.mechanical_state_count = len(mechanical_closure.initial_state_vector()) @property def state_count(self) -> int: return self.pneumatic_state_count + self.mechanical_state_count def initial_state_vector(self) -> list[float]: return [ *self.pneumatic_closure.initial_state_vector(), *self.mechanical_closure.initial_state_vector(), ] def _split_state(self, state_vector: list[float]) -> tuple[list[float], list[float]]: if len(state_vector) != self.state_count: raise ValueError("full test_mql state vector requires 132 values") return ( state_vector[: self.pneumatic_state_count], state_vector[self.pneumatic_state_count :], ) def snapshot(self, state_vector: list[float] | None = None) -> TestMqlFullStateSnapshot: return self.snapshot_at(0.0, state_vector) def snapshot_at( self, time_s: float, state_vector: list[float] | None = None, ) -> TestMqlFullStateSnapshot: values = self.initial_state_vector() if state_vector is None else list(state_vector) pneumatic_state, mechanical_state = self._split_state(values) mechanical_snapshot = self.mechanical_closure.snapshot(mechanical_state) self._sync_variable_chamber_kinematics(mechanical_snapshot) self.pneumatic_assembly.set_variable_orifice_openings(time_s) pneumatic_snapshot = self.pneumatic_closure.snapshot(pneumatic_state) return TestMqlFullStateSnapshot( pneumatic=pneumatic_snapshot, mechanical=mechanical_snapshot, mechanical_node_total_force_by_alias=( self._mechanical_node_total_force_by_alias( pneumatic_snapshot, mechanical_snapshot, ) ), ) def rhs(self, state_vector: list[float]) -> list[float]: return self.rhs_at(0.0, state_vector) def rhs_at(self, time_s: float, state_vector: list[float]) -> list[float]: pneumatic_state, mechanical_state = self._split_state(list(state_vector)) mechanical_snapshot = self.mechanical_closure.snapshot(mechanical_state) self._sync_variable_chamber_kinematics(mechanical_snapshot) self.pneumatic_assembly.set_variable_orifice_openings(time_s) pneumatic_snapshot = self.pneumatic_closure.snapshot(pneumatic_state) return [ *self.pneumatic_closure.rhs(pneumatic_state), *self.mechanical_closure.rhs( mechanical_state, force_by_mass_alias=self._force_by_mass_alias( time_s, pneumatic_snapshot, mechanical_snapshot, ), constrained_mass_aliases={ "mass_friction_endstops_18", "mass_friction_endstops_19", }, ), ] def _sync_variable_chamber_kinematics(self, mechanical_snapshot: object) -> None: for _mass_alias, piston_alias, chamber_field in _PISTON_FORCE_BINDINGS: piston = self.mechanical_closure.assembly.pistons[piston_alias] kinematics = mechanical_snapshot.piston_kinematics_by_alias[piston_alias] chamber = getattr(self.pneumatic_closure.components, chamber_field) chamber.set_external_volume_m3( piston.geometry().chamber_volume_m3( kinematics.port_3_displacement_m, kinematics.port_2_displacement_m, ), piston.geometry().chamber_volume_rate_m3_s( kinematics.port_3_velocity_m_s, kinematics.port_2_velocity_m_s, ), ) def variable_chamber_rhs_diagnostic( self, *, chamber_alias: str, state_vector: list[float], time_s: float = 0.0, ) -> TestMqlVariableChamberRhsDiagnostic: if chamber_alias not in _PRIMARY_CHAMBER_DIAGNOSTIC_FIELDS: raise KeyError(chamber_alias) chamber_field, line_field, flow_field = _PRIMARY_CHAMBER_DIAGNOSTIC_FIELDS[ chamber_alias ] piston_alias = next( piston_alias for _mass_alias, piston_alias, bound_chamber_field in _PISTON_FORCE_BINDINGS if bound_chamber_field == chamber_field ) snapshot = self.snapshot_at(time_s, state_vector) chamber = getattr(self.pneumatic_closure.components, chamber_field) chamber_properties = getattr(snapshot.pneumatic, chamber_field) line_properties = getattr(snapshot.pneumatic, line_field) chamber_to_line_flow = getattr(snapshot.pneumatic, flow_field) port_a_mass_flow = -chamber_to_line_flow port_b_mass_flow = 0.0 port_a_inlet_h = chamber.connection_inlet_enthalpy( port_m_flow=port_a_mass_flow, connected_h=line_properties.h, internal_h=chamber_properties.h, ) port_b_inlet_h = chamber.connection_inlet_enthalpy( port_m_flow=port_b_mass_flow, connected_h=chamber_properties.h, internal_h=chamber_properties.h, ) port_a_energy_flow = port_a_mass_flow * port_a_inlet_h port_b_energy_flow = port_b_mass_flow * port_b_inlet_h boundary_work = -chamber_properties.p * chamber.volume_rate_m3_s() thermal_energy_flow = chamber.thermal_energy_flow_w( chamber_properties.T ) return TestMqlVariableChamberRhsDiagnostic( chamber_alias=chamber_alias, piston_alias=piston_alias, chamber_pressure_pa=chamber_properties.p, chamber_temperature_k=chamber_properties.T, chamber_volume_m3=chamber.volume, chamber_volume_rate_m3_s=chamber.volume_rate_m3_s(), port_a_mass_flow_kg_s=port_a_mass_flow, port_b_mass_flow_kg_s=port_b_mass_flow, mass_derivative_kg_s=port_a_mass_flow + port_b_mass_flow, port_a_energy_flow_w=port_a_energy_flow, port_b_energy_flow_w=port_b_energy_flow, boundary_work_w=boundary_work, thermal_energy_flow_w=thermal_energy_flow, energy_derivative_w=( port_a_energy_flow + port_b_energy_flow + boundary_work + thermal_energy_flow ), ) def pnl0001_line_rhs_diagnostic( self, *, line_alias: str, state_vector: list[float], time_s: float = 0.0, ) -> TestMqlPnl0001LineRhsDiagnostic: if line_alias not in _PNL0001_LINE_DIAGNOSTIC_FIELDS: raise KeyError(line_alias) ( line_field, chamber_field, chamber_flow_field, node_flow_field, ) = _PNL0001_LINE_DIAGNOSTIC_FIELDS[line_alias] chamber_alias = _PNCH012_ALIAS_BY_SNAPSHOT_FIELD[chamber_field] snapshot = self.snapshot_at(time_s, state_vector) line = getattr(self.pneumatic_closure.components, line_field) line_properties = getattr(snapshot.pneumatic, line_field) chamber_properties = getattr(snapshot.pneumatic, chamber_field) chamber_to_line_flow = getattr(snapshot.pneumatic, chamber_flow_field) node_to_line_flow = getattr(snapshot.pneumatic, node_flow_field) p4_balance = snapshot.pneumatic.p4_port3_remote_balance p4_port_2_mass_flow_kg_s = p4_balance.port_2_mass_flow_g_s * 1.0e-3 node_connected_h = ( line_properties.h if abs(p4_port_2_mass_flow_kg_s) <= 1.0e-12 else p4_balance.port_2_enthalpy_flow_w / p4_port_2_mass_flow_kg_s ) line_derivative = line.derivatives_from_transport_enthalpy_connections( port_1_m_flow=chamber_to_line_flow, connected_h_1=chamber_properties.h, port_2_m_flow=node_to_line_flow, connected_h_2=node_connected_h, ) port_1_inlet_h = ( chamber_properties.h if chamber_to_line_flow > 0.0 else line_properties.h ) port_2_inlet_h = ( node_connected_h if node_to_line_flow > 0.0 else line_properties.h ) thermal_energy_flow = ( line.heat_transfer_coefficient * line.heat_transfer_area * (line.external_temperature - line_properties.T) ) return TestMqlPnl0001LineRhsDiagnostic( line_alias=line_alias, chamber_alias=chamber_alias, line_pressure_pa=line_properties.p, line_temperature_k=line_properties.T, chamber_pressure_pa=chamber_properties.p, chamber_temperature_k=chamber_properties.T, chamber_to_line_flow_kg_s=chamber_to_line_flow, node_to_line_flow_kg_s=node_to_line_flow, mass_derivative_kg_s=line_derivative.m, port_1_energy_flow_w=chamber_to_line_flow * port_1_inlet_h, port_2_energy_flow_w=node_to_line_flow * port_2_inlet_h, thermal_energy_flow_w=thermal_energy_flow, energy_derivative_w=line_derivative.U, ) def data_path_values( self, *, time_s: float, state_vector: list[float], data_paths: tuple[str, ...] | list[str] | None = None, ) -> dict[str, float]: from PythonModels.systems.test_mql_pneumatic import pressure_to_amesim_gauge_pa selected_paths = tuple(data_paths) if data_paths is not None else _default_full_state_data_paths() snapshot = self.snapshot_at(time_s, state_vector) rhs = self.rhs_at(time_s, state_vector) chamber_properties_by_alias = {} chamber_by_alias = {} for _mass_alias, _piston_alias, chamber_field in _PISTON_FORCE_BINDINGS: chamber = getattr(self.pneumatic_closure.components, chamber_field) chamber_by_alias[chamber.name] = chamber chamber_properties_by_alias[chamber.name] = getattr(snapshot.pneumatic, chamber_field) state_by_alias = {state.alias: state for state in snapshot.mechanical.states} acceleration_by_mass_alias = { alias: rhs[self.pneumatic_state_count + 2 * index] for index, alias in enumerate(self.mechanical_closure.mass_aliases) } values_by_data_path = {} for data_path in selected_paths: signal, alias = self._split_data_path(data_path) if alias in _PNL0001_LINE_DIAGNOSTIC_FIELDS: ( line_field, _chamber_field, chamber_flow_field, _node_flow_field, ) = _PNL0001_LINE_DIAGNOSTIC_FIELDS[alias] if signal == "dm1": canonical_flow_kg_s = getattr(snapshot.pneumatic, chamber_flow_field) values_by_data_path[data_path] = -canonical_flow_kg_s * 1.0e3 elif signal == "p2": line_properties = getattr(snapshot.pneumatic, line_field) values_by_data_path[data_path] = pressure_to_amesim_gauge_pa( line_properties.p ) elif signal == "t2": line_properties = getattr(snapshot.pneumatic, line_field) values_by_data_path[data_path] = line_properties.T elif signal == "mgas": line = getattr(self.pneumatic_closure.components, line_field) values_by_data_path[data_path] = line.gas_mass_g() elif signal in {"re", "v", "ff"}: line = getattr(self.pneumatic_closure.components, line_field) line_properties = getattr(snapshot.pneumatic, line_field) canonical_flow_kg_s = getattr(snapshot.pneumatic, chamber_flow_field) diagnostics = line.diagnostics( mass_flow_kg_s=-canonical_flow_kg_s, temperature_k=line_properties.T, ) if signal == "re": values_by_data_path[data_path] = diagnostics.reynolds_number elif signal == "v": values_by_data_path[data_path] = diagnostics.gas_velocity_m_s else: values_by_data_path[data_path] = diagnostics.friction_factor else: raise KeyError(data_path) elif alias in self.pneumatic_assembly.variable_orifices: orifice = self.pneumatic_assembly.variable_orifices[alias] if signal == "xv": values_by_data_path[data_path] = orifice.opening elif ( signal == "dm2" and alias in _VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS ): flow_kg_s = getattr( snapshot.pneumatic, _VARIABLE_ORIFICE_MASS_FLOW_DIAGNOSTIC_FIELDS[alias], ) values_by_data_path[data_path] = flow_kg_s * 1.0e3 else: raise KeyError(data_path) elif alias in chamber_properties_by_alias: chamber_properties = chamber_properties_by_alias[alias] chamber = chamber_by_alias[alias] if signal == "press": values_by_data_path[data_path] = pressure_to_amesim_gauge_pa( chamber_properties.p ) elif signal == "temp": values_by_data_path[data_path] = chamber_properties.T elif signal == "vol": values_by_data_path[data_path] = chamber.volume_cm3() elif signal in {"mgas", "mgas1"}: values_by_data_path[data_path] = chamber.gas_mass_g() else: raise KeyError(data_path) elif alias in self.mechanical_closure.assembly.pistons: piston = self.mechanical_closure.assembly.pistons[alias] kinematics = snapshot.mechanical.piston_kinematics_by_alias[alias] geometry = piston.geometry() if signal == "vol1": values_by_data_path[data_path] = geometry.chamber_volume_cm3( kinematics.port_3_displacement_m, kinematics.port_2_displacement_m, ) elif signal == "vvol1": values_by_data_path[data_path] = geometry.chamber_volume_rate_l_min( kinematics.port_3_velocity_m_s, kinematics.port_2_velocity_m_s, ) elif signal == "length": values_by_data_path[data_path] = geometry.chamber_length_mm( kinematics.port_3_displacement_m, kinematics.port_2_displacement_m, ) elif signal == "x4": values_by_data_path[data_path] = kinematics.port_3_displacement_m elif signal == "x5": values_by_data_path[data_path] = kinematics.port_2_displacement_m elif signal == "v4": values_by_data_path[data_path] = kinematics.port_3_velocity_m_s elif signal == "v5": values_by_data_path[data_path] = kinematics.port_2_velocity_m_s else: raise KeyError(data_path) elif alias in state_by_alias: mass_state = state_by_alias[alias] if signal == "x1": values_by_data_path[data_path] = mass_state.displacement_m elif signal == "v1": values_by_data_path[data_path] = mass_state.velocity_m_s elif signal == "acc1": values_by_data_path[data_path] = acceleration_by_mass_alias[alias] else: raise KeyError(data_path) else: raise KeyError(data_path) return values_by_data_path def data_path_series( self, *, times: tuple[float, ...] | list[float], state_rows: list[list[float]], data_paths: tuple[str, ...] | list[str] | None = None, ) -> dict[str, list[float]]: selected_paths = tuple(data_paths) if data_paths is not None else _default_full_state_data_paths() series = {data_path: [] for data_path in selected_paths} for sample_index, time_value in enumerate(times): state_vector = [row[sample_index] for row in state_rows] values = self.data_path_values( time_s=float(time_value), state_vector=state_vector, data_paths=selected_paths, ) for data_path in selected_paths: series[data_path].append(values[data_path]) return series @staticmethod def _split_data_path(data_path: str) -> tuple[str, str]: if "@" not in data_path: raise KeyError(data_path) signal, alias = data_path.split("@", 1) return signal, alias def _force_by_mass_alias( self, time_s: float, pneumatic_snapshot: object, mechanical_snapshot: object, ) -> dict[str, float]: force_by_mass_alias = self._piston_force_by_mass_alias(pneumatic_snapshot) elastic_force_by_mass_alias = self._elastic_endstop_force_by_mass_alias( mechanical_snapshot ) for mass_alias, contact_force in elastic_force_by_mass_alias.items(): force_by_mass_alias[mass_alias] = ( force_by_mass_alias.get(mass_alias, 0.0) - contact_force ) force_by_mass_alias.update( self._large_mass_force_by_alias( time_s, pneumatic_snapshot, mechanical_snapshot, ) ) return force_by_mass_alias def _mechanical_node_total_force_by_alias( self, pneumatic_snapshot: object, mechanical_snapshot: object, ) -> dict[str, float]: return { "dynamic_mechanical_node_alternative_2": sum( self._elastic_endstop_force_by_mass_alias(mechanical_snapshot).values() ), "dynamic_mechanical_node_alternative_3": sum( self._piston_force_by_mass_alias(pneumatic_snapshot).values() ), } def _large_mass_force_by_alias( self, time_s: float, pneumatic_snapshot: object, mechanical_snapshot: object, ) -> dict[str, float]: node_force = self._mechanical_node_total_force_by_alias( pneumatic_snapshot, mechanical_snapshot, ) forcecon_1 = self.mechanical_closure.assembly.force_connectors["forcecon_1"] forcecon_2 = self.mechanical_closure.assembly.force_connectors["forcecon_2"] signals = self.mechanical_closure.assembly.piecewise_signals return { "mass_friction_endstops_18": ( node_force["dynamic_mechanical_node_alternative_2"] - forcecon_2.force_at(time_s, signals) ), "mass_friction_endstops_19": ( forcecon_1.force_at(time_s, signals) - node_force["dynamic_mechanical_node_alternative_3"] ), } def _piston_force_by_mass_alias(self, pneumatic_snapshot: object) -> dict[str, float]: from PythonModels.systems.test_mql_pneumatic import pressure_to_amesim_gauge_pa force_by_mass_alias: dict[str, float] = {} for mass_alias, piston_alias, chamber_field in _PISTON_FORCE_BINDINGS: chamber = getattr(pneumatic_snapshot, chamber_field) piston = self.mechanical_closure.assembly.pistons[piston_alias] force_by_mass_alias[mass_alias] = ( pressure_to_amesim_gauge_pa(chamber.p) * piston.annulus_area_m2 ) return force_by_mass_alias def _elastic_endstop_force_by_mass_alias( self, mechanical_snapshot: object, ) -> dict[str, float]: state_by_alias = {state.alias: state for state in mechanical_snapshot.states} force_by_mass_alias: dict[str, float] = {} for mass_alias, support_mass_alias, endstop_alias in _ELASTIC_ENDSTOP_FORCE_BINDINGS: mass_state = state_by_alias[mass_alias] support_state = state_by_alias[support_mass_alias] endstop = self.mechanical_closure.assembly.elastic_endstops[ endstop_alias ].endstop() gap_mm = (support_state.displacement_m - mass_state.displacement_m) * 1.0e3 penetration_velocity_m_s = ( mass_state.velocity_m_s - support_state.velocity_m_s ) force_by_mass_alias[mass_alias] = endstop.contact_force( gap_mm, penetration_velocity_m_s, ) return force_by_mass_alias class AmesimStructuralComponent(Component): def __init__(self, spec: dict[str, object]) -> None: super().__init__(name=str(spec["alias"])) self.spec = spec self.submodel = str(spec["submodel"]) self.component_name = str(spec["component_name"]) self.parameters = { str(parameter["name"]): parameter for parameter in spec.get("parameters", []) } @property def port_names(self) -> tuple[str, ...]: return tuple(str(port["name"]) for port in self.spec.get("ports", [])) class TestMqlSystem: """Structural Python port scaffold for AMESim model ``test_mql``.""" def __init__(self, archive_path: Path | None = None) -> None: self.archive_path = archive_path or Path(__file__).resolve().parents[2] / AMESIM_ARCHIVE_RELATIVE_PATH self.network = SimulationNetwork(name=MODEL_NAME) self.pnl0001_assembly = self._build_pnl0001_assembly() self.pnl0002_assembly = self._build_pnl0002_assembly() self.pnl0003_assembly = self._build_pnl0003_assembly() self.pnl00r_assembly = self._build_pnl00r_assembly() self.node3_assembly = self._build_node3_assembly() self.node4_assembly = self._build_node4_assembly() self.mechanical_assembly = self._build_mechanical_assembly() self.pneumatic_assembly = self._build_pneumatic_assembly() pneumatic_components = self._pneumatic_components_by_alias() for spec in COMPONENT_SPECS: alias = str(spec["alias"]) self.network.add_component( pneumatic_components.get(alias, AmesimStructuralComponent(spec)) ) for spec in CONNECTION_SPECS: self.network.connect( str(spec["source_component"]), str(spec["source_port"]), str(spec["target_component"]), str(spec["target_port"]), ) @staticmethod def _build_pneumatic_assembly(): # Local import avoids a module cycle: test_mql_config reads constants from this module. from PythonModels.systems.test_mql_pneumatic import build_test_mql_pneumatic_assembly return build_test_mql_pneumatic_assembly() @staticmethod def _build_mechanical_assembly(): # Local import avoids a module cycle: test_mql_config reads constants from this module. from PythonModels.systems.test_mql_mechanical import build_test_mql_mechanical_assembly return build_test_mql_mechanical_assembly() def _build_pnl0001_assembly(self): from PythonModels.systems.test_mql_pneumatic_lines import ( build_test_mql_pnl0001_assembly, ) return build_test_mql_pnl0001_assembly(self.archive_path) def _build_pnl0002_assembly(self): from PythonModels.systems.test_mql_pneumatic_lines import ( build_test_mql_pnl0002_assembly, ) return build_test_mql_pnl0002_assembly(self.archive_path) def _build_pnl0003_assembly(self): from PythonModels.systems.test_mql_pneumatic_lines import ( build_test_mql_pnl0003_assembly, ) return build_test_mql_pnl0003_assembly(self.archive_path) def _build_pnl00r_assembly(self): from PythonModels.systems.test_mql_pneumatic_lines import ( build_test_mql_pnl00r_assembly, ) return build_test_mql_pnl00r_assembly(self.archive_path) @staticmethod def _build_node3_assembly(): from PythonModels.systems.test_mql_nodes import build_test_mql_node3_assembly return build_test_mql_node3_assembly() @staticmethod def _build_node4_assembly(): from PythonModels.systems.test_mql_nodes import build_test_mql_node4_assembly return build_test_mql_node4_assembly() def _pneumatic_components_by_alias(self) -> dict[str, Component]: return { **self.pneumatic_assembly.fixed_chambers, **self.pneumatic_assembly.variable_chambers, **self.pneumatic_assembly.fixed_orifices, **self.pneumatic_assembly.variable_orifices, } @property def typed_pneumatic_component_count(self) -> int: return len(self._pneumatic_components_by_alias()) @property def typed_pnl0001_line_count(self) -> int: return len(self.pnl0001_assembly.lines) @property def typed_pnl0002_line_count(self) -> int: return len(self.pnl0002_assembly.lines) @property def typed_pnl0003_line_count(self) -> int: return len(self.pnl0003_assembly.lines) @property def typed_pnl00r_line_count(self) -> int: return len(self.pnl00r_assembly.lines) @property def typed_node3_count(self) -> int: return len(self.node3_assembly) @property def typed_node4_count(self) -> int: return len(self.node4_assembly) def _pnl0001_spec_for_node_port(self, node_alias: str, port_name: str): for spec in self.pnl0001_assembly.specs: if spec.source_component == node_alias and spec.source_port == port_name: return spec if spec.target_component == node_alias and spec.target_port == port_name: return spec raise KeyError(f"No PNL0001 line attached to {node_alias}.{port_name}") def _pnl0001_line_for_node_port(self, node_alias: str, port_name: str): spec = self._pnl0001_spec_for_node_port(node_alias, port_name) return self.pnl0001_assembly.lines[spec.alias] def _pnl0002_connection_for_node_port(self, node_alias: str, port_name: str): from PythonModels.systems.test_mql_nodes import TestMqlP4NodePortConnection spec = self._pnl0002_spec_for_node_port(node_alias, port_name) if spec.source_component == node_alias and spec.source_port == port_name: remote_node_alias = spec.target_component remote_port = spec.target_port elif spec.target_component == node_alias and spec.target_port == port_name: remote_node_alias = spec.source_component remote_port = spec.source_port else: raise KeyError(f"No PNL0002 line attached to {node_alias}.{port_name}") if remote_node_alias not in self.node4_assembly: raise KeyError( f"PNL0002 line {spec.alias} remote endpoint is not a P4 node: " f"{remote_node_alias}.{remote_port}" ) return TestMqlP4NodePortConnection( line_alias=spec.alias, local_node_alias=node_alias, local_port=port_name, remote_node_alias=remote_node_alias, remote_port=remote_port, ) def _pnl0002_spec_for_node_port(self, node_alias: str, port_name: str): for spec in self.pnl0002_assembly.specs: if spec.source_component == node_alias and spec.source_port == port_name: return spec if spec.target_component == node_alias and spec.target_port == port_name: return spec raise KeyError(f"No PNL0002 line attached to {node_alias}.{port_name}") def _pnl0002_line_for_node_port(self, node_alias: str, port_name: str): spec = self._pnl0002_spec_for_node_port(node_alias, port_name) return self.pnl0002_assembly.lines[spec.alias] def _p4_primary_connection_for_node(self, node_alias: str): from PythonModels.systems.test_mql_nodes import TestMqlP4NodePrimaryConnection spec = self._pnl0001_spec_for_node_port(node_alias, "port_2") if spec.source_component == node_alias and spec.source_port == "port_2": chamber_alias = spec.target_component chamber_port = spec.target_port elif spec.target_component == node_alias and spec.target_port == "port_2": chamber_alias = spec.source_component chamber_port = spec.source_port else: raise KeyError(f"No PNL0001 primary line attached to {node_alias}.port_2") return TestMqlP4NodePrimaryConnection( line_alias=spec.alias, node_alias=node_alias, node_port="port_2", chamber_alias=chamber_alias, chamber_port=chamber_port, ) def _p4_port4_orifice_connection_for_node(self, node_alias: str): from PythonModels.systems.test_mql_nodes import TestMqlP4NodeOrificeConnection for spec in CONNECTION_SPECS: if spec["submodel"] != "DIRECT": continue if spec["target_component"] == node_alias and spec["target_port"] == "port_4": orifice_alias = str(spec["source_component"]) if orifice_alias in self.pneumatic_assembly.variable_orifices: return TestMqlP4NodeOrificeConnection( orifice_alias=orifice_alias, node_alias=node_alias, node_port="port_4", direct_line_alias=str(spec["alias"]), ) if spec["source_component"] == node_alias and spec["source_port"] == "port_4": orifice_alias = str(spec["target_component"]) if orifice_alias in self.pneumatic_assembly.variable_orifices: return TestMqlP4NodeOrificeConnection( orifice_alias=orifice_alias, node_alias=node_alias, node_port="port_4", direct_line_alias=str(spec["alias"]), ) raise KeyError(f"No PNVO orifice attached to {node_alias}.port_4") def p4_node_neighborhood(self, node_alias: str): from PythonModels.systems.test_mql_nodes import TestMqlP4NodeNeighborhood if node_alias not in self.node4_assembly: raise KeyError(f"Unknown P4 node: {node_alias}") return TestMqlP4NodeNeighborhood( node_alias=node_alias, primary=self._p4_primary_connection_for_node(node_alias), port_1=self._pnl0002_connection_for_node_port(node_alias, "port_1"), port_3=self._pnl0002_connection_for_node_port(node_alias, "port_3"), port_4=self._p4_port4_orifice_connection_for_node(node_alias), ) def _p4_node_alias_for_orifice_port_2(self, orifice_alias: str) -> str: for spec in CONNECTION_SPECS: if spec["submodel"] != "DIRECT": continue if ( spec["source_component"] == orifice_alias and spec["source_port"] == "port_2" and str(spec["target_component"]) in self.node4_assembly ): return str(spec["target_component"]) if ( spec["target_component"] == orifice_alias and spec["target_port"] == "port_2" and str(spec["source_component"]) in self.node4_assembly ): return str(spec["source_component"]) raise KeyError(f"No P4 node attached to {orifice_alias}.port_2") def _pnl0003_spec_for_node_port(self, node_alias: str, port_name: str): for spec in self.pnl0003_assembly.specs: if spec.source_component == node_alias and spec.source_port == port_name: return spec if spec.target_component == node_alias and spec.target_port == port_name: return spec raise KeyError(f"No PNL0003 line attached to {node_alias}.{port_name}") def _pnl0003_line_for_node_port(self, node_alias: str, port_name: str): spec = self._pnl0003_spec_for_node_port(node_alias, port_name) return self.pnl0003_assembly.lines[spec.alias] def _pnl00r_line_for_node_port(self, node_alias: str, port_name: str): for spec in self.pnl00r_assembly.specs: if spec.source_component == node_alias and spec.source_port == port_name: return self.pnl00r_assembly.lines[spec.alias] if spec.target_component == node_alias and spec.target_port == port_name: return self.pnl00r_assembly.lines[spec.alias] raise KeyError(f"No PNL00R line attached to {node_alias}.{port_name}") def pneumatic_state_vector(self) -> list[float]: return self.network.initial_state_vector() def mechanical_mass_closure(self): from PythonModels.systems.test_mql_mechanical import TestMqlMechanicalMassClosure return TestMqlMechanicalMassClosure(self.mechanical_assembly) def mechanical_state_vector(self) -> list[float]: return self.mechanical_mass_closure().initial_state_vector() def simulate_mechanical_masses( self, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.mechanical_mass_closure() return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=config or SolveIVPConfig(), t_eval=t_eval, ) def full_state_closure_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, use_pneumatic_96_reference_rhs: bool = False, ) -> TestMqlFullStateClosure: return TestMqlFullStateClosure( pneumatic_closure=self.pn3_p4_node_chamber_segment_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, use_inlet_line_reference_rhs=use_pneumatic_96_reference_rhs, ), mechanical_closure=self.mechanical_mass_closure(), pneumatic_assembly=self.pneumatic_assembly, ) def simulate_full_state_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, use_pneumatic_96_reference_rhs: bool = False, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.full_state_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, use_pneumatic_96_reference_rhs=use_pneumatic_96_reference_rhs, ) return integrate_ode( rhs=lambda t, state: closure.rhs_at(t, state), initial_state=closure.initial_state_vector(), config=config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5), t_eval=t_eval, ) def simulate_full_state_series_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, data_paths: tuple[str, ...] | list[str] | None = None, use_pneumatic_96_reference_rhs: bool = False, ) -> TestMqlSimulationResult: closure = self.full_state_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, use_pneumatic_96_reference_rhs=use_pneumatic_96_reference_rhs, ) solution = integrate_ode( rhs=lambda t, state: closure.rhs_at(t, state), initial_state=closure.initial_state_vector(), config=config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5), t_eval=t_eval, ) times = [float(value) for value in solution.t] state_rows = [list(row) for row in solution.y] series = { "time": times, **closure.data_path_series( times=times, state_rows=state_rows, data_paths=data_paths, ), } return TestMqlSimulationResult(t=times, y=state_rows, series=series) @staticmethod def pneumatic_branch_spec( *, name: str, upstream_volume_alias: str, orifice_alias: str, downstream_volume_alias: str, source: str = "manual", ): from PythonModels.systems.test_mql_closure import TestMqlPneumaticBranchSpec return TestMqlPneumaticBranchSpec( name=name, upstream_volume_alias=upstream_volume_alias, orifice_alias=orifice_alias, downstream_volume_alias=downstream_volume_alias, source=source, ) def discover_pneumatic_branch_topology(self): from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticTopologyCandidate, TestMqlPneumaticTopologyDiscovery, ) from PythonModels.systems.test_mql_pneumatic_topology import ( discover_fixed_chamber_segments, ) from PythonModels.systems.test_mql_topology import load_test_mql_cir_topology topology = load_test_mql_cir_topology(self.archive_path) chamber_segment_specs = discover_fixed_chamber_segments( topology, COMPONENT_SPECS, CONNECTION_SPECS, ) typed_aliases = set(self._pneumatic_components_by_alias()) component_submodels = { str(component["alias"]): str(component["submodel"]) for component in COMPONENT_SPECS } blocked_candidates = [] for spec in CONNECTION_SPECS: source_component = str(spec["source_component"]) target_component = str(spec["target_component"]) source_is_typed = source_component in typed_aliases target_is_typed = target_component in typed_aliases if not (source_is_typed or target_is_typed): continue line_submodel = str(spec["submodel"]) endpoint_submodels = { component_submodels.get(source_component, ""), component_submodels.get(target_component, ""), } if "PNRP17" in endpoint_submodels: category = "piston-boundary" reason = "requires pneumatic piston and mechanical coupling interpretation" elif "STEP0" in endpoint_submodels: category = "control-boundary" reason = "requires modulated-orifice control signal evaluation" elif endpoint_submodels & {"PN3NODE2", "P4NODE2"}: category = "node-line-boundary" reason = "requires AMESim node/line equations before full-network closure" elif source_is_typed and target_is_typed: category = "typed-direct" reason = "direct typed connection is not a complete simulated subnetwork" elif line_submodel != "DIRECT": category = "line-boundary" reason = "requires AMESim line equations before full-network closure" else: category = "component-boundary" reason = "requires AMESim boundary component interpretation" blocked_candidates.append( TestMqlPneumaticTopologyCandidate( connection_alias=str(spec["alias"]), line_submodel=line_submodel, source_component=source_component, source_port=str(spec["source_port"]), target_component=target_component, target_port=str(spec["target_port"]), source_is_typed_pneumatic=source_is_typed, target_is_typed_pneumatic=target_is_typed, category=category, reason=reason, ) ) return TestMqlPneumaticTopologyDiscovery( branch_specs=(), chamber_segment_specs=chamber_segment_specs, blocked_candidates=tuple(blocked_candidates), ) def pneumatic_chamber_segment_closure_from_spec( self, spec, *, inlet_pressure_pa: float, outlet_pressure_pa: float, inlet_temperature_k: float = 293.15, outlet_temperature_k: float = 293.15, ): """Build a reduced segment using absolute-pressure line boundaries. Boundary values apply at the PNL0001/orifice interfaces, not at the nodes. """ from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBoundaryCondition, TestMqlPneumaticChamberSegmentClosure, TestMqlPneumaticChamberSegmentComponents, ) volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] if not isinstance(volume, AmesimPneumaticVolume): raise TypeError(f"{spec.volume_alias} is not an AMESim pneumatic volume") if not isinstance(inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) return TestMqlPneumaticChamberSegmentClosure( components=TestMqlPneumaticChamberSegmentComponents( volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, spec=spec, ), inlet_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=inlet_pressure_pa, temperature_k=inlet_temperature_k, ), outlet_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=outlet_pressure_pa, temperature_k=outlet_temperature_k, ), ) def simulate_pneumatic_chamber_segment_from_spec( self, spec, *, inlet_pressure_pa: float, outlet_pressure_pa: float, inlet_temperature_k: float = 293.15, outlet_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): """Integrate a reduced segment with absolute-pressure line boundaries.""" closure = self.pneumatic_chamber_segment_closure_from_spec( spec, inlet_pressure_pa=inlet_pressure_pa, outlet_pressure_pa=outlet_pressure_pa, inlet_temperature_k=inlet_temperature_k, outlet_temperature_k=outlet_temperature_k, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def pnl0001_chamber_segment_closure_from_spec( self, spec, *, inlet_node_pressure_pa: float, outlet_pressure_pa: float, inlet_node_temperature_k: float = 293.15, outlet_temperature_k: float = 293.15, ): """Insert the topology-derived inlet PNL0001 into a chamber segment.""" from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBoundaryCondition, TestMqlPnl0001ChamberSegmentClosure, TestMqlPnl0001ChamberSegmentComponents, ) inlet_line = self.pnl0001_assembly.lines[spec.inlet_line_alias] volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] if not isinstance(volume, AmesimPneumaticVolume): raise TypeError(f"{spec.volume_alias} is not an AMESim pneumatic volume") if not isinstance(inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) return TestMqlPnl0001ChamberSegmentClosure( components=TestMqlPnl0001ChamberSegmentComponents( inlet_line=inlet_line, volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, spec=spec, ), inlet_node=TestMqlPneumaticBoundaryCondition( pressure_pa=inlet_node_pressure_pa, temperature_k=inlet_node_temperature_k, ), outlet_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=outlet_pressure_pa, temperature_k=outlet_temperature_k, ), ) def simulate_pnl0001_chamber_segment_from_spec( self, spec, *, inlet_node_pressure_pa: float, outlet_pressure_pa: float, inlet_node_temperature_k: float = 293.15, outlet_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.pnl0001_chamber_segment_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, outlet_pressure_pa=outlet_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, outlet_temperature_k=outlet_temperature_k, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def pnl0001_pair_chamber_segment_closure_from_spec( self, spec, *, inlet_node_pressure_pa: float, outlet_node_pressure_pa: float, inlet_node_temperature_k: float = 293.15, outlet_node_temperature_k: float = 293.15, ): """Insert both topology-derived PNL0001 states into the segment.""" from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBoundaryCondition, TestMqlPnl0001PairChamberSegmentClosure, TestMqlPnl0001PairChamberSegmentComponents, ) inlet_line = self.pnl0001_assembly.lines[spec.inlet_line_alias] outlet_line = self.pnl0001_assembly.lines[spec.outlet_line_alias] volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] if not isinstance(volume, AmesimPneumaticVolume): raise TypeError(f"{spec.volume_alias} is not an AMESim pneumatic volume") if not isinstance(inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) return TestMqlPnl0001PairChamberSegmentClosure( components=TestMqlPnl0001PairChamberSegmentComponents( inlet_line=inlet_line, outlet_line=outlet_line, volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, spec=spec, ), inlet_node=TestMqlPneumaticBoundaryCondition( pressure_pa=inlet_node_pressure_pa, temperature_k=inlet_node_temperature_k, ), outlet_node=TestMqlPneumaticBoundaryCondition( pressure_pa=outlet_node_pressure_pa, temperature_k=outlet_node_temperature_k, ), ) def simulate_pnl0001_pair_chamber_segment_from_spec( self, spec, *, inlet_node_pressure_pa: float, outlet_node_pressure_pa: float, inlet_node_temperature_k: float = 293.15, outlet_node_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.pnl0001_pair_chamber_segment_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, outlet_node_pressure_pa=outlet_node_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, outlet_node_temperature_k=outlet_node_temperature_k, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def pn3_node_chamber_segment_closure_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, p4_boundary_pressure_pa: float = 15.3e6, p4_boundary_temperature_k: float = 293.15, ): """Close a PNL0001 chamber segment with the real outlet PN3 node. The PN3 primary pressure/temperature is taken from the attached PNL0003 port-1 compliance. The PNL0003 port-2 side is connected through the real PNVO001 orifice to a prescribed P4 pressure boundary. """ from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBoundaryCondition, TestMqlPn3NodeChamberSegmentClosure, TestMqlPn3NodeChamberSegmentComponents, ) inlet_line = self.pnl0001_assembly.lines[spec.inlet_line_alias] outlet_line = self.pnl0001_assembly.lines[spec.outlet_line_alias] node_line_spec = self._pnl0003_spec_for_node_port(spec.outlet_node_alias, "port_2") node_line = self.pnl0003_assembly.lines[node_line_spec.alias] node_orifice_alias = ( node_line_spec.target_component if node_line_spec.source_component == spec.outlet_node_alias else node_line_spec.source_component ) node_orifice = self.pneumatic_assembly.variable_orifices[node_orifice_alias] node_resistance = self._pnl00r_line_for_node_port( spec.outlet_node_alias, "port_1" ) node = self.node3_assembly[spec.outlet_node_alias] volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] if not isinstance(volume, AmesimPneumaticVolume): raise TypeError(f"{spec.volume_alias} is not an AMESim pneumatic volume") if not isinstance(inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) return TestMqlPn3NodeChamberSegmentClosure( components=TestMqlPn3NodeChamberSegmentComponents( inlet_line=inlet_line, outlet_line=outlet_line, node_line=node_line, node_resistance=node_resistance, node_orifice=node_orifice, node=node, volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, spec=spec, ), inlet_node=TestMqlPneumaticBoundaryCondition( pressure_pa=inlet_node_pressure_pa, temperature_k=inlet_node_temperature_k, ), resistance_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=resistance_boundary_pressure_pa, temperature_k=resistance_boundary_temperature_k, ), p4_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=p4_boundary_pressure_pa, temperature_k=p4_boundary_temperature_k, ), ) def simulate_pn3_node_chamber_segment_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, p4_boundary_pressure_pa: float = 15.3e6, p4_boundary_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.pn3_node_chamber_segment_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, p4_boundary_pressure_pa=p4_boundary_pressure_pa, p4_boundary_temperature_k=p4_boundary_temperature_k, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def pn3_p4_node_chamber_segment_closure_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, use_inlet_line_reference_rhs: bool = False, ): """Close a PN3 chamber segment through the adjacent real P4 node. The P4 primary pressure/temperature is supplied by the PNL0001 line on P4 port 2. Ports 1 and 3 use the adjacent PNL0002 center compliances. The next P4 nodes contribute their primary PNL0001/chamber states, and PNVO upstream endpoints are closed through their adjacent PN3/PNL0003 subnets. """ from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBoundaryCondition, TestMqlPn3P4NodeChamberSegmentClosure, TestMqlPn3P4NodeChamberSegmentComponents, ) def pnl0003_line_and_node_for_orifice(orifice_alias: str): for line_spec in self.pnl0003_assembly.specs: if ( line_spec.target_component == orifice_alias and line_spec.target_port == "port_3" and line_spec.source_component in self.node3_assembly ): return ( self.pnl0003_assembly.lines[line_spec.alias], self.node3_assembly[line_spec.source_component], ) if ( line_spec.source_component == orifice_alias and line_spec.source_port == "port_3" and line_spec.target_component in self.node3_assembly ): return ( self.pnl0003_assembly.lines[line_spec.alias], self.node3_assembly[line_spec.target_component], ) raise KeyError(f"No PN3/PNL0003 line attached to {orifice_alias}.port_3") def other_node3_for_pnl00r(line_alias: str, local_node_alias: str): for line_spec in self.pnl00r_assembly.specs: if line_spec.alias != line_alias: continue if line_spec.source_component == local_node_alias: return self.node3_assembly[line_spec.target_component] if line_spec.target_component == local_node_alias: return self.node3_assembly[line_spec.source_component] raise KeyError(f"No remote PN3 node found for {line_alias}") def chamber_segment_for_inlet_node(node_alias: str): chamber_specs = ( self.discover_pneumatic_branch_topology().chamber_segment_specs ) for chamber_spec in chamber_specs: if chamber_spec.inlet_node_alias == node_alias: return chamber_spec raise KeyError(f"No fixed chamber segment starts at {node_alias}") def chamber_segment_for_outlet_node(node_alias: str): chamber_specs = ( self.discover_pneumatic_branch_topology().chamber_segment_specs ) for chamber_spec in chamber_specs: if chamber_spec.outlet_node_alias == node_alias: return chamber_spec raise KeyError(f"No fixed chamber segment ends at {node_alias}") inlet_line = self.pnl0001_assembly.lines[spec.inlet_line_alias] outlet_line = self.pnl0001_assembly.lines[spec.outlet_line_alias] node_line_spec = self._pnl0003_spec_for_node_port( spec.outlet_node_alias, "port_2", ) node_line = self.pnl0003_assembly.lines[node_line_spec.alias] node_orifice_alias = ( node_line_spec.target_component if node_line_spec.source_component == spec.outlet_node_alias else node_line_spec.source_component ) p4_node_alias = self._p4_node_alias_for_orifice_port_2(node_orifice_alias) p4_neighborhood = self.p4_node_neighborhood(p4_node_alias) if p4_neighborhood.port_4.orifice_alias != node_orifice_alias: raise ValueError( f"P4 neighborhood for {p4_node_alias} does not match " f"{node_orifice_alias}" ) node_orifice = self.pneumatic_assembly.variable_orifices[ p4_neighborhood.port_4.orifice_alias ] node_resistance = self._pnl00r_line_for_node_port( spec.outlet_node_alias, "port_1", ) node = self.node3_assembly[spec.outlet_node_alias] p4_node = self.node4_assembly[p4_neighborhood.node_alias] p4_primary_line = self.pnl0001_assembly.lines[ p4_neighborhood.primary.line_alias ] p4_primary_chamber_alias = p4_neighborhood.primary.chamber_alias p4_primary_chamber = self.network.components[p4_primary_chamber_alias] p4_port1_line = self.pnl0002_assembly.lines[ p4_neighborhood.port_1.line_alias ] p4_port3_line = self.pnl0002_assembly.lines[ p4_neighborhood.port_3.line_alias ] p4_port1_remote_neighborhood = self.p4_node_neighborhood( p4_neighborhood.port_1.remote_node_alias ) p4_port1_remote_node = self.node4_assembly[ p4_port1_remote_neighborhood.node_alias ] p4_port1_remote_primary_line = self.pnl0001_assembly.lines[ p4_port1_remote_neighborhood.primary.line_alias ] p4_port1_remote_primary_chamber_alias = ( p4_port1_remote_neighborhood.primary.chamber_alias ) p4_port1_remote_primary_chamber = self.network.components[ p4_port1_remote_primary_chamber_alias ] p4_port1_remote_port1_line = self.pnl0002_assembly.lines[ p4_port1_remote_neighborhood.port_1.line_alias ] p4_port1_far_node_alias = p4_port1_remote_neighborhood.port_1.remote_node_alias p4_port1_far_node = self.node4_assembly[p4_port1_far_node_alias] p4_port1_far_primary = self._p4_primary_connection_for_node( p4_port1_far_node_alias ) p4_port1_far_primary_line = self.pnl0001_assembly.lines[ p4_port1_far_primary.line_alias ] p4_port1_far_primary_chamber_alias = p4_port1_far_primary.chamber_alias p4_port1_far_primary_chamber = self.network.components[ p4_port1_far_primary_chamber_alias ] p4_port1_far_port1 = self._pnl0002_connection_for_node_port( p4_port1_far_node_alias, "port_1", ) p4_port1_far_port1_line = self.pnl0002_assembly.lines[ p4_port1_far_port1.line_alias ] p4_port1_next_node_alias = p4_port1_far_port1.remote_node_alias p4_port1_next_node = self.node4_assembly[p4_port1_next_node_alias] p4_port1_next_primary = self._p4_primary_connection_for_node( p4_port1_next_node_alias ) p4_port1_next_primary_line = self.pnl0001_assembly.lines[ p4_port1_next_primary.line_alias ] p4_port1_next_primary_chamber_alias = p4_port1_next_primary.chamber_alias p4_port1_next_primary_chamber = self.network.components[ p4_port1_next_primary_chamber_alias ] p4_port1_next_port1 = self._pnl0002_connection_for_node_port( p4_port1_next_node_alias, "port_1", ) p4_port1_next_port1_line = self.pnl0002_assembly.lines[ p4_port1_next_port1.line_alias ] p4_port1_next_orifice_output_spec = self._pnl0001_spec_for_node_port( p4_port1_next_node_alias, "port_4", ) p4_port1_next_orifice_output_line = self.pnl0001_assembly.lines[ p4_port1_next_orifice_output_spec.alias ] p4_bridge_node_alias = p4_port1_next_port1.remote_node_alias p4_bridge_node = self.node4_assembly[p4_bridge_node_alias] p4_bridge_primary = self._p4_primary_connection_for_node( p4_bridge_node_alias ) p4_bridge_primary_line = self.pnl0001_assembly.lines[ p4_bridge_primary.line_alias ] p4_bridge_primary_chamber_alias = p4_bridge_primary.chamber_alias p4_bridge_primary_chamber = self.network.components[ p4_bridge_primary_chamber_alias ] p4_port1_remote_orifice = self.pneumatic_assembly.variable_orifices[ p4_port1_remote_neighborhood.port_4.orifice_alias ] ( p4_port1_remote_orifice_line, p4_port1_remote_orifice_node, ) = pnl0003_line_and_node_for_orifice( p4_port1_remote_neighborhood.port_4.orifice_alias ) p4_port3_remote_neighborhood = self.p4_node_neighborhood( p4_neighborhood.port_3.remote_node_alias ) p4_port3_remote_node = self.node4_assembly[ p4_port3_remote_neighborhood.node_alias ] p4_port3_remote_primary_line = self.pnl0001_assembly.lines[ p4_port3_remote_neighborhood.primary.line_alias ] p4_port3_remote_primary_chamber_alias = ( p4_port3_remote_neighborhood.primary.chamber_alias ) p4_port3_remote_primary_chamber = self.network.components[ p4_port3_remote_primary_chamber_alias ] p4_port3_remote_port3_line = self.pnl0002_assembly.lines[ p4_port3_remote_neighborhood.port_3.line_alias ] p4_port3_far_node_alias = p4_port3_remote_neighborhood.port_3.remote_node_alias p4_port3_far_node = self.node4_assembly[p4_port3_far_node_alias] p4_port3_far_primary = self._p4_primary_connection_for_node( p4_port3_far_node_alias ) p4_port3_far_primary_line = self.pnl0001_assembly.lines[ p4_port3_far_primary.line_alias ] p4_port3_far_primary_chamber_alias = p4_port3_far_primary.chamber_alias p4_port3_far_primary_chamber = self.network.components[ p4_port3_far_primary_chamber_alias ] p4_port3_far_port3 = self._pnl0002_connection_for_node_port( p4_port3_far_node_alias, "port_3", ) p4_port3_far_port3_line = self.pnl0002_assembly.lines[ p4_port3_far_port3.line_alias ] p4_port3_next_node_alias = p4_port3_far_port3.remote_node_alias p4_port3_next_node = self.node4_assembly[p4_port3_next_node_alias] p4_port3_next_primary = self._p4_primary_connection_for_node( p4_port3_next_node_alias ) p4_port3_next_primary_line = self.pnl0001_assembly.lines[ p4_port3_next_primary.line_alias ] p4_port3_next_primary_chamber_alias = p4_port3_next_primary.chamber_alias p4_port3_next_primary_chamber = self.network.components[ p4_port3_next_primary_chamber_alias ] p4_port3_next_port3 = self._pnl0002_connection_for_node_port( p4_port3_next_node_alias, "port_3", ) if p4_port3_next_port3.remote_node_alias != p4_bridge_node_alias: raise ValueError( f"{p4_port3_next_port3.line_alias} does not connect back to " f"{p4_bridge_node_alias}" ) p4_port3_next_port3_line = self.pnl0002_assembly.lines[ p4_port3_next_port3.line_alias ] p4_port3_next_orifice_output_spec = self._pnl0001_spec_for_node_port( p4_port3_next_node_alias, "port_4", ) p4_port3_next_orifice_alias = ( p4_port3_next_orifice_output_spec.source_component if p4_port3_next_orifice_output_spec.target_component == p4_port3_next_node_alias else p4_port3_next_orifice_output_spec.target_component ) p4_port3_next_orifice = self.pneumatic_assembly.variable_orifices[ p4_port3_next_orifice_alias ] ( p4_port3_next_orifice_line, p4_port3_next_orifice_node, ) = pnl0003_line_and_node_for_orifice(p4_port3_next_orifice_alias) p4_port3_next_orifice_output_line = self.pnl0001_assembly.lines[ p4_port3_next_orifice_output_spec.alias ] p4_port3_next_chamber_spec = chamber_segment_for_inlet_node( p4_port3_next_orifice_node.alias ) p4_port3_next_chamber_inlet_line = self.pnl0001_assembly.lines[ p4_port3_next_chamber_spec.inlet_line_alias ] p4_port3_next_chamber = self.network.components[ p4_port3_next_chamber_spec.volume_alias ] p4_port3_next_chamber_outlet_line = self.pnl0001_assembly.lines[ p4_port3_next_chamber_spec.outlet_line_alias ] p4_port3_next_chamber_inlet_orifice = self.pneumatic_assembly.fixed_orifices[ p4_port3_next_chamber_spec.inlet_orifice_alias ] p4_port3_next_chamber_outlet_orifice = self.pneumatic_assembly.fixed_orifices[ p4_port3_next_chamber_spec.outlet_orifice_alias ] p4_port3_next_orifice_resistance = self._pnl00r_line_for_node_port( p4_port3_next_orifice_node.alias, "port_3", ) p4_port3_next_resistance_node = other_node3_for_pnl00r( p4_port3_next_orifice_resistance.name, p4_port3_next_orifice_node.alias, ) p4_port3_next_resistance_node_line_spec = self._pnl0003_spec_for_node_port( p4_port3_next_resistance_node.alias, "port_2", ) p4_port3_next_resistance_node_line = self.pnl0003_assembly.lines[ p4_port3_next_resistance_node_line_spec.alias ] p4_port3_next_resistance_orifice_alias = ( p4_port3_next_resistance_node_line_spec.target_component if p4_port3_next_resistance_node_line_spec.source_component == p4_port3_next_resistance_node.alias else p4_port3_next_resistance_node_line_spec.source_component ) p4_port3_next_resistance_orifice = self.pneumatic_assembly.variable_orifices[ p4_port3_next_resistance_orifice_alias ] p4_port3_next_resistance_output_spec = self._pnl0001_spec_for_node_port( p4_bridge_node_alias, "port_4", ) if ( p4_port3_next_resistance_output_spec.source_component != p4_port3_next_resistance_orifice_alias ): raise ValueError( f"{p4_port3_next_resistance_output_spec.alias} is not fed by " f"{p4_port3_next_resistance_orifice_alias}" ) p4_port3_next_resistance_output_line = self.pnl0001_assembly.lines[ p4_port3_next_resistance_output_spec.alias ] p4_port3_next_resistance_chamber_spec = chamber_segment_for_outlet_node( p4_port3_next_resistance_node.alias ) p4_port3_next_resistance_chamber_inlet_line = self.pnl0001_assembly.lines[ p4_port3_next_resistance_chamber_spec.inlet_line_alias ] p4_port3_next_resistance_chamber = self.network.components[ p4_port3_next_resistance_chamber_spec.volume_alias ] p4_port3_next_resistance_chamber_outlet_line = self.pnl0001_assembly.lines[ p4_port3_next_resistance_chamber_spec.outlet_line_alias ] p4_port3_next_resistance_chamber_inlet_orifice = ( self.pneumatic_assembly.fixed_orifices[ p4_port3_next_resistance_chamber_spec.inlet_orifice_alias ] ) p4_port3_next_resistance_chamber_outlet_orifice = ( self.pneumatic_assembly.fixed_orifices[ p4_port3_next_resistance_chamber_spec.outlet_orifice_alias ] ) p4_port1_next_orifice_node = self.node3_assembly[ p4_port3_next_resistance_chamber_spec.inlet_node_alias ] p4_port1_next_orifice_line_spec = self._pnl0003_spec_for_node_port( p4_port1_next_orifice_node.alias, "port_2", ) p4_port1_next_orifice_line = self.pnl0003_assembly.lines[ p4_port1_next_orifice_line_spec.alias ] p4_port1_next_orifice_alias = ( p4_port1_next_orifice_line_spec.target_component if p4_port1_next_orifice_line_spec.source_component == p4_port1_next_orifice_node.alias else p4_port1_next_orifice_line_spec.source_component ) p4_port1_next_orifice = self.pneumatic_assembly.variable_orifices[ p4_port1_next_orifice_alias ] if ( p4_port1_next_orifice_output_spec.source_component != p4_port1_next_node_alias or p4_port1_next_orifice_output_spec.target_component != p4_port1_next_orifice_alias ): raise ValueError( f"{p4_port1_next_orifice_output_spec.alias} does not connect " f"{p4_port1_next_node_alias}.port_4 to {p4_port1_next_orifice_alias}" ) p4_port1_next_orifice_resistance = self._pnl00r_line_for_node_port( p4_port1_next_orifice_node.alias, "port_3", ) p4_port1_next_orifice_resistance_node = other_node3_for_pnl00r( p4_port1_next_orifice_resistance.name, p4_port1_next_orifice_node.alias, ) p4_port1_next_orifice_resistance_line_spec = self._pnl0003_spec_for_node_port( p4_port1_next_orifice_resistance_node.alias, "port_2", ) p4_port1_next_orifice_resistance_line = self.pnl0003_assembly.lines[ p4_port1_next_orifice_resistance_line_spec.alias ] p4_port1_next_orifice_resistance_orifice_alias = ( p4_port1_next_orifice_resistance_line_spec.target_component if p4_port1_next_orifice_resistance_line_spec.source_component == p4_port1_next_orifice_resistance_node.alias else p4_port1_next_orifice_resistance_line_spec.source_component ) p4_port1_next_orifice_resistance_orifice = ( self.pneumatic_assembly.variable_orifices[ p4_port1_next_orifice_resistance_orifice_alias ] ) p4_port1_far_orifice_direct = self.p4_node_neighborhood( p4_port1_far_node_alias ).port_4 if ( p4_port1_far_orifice_direct.orifice_alias != p4_port1_next_orifice_resistance_orifice_alias ): raise ValueError( f"{p4_port1_far_node_alias}.port_4 does not use " f"{p4_port1_next_orifice_resistance_orifice_alias}" ) p4_port1_next_orifice_resistance_chamber_spec = ( chamber_segment_for_outlet_node( p4_port1_next_orifice_resistance_node.alias ) ) p4_port1_next_orifice_resistance_chamber_inlet_line = ( self.pnl0001_assembly.lines[ p4_port1_next_orifice_resistance_chamber_spec.inlet_line_alias ] ) p4_port1_next_orifice_resistance_chamber = self.network.components[ p4_port1_next_orifice_resistance_chamber_spec.volume_alias ] p4_port1_next_orifice_resistance_chamber_outlet_line = ( self.pnl0001_assembly.lines[ p4_port1_next_orifice_resistance_chamber_spec.outlet_line_alias ] ) p4_port1_next_orifice_resistance_chamber_inlet_orifice = ( self.pneumatic_assembly.fixed_orifices[ p4_port1_next_orifice_resistance_chamber_spec.inlet_orifice_alias ] ) p4_port1_next_orifice_resistance_chamber_outlet_orifice = ( self.pneumatic_assembly.fixed_orifices[ p4_port1_next_orifice_resistance_chamber_spec.outlet_orifice_alias ] ) p4_port3_remote_orifice = self.pneumatic_assembly.variable_orifices[ p4_port3_remote_neighborhood.port_4.orifice_alias ] ( p4_port3_remote_orifice_line, p4_port3_remote_orifice_node, ) = pnl0003_line_and_node_for_orifice( p4_port3_remote_neighborhood.port_4.orifice_alias ) p4_port3_remote_orifice_resistance = self._pnl00r_line_for_node_port( p4_port3_remote_orifice_node.alias, "port_3", ) p4_port3_remote_resistance_node = other_node3_for_pnl00r( p4_port3_remote_orifice_resistance.name, p4_port3_remote_orifice_node.alias, ) p4_port3_remote_resistance_node_line_spec = self._pnl0003_spec_for_node_port( p4_port3_remote_resistance_node.alias, "port_2", ) p4_port3_remote_resistance_node_line = self.pnl0003_assembly.lines[ p4_port3_remote_resistance_node_line_spec.alias ] p4_port3_remote_resistance_orifice_alias = ( p4_port3_remote_resistance_node_line_spec.target_component if p4_port3_remote_resistance_node_line_spec.source_component == p4_port3_remote_resistance_node.alias else p4_port3_remote_resistance_node_line_spec.source_component ) p4_port3_remote_resistance_orifice = self.pneumatic_assembly.variable_orifices[ p4_port3_remote_resistance_orifice_alias ] p4_port3_remote_resistance_output_spec = self._pnl0001_spec_for_node_port( p4_port3_far_node_alias, "port_4", ) if ( p4_port3_remote_resistance_output_spec.source_component != p4_port3_remote_resistance_orifice_alias ): raise ValueError( f"{p4_port3_remote_resistance_output_spec.alias} is not fed by " f"{p4_port3_remote_resistance_orifice_alias}" ) p4_port3_remote_resistance_output_line = self.pnl0001_assembly.lines[ p4_port3_remote_resistance_output_spec.alias ] volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] if not isinstance(volume, AmesimPneumaticVolume): raise TypeError(f"{spec.volume_alias} is not an AMESim pneumatic volume") if not isinstance(p4_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port1_remote_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port1_remote_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port3_remote_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port3_remote_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port1_far_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port1_far_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port3_far_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port3_far_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port1_next_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port1_next_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port3_next_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port3_next_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port3_next_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port3_next_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port3_next_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port3_next_chamber_spec.volume_alias} is not an AMESim pneumatic volume" ) if not isinstance(p4_port3_next_chamber_inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port3_next_chamber_spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port3_next_chamber_outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port3_next_chamber_spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port3_next_resistance_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port3_next_resistance_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port3_next_resistance_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_port3_next_resistance_chamber_spec.volume_alias} is not an AMESim pneumatic volume" ) if not isinstance( p4_port3_next_resistance_chamber_inlet_orifice, AmesimPneumaticOrifice, ): raise TypeError( f"{p4_port3_next_resistance_chamber_spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance( p4_port3_next_resistance_chamber_outlet_orifice, AmesimPneumaticOrifice, ): raise TypeError( f"{p4_port3_next_resistance_chamber_spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port1_next_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port1_next_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance( p4_port1_next_orifice_resistance_orifice, AmesimPneumaticOrifice, ): raise TypeError( f"{p4_port1_next_orifice_resistance_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance( p4_port1_next_orifice_resistance_chamber, AmesimPneumaticVolume, ): raise TypeError( f"{p4_port1_next_orifice_resistance_chamber_spec.volume_alias} is not an AMESim pneumatic volume" ) if not isinstance( p4_port1_next_orifice_resistance_chamber_inlet_orifice, AmesimPneumaticOrifice, ): raise TypeError( f"{p4_port1_next_orifice_resistance_chamber_spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance( p4_port1_next_orifice_resistance_chamber_outlet_orifice, AmesimPneumaticOrifice, ): raise TypeError( f"{p4_port1_next_orifice_resistance_chamber_spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_bridge_primary_chamber, AmesimPneumaticVolume): raise TypeError( f"{p4_bridge_primary_chamber_alias} is not an AMESim pneumatic volume" ) if not isinstance(inlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.inlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(outlet_orifice, AmesimPneumaticOrifice): raise TypeError( f"{spec.outlet_orifice_alias} is not an AMESim pneumatic orifice" ) if not isinstance(p4_port3_remote_resistance_orifice, AmesimPneumaticOrifice): raise TypeError( f"{p4_port3_remote_resistance_orifice_alias} is not an AMESim pneumatic orifice" ) return TestMqlPn3P4NodeChamberSegmentClosure( components=TestMqlPn3P4NodeChamberSegmentComponents( inlet_line=inlet_line, outlet_line=outlet_line, node_line=node_line, node_resistance=node_resistance, node_orifice=node_orifice, node=node, p4_node=p4_node, p4_primary_line=p4_primary_line, p4_primary_chamber=p4_primary_chamber, p4_port1_line=p4_port1_line, p4_port1_remote_node=p4_port1_remote_node, p4_port1_remote_primary_line=p4_port1_remote_primary_line, p4_port1_remote_primary_chamber=p4_port1_remote_primary_chamber, p4_port1_remote_port1_line=p4_port1_remote_port1_line, p4_port1_far_node=p4_port1_far_node, p4_port1_far_primary_line=p4_port1_far_primary_line, p4_port1_far_primary_chamber=p4_port1_far_primary_chamber, p4_port1_far_port1_line=p4_port1_far_port1_line, p4_port1_next_node=p4_port1_next_node, p4_port1_next_primary_line=p4_port1_next_primary_line, p4_port1_next_primary_chamber=p4_port1_next_primary_chamber, p4_port1_next_port1_line=p4_port1_next_port1_line, p4_port1_next_orifice=p4_port1_next_orifice, p4_port1_next_orifice_line=p4_port1_next_orifice_line, p4_port1_next_orifice_node=p4_port1_next_orifice_node, p4_port1_next_orifice_output_line=p4_port1_next_orifice_output_line, p4_port1_next_orifice_resistance=p4_port1_next_orifice_resistance, p4_port1_next_orifice_resistance_node=( p4_port1_next_orifice_resistance_node ), p4_port1_next_orifice_resistance_line=( p4_port1_next_orifice_resistance_line ), p4_port1_next_orifice_resistance_orifice=( p4_port1_next_orifice_resistance_orifice ), p4_port1_next_orifice_resistance_chamber_inlet_line=( p4_port1_next_orifice_resistance_chamber_inlet_line ), p4_port1_next_orifice_resistance_chamber=( p4_port1_next_orifice_resistance_chamber ), p4_port1_next_orifice_resistance_chamber_outlet_line=( p4_port1_next_orifice_resistance_chamber_outlet_line ), p4_port1_next_orifice_resistance_chamber_inlet_orifice=( p4_port1_next_orifice_resistance_chamber_inlet_orifice ), p4_port1_next_orifice_resistance_chamber_outlet_orifice=( p4_port1_next_orifice_resistance_chamber_outlet_orifice ), p4_port1_next_orifice_resistance_chamber_spec=( p4_port1_next_orifice_resistance_chamber_spec ), p4_bridge_node=p4_bridge_node, p4_bridge_primary_line=p4_bridge_primary_line, p4_bridge_primary_chamber=p4_bridge_primary_chamber, p4_port1_remote_orifice=p4_port1_remote_orifice, p4_port1_remote_orifice_line=p4_port1_remote_orifice_line, p4_port1_remote_orifice_node=p4_port1_remote_orifice_node, p4_port3_line=p4_port3_line, p4_port3_remote_node=p4_port3_remote_node, p4_port3_remote_primary_line=p4_port3_remote_primary_line, p4_port3_remote_primary_chamber=p4_port3_remote_primary_chamber, p4_port3_remote_port3_line=p4_port3_remote_port3_line, p4_port3_far_node=p4_port3_far_node, p4_port3_far_primary_line=p4_port3_far_primary_line, p4_port3_far_primary_chamber=p4_port3_far_primary_chamber, p4_port3_far_port3_line=p4_port3_far_port3_line, p4_port3_next_node=p4_port3_next_node, p4_port3_next_primary_line=p4_port3_next_primary_line, p4_port3_next_primary_chamber=p4_port3_next_primary_chamber, p4_port3_next_port3_line=p4_port3_next_port3_line, p4_port3_next_orifice=p4_port3_next_orifice, p4_port3_next_orifice_line=p4_port3_next_orifice_line, p4_port3_next_orifice_node=p4_port3_next_orifice_node, p4_port3_next_orifice_output_line=p4_port3_next_orifice_output_line, p4_port3_next_chamber_inlet_line=p4_port3_next_chamber_inlet_line, p4_port3_next_chamber=p4_port3_next_chamber, p4_port3_next_chamber_outlet_line=p4_port3_next_chamber_outlet_line, p4_port3_next_chamber_inlet_orifice=p4_port3_next_chamber_inlet_orifice, p4_port3_next_chamber_outlet_orifice=p4_port3_next_chamber_outlet_orifice, p4_port3_next_chamber_spec=p4_port3_next_chamber_spec, p4_port3_next_orifice_resistance=p4_port3_next_orifice_resistance, p4_port3_next_resistance_node=p4_port3_next_resistance_node, p4_port3_next_resistance_node_line=p4_port3_next_resistance_node_line, p4_port3_next_resistance_orifice=p4_port3_next_resistance_orifice, p4_port3_next_resistance_output_line=p4_port3_next_resistance_output_line, p4_port3_next_resistance_chamber_inlet_line=( p4_port3_next_resistance_chamber_inlet_line ), p4_port3_next_resistance_chamber=p4_port3_next_resistance_chamber, p4_port3_next_resistance_chamber_outlet_line=( p4_port3_next_resistance_chamber_outlet_line ), p4_port3_next_resistance_chamber_inlet_orifice=( p4_port3_next_resistance_chamber_inlet_orifice ), p4_port3_next_resistance_chamber_outlet_orifice=( p4_port3_next_resistance_chamber_outlet_orifice ), p4_port3_next_resistance_chamber_spec=( p4_port3_next_resistance_chamber_spec ), p4_port3_remote_orifice=p4_port3_remote_orifice, p4_port3_remote_orifice_line=p4_port3_remote_orifice_line, p4_port3_remote_orifice_node=p4_port3_remote_orifice_node, p4_port3_remote_orifice_resistance=p4_port3_remote_orifice_resistance, p4_port3_remote_resistance_node=p4_port3_remote_resistance_node, p4_port3_remote_resistance_node_line=( p4_port3_remote_resistance_node_line ), p4_port3_remote_resistance_orifice=( p4_port3_remote_resistance_orifice ), p4_port3_remote_resistance_output_line=( p4_port3_remote_resistance_output_line ), volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, spec=spec, ), inlet_node=TestMqlPneumaticBoundaryCondition( pressure_pa=inlet_node_pressure_pa, temperature_k=inlet_node_temperature_k, ), resistance_boundary=TestMqlPneumaticBoundaryCondition( pressure_pa=resistance_boundary_pressure_pa, temperature_k=resistance_boundary_temperature_k, ), use_inlet_line_reference_rhs=use_inlet_line_reference_rhs, ) def simulate_pn3_p4_node_chamber_segment_from_spec( self, spec, *, inlet_node_pressure_pa: float, resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.pn3_p4_node_chamber_segment_closure_from_spec( spec, inlet_node_pressure_pa=inlet_node_pressure_pa, resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def pneumatic_branch_closure_from_spec(self, spec): return self.pneumatic_branch_closure( name=spec.name, upstream_volume_alias=spec.upstream_volume_alias, orifice_alias=spec.orifice_alias, downstream_volume_alias=spec.downstream_volume_alias, spec=spec, ) def pneumatic_branch_closure( self, *, name: str, upstream_volume_alias: str, orifice_alias: str, downstream_volume_alias: str, spec=None, ): from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.systems.test_mql_closure import ( TestMqlPneumaticBranchComponents, TestMqlPneumaticBranchSpec, TestMqlPneumaticClosure, ) upstream_volume = self.network.components[upstream_volume_alias] orifice = self.network.components[orifice_alias] downstream_volume = self.network.components[downstream_volume_alias] if not isinstance(upstream_volume, AmesimPneumaticVolume): raise TypeError(f"{upstream_volume_alias} is not an AMESim pneumatic volume") if not isinstance(downstream_volume, AmesimPneumaticVolume): raise TypeError(f"{downstream_volume_alias} is not an AMESim pneumatic volume") if not isinstance(orifice, AmesimPneumaticOrifice): raise TypeError(f"{orifice_alias} is not an AMESim pneumatic orifice") def initial_state_vector() -> list[float]: return [ *upstream_volume.get_state_vector(), *downstream_volume.get_state_vector(), ] def apply_state_vector(values: list[float]) -> None: if len(values) != 4: raise ValueError("two-volume pneumatic branch state vector requires four values") upstream_volume.set_state_vector(values[:2]) downstream_volume.set_state_vector(values[2:]) branch_spec = spec or TestMqlPneumaticBranchSpec( name=name, upstream_volume_alias=upstream_volume_alias, orifice_alias=orifice_alias, downstream_volume_alias=downstream_volume_alias, ) return TestMqlPneumaticClosure( components=TestMqlPneumaticBranchComponents( name=name, upstream_volume=upstream_volume, orifice=orifice, downstream_volume=downstream_volume, spec=branch_spec, ), initial_state_vector=initial_state_vector, apply_state_vector=apply_state_vector, ) def simulate_pneumatic_branch( self, *, name: str, upstream_volume_alias: str, orifice_alias: str, downstream_volume_alias: str, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): closure = self.pneumatic_branch_closure( name=name, upstream_volume_alias=upstream_volume_alias, orifice_alias=orifice_alias, downstream_volume_alias=downstream_volume_alias, ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( rhs=lambda t, state: closure.rhs(state), initial_state=closure.initial_state_vector(), config=run_config, t_eval=t_eval, ) def simulate_pneumatic_branch_from_spec( self, spec, *, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): return self.simulate_pneumatic_branch( name=spec.name, upstream_volume_alias=spec.upstream_volume_alias, orifice_alias=spec.orifice_alias, downstream_volume_alias=spec.downstream_volume_alias, config=config, t_eval=t_eval, ) def evaluate_pneumatic_branch_solution_from_spec( self, solution: object, spec, ) -> dict[str, list[float]]: return self.evaluate_pneumatic_branch_solution( solution, name=spec.name, upstream_volume_alias=spec.upstream_volume_alias, orifice_alias=spec.orifice_alias, downstream_volume_alias=spec.downstream_volume_alias, ) def evaluate_pneumatic_branch_solution( self, solution: object, *, name: str, upstream_volume_alias: str, orifice_alias: str, downstream_volume_alias: str, ) -> dict[str, list[float]]: closure = self.pneumatic_branch_closure( name=name, upstream_volume_alias=upstream_volume_alias, orifice_alias=orifice_alias, downstream_volume_alias=downstream_volume_alias, ) series = { "time": [], f"{name}.flow": [], f"{upstream_volume_alias}.p": [], f"{upstream_volume_alias}.T": [], f"{upstream_volume_alias}.m_flow": [], f"{downstream_volume_alias}.p": [], f"{downstream_volume_alias}.T": [], f"{downstream_volume_alias}.m_flow": [], } for index, time_value in enumerate(solution.t): state_vector = [row[index] for row in solution.y] snapshot = closure.snapshot(state_vector) series["time"].append(float(time_value)) series[f"{name}.flow"].append(snapshot.flow) series[f"{upstream_volume_alias}.p"].append(snapshot.upstream.p) series[f"{upstream_volume_alias}.T"].append(snapshot.upstream.T) series[f"{upstream_volume_alias}.m_flow"].append( closure.components.upstream_volume.port_a.m_flow ) series[f"{downstream_volume_alias}.p"].append(snapshot.downstream.p) series[f"{downstream_volume_alias}.T"].append(snapshot.downstream.T) series[f"{downstream_volume_alias}.m_flow"].append( closure.components.downstream_volume.port_a.m_flow ) return series def snapshot(self) -> TestMqlSnapshot: return TestMqlSnapshot( model_name=MODEL_NAME, component_count=len(COMPONENT_SPECS), connection_count=len(CONNECTION_SPECS), continuous_state_count=int(MODEL_INFO.get("num_states", 0)), discrete_state_count=int(MODEL_INFO.get("num_discrete_states", 0)), global_parameters=dict(GLOBAL_PARAMETERS), submodel_counts=dict(SUBMODEL_COUNTS), ) def initial_state_vector(self) -> list[float]: return [0.0] * int(MODEL_INFO.get("num_states", 0)) def simulate(self, config: TestMqlRunConfig | None = None) -> TestMqlSimulationResult: run_config = config or TestMqlRunConfig() times = run_config.sample_times() state_count = int(MODEL_INFO.get("num_states", 0)) y = [[0.0 for _ in times] for _ in range(state_count)] series = self.evaluate_solution(SimpleNamespace(t=times, y=y)) return TestMqlSimulationResult(t=times, y=y, series=series) def evaluate_solution(self, solution: object) -> dict[str, list[float]]: times = [float(value) for value in solution.t] return { "time": times, "component_count": [float(len(COMPONENT_SPECS)) for _ in times], "connection_count": [float(len(CONNECTION_SPECS)) for _ in times], "continuous_state_count": [float(MODEL_INFO.get("num_states", 0)) for _ in times], "discrete_state_count": [float(MODEL_INFO.get("num_discrete_states", 0)) for _ in times], } def component_specs_by_submodel(self) -> dict[str, list[dict[str, object]]]: grouped: dict[str, list[dict[str, object]]] = {} for spec in COMPONENT_SPECS: grouped.setdefault(str(spec["submodel"]), []).append(spec) return grouped def connection_specs_by_submodel(self) -> dict[str, list[dict[str, object]]]: grouped: dict[str, list[dict[str, object]]] = {} for spec in CONNECTION_SPECS: grouped.setdefault(str(spec["submodel"]), []).append(spec) return grouped def build_test_mql() -> SimulationNetwork: return TestMqlSystem().network