diff --git a/example_graphs/stick_slip.json b/example_graphs/stick_slip.json new file mode 100644 index 0000000..b833ee8 --- /dev/null +++ b/example_graphs/stick_slip.json @@ -0,0 +1,585 @@ +{ + "version": { + "pathsim_version": "0.8.2", + "pathview_version": "0.1.dev470+g017515800.d20250812" + }, + "nodes": [ + { + "id": "4", + "type": "switch", + "position": { + "x": 287.58553688651915, + "y": 295.276810064864 + }, + "data": { + "label": "switch", + "nodeColor": "#DDE6ED", + "state": "1" + }, + "measured": { + "width": 200, + "height": 48 + }, + "selected": false, + "dragging": false + }, + { + "id": "5", + "type": "integrator", + "position": { + "x": 606.8593557699816, + "y": 345.51545415024714 + }, + "data": { + "label": "integrator 2", + "nodeColor": "#DDE6ED", + "initial_value": "", + "reset_times": "" + }, + "measured": { + "width": 200, + "height": 48 + }, + "selected": false, + "dragging": false + }, + { + "id": "6", + "type": "amplifier_reverse", + "position": { + "x": 352.6666717529297, + "y": 410.6666660308838 + }, + "data": { + "label": "amp 1", + "nodeColor": "#DDE6ED", + "gain": "-d" + }, + "measured": { + "width": 90, + "height": 80 + }, + "selected": false + }, + { + "id": "7", + "type": "amplifier_reverse", + "position": { + "x": 519.9064229187702, + "y": 477.3246406593927 + }, + "data": { + "label": "amp 2", + "nodeColor": "#DDE6ED", + "gain": "-k" + }, + "measured": { + "width": 90, + "height": 80 + }, + "selected": false, + "dragging": false + }, + { + "id": "8", + "type": "adder", + "position": { + "x": -244.1463565072987, + "y": 380.748898887575 + }, + "data": { + "label": "add", + "nodeColor": "#DDE6ED", + "operations": "" + }, + "measured": { + "width": 64, + "height": 64 + }, + "selected": false, + "dragging": false + }, + { + "id": "9", + "type": "amplifier", + "position": { + "x": -126.87085819778244, + "y": 388.65952949607794 + }, + "data": { + "label": "amp 3", + "nodeColor": "#DDE6ED", + "gain": "1/m" + }, + "measured": { + "width": 90, + "height": 80 + }, + "selected": false, + "dragging": false + }, + { + "id": "10", + "type": "integrator", + "position": { + "x": 36.22081843250754, + "y": 388.0656128814263 + }, + "data": { + "label": "integrator 1", + "nodeColor": "#DDE6ED", + "initial_value": "v0", + "reset_times": "" + }, + "measured": { + "width": 200, + "height": 48 + }, + "selected": false, + "dragging": false + }, + { + "id": "11", + "type": "function", + "position": { + "x": -54.52837524178651, + "y": 186.62617481093713 + }, + "data": { + "label": "Function", + "nodeColor": "#DDE6ED", + "inputCount": "2", + "outputCount": 1, + "func": "f_coulomb" + }, + "measured": { + "width": 200, + "height": 100 + }, + "selected": false, + "dragging": false + }, + { + "id": "12", + "type": "source", + "position": { + "x": -257.2259405285811, + "y": 57.613473116620824 + }, + "data": { + "label": "source", + "nodeColor": "#DDE6ED", + "func": "v_belt" + }, + "measured": { + "width": 206, + "height": 54 + }, + "selected": false, + "dragging": false + }, + { + "id": "18", + "type": "scope", + "position": { + "x": 195.9877730435556, + "y": -66.655183047029 + }, + "data": { + "label": "scope 18", + "nodeColor": "#DDE6ED", + "labels": "", + "sampling_rate": "", + "t_wait": "" + }, + "measured": { + "width": 120, + "height": 140 + }, + "selected": false, + "dragging": false + }, + { + "id": "19", + "type": "scope", + "position": { + "x": 763.7772276046377, + "y": 100.40917312631821 + }, + "data": { + "label": "scope 19", + "nodeColor": "#DDE6ED", + "labels": "", + "sampling_rate": "", + "t_wait": "" + }, + "measured": { + "width": 120, + "height": 140 + }, + "selected": false, + "dragging": false + } + ], + "edges": [ + { + "id": "e5-7", + "source": "5", + "target": "7", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e6-8", + "source": "6", + "target": "8", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e7-8", + "source": "7", + "target": "8", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e8-9", + "source": "8", + "target": "9", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e9-10", + "source": "9", + "target": "10", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e11-8-from_source-0", + "source": "11", + "target": "8", + "sourceHandle": "source-0", + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + }, + "selected": false + }, + { + "id": "e11-18-from_source-0", + "source": "11", + "target": "18", + "sourceHandle": "source-0", + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + }, + "selected": false + }, + { + "id": "e8-18", + "source": "8", + "target": "18", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + }, + "selected": false + }, + { + "id": "e5-19", + "source": "5", + "target": "19", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e12-19", + "source": "12", + "target": "19", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + }, + "selected": false + }, + { + "id": "e10-4-to_target-0", + "source": "10", + "target": "4", + "sourceHandle": null, + "targetHandle": "target-0", + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e12-4-to_target-1", + "source": "12", + "target": "4", + "sourceHandle": null, + "targetHandle": "target-1", + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e4-5", + "source": "4", + "target": "5", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e4-6", + "source": "4", + "target": "6", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e4-19", + "source": "4", + "target": "19", + "sourceHandle": null, + "targetHandle": null, + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e4-11-to_target-0", + "source": "4", + "target": "11", + "sourceHandle": null, + "targetHandle": "target-0", + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + }, + { + "id": "e12-11-to_target-1", + "source": "12", + "target": "11", + "sourceHandle": null, + "targetHandle": "target-1", + "type": "smoothstep", + "data": {}, + "style": { + "strokeWidth": 2, + "stroke": "#ECDFCC" + }, + "markerEnd": { + "type": "arrowclosed", + "width": 20, + "height": 20, + "color": "#ECDFCC" + } + } + ], + "nodeCounter": 20, + "solverParams": { + "dt": "0.01", + "dt_min": "1e-16", + "dt_max": "0.1", + "Solver": "RKBS32", + "tolerance_fpi": "1e-10", + "iterations_max": "200", + "log": "true", + "simulation_duration": "100", + "extra_params": "{\"tolerance_lte_abs\":1e-6, \"tolerance_lte_rel\":1e-4}" + }, + "globalVariables": [], + "events": [ + { + "name": "E_slip_to_stick", + "type": "ZeroCrossing", + "func_evt": "slip_to_stick_evt", + "func_act": "slip_to_stick_act", + "tolerance": "1e-3", + "id": 1755090589822 + }, + { + "name": "E_stick_to_slip", + "type": "ZeroCrossing", + "func_evt": "stick_to_slip_evt", + "func_act": "stick_to_slip_act", + "tolerance": "1e-3", + "id": 1755090603806 + } + ], + "pythonCode": "import numpy as np\n#initial position and velocity\nx0, v0 = 0, 0\n\n#system parameters\nm = 20.0 # mass\nk = 70.0 # spring constant\nd = 10.0 # spring damping\nmu = 1.5 # friction coefficient\ng = 9.81 # gravity\nv = 3.0 # belt velocity magnitude\nT = 50.0 # excitation period\n\nF_c = mu * m * g # friction force\n\n#function for belt velocity\ndef v_belt(t):\n return v * np.sin(2*np.pi*t/T)\n\n#function for coulomb friction force\ndef f_coulomb(v, vb):\n return F_c * np.sign(vb - v)\n\ndef slip_to_stick_evt(t):\n _1, v_box , _2 = switch_4()\n _1, v_belt, _2 = source_12()\n dv = v_box - v_belt\n\n return dv\n\ndef slip_to_stick_act(t):\n\n #change switch state\n switch_4.state = 1\n\n integrator_1_10.off()\n function_11.off()\n\n E_slip_to_stick.off()\n E_stick_to_slip.on()\n\ndef stick_to_slip_evt(t):\n _1, F, _2 = add_8()\n return F_c - abs(F)\n\ndef stick_to_slip_act(t):\n\n #change switch state\n switch_4.state = 0\n\n integrator_1_10.on()\n function_11.on()\n\n #set integrator state\n _1, v_box , _2 = switch_4()\n integrator_1_10.engine.set(v_box)\n\n E_slip_to_stick.on()\n E_stick_to_slip.off()\n" +} \ No newline at end of file diff --git a/src/components/EventsTab.jsx b/src/components/EventsTab.jsx index 6405461..fb1cb1a 100644 --- a/src/components/EventsTab.jsx +++ b/src/components/EventsTab.jsx @@ -46,7 +46,7 @@ const EventsTab = ({ events, setEvents }) => { ...eventDefaults[initialEventType] }; }); - + // State to track if we're editing an existing event const [editingEventId, setEditingEventId] = useState(null); @@ -79,13 +79,13 @@ const EventsTab = ({ events, setEvents }) => { const addEvent = () => { if (currentEvent.name) { // Validate required fields based on event type - + // For Schedule, func_act is required if (['Schedule', 'ScheduleList'].includes(currentEvent.type) && !currentEvent.func_act) { alert('func_act is required for Schedule events'); return; } - + // For other event types, both func_evt and func_act are typically required if (!['Schedule', 'ScheduleList'].includes(currentEvent.type) && (!currentEvent.func_evt || !currentEvent.func_act)) { alert('Both func_evt and func_act are required for this event type'); @@ -93,7 +93,7 @@ const EventsTab = ({ events, setEvents }) => { } setEvents(prev => [...prev, { ...currentEvent, id: Date.now() }]); - + // Reset to defaults for current type const resetDefaults = eventDefaults[currentEvent.type] || {}; setCurrentEvent({ @@ -111,23 +111,23 @@ const EventsTab = ({ events, setEvents }) => { const saveEditedEvent = () => { if (currentEvent.name) { - + // For Schedule, func_act is required if (currentEvent.type === 'Schedule' && !currentEvent.func_act) { alert('func_act is required for Schedule events'); return; } - + // For other event types, both func_evt and func_act are typically required if (currentEvent.type !== 'Schedule' && (!currentEvent.func_evt || !currentEvent.func_act)) { alert('Both func_evt and func_act are required for this event type'); return; } - setEvents(prev => prev.map(event => + setEvents(prev => prev.map(event => event.id === editingEventId ? { ...currentEvent } : event )); - + // Reset form and exit edit mode cancelEdit(); } @@ -179,7 +179,7 @@ const EventsTab = ({ events, setEvents }) => {

{editingEventId ? 'Edit Event' : 'Add New Event'}

- +
-