diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1dd19e1..430d280 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,9 @@ jobs: HDF5_DISABLE_VERSION_CHECK: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -35,7 +35,7 @@ jobs: pip install . pip install -r requirements-extra.txt - pip install 'numpy<=1.23.0' # temp fix, see https://github.com/OpenSourceBrain/osb-model-validation/issues/91 + #pip install 'numpy<=1.23.0' # temp fix, see https://github.com/OpenSourceBrain/osb-model-validation/issues/91 - name: Lint with flake8 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 0fe16bc..85cc411 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -18,9 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies diff --git a/docs/NeuroMLlite_specification.json b/docs/NeuroMLlite_specification.json index 48f192e..38c364a 100644 --- a/docs/NeuroMLlite_specification.json +++ b/docs/NeuroMLlite_specification.json @@ -1,5 +1,5 @@ { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "specification": { "Network": { "definition": "A Network containing multiple Population's, connected by Projection's and receiving Input's", diff --git a/docs/NeuroMLlite_specification.yaml b/docs/NeuroMLlite_specification.yaml index c05d843..99551d5 100644 --- a/docs/NeuroMLlite_specification.yaml +++ b/docs/NeuroMLlite_specification.yaml @@ -1,4 +1,4 @@ -version: NeuroMLlite v0.5.7 +version: NeuroMLlite v0.6.0 specification: Network: definition: A Network containing multiple Population's, connected by Projection's diff --git a/docs/README.md b/docs/README.md index 1833050..53835d8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Specification of NeuroMLlite v0.5.7 +# Specification of NeuroMLlite v0.6.0 **Note: the NeuroMLlite specification is still in development! Subject to change...** ## Network diff --git a/examples/Example10_Lorenz.json b/examples/Example10_Lorenz.json index 5380a74..e37bf0f 100644 --- a/examples/Example10_Lorenz.json +++ b/examples/Example10_Lorenz.json @@ -1,6 +1,6 @@ { "Example10_Lorenz": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 10: Lorenz", "parameters": { "N": 1, diff --git a/examples/Example11_Synapses.json b/examples/Example11_Synapses.json index e8a3ace..5dc63dd 100644 --- a/examples/Example11_Synapses.json +++ b/examples/Example11_Synapses.json @@ -1,6 +1,6 @@ { "Example11_Synapses": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 11: synaptic properties", "parameters": { "input_amp": 0.23, diff --git a/examples/Example11_Synapses.net.nml b/examples/Example11_Synapses.net.nml index 34f2db2..ff42b29 100644 --- a/examples/Example11_Synapses.net.nml +++ b/examples/Example11_Synapses.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example11_Synapses Generation seed: 1234 NeuroMLlite parameters: diff --git a/examples/Example12_MultiComp.json b/examples/Example12_MultiComp.json index 899d352..61e8b13 100644 --- a/examples/Example12_MultiComp.json +++ b/examples/Example12_MultiComp.json @@ -1,6 +1,6 @@ { "Example12_MultiComp": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 12: Multicompartmental cells...", "parameters": { "N": 20, diff --git a/examples/Example1_TestNetwork.json b/examples/Example1_TestNetwork.json index 76a405a..ed1df17 100644 --- a/examples/Example1_TestNetwork.json +++ b/examples/Example1_TestNetwork.json @@ -1,6 +1,6 @@ { "TestNetwork": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "A simple network with 2 populations & projection between them. No info yet on what the cells are so network can't be simulated.", "populations": { "pop0": { diff --git a/examples/Example2_TestNetwork.json b/examples/Example2_TestNetwork.json index 42e386d..c3f0dd4 100644 --- a/examples/Example2_TestNetwork.json +++ b/examples/Example2_TestNetwork.json @@ -1,6 +1,6 @@ { "Example2_TestNetwork": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "A simple network with 2 populations & projection between them. Cells are specified to be NeuroML 2 HH cell models & pre population is given a spiking input.", "cells": { "hhcell": { diff --git a/examples/Example2_TestNetwork.net.nml b/examples/Example2_TestNetwork.net.nml index e1de4e8..0f91bb5 100644 --- a/examples/Example2_TestNetwork.net.nml +++ b/examples/Example2_TestNetwork.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example2_TestNetwork Generation seed: 1234 diff --git a/examples/Example3_Network.json b/examples/Example3_Network.json index a323ac5..c3bf5c8 100644 --- a/examples/Example3_Network.json +++ b/examples/Example3_Network.json @@ -1,6 +1,6 @@ { "Example3_Network": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 3: simple network with 2 populations of NeuroML2 cells, a projection between them and spiking input.", "cells": { "hhcell": { diff --git a/examples/Example3_Network.net.nml b/examples/Example3_Network.net.nml index 8993003..2036d74 100644 --- a/examples/Example3_Network.net.nml +++ b/examples/Example3_Network.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example3_Network Generation seed: 1234 diff --git a/examples/Example4.py b/examples/Example4.py index d579f83..fcf3d10 100644 --- a/examples/Example4.py +++ b/examples/Example4.py @@ -109,6 +109,7 @@ print(net.to_json()) net_json_file = net.to_json_file("%s.json" % net.id) net_yaml_file = net.to_yaml_file("%s.yaml" % net.id) +net_xml_file = net.to_xml_file("%s.nmllite.xml" % net.id) ################################################################################ diff --git a/examples/Example4_PyNN.json b/examples/Example4_PyNN.json index 69ae655..cf1a9ed 100644 --- a/examples/Example4_PyNN.json +++ b/examples/Example4_PyNN.json @@ -1,6 +1,6 @@ { "Example4_PyNN": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 4: a network with PyNN cells & inputs", "parameters": { "input_amp": 0.99 diff --git a/examples/Example4_PyNN.net.nml b/examples/Example4_PyNN.net.nml index 20d156f..bf46562 100644 --- a/examples/Example4_PyNN.net.nml +++ b/examples/Example4_PyNN.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example4_PyNN Generation seed: 1234 NeuroMLlite parameters: diff --git a/examples/Example4_PyNN.yaml b/examples/Example4_PyNN.yaml index b9895fb..fb7365a 100644 --- a/examples/Example4_PyNN.yaml +++ b/examples/Example4_PyNN.yaml @@ -1,5 +1,5 @@ Example4_PyNN: - version: NeuroMLlite v0.5.7 + version: NeuroMLlite v0.6.0 notes: 'Example 4: a network with PyNN cells & inputs' parameters: input_amp: 0.99 diff --git a/examples/Example6_PyNN.json b/examples/Example6_PyNN.json index 90719f4..32c91c8 100644 --- a/examples/Example6_PyNN.json +++ b/examples/Example6_PyNN.json @@ -1,6 +1,6 @@ { "Example6_PyNN": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Another network for PyNN - work in progress...", "parameters": { "N_scaling": 0.005, diff --git a/examples/Example6_PyNN.net.nml b/examples/Example6_PyNN.net.nml index 4fe9d45..77bbcd1 100644 --- a/examples/Example6_PyNN.net.nml +++ b/examples/Example6_PyNN.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example6_PyNN Generation seed: 1234 NeuroMLlite parameters: diff --git a/examples/Example6_PyNN_noinputs.json b/examples/Example6_PyNN_noinputs.json index a141bf4..bdce92b 100644 --- a/examples/Example6_PyNN_noinputs.json +++ b/examples/Example6_PyNN_noinputs.json @@ -1,6 +1,6 @@ { "Example6_PyNN_noinputs": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Another network for PyNN - work in progress...", "parameters": { "N_scaling": 0.005, diff --git a/examples/Example6_PyNN_noinputs.net.nml b/examples/Example6_PyNN_noinputs.net.nml index acc00d0..c192244 100644 --- a/examples/Example6_PyNN_noinputs.net.nml +++ b/examples/Example6_PyNN_noinputs.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example6_PyNN_noinputs Generation seed: 1234 NeuroMLlite parameters: diff --git a/examples/Example7_Brunel2000.json b/examples/Example7_Brunel2000.json index 1876d95..4dbb9ab 100644 --- a/examples/Example7_Brunel2000.json +++ b/examples/Example7_Brunel2000.json @@ -1,6 +1,6 @@ { "Example7_Brunel2000": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 7: based on network of Brunel 2000", "parameters": { "g": 4, diff --git a/examples/Example7_Brunel2000.net.nml b/examples/Example7_Brunel2000.net.nml index 767a913..5b191f8 100644 --- a/examples/Example7_Brunel2000.net.nml +++ b/examples/Example7_Brunel2000.net.nml @@ -1,5 +1,5 @@ - - Generated by NeuroMLlite v0.5.7 + + Generated by NeuroMLlite v0.6.0 Generated network: Example7_Brunel2000 Generation seed: 1234 NeuroMLlite parameters: diff --git a/examples/Example8_Extension.json b/examples/Example8_Extension.json index ca00411..77ac1f1 100644 --- a/examples/Example8_Extension.json +++ b/examples/Example8_Extension.json @@ -1,6 +1,6 @@ { "Example8_Extension": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 8: general testing...", "parameters": { "N": 10, diff --git a/examples/Example9_HindmarshRose.json b/examples/Example9_HindmarshRose.json index 7792ec6..83f4fb8 100644 --- a/examples/Example9_HindmarshRose.json +++ b/examples/Example9_HindmarshRose.json @@ -1,6 +1,6 @@ { "Example9_HindmarshRose": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example 9: HindmarshRose", "parameters": { "N": 1, diff --git a/examples/LEMS_SimExample3.xml b/examples/LEMS_SimExample3.xml index c683160..e270493 100644 --- a/examples/LEMS_SimExample3.xml +++ b/examples/LEMS_SimExample3.xml @@ -1,11 +1,11 @@ - + - + @@ -13,14 +13,13 @@ - + - + - @@ -28,7 +27,7 @@ - + @@ -41,28 +40,28 @@ - + - - - - - + + + + + - + - - - - - - - - - - + + + + + + + + + + - + diff --git a/examples/LEMS_SimExample4.xml b/examples/LEMS_SimExample4.xml index 449619e..b9eed34 100644 --- a/examples/LEMS_SimExample4.xml +++ b/examples/LEMS_SimExample4.xml @@ -1,11 +1,11 @@ - + - + @@ -13,45 +13,44 @@ - + - + - - + - + - + - - + + - + - - + + - + - + - + - - + + - + diff --git a/examples/SimExample10.json b/examples/SimExample10.json index 3326ea9..1ffd155 100644 --- a/examples/SimExample10.json +++ b/examples/SimExample10.json @@ -1,6 +1,6 @@ { "SimExample10": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example10_Lorenz.json", "duration": 10000.0, "dt": 1.0, diff --git a/examples/SimExample11.json b/examples/SimExample11.json index e816096..b712dfa 100644 --- a/examples/SimExample11.json +++ b/examples/SimExample11.json @@ -1,6 +1,6 @@ { "SimExample11": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example11_Synapses.json", "duration": 1000.0, "dt": 0.01, diff --git a/examples/SimExample12_MultiComp.json b/examples/SimExample12_MultiComp.json index 7833778..ee3f824 100644 --- a/examples/SimExample12_MultiComp.json +++ b/examples/SimExample12_MultiComp.json @@ -1,6 +1,6 @@ { "SimExample12_MultiComp": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example12_MultiComp.json", "duration": 1000.0, "dt": 0.025, diff --git a/examples/SimExample3.json b/examples/SimExample3.json index 30e11d9..80f1e01 100644 --- a/examples/SimExample3.json +++ b/examples/SimExample3.json @@ -1,6 +1,6 @@ { "SimExample3": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example3_Network.json", "duration": 1000.0, "dt": 0.025, diff --git a/examples/SimExample4.json b/examples/SimExample4.json index 309083d..4da66d4 100644 --- a/examples/SimExample4.json +++ b/examples/SimExample4.json @@ -1,6 +1,6 @@ { "SimExample4": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example4_PyNN.json", "duration": 1000.0, "dt": 0.01, diff --git a/examples/SimExample4.yaml b/examples/SimExample4.yaml index 875fcf9..a7b58d4 100644 --- a/examples/SimExample4.yaml +++ b/examples/SimExample4.yaml @@ -1,5 +1,5 @@ SimExample4: - version: NeuroMLlite v0.5.7 + version: NeuroMLlite v0.6.0 network: Example4_PyNN.yaml duration: 1000.0 dt: 0.01 diff --git a/examples/SimExample6_PyNN.json b/examples/SimExample6_PyNN.json index a0686d6..5a6b13d 100644 --- a/examples/SimExample6_PyNN.json +++ b/examples/SimExample6_PyNN.json @@ -1,6 +1,6 @@ { "SimExample6_PyNN": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example6_PyNN.json", "duration": 100.0, "dt": 0.025, diff --git a/examples/SimExample7.json b/examples/SimExample7.json index b827ae4..5ffb1d7 100644 --- a/examples/SimExample7.json +++ b/examples/SimExample7.json @@ -1,6 +1,6 @@ { "SimExample7": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example7_Brunel2000.json", "duration": 1000.0, "dt": 0.025, diff --git a/examples/SimExample8.json b/examples/SimExample8.json index e7924ab..5a5bc4f 100644 --- a/examples/SimExample8.json +++ b/examples/SimExample8.json @@ -1,6 +1,6 @@ { "SimExample8": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example8_Extension.json", "duration": 1000.0, "dt": 0.025, diff --git a/examples/SimExample9.json b/examples/SimExample9.json index 31eefa7..7ca7a77 100644 --- a/examples/SimExample9.json +++ b/examples/SimExample9.json @@ -1,6 +1,6 @@ { "SimExample9": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Example9_HindmarshRose.json", "duration": 1000000.0, "dt": 25.0, diff --git a/examples/arbor/ArborExample.json b/examples/arbor/ArborExample.json index 3b7acec..05edac6 100644 --- a/examples/arbor/ArborExample.json +++ b/examples/arbor/ArborExample.json @@ -1,6 +1,6 @@ { "ArborExample": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example for testing Arbor", "parameters": { "v_init": -50, diff --git a/examples/arbor/ArborExample.yaml b/examples/arbor/ArborExample.yaml index f3d8586..acb1fd7 100644 --- a/examples/arbor/ArborExample.yaml +++ b/examples/arbor/ArborExample.yaml @@ -1,5 +1,5 @@ ArborExample: - version: NeuroMLlite v0.5.7 + version: NeuroMLlite v0.6.0 notes: Example for testing Arbor parameters: v_init: -50 diff --git a/examples/arbor/SimArborExample.json b/examples/arbor/SimArborExample.json index ca27e3b..4696fc0 100644 --- a/examples/arbor/SimArborExample.json +++ b/examples/arbor/SimArborExample.json @@ -1,6 +1,6 @@ { "SimArborExample": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "ArborExample.json", "duration": 100.0, "dt": 0.01, diff --git a/examples/arbor/SimArborExample.yaml b/examples/arbor/SimArborExample.yaml index 6951a5b..ee2739c 100644 --- a/examples/arbor/SimArborExample.yaml +++ b/examples/arbor/SimArborExample.yaml @@ -1,5 +1,5 @@ SimArborExample: - version: NeuroMLlite v0.5.7 + version: NeuroMLlite v0.6.0 network: ArborExample.yaml duration: 100.0 dt: 0.01 diff --git a/examples/sonatatest/SimSonataExample.json b/examples/sonatatest/SimSonataExample.json index ecac3c6..22f6329 100644 --- a/examples/sonatatest/SimSonataExample.json +++ b/examples/sonatatest/SimSonataExample.json @@ -1,13 +1,13 @@ { "SimSonataExample": { - "version": "NeuroMLlite v0.1.9", - "network": "SonataExample.json", - "duration": 1000.0, - "dt": 0.01, - "recordTraces": { + "version": "NeuroMLlite v0.6.0", + "network": "SonataExample.json", + "duration": 1000.0, + "dt": 0.01, + "record_traces": { "all": "*" - }, - "recordSpikes": { + }, + "record_spikes": { "pop0": "*" } } diff --git a/examples/sonatatest/SonataExample.json b/examples/sonatatest/SonataExample.json index fdffef3..dae6d58 100644 --- a/examples/sonatatest/SonataExample.json +++ b/examples/sonatatest/SonataExample.json @@ -1,74 +1,64 @@ { "SonataExample": { - "version": "NeuroMLlite v0.1.9", + "version": "NeuroMLlite v0.6.0", + "notes": "Example for testing Sonata", "parameters": { - "input_del": 100, - "input_dur": 800, - "input_amp": 0.19 - }, - "notes": "Example for testing Sonata", - "cells": [ - { - "testcell": { - "pynn_cell": "IF_cond_alpha", - "parameters": { - "tau_refrac": 3, - "tau_m": 22.1, - "i_offset": 0, - "cm": 0.117, - "v_thresh": -47, - "v_rest": -78, - "v_reset": -50 - } - } + "input_amp": 0.19, + "input_del": 100, + "input_dur": 800 + }, + "cells": { + "testcell": { + "parameters": { + "i_offset": 0, + "cm": 0.117, + "tau_m": 22.1, + "tau_refrac": 3, + "v_reset": -50, + "v_rest": -78, + "v_thresh": -47 + }, + "pynn_cell": "IF_cond_alpha" } - ], - "input_sources": [ - { - "i_clamp": { - "pynn_input": "DCSource", - "parameters": { - "start": "input_del", - "stop": "input_del+input_dur", - "amplitude": "input_amp" - } - } + }, + "input_sources": { + "i_clamp": { + "parameters": { + "amplitude": "input_amp", + "start": "input_del", + "stop": "input_del+input_dur" + }, + "pynn_input": "DCSource" } - ], - "regions": [ - { - "region1": { - "x": 0.0, - "y": 0.0, - "z": 0.0, - "width": 1000.0, - "height": 100.0, - "depth": 1000.0 - } + }, + "regions": { + "region1": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "width": 1000.0, + "height": 100.0, + "depth": 1000.0 } - ], - "populations": [ - { - "pop0": { - "size": 2, - "component": "testcell", - "properties": { - "color": "1 0 0" - }, - "random_layout": { - "region": "region1" - } + }, + "populations": { + "pop0": { + "size": 2, + "component": "testcell", + "properties": { + "color": "1 0 0" + }, + "random_layout": { + "region": "region1" } } - ], - "inputs": [ - { - "stim": { - "input_source": "i_clamp", - "population": "pop0", - "percentage": 50.0 - } + }, + "inputs": { + "stim": { + "input_source": "i_clamp", + "population": "pop0", + "percentage": 50 } - ] + } } } \ No newline at end of file diff --git a/examples/sonatatest/SonataExample.py b/examples/sonatatest/SonataExample.py index 7c74bae..cd42d3d 100644 --- a/examples/sonatatest/SonataExample.py +++ b/examples/sonatatest/SonataExample.py @@ -106,8 +106,8 @@ network=new_file, duration="1000", dt="0.01", - recordTraces={"all": "*"}, - recordSpikes={"pop0": "*"}, + record_traces={"all": "*"}, + record_spikes={"pop0": "*"}, ) sim.to_json_file() diff --git a/examples/sonatatest/circuit_config.json b/examples/sonatatest/circuit_config.json index 787cd75..1731543 100644 --- a/examples/sonatatest/circuit_config.json +++ b/examples/sonatatest/circuit_config.json @@ -1,18 +1,18 @@ { + "manifest": { + "$NETWORK_DIR": "./network", + "$COMPONENT_DIR": "./components" + }, + "components": { + "synaptic_models_dir": "$COMPONENT_DIR/synaptic_models", + "point_neuron_models_dir": "$COMPONENT_DIR/point_neuron_models_dir" + }, "networks": { "nodes": [ { - "node_types_file": "$NETWORK_DIR/SonataExample_node_types.csv", - "nodes_file": "$NETWORK_DIR/SonataExample_nodes.sonata.h5" + "nodes_file": "$NETWORK_DIR/SonataExample_nodes.sonata.h5", + "node_types_file": "$NETWORK_DIR/SonataExample_node_types.csv" } ] - }, - "components": { - "point_neuron_models_dir": "$COMPONENT_DIR/point_neuron_models_dir", - "synaptic_models_dir": "$COMPONENT_DIR/synaptic_models" - }, - "manifest": { - "$NETWORK_DIR": "./network", - "$COMPONENT_DIR": "./components" } } \ No newline at end of file diff --git a/examples/sonatatest/components/point_neuron_models_dir/testcell.json b/examples/sonatatest/components/point_neuron_models_dir/testcell.json index 894d196..c9ffe0b 100644 --- a/examples/sonatatest/components/point_neuron_models_dir/testcell.json +++ b/examples/sonatatest/components/point_neuron_models_dir/testcell.json @@ -1,9 +1,9 @@ { - "tau_m": 22.1, - "V_th": -47.0, - "I_e": 0.0, - "C_m": 117.0, - "V_reset": -50.0, - "t_ref": 3.0, - "E_L": -78.0 + "E_L": -78.0, + "C_m": 117.0, + "tau_m": 22.1, + "t_ref": 3.0, + "V_th": -47.0, + "V_reset": -50.0, + "I_e": 0.0 } \ No newline at end of file diff --git a/examples/sonatatest/config.json b/examples/sonatatest/config.json index 0a8af5b..9591b8f 100644 --- a/examples/sonatatest/config.json +++ b/examples/sonatatest/config.json @@ -1,4 +1,4 @@ { - "network": "./circuit_config.json", + "network": "./circuit_config.json", "simulation": "./simulation_config.json" } \ No newline at end of file diff --git a/examples/sonatatest/network/SonataExample_node_types.csv b/examples/sonatatest/network/SonataExample_node_types.csv index 8d048ed..7e6a49c 100644 --- a/examples/sonatatest/network/SonataExample_node_types.csv +++ b/examples/sonatatest/network/SonataExample_node_types.csv @@ -1,2 +1,2 @@ -node_type_id dynamics_params pop_name model_template model_type model_name -100 testcell.json pop0 nest:iaf_psc_alpha point_process testcell +node_type_id pop_name model_name model_template model_type dynamics_params +100 pop0 testcell nest:iaf_psc_alpha point_process testcell.json diff --git a/examples/sonatatest/network/SonataExample_nodes.sonata.h5 b/examples/sonatatest/network/SonataExample_nodes.sonata.h5 index 5851662..6a720e3 100644 Binary files a/examples/sonatatest/network/SonataExample_nodes.sonata.h5 and b/examples/sonatatest/network/SonataExample_nodes.sonata.h5 differ diff --git a/examples/sonatatest/regenerateAndTest.sh b/examples/sonatatest/regenerateAndTest.sh new file mode 100755 index 0000000..46aee6f --- /dev/null +++ b/examples/sonatatest/regenerateAndTest.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ex + +python SonataExample.py -sonata + +python run_bmtk.py + +./run_pynml.jnml.sh diff --git a/examples/sonatatest/run_bmtk.py b/examples/sonatatest/run_bmtk.py index 193efbc..17006e5 100644 --- a/examples/sonatatest/run_bmtk.py +++ b/examples/sonatatest/run_bmtk.py @@ -14,7 +14,6 @@ def run(config_file, simulator): elif simulator == "NEST": from bmtk.simulator import pointnet - conf = pointnet.Config.from_json(config_file) conf.build_env() net = pointnet.PointNetwork.from_config(conf) @@ -24,4 +23,4 @@ def run(config_file, simulator): if __name__ == "__main__": - run("config.json", "NEST") + run("config.json", "NEST") \ No newline at end of file diff --git a/examples/sonatatest/run_pynml.jnml.sh b/examples/sonatatest/run_pynml.jnml.sh index 107ec4d..11f2c71 100755 --- a/examples/sonatatest/run_pynml.jnml.sh +++ b/examples/sonatatest/run_pynml.jnml.sh @@ -1,5 +1,4 @@ #!/bin/bash - -set -e +set -ex pynml-sonata Back2NML config.json -jnml diff --git a/examples/sonatatest/simulation_config.json b/examples/sonatatest/simulation_config.json index 152701c..60a2295 100644 --- a/examples/sonatatest/simulation_config.json +++ b/examples/sonatatest/simulation_config.json @@ -1,45 +1,45 @@ { - "inputs": { - "stim": { - "input_type": "current_clamp", - "node_set": "inputset_stim_i_clamp", - "module": "IClamp", - "delay": 100.0, - "duration": 800.0, - "amp": 190.00000000000003 - } - }, - "target_simulator": "NEST", - "reports": { - "membrane_potential": { - "enabled": true, - "cells": "point_nodes", - "sections": "soma", - "module": "multimeter_report", - "variable_name": "V_m" - } - }, - "manifest": { - "$OUTPUT_DIR": "./output", - "$INPUT_DIR": "./" - }, "run": { - "tstop": 1000.0, + "tstop": 1000.0, "dt": 0.01 - }, + }, + "target_simulator": "NEST", + "manifest": { + "$OUTPUT_DIR": "./output", + "$INPUT_DIR": "./" + }, + "output": { + "output_dir": "$OUTPUT_DIR", + "log_file": "log.txt", + "spikes_file": "spikes.h5", + "spikes_sort_order": "time" + }, "node_sets": { "point_nodes": { "model_type": "point_process" - }, + }, "inputset_stim_i_clamp": { - "model_type": "point_process", + "model_type": "point_process", "population": "pop0" } - }, - "output": { - "spikes_sort_order": "time", - "spikes_file": "spikes.h5", - "log_file": "log.txt", - "output_dir": "$OUTPUT_DIR" + }, + "reports": { + "membrane_potential": { + "cells": "point_nodes", + "variable_name": "V_m", + "module": "multimeter_report", + "sections": "soma", + "enabled": true + } + }, + "inputs": { + "stim": { + "input_type": "current_clamp", + "module": "IClamp", + "amp": 190.00000000000003, + "delay": 100.0, + "duration": 800.0, + "node_set": "inputset_stim_i_clamp" + } } } \ No newline at end of file diff --git a/examples/spikeratetest/SimSpikers.json b/examples/spikeratetest/SimSpikers.json index 65b72b0..6481df6 100644 --- a/examples/spikeratetest/SimSpikers.json +++ b/examples/spikeratetest/SimSpikers.json @@ -1,6 +1,6 @@ { "SimSpikers": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "network": "Spikers.json", "duration": 10000.0, "dt": 0.025, diff --git a/examples/spikeratetest/Spikers.json b/examples/spikeratetest/Spikers.json index 9ce401e..a9b5fe9 100644 --- a/examples/spikeratetest/Spikers.json +++ b/examples/spikeratetest/Spikers.json @@ -1,6 +1,6 @@ { "Spikers": { - "version": "NeuroMLlite v0.5.7", + "version": "NeuroMLlite v0.6.0", "notes": "Example with spiking entities..", "parameters": { "N": 10, diff --git a/examples/test_files/.test.ex4.jnmleden.omt b/examples/test_files/.test.ex4.jnmleden.omt index a013434..3046d31 100644 --- a/examples/test_files/.test.ex4.jnmleden.omt +++ b/examples/test_files/.test.ex4.jnmleden.omt @@ -14,7 +14,7 @@ experiments: spike detection: method: threshold threshold: -64 - tolerance: 0.0002527679474217274 + tolerance: 0.00025278058645101804 v1: observables: @@ -26,4 +26,4 @@ experiments: spike detection: method: threshold threshold: -69 - tolerance: 0.0002327287423609406 + tolerance: 0.00023269200151868833 diff --git a/neuromllite/MDFHandler.py b/neuromllite/MDFHandler.py index b6bb48e..84295e5 100644 --- a/neuromllite/MDFHandler.py +++ b/neuromllite/MDFHandler.py @@ -409,7 +409,7 @@ def _comp_to_mdf_node(self, nmllite_comp, lems_comp_id, size=1, properties=None) # node["parameters"][sv.name]["value"] = [0]*size node["output_ports"][sv.name] = {"value": sv.name} - print_v("Adding %s as an output port"%sv.name) + print_v("Adding %s as an output port" % sv.name) if sv.exposure: node["output_ports"][sv.exposure] = {"value": sv.name} diff --git a/neuromllite/MatrixHandler.py b/neuromllite/MatrixHandler.py index de1c859..3d1fa3b 100644 --- a/neuromllite/MatrixHandler.py +++ b/neuromllite/MatrixHandler.py @@ -11,16 +11,20 @@ from neuromllite.NetworkGenerator import _get_rng_for_network import numpy as np +import os class MatrixHandler(ConnectivityHandler): colormaps_used = [] weight_arrays_to_show = {} + weight_array_figures = {} - def __init__(self, level=10, nl_network=None): + def __init__(self, level=10, nl_network=None, show_already=True, save_figs_to_dir=None): self.nl_network = nl_network self.level = level + self.show_already = show_already + self.save_figs_to_dir=save_figs_to_dir self.rng, seed = _get_rng_for_network(self.nl_network) @@ -34,11 +38,6 @@ def print_settings(self): print_v("* level: %s" % self.level) print_v("* is_cell_level: %s" % self.is_cell_level()) print_v("* CUTOFF_INH_SYN_MV: %s" % self.CUTOFF_INH_SYN_MV) - # print_v('* include_inputs: %s'%self.include_inputs) - # print_v('* scale_by_post_pop_size: %s'%self.scale_by_post_pop_size) - # print_v('* scale_by_post_pop_cond: %s'%self.scale_by_post_pop_cond) - # print_v('* min_weight_to_show: %s'%self.min_weight_to_show) - # print_v('* min_weight_to_show: %s'%self.min_weight_to_show) print_v("*") print_v("* Used values: ") print_v("* colormaps_used: %s" % self.colormaps_used) @@ -68,6 +67,9 @@ def finalise_document(self): for v in self.proj_post_pops.values(): all_pops.append(v) + self.weight_matrices_generated = {} + self.weight_matrices_saved = {} + for pop in all_pops: if self.is_cell_level(): for i in range(self.pop_sizes[pop]): @@ -248,7 +250,7 @@ def finalise_document(self): title = "%s" % (proj_type) title2 = "%s" % (proj_type) plt.title(title) - fig.canvas.set_window_title(title2) + fig.canvas.manager.set_window_title(title2) max_abs_weight = max(weight_array.max(), -1.0 * (weight_array.min())) min_abs_weight = np.min(abs(weight_array[np.nonzero(weight_array)])) @@ -308,14 +310,33 @@ def finalise_document(self): ax.set_yticklabels(entries) ax.set_xticklabels(entries) ax.set_ylabel("presynaptic") - tick_size = ( - 10 + + # change in relation to default so that users can override + default_tick_size_x = matplotlib.rcParams["xtick.labelsize"] + tick_size_x = ( + default_tick_size_x + if weight_array.shape[0] < 20 + else ( + (default_tick_size_x - 2) + if weight_array.shape[0] < 40 + else (default_tick_size_x - 4) + ) + ) + ax.tick_params(axis="x", labelsize=tick_size_x) + + default_tick_size_y = matplotlib.rcParams["ytick.labelsize"] + tick_size_y = ( + default_tick_size_y if weight_array.shape[0] < 20 - else (8 if weight_array.shape[0] < 40 else 6) + else ( + (default_tick_size_y - 2) + if weight_array.shape[0] < 40 + else (default_tick_size_y - 4) + ) ) - ax.tick_params(axis="y", labelsize=tick_size) + ax.tick_params(axis="y", labelsize=tick_size_y) + ax.set_xlabel("postsynaptic") - ax.tick_params(axis="x", labelsize=tick_size) fig.autofmt_xdate() for i in range(len(entries)): @@ -357,10 +378,22 @@ def finalise_document(self): if proj_type in cbar_labels: cbar.set_label(cbar_labels[proj_type]) + if self.save_figs_to_dir: + safe = proj_type.replace(' ','_').replace('(','-').replace(')','-').replace('*','_').replace('/','_') + save_figure_to = os.path.join(self.save_figs_to_dir, '%s_%s.png'%(self.network_id, safe)) + plt.savefig(save_figure_to, bbox_inches="tight") + print_v("Saved image to %s of plot: %s" % (save_figure_to, title)) + self.weight_array_figures[title] = save_figure_to + + + print_v("Generating matrix for: %s" % self.network_id) + + self.print_settings() - plt.show() + if self.show_already: + plt.show() def handle_population( self, @@ -516,3 +549,31 @@ def finalise_projection( def finalise_input_source(self, inputListId): pass + +if __name__ == "__main__": + + from neuromllite.utils import load_network_json + + tests = ['/Users/padraig/neuroConstruct/osb/cerebral_cortex/networks/del-Molino2017/NeuroML/delMolinoEtAl_low_baseline.json', + '/Users/padraig/NeuroMLlite/examples/Example12_MultiComp.json'] + + for test in tests: + + network = load_network_json(test) + + from neuromllite.NetworkGenerator import generate_network + + level = 1 + handler = MatrixHandler(level, + nl_network=network, + show_already=True, + save_figs_to_dir='.') + + generate_network( + network, handler, always_include_props=True, base_dir=os.path.dirname(test) + ) + + print_v("Done with MatrixHandler...") + + for w in handler.weight_arrays_to_show: + print('%s:\n%s'%(w, handler.weight_arrays_to_show[w])) \ No newline at end of file diff --git a/neuromllite/NetworkGenerator.py b/neuromllite/NetworkGenerator.py index f057388..ed5fbb5 100644 --- a/neuromllite/NetworkGenerator.py +++ b/neuromllite/NetworkGenerator.py @@ -11,6 +11,7 @@ import numpy as np import os import random +import time import lems.api as lems # from pylems @@ -410,7 +411,9 @@ def generate_network( if input.weight else 1 ) - if flip * 100.0 < evaluate(input.percentage, nl_model.parameters, rng): + if flip * 100.0 < evaluate( + input.percentage, nl_model.parameters, rng + ): if input.number_per_cell and input.segment_ids: raise Exception( "On input: %s, only one of number_per_cell or segment_ids is allowed" @@ -911,6 +914,7 @@ def generate_neuroml2_from_network( if len(extra_lems_components.components) > 0: extra_lems_components.export_to_file(extra_lems_file) + time.sleep(0.5) if validate and format == "xml": from pyneuroml import pynml @@ -1282,33 +1286,30 @@ def generate_value_array(node, index, context='{0}', param='value'): run_bmtk_template = """#!/bin/env python - import sys - - def run(config_file, simulator): +import sys - if simulator=='NEURON': - from bmtk.simulator import bionet - conf = bionet.Config.from_json(config_file, validate=True) - conf.build_env() - net = bionet.BioNetwork.from_config(conf) - sim = bionet.BioSimulator.from_config(conf, network=net) +def run(config_file, simulator): + if simulator == "NEURON": + from bmtk.simulator import bionet - elif simulator=='NEST': - from bmtk.simulator import pointnet - conf = pointnet.Config.from_json(config_file) - conf.build_env() - net = pointnet.PointNetwork.from_config(conf) - sim = pointnet.PointSimulator.from_config(conf, net) + conf = bionet.Config.from_json(config_file, validate=True) + conf.build_env() + net = bionet.BioNetwork.from_config(conf) + sim = bionet.BioSimulator.from_config(conf, network=net) - sim.run() + elif simulator == "NEST": + from bmtk.simulator import pointnet + conf = pointnet.Config.from_json(config_file) + conf.build_env() + net = pointnet.PointNetwork.from_config(conf) + sim = pointnet.PointSimulator.from_config(conf, net) + sim.run() - if __name__ == '__main__': - run('config.json', '%s') - - """ +if __name__ == "__main__": + run("config.json", "%s")""" run_bmtk_file = open("run_bmtk.py", "w") run_bmtk_file.write(run_bmtk_template % (target_simulator)) diff --git a/neuromllite/__init__.py b/neuromllite/__init__.py index ca81abc..6e0c076 100644 --- a/neuromllite/__init__.py +++ b/neuromllite/__init__.py @@ -1,6 +1,6 @@ import collections -__version__ = "0.5.7" +__version__ = "0.6.0" # import pyNN # import nest diff --git a/neuromllite/gui/NMLliteUI.py b/neuromllite/gui/NMLliteUI.py index d54bbbb..deb8d92 100644 --- a/neuromllite/gui/NMLliteUI.py +++ b/neuromllite/gui/NMLliteUI.py @@ -1044,7 +1044,7 @@ def replotSimResults(self): ax_heatmap.clear() if len(heat_array) > 0: - cm = matplotlib.cm.get_cmap("jet") + cm = matplotlib.pyplot.get_cmap("jet") hm = ax_heatmap.pcolormesh(heat_array, cmap=cm) # cbar = ax_heatmap.colorbar(im) @@ -1128,7 +1128,7 @@ def replotSimResults(self): # ax_3d = fig.add_subplot(111) from mpl_toolkits.mplot3d import Axes3D - ax_3d = fig.gca(projection="3d") + ax_3d = fig.add_subplot(projection="3d") ax_3d.clear() xs = self.current_traces[info["x_axis"]] diff --git a/neuromllite/sweep/ParameterSweep.py b/neuromllite/sweep/ParameterSweep.py index 9130c89..3afb9be 100644 --- a/neuromllite/sweep/ParameterSweep.py +++ b/neuromllite/sweep/ParameterSweep.py @@ -98,7 +98,7 @@ def __init__( "Traces generated from %s" % self.sim.id, # Title labels=[], xaxis="Time (ms)", # x axis legend - yaxis="Membrane potential (mV)", # y axis legend + yaxis="(SI units)", # y axis legend title_above_plot=True, show_plot_already=False, ) # Save figure @@ -283,7 +283,7 @@ def _run_all(self): label = "%s (%s)" % (y, params) self.ax.plot( [t * 1000 for t in traces["t"]], - [v * 1000 for v in traces[y]], + [v for v in traces[y]], label=label, ) @@ -301,7 +301,7 @@ def _run_all(self): if i % downscale == 0 ] - param_name = self.vary.keys()[0] + param_name = list(self.vary.keys())[0] pval = get_value_in_si(params[param_name]) if self.hm_x == None: self.hm_x = tt @@ -344,7 +344,7 @@ def run(self): z = np.array(self.hm_z) print_v( - "Plotting x: %s->%s (%i), y: %s->%s (%i), z: %s->%s (%i)" + "Plotting x: %s->%s (%i), y: %s->%s (%i), z: %s->%s (%s)" % ( self.hm_x[0], self.hm_x[-1], @@ -354,7 +354,7 @@ def run(self): len(self.hm_y), z.min(), z.max(), - z.size, + z.shape, ) ) @@ -362,6 +362,7 @@ def run(self): # yvals = np.array(self.hm_y) if not self.heatmap_lims: + plot0 = self.hm_ax.pcolormesh( np.array(self.hm_x), np.array(self.hm_y), z, cmap=self.colormap ) @@ -379,11 +380,11 @@ def run(self): # self.hm_ax.set_yticklabels(['ff%s'%i for i in range(len(self.hm_y))]) plt.xlabel("Time (ms)") - plt.ylabel("%s " % self.vary.keys()[0]) + plt.ylabel("%s " % list(self.vary.keys())[0]) plt.xlim([self.hm_x[0], self.hm_x[-1]]) plt.ylim([self.hm_y[0], self.hm_y[-1]]) title = "Values of %s" % self.vary.keys() - self.hm_fig.canvas.set_window_title(title) + self.hm_fig.canvas.manager.set_window_title(title) plt.title(title) # plt.axes().set_aspect('equal') @@ -531,7 +532,7 @@ def plotLines( logx=logx, logy=logy, show_plot_already=False, - legend_position="right", + legend_position="bottom center", save_figure_to=save_figure_to, ) # Save figure @@ -585,7 +586,7 @@ def run_once(self, job_dir, **kwargs): if a in network.parameters: print_v(" Setting %s to %s in network..." % (a, kwargs[a])) network.parameters[a] = kwargs[a] - elif a in sim.fields: + elif a in sim.allowed_fields: print_v(" Setting %s to %s in simulator..." % (a, kwargs[a])) setattr(sim, a, kwargs[a]) else: @@ -612,8 +613,8 @@ def run_once(self, job_dir, **kwargs): if "-2d" in sys.argv: fixed = {"dt": 0.025} vary = { - "stim_amp": ["%spA" % (i) for i in xrange(-40, 220, 40)], - "stim_del": ["%sms" % (i) for i in xrange(10, 40, 10)], + "stim_amp": ["%spA" % (i) for i in range(-40, 220, 40)], + "stim_del": ["%sms" % (i) for i in range(10, 40, 10)], } vary = { @@ -622,7 +623,7 @@ def run_once(self, job_dir, **kwargs): } vary = { - "stim_amp": ["%spA" % (i) for i in xrange(-40, 220, 20)], + "stim_amp": ["%spA" % (i) for i in range(-40, 220, 20)], "stim_del": ["%sms" % (i) for i in [10, 20]], } @@ -671,9 +672,9 @@ def run_once(self, job_dir, **kwargs): elif "-hh" in sys.argv: fixed = {"dt": 0.025} - vary = {"stim_amp": ["%spA" % (i) for i in xrange(-200, 1500, 10)]} - vary = {"stim_amp": ["%spA" % (i) for i in xrange(-100, 1800, 20)]} - # vary = {'stim_amp':['%spA'%(i) for i in xrange(-100,500,5)]} + vary = {"stim_amp": ["%spA" % (i) for i in range(-200, 1500, 10)]} + vary = {"stim_amp": ["%spA" % (i) for i in range(-100, 1800, 20)]} + # vary = {'stim_amp':['%spA'%(i) for i in range(-100,500,5)]} simulator = "jNeuroML_NetPyNE" simulator = "NetPyNE" @@ -707,10 +708,11 @@ def run_once(self, job_dir, **kwargs): plt.show() elif "-dt" in sys.argv: - fixed = {"stim_amp": "500pA"} + fixed = {"stim_amp": "500pA", "duration": 300} vary = {"dt": [0.025, 0.02, 0.015, 0.01, 0.005, 0.0025]} vary = {"dt": [0.1, 0.05, 0.025, 0.01, 0.005, 0.0025, 0.001]} + #vary = {"dt": [0.1, 0.05, 0.025]} simulator = "jNeuroML_NetPyNE" simulator = "NetPyNE" @@ -764,7 +766,7 @@ def run_once(self, job_dir, **kwargs): vary = {"c": [-3, -1, 1, 3]} # vary = {'a':[.8,1,1.2]} # vary = {'eta':['100Hz']} - # vary = {'stim_amp':['1.5pA']} + vary = {'I':[5,5.2]} simulator = "jNeuroML" simulator = "jNeuroML_NEURON" @@ -805,11 +807,11 @@ def run_once(self, job_dir, **kwargs): quick = False # quick=True - vary = {"stim_amp": ["%spA" % (i / 10.0) for i in xrange(-10, 20, 2)]} - vary = {"stim_amp": ["%spA" % (i / 10.0) for i in xrange(-10, 20, 5)]} + vary = {"stim_amp": ["%spA" % (i / 10.0) for i in range(-10, 20, 2)]} + vary = {"stim_amp": ["%spA" % (i / 10.0) for i in range(-10, 20, 5)]} vary = {"weightInput": [1, 2, 5, 10]} vary = {"weightInput": [1, 2, 3, 20]} - vary = {"eta": [i / 100.0 for i in xrange(0, 200, 20)]} + vary = {"eta": [i / 100.0 for i in range(0, 200, 20)]} # vary = {'eta':['100Hz']} # vary = {'stim_amp':['1.5pA']} diff --git a/neuromllite/sweep/cleanup.sh b/neuromllite/sweep/cleanup.sh new file mode 100755 index 0000000..109c440 --- /dev/null +++ b/neuromllite/sweep/cleanup.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -ex + +rm -rf ParamSweep_* *.dat *.txt *kes *.png + diff --git a/neuromllite/utils.py b/neuromllite/utils.py index 86c67e6..a5d030d 100644 --- a/neuromllite/utils.py +++ b/neuromllite/utils.py @@ -80,6 +80,7 @@ def load_network_yaml(filename): return net + def load_simulation(filename): """ Load a NeuroMLlite simulation JSON/YAML file @@ -89,6 +90,7 @@ def load_simulation(filename): else: return load_simulation_json(filename) + def load_simulation_json(filename: str) -> Optional[dict]: """ Load a NeuroMLlite simulation JSON file diff --git a/requirements-extra.txt b/requirements-extra.txt index 46e442a..83c7838 100644 --- a/requirements-extra.txt +++ b/requirements-extra.txt @@ -4,8 +4,6 @@ matplotlib PyQt5 pyneuroml pyelectro -numpy neuron h5py graphviz -pylems diff --git a/setup.py b/setup.py index ba65143..1b8e1ff 100644 --- a/setup.py +++ b/setup.py @@ -22,10 +22,11 @@ install_requires=[ "libNeuroML>=0.5.1", "pyyaml", - "numpy", + "numpy<2.0.0", "tables", "h5py", "modelspec>=0.2.6", + "ppft" ], classifiers=[ "Intended Audience :: Science/Research",