From e999d535902fbe74a8417efaf687e628bc0f82d3 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Thu, 31 Aug 2023 10:11:30 +0200 Subject: [PATCH 1/4] Bump to Arbor v0.9.0. --- src/gui_state.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui_state.cpp b/src/gui_state.cpp index 02391a0..119c584 100644 --- a/src/gui_state.cpp +++ b/src/gui_state.cpp @@ -736,8 +736,11 @@ namespace { } } } - std::sort(state_vars.begin(), state_vars.end()); - std::unique(state_vars.begin(), state_vars.end()); + { + std::sort(state_vars.begin(), state_vars.end()); + auto last = std::unique(state_vars.begin(), state_vars.end()); + state_vars.erase(last, state_vars.end()); + } for (const auto& locset: state.locsets) { with_id id{locset}; From 7f3f20fd07cf01a7b93e8a33aa20603c60af6d0c Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Thu, 31 Aug 2023 10:11:30 +0200 Subject: [PATCH 2/4] Bump completed --- src/gui_state.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui_state.cpp b/src/gui_state.cpp index 02391a0..119c584 100644 --- a/src/gui_state.cpp +++ b/src/gui_state.cpp @@ -736,8 +736,11 @@ namespace { } } } - std::sort(state_vars.begin(), state_vars.end()); - std::unique(state_vars.begin(), state_vars.end()); + { + std::sort(state_vars.begin(), state_vars.end()); + auto last = std::unique(state_vars.begin(), state_vars.end()); + state_vars.erase(last, state_vars.end()); + } for (const auto& locset: state.locsets) { with_id id{locset}; From f23d9f38c178997088dfa8651349f634dedfe34e Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:50:36 +0200 Subject: [PATCH 3/4] Bump to Arbor v0.9.0. complete --- src/gui_state.cpp | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/gui_state.cpp b/src/gui_state.cpp index 119c584..8c318c6 100644 --- a/src/gui_state.cpp +++ b/src/gui_state.cpp @@ -1,7 +1,6 @@ #include "gui_state.hpp" #include -#include #include #include @@ -390,8 +389,8 @@ namespace { state.renderer.render(vs, {mouse.x - win_pos.x, size.y + win_pos.y - mouse.y}); ImGui::Image(reinterpret_cast(state.renderer.cell.tex), size, ImVec2(0, 1), ImVec2(1, 0)); if (ImGui::IsItemHovered()) { - auto shft = ImGui::IsKeyDown(GLFW_KEY_LEFT_SHIFT) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_SHIFT); - auto ctrl = ImGui::IsKeyDown(GLFW_KEY_LEFT_CONTROL) || ImGui::IsKeyDown(GLFW_KEY_RIGHT_CONTROL); + auto shft = ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift); + auto ctrl = ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl); if (shft || ctrl) { auto what = shft ? ImGuizmo::ROTATE : ImGuizmo::TRANSLATE; glm::vec3 shift = {vs.offset.x/vs.size.x, vs.offset.y/vs.size.y, 0.0f}; @@ -1083,33 +1082,33 @@ void gui_state::deserialize(const std::filesystem::path& fn) { return id; } - void operator()(const arb::init_membrane_potential& t) { state->parameter_defs[region].Vm = t.value; } - void operator()(const arb::axial_resistivity& t) { state->parameter_defs[region].RL = t.value; } - void operator()(const arb::temperature_K& t) { state->parameter_defs[region].TK = t.value; } - void operator()(const arb::membrane_capacitance& t) { state->parameter_defs[region].Cm = t.value; } + void operator()(const arb::init_membrane_potential& t) { state->parameter_defs[region].Vm = t.value.get_scalar(); } + void operator()(const arb::axial_resistivity& t) { state->parameter_defs[region].RL = t.value.get_scalar(); } + void operator()(const arb::temperature_K& t) { state->parameter_defs[region].TK = t.value.get_scalar(); } + void operator()(const arb::membrane_capacitance& t) { state->parameter_defs[region].Cm = t.value.get_scalar(); } void operator()(const arb::init_int_concentration& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Xi = t.value; + state->ion_par_defs[{region, *ion}].Xi = t.value.get_scalar(); } void operator()(const arb::init_ext_concentration& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Xo = t.value; + state->ion_par_defs[{region, *ion}].Xo = t.value.get_scalar(); } void operator()(const arb::init_reversal_potential& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Er = t.value; + state->ion_par_defs[{region, *ion}].Er = t.value.get_scalar(); } void operator()(const arb::ion_diffusivity& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].D = t.value; + state->ion_par_defs[{region, *ion}].D = t.value.get_scalar(); } void operator()(const arb::scaled_mechanism& s) { auto id = make_density(s.t_mech); @@ -1120,20 +1119,7 @@ void gui_state::deserialize(const std::filesystem::path& fn) { } } void operator()(const arb::density& d) { make_density(d); } - }; - - struct df_visitor { - gui_state* state; - void operator()(const arb::init_membrane_potential& t) { log_error("Cannot handle this"); } - void operator()(const arb::axial_resistivity& t) { log_error("Cannot handle this"); } - void operator()(const arb::temperature_K& t) { log_error("Cannot handle this"); } - void operator()(const arb::membrane_capacitance& t) { log_error("Cannot handle this"); } - void operator()(const arb::init_int_concentration& t) { log_error("Cannot handle this"); } - void operator()(const arb::init_ext_concentration& t) { log_error("Cannot handle this"); } - void operator()(const arb::init_reversal_potential& t) { log_error("Cannot handle this"); } - void operator()(const arb::ion_reversal_potential_method& t) { log_error("Cannot handle this"); } - void operator()(const arb::ion_diffusivity& t) { log_error("Cannot handle this"); } - void operator()(const arb::cv_policy& t) { log_error("Cannot handle this"); } + void operator()(const arb::voltage_process& d) { log_error("Cannot handle this"); } }; struct acc_visitor { @@ -1482,8 +1468,7 @@ void gui_state::run_simulation() { t.values.push_back(*value); } sim.traces[t.id] = t; - }, - arb::sampling_policy::exact); + }); try { sm.run(sim.until, sim.dt); } catch (...) { From 13c6e8f759511dafab2e4b6c9815418695383461 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Mon, 5 Aug 2024 09:08:16 +0200 Subject: [PATCH 4/4] Update to arbor/master (0.10.0) --- 3rd-party/ImGuizmo | 2 +- 3rd-party/arbor | 2 +- 3rd-party/fmt | 2 +- 3rd-party/glbinding | 2 +- 3rd-party/glfw | 2 +- 3rd-party/icons | 2 +- 3rd-party/imgui | 2 +- 3rd-party/implot | 2 +- 3rd-party/json | 2 +- 3rd-party/spdlog | 2 +- CMakeLists.txt | 5 ++- src/gui_state.cpp | 105 +++++++++++++++++++++++++------------------- src/loader.cpp | 26 ++++++++--- src/loader.hpp | 1 - src/recipe.hpp | 2 +- src/simulation.hpp | 9 +++- 16 files changed, 101 insertions(+), 67 deletions(-) diff --git a/3rd-party/ImGuizmo b/3rd-party/ImGuizmo index 664cf2d..ba662b1 160000 --- a/3rd-party/ImGuizmo +++ b/3rd-party/ImGuizmo @@ -1 +1 @@ -Subproject commit 664cf2d73864a36b2a8b5091d33fc4578c885eca +Subproject commit ba662b119d64f9ab700bb2cd7b2781f9044f5565 diff --git a/3rd-party/arbor b/3rd-party/arbor index 8e82ec1..9ff54f8 160000 --- a/3rd-party/arbor +++ b/3rd-party/arbor @@ -1 +1 @@ -Subproject commit 8e82ec1947a3a6d84452969d1d628b2292654319 +Subproject commit 9ff54f8e7c989203960da64779f9900aeb56a08b diff --git a/3rd-party/fmt b/3rd-party/fmt index c4ee726..0c9fce2 160000 --- a/3rd-party/fmt +++ b/3rd-party/fmt @@ -1 +1 @@ -Subproject commit c4ee726532178e556d923372f29163bd206d7732 +Subproject commit 0c9fce2ffefecfdce794e1859584e25877b7b592 diff --git a/3rd-party/glbinding b/3rd-party/glbinding index 21729a0..ff2ff7a 160000 --- a/3rd-party/glbinding +++ b/3rd-party/glbinding @@ -1 +1 @@ -Subproject commit 21729a0f5e6f64565d708f6221d436662c467325 +Subproject commit ff2ff7a7aad77b907a67bd5962d6e11a4f9c699e diff --git a/3rd-party/glfw b/3rd-party/glfw index 7482de6..7b6aead 160000 --- a/3rd-party/glfw +++ b/3rd-party/glfw @@ -1 +1 @@ -Subproject commit 7482de6071d21db77a7236155da44c172a7f6c9e +Subproject commit 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 diff --git a/3rd-party/icons b/3rd-party/icons index 7d6ff1f..f30b1e7 160000 --- a/3rd-party/icons +++ b/3rd-party/icons @@ -1 +1 @@ -Subproject commit 7d6ff1f4ba51e7a2b142be39457768abece1549c +Subproject commit f30b1e73b2d71eb331d77619c3f1de34199afc38 diff --git a/3rd-party/imgui b/3rd-party/imgui index 8cbd391..139e99c 160000 --- a/3rd-party/imgui +++ b/3rd-party/imgui @@ -1 +1 @@ -Subproject commit 8cbd391f096b9314a08670052cc0025cbcadb249 +Subproject commit 139e99ca37a3e127c87690202faec005cd892d36 diff --git a/3rd-party/implot b/3rd-party/implot index b47c8ba..18c7243 160000 --- a/3rd-party/implot +++ b/3rd-party/implot @@ -1 +1 @@ -Subproject commit b47c8bacdbc78bc521691f70666f13924bb522ab +Subproject commit 18c72431f8265e2b0b5378a3a73d8a883b2175ff diff --git a/3rd-party/json b/3rd-party/json index 69d7448..9cca280 160000 --- a/3rd-party/json +++ b/3rd-party/json @@ -1 +1 @@ -Subproject commit 69d744867f8847c91a126fa25e9a6a3d67b3be41 +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03 diff --git a/3rd-party/spdlog b/3rd-party/spdlog index 76fb40d..27cb4c7 160000 --- a/3rd-party/spdlog +++ b/3rd-party/spdlog @@ -1 +1 @@ -Subproject commit 76fb40d95455f249bd70824ecfcae7a8f0930fa3 +Subproject commit 27cb4c76708608465c413f6d0e6b8d99a4d84302 diff --git a/CMakeLists.txt b/CMakeLists.txt index d238a21..41aa5b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,11 @@ cmake_minimum_required(VERSION 3.19) find_package(Git) project(the-arbor-gui - VERSION 0.8.1 + VERSION 0.10.1 LANGUAGES C CXX) +set(EXPORT_COMPILE_COMMANDS ON) + set(CMAKE_CXX_STANDARD 20) include(GNUInstallDirs) @@ -141,6 +143,7 @@ target_include_directories(imgui PRIVATE 3rd-party/imgui) target_include_directories(imgui PUBLIC 3rd-party/implot) target_include_directories(imgui PUBLIC 3rd-party/ImGuizmo/) target_link_libraries(imgui PRIVATE glfw) +target_compile_definitions(arbor-gui-deps INTERFACE SPDLOG_FMT_EXTERNAL) # Get commit hashes from git and inject into config execute_process(COMMAND ${GIT_EXECUTABLE} -C ${PROJECT_SOURCE_DIR} describe --always --dirty --abbrev=0 diff --git a/src/gui_state.cpp b/src/gui_state.cpp index 8c318c6..67b3630 100644 --- a/src/gui_state.cpp +++ b/src/gui_state.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "gui.hpp" #include "utils.hpp" @@ -36,6 +37,7 @@ extern float delta_zoom; extern glm::vec2 mouse; using namespace std::literals; +namespace U = arb::units; namespace { inline void gui_read_morphology(gui_state& state, bool& open); @@ -852,20 +854,22 @@ namespace { i_clamp.frequency = item.frequency; i_clamp.phase = item.phase; std::sort(item.envelope.begin(), item.envelope.end()); - for (const auto& [t, i]: item.envelope) i_clamp.envelope.emplace_back(arb::i_clamp::envelope_point{t, i}); + for (const auto& [t, i]: item.envelope) { + i_clamp.envelope.emplace_back(arb::i_clamp::envelope_point{t * U::ms , i * U::nA }); + } decor.place(locset, i_clamp, item.tag); } for (const auto child: state.detectors.get_children(id)) { auto item = state.detectors[child]; - decor.place(locset, arb::threshold_detector{item.threshold}, item.tag); + decor.place(locset, arb::threshold_detector{item.threshold * U::mV}, item.tag); } } auto param = state.parameter_defaults; - if (param.RL) decor.set_default(arb::axial_resistivity{param.RL.value()}); - if (param.Cm) decor.set_default(arb::membrane_capacitance{param.Cm.value()}); - if (param.TK) decor.set_default(arb::temperature_K{param.TK.value()}); - if (param.Vm) decor.set_default(arb::init_membrane_potential{param.Vm.value()}); + if (param.RL) decor.set_default(arb::axial_resistivity{param.RL.value() * U::Ohm * U::cm}); + if (param.Cm) decor.set_default(arb::membrane_capacitance{param.Cm.value() * U::F / U::m2}); + if (param.TK) decor.set_default(arb::temperature{param.TK.value() * U::Kelvin }); + if (param.Vm) decor.set_default(arb::init_membrane_potential{param.Vm.value() * U::mV}); for (const auto& ion: state.ions) { const auto& data = state.ion_defaults[ion]; @@ -878,13 +882,13 @@ namespace { if (state.presets.ion_data.contains(name)) { auto p = state.presets.ion_data.at(name); - decor.set_default(arb::init_int_concentration{name, data.Xi.value_or(p.init_int_concentration.value())}); - decor.set_default(arb::init_ext_concentration{name, data.Xo.value_or(p.init_ext_concentration.value())}); - decor.set_default(arb::init_reversal_potential{name, data.Er.value_or(p.init_reversal_potential.value())}); + decor.set_default(arb::init_int_concentration{name, data.Xi.value_or(p.init_int_concentration.value()) * U::mM}); + decor.set_default(arb::init_ext_concentration{name, data.Xo.value_or(p.init_ext_concentration.value()) * U::mM}); + decor.set_default(arb::init_reversal_potential{name, data.Er.value_or(p.init_reversal_potential.value())* U::mV}); } else { - decor.set_default(arb::init_int_concentration{name, data.Xi.value()}); - decor.set_default(arb::init_ext_concentration{name, data.Xo.value()}); - decor.set_default(arb::init_reversal_potential{name, data.Er.value()}); + decor.set_default(arb::init_int_concentration{name, data.Xi.value() * U::mM}); + decor.set_default(arb::init_ext_concentration{name, data.Xo.value() * U::mM}); + decor.set_default(arb::init_reversal_potential{name, data.Er.value() * U::mV}); } } @@ -892,17 +896,17 @@ namespace { auto rg = state.region_defs[id]; if (!rg.data) continue; auto param = state.parameter_defs[id]; - if (param.RL) decor.paint(rg.data.value(), arb::axial_resistivity{param.RL.value()}); - if (param.Cm) decor.paint(rg.data.value(), arb::membrane_capacitance{param.Cm.value()}); - if (param.TK) decor.paint(rg.data.value(), arb::temperature_K{param.TK.value()}); - if (param.Vm) decor.paint(rg.data.value(), arb::init_membrane_potential{param.Vm.value()}); + if (param.RL) decor.paint(rg.data.value(), arb::axial_resistivity{param.RL.value() * U::Ohm * U::cm}); + if (param.Cm) decor.paint(rg.data.value(), arb::membrane_capacitance{param.Cm.value() * U::F / U::m2}); + if (param.TK) decor.paint(rg.data.value(), arb::temperature{param.TK.value() * U::Kelvin}); + if (param.Vm) decor.paint(rg.data.value(), arb::init_membrane_potential{param.Vm.value() * U::mV}); for (const auto& ion: state.ions) { const auto& data = state.ion_par_defs[{id, ion}]; const auto& name = state.ion_defs[ion].name; - if (data.Xi) decor.paint(rg.data.value(), arb::init_int_concentration{name, data.Xi.value()}); - if (data.Xo) decor.paint(rg.data.value(), arb::init_ext_concentration{name, data.Xo.value()}); - if (data.Er) decor.paint(rg.data.value(), arb::init_reversal_potential{name, data.Er.value()}); + if (data.Xi) decor.paint(rg.data.value(), arb::init_int_concentration{name, data.Xi.value() * U::mM}); + if (data.Xo) decor.paint(rg.data.value(), arb::init_ext_concentration{name, data.Xo.value() * U::mM}); + if (data.Er) decor.paint(rg.data.value(), arb::init_reversal_potential{name, data.Er.value() * U::mV}); } for (const auto child: state.mechanisms.get_children(id)) { @@ -940,7 +944,7 @@ namespace { if (ImGui::BeginChild("TracePlot", {-180.0f, 0.0f})) { if (to_plot) { auto probe = to_plot.value(); - auto trace = state.sim.traces.at(probe); + auto trace = state.sim.traces.at(probe.value); const auto& [lo, hi] = std::accumulate(trace.values.begin(), trace.values.end(), std::make_pair(std::numeric_limits::max(), std::numeric_limits::min()), @@ -1014,9 +1018,9 @@ void gui_state::deserialize(const std::filesystem::path& fn) { struct ls_visitor { gui_state* state; id_type locset; - std::string tag; + arb::hash_type tag; - ls_visitor(gui_state* s, const arb::locset& l, const std::string& t): state{s}, tag{t} { + ls_visitor(gui_state* s, const arb::locset& l, const arb::hash_type& t): state{s}, tag{t} { auto ls = to_string(l); auto res = std::find_if(state->locsets.begin(), state->locsets.end(), [&](const auto& id) { @@ -1082,33 +1086,33 @@ void gui_state::deserialize(const std::filesystem::path& fn) { return id; } - void operator()(const arb::init_membrane_potential& t) { state->parameter_defs[region].Vm = t.value.get_scalar(); } - void operator()(const arb::axial_resistivity& t) { state->parameter_defs[region].RL = t.value.get_scalar(); } - void operator()(const arb::temperature_K& t) { state->parameter_defs[region].TK = t.value.get_scalar(); } - void operator()(const arb::membrane_capacitance& t) { state->parameter_defs[region].Cm = t.value.get_scalar(); } + void operator()(const arb::init_membrane_potential& t) { state->parameter_defs[region].Vm = t.value; } + void operator()(const arb::axial_resistivity& t) { state->parameter_defs[region].RL = t.value; } + void operator()(const arb::temperature& t) { state->parameter_defs[region].TK = t.value; } + void operator()(const arb::membrane_capacitance& t) { state->parameter_defs[region].Cm = t.value; } void operator()(const arb::init_int_concentration& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Xi = t.value.get_scalar(); + state->ion_par_defs[{region, *ion}].Xi = t.value; } void operator()(const arb::init_ext_concentration& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Xo = t.value.get_scalar(); + state->ion_par_defs[{region, *ion}].Xo = t.value; } void operator()(const arb::init_reversal_potential& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].Er = t.value.get_scalar(); + state->ion_par_defs[{region, *ion}].Er = t.value; } void operator()(const arb::ion_diffusivity& t) { auto ion = std::find_if(state->ions.begin(), state->ions.end(), [&](const auto& id) { return state->ion_defs[id].name == t.ion; }); if (ion == state->ions.end()) log_error("Unknown ion"); - state->ion_par_defs[{region, *ion}].D = t.value.get_scalar(); + state->ion_par_defs[{region, *ion}].D = t.value; } void operator()(const arb::scaled_mechanism& s) { auto id = make_density(s.t_mech); @@ -1426,15 +1430,15 @@ void gui_state::run_simulation() { auto p = presets.ion_data.at(name); prop.add_ion(name, data.charge, - def.Xi.value_or(p.init_int_concentration.value()), - def.Xo.value_or(p.init_ext_concentration.value()), - def.Er.value_or(p.init_reversal_potential.value())); + def.Xi.value_or(p.init_int_concentration.value()) * U::mM, + def.Xo.value_or(p.init_ext_concentration.value()) * U::mM, + def.Er.value_or(p.init_reversal_potential.value())* U::mV); } else { prop.add_ion(name, data.charge, - def.Xi.value(), - def.Xo.value(), - def.Er.value()); + def.Xi.value() * U::mM, + def.Xo.value() * U::mM, + def.Er.value() * U::mV); } } auto rec = make_recipe(prop, cell); @@ -1444,33 +1448,42 @@ void gui_state::run_simulation() { const auto& where = locset_defs[ls]; if (!where.data) continue; auto loc = where.data.value(); + // TODO this is quite crude... + auto tag = std::to_string(pb.value); if (data.kind == "Voltage") { - rec.probes.emplace_back(arb::cable_probe_membrane_voltage{loc}, pb.value); + rec.probes.emplace_back(arb::cable_probe_membrane_voltage{loc}, tag); } else if (data.kind == "Axial Current") { - rec.probes.emplace_back(arb::cable_probe_axial_current{loc}, pb.value); + rec.probes.emplace_back(arb::cable_probe_axial_current{loc}, tag); } else if (data.kind == "Membrane Current") { - rec.probes.emplace_back(arb::cable_probe_total_ion_current_density{loc}, pb.value); + rec.probes.emplace_back(arb::cable_probe_total_ion_current_density{loc}, tag); } // TODO Finish } } // Make simulation - auto sm = arb::simulation(rec); + auto sm = arb::simulation(rec); sim.traces.clear(); + sim.tag_to_id.clear(); sm.add_sampler(arb::all_probes, - arb::regular_schedule(this->sim.dt), - [&](arb::probe_metadata pm, std::size_t n, const arb::sample_record* samples) { - auto loc = arb::util::any_cast(pm.meta); - trace t{(size_t)pm.tag, pm.index, loc->pos, loc->branch, {}, {}}; + arb::regular_schedule(this->sim.dt * U::ms), + [&](const arb::probe_metadata pm, std::size_t n, const arb::sample_record* samples) { + auto loc = arb::util::any_cast(pm.meta); + auto tag = pm.id.tag; + if (sim.tag_to_id.count(tag) == 0) { + id_type id = {sim.traces.size()}; + sim.tag_to_id[tag] = id; + sim.traces.emplace_back(tag, id, pm.index, loc->pos, loc->branch); + } + auto id = sim.tag_to_id[tag]; + auto& t = sim.traces.at(id.value); for (std::size_t i = 0; i(samples[i].data); t.times.push_back(samples[i].time); t.values.push_back(*value); } - sim.traces[t.id] = t; }); try { - sm.run(sim.until, sim.dt); + sm.run(sim.until * U::ms, sim.dt * U::ms); } catch (...) { ImGui::OpenPopup("Error"); } diff --git a/src/loader.cpp b/src/loader.cpp index d25a97f..06e6c31 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -14,6 +14,7 @@ namespace io { loaded_morphology load_swc(const std::filesystem::path &fn, std::function &)> swc_to_morph) { + return { swc_to_morph(arborio::parse_swc(slurp(fn)).records()), {{"soma", "(tag 1)"}, {"axon", "(tag 2)"}, @@ -22,8 +23,21 @@ loaded_morphology load_swc(const std::filesystem::path &fn, {}}; } -loaded_morphology load_neuron_swc(const std::filesystem::path &fn) { return load_swc(fn, arborio::load_swc_neuron); } -loaded_morphology load_arbor_swc(const std::filesystem::path &fn) { return load_swc(fn, arborio::load_swc_arbor); } +loaded_morphology load_neuron_swc(const std::filesystem::path &fn) { + auto loaded = arborio::load_swc_neuron(fn); + loaded_morphology res{.morph=loaded.morphology}; + for (const auto& [k, v]: loaded.labels.regions()) res.regions.emplace_back(k, to_string(v)); + for (const auto& [k, v]: loaded.labels.locsets()) res.locsets.emplace_back(k, to_string(v)); + return res; +} + +loaded_morphology load_arbor_swc(const std::filesystem::path &fn) { + auto loaded = arborio::load_swc_arbor(fn); + loaded_morphology res{.morph=loaded.morphology}; + for (const auto& [k, v]: loaded.labels.regions()) res.regions.emplace_back(k, to_string(v)); + for (const auto& [k, v]: loaded.labels.locsets()) res.locsets.emplace_back(k, to_string(v)); + return res; +} loaded_morphology load_neuroml_morph(const std::filesystem::path &fn) { arborio::neuroml nml(slurp(fn)); @@ -33,8 +47,8 @@ loaded_morphology load_neuroml_morph(const std::filesystem::path &fn) { if (!morph_data) log_error("Invalid morphology id {} in NML file."); auto morph = morph_data.value(); loaded_morphology result{.morph=morph.morphology}; - for (const auto& [k, v]: morph.groups.regions()) result.regions.emplace_back(k, to_string(v)); - for (const auto& [k, v]: morph.groups.locsets()) result.locsets.emplace_back(k, to_string(v)); + for (const auto& [k, v]: morph.labels.regions()) result.regions.emplace_back(k, to_string(v)); + for (const auto& [k, v]: morph.labels.locsets()) result.locsets.emplace_back(k, to_string(v)); return result; } @@ -46,8 +60,8 @@ loaded_morphology load_neuroml_cell(const std::filesystem::path &fn) { if (!morph_data) log_error("Invalid cell id {} in NML file."); auto morph = morph_data.value(); loaded_morphology result{.morph=morph.morphology}; - for (const auto& [k, v]: morph.groups.regions()) result.regions.emplace_back(k, to_string(v)); - for (const auto& [k, v]: morph.groups.locsets()) result.locsets.emplace_back(k, to_string(v)); + for (const auto& [k, v]: morph.labels.regions()) result.regions.emplace_back(k, to_string(v)); + for (const auto& [k, v]: morph.labels.locsets()) result.locsets.emplace_back(k, to_string(v)); return result; } diff --git a/src/loader.hpp b/src/loader.hpp index 2784cd8..3384804 100644 --- a/src/loader.hpp +++ b/src/loader.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/src/recipe.hpp b/src/recipe.hpp index b2455f2..6d8af70 100644 --- a/src/recipe.hpp +++ b/src/recipe.hpp @@ -22,7 +22,7 @@ struct recipe: arb::recipe { std::any get_global_properties(arb::cell_kind) const override { return properties; } }; - +inline recipe make_recipe(const arb::cable_cell_global_properties& properties, const arb::cable_cell& cell) { recipe result; diff --git a/src/simulation.hpp b/src/simulation.hpp index 9ce4330..718e2e5 100644 --- a/src/simulation.hpp +++ b/src/simulation.hpp @@ -5,9 +5,9 @@ #include #include "id.hpp" -#include "utils.hpp" struct trace { + std::string tag; id_type id; size_t index; double location; @@ -15,6 +15,10 @@ struct trace { bool show = true; std::vector times; std::vector values; + + trace(const std::string t, const id_type i, size_t x, const double l, const size_t b): + tag{std::move(t)}, id{i}, index{x}, location{l}, branch{b} + {} }; @@ -25,7 +29,8 @@ struct simulation { bool should_run = false; bool show_trace = false; - std::unordered_map traces; + std::unordered_map tag_to_id; + std::vector traces; }; void gui_sim(simulation&);