Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbor cable cell exporter and backend #393

Merged
merged 53 commits into from
Jan 17, 2023

Conversation

lukasgd
Copy link
Contributor

@lukasgd lukasgd commented Apr 7, 2022

I'm working on an Arbor cable cell exporter for BluePyOpt optimized cell models (related to arbor-sim/arbor#1839) and looking for feedback here.

I've added a create_acc module analogous to create_hoc in bluepyopt.ephys. It works with the simplecell and l5pc examples. Using generate_acc.py in the corresponding example folder, you can output a cell with optimized parameters to 3 files (plus morphology) - a JSON file for metainformation that references a morphology file as well as two ACC files - one for the decor and one for the label dictionary. The output of running

$ BluePyOpt/examples/simplecell/generate_acc.py -o <output-dir>

is

$ tree <output-dir>
<output-dir>
├── simple_cell_decor.acc
├── simple_cell.json
├── simple_cell_label_dict.acc
└── simple.swc

0 directories, 4 files

with file contents

  • simple_cell.json
{ 
  "cell_model_name": "simple_cell",
  "produced_by": "Created by BluePyOpt(1.12.5) at 2022-04-06 18:17:54.383572", 
  "morphology": "simple.swc",
  "label_dict": "simple_cell_label_dict.acc",
  "decor": "simple_cell_decor.acc"
}
  • label_dict.acc
(arbor-component
  (meta-data (version "0.1-dev"))
  (label-dict 
    (region-def "all" (all)) 
    (region-def "apic" (tag 4)) 
    (region-def "axon" (tag 2)) 
    (region-def "dend" (tag 3)) 
    (region-def "soma" (tag 1)) ))
  • decor.acc
(arbor-component
  (meta-data (version "0.1-dev"))
  (decor
    (paint (region "soma") (membrane-capacitance 1))
    (paint (region "soma") (density (mechanism "hh" ("gnabar" 0.10299326453483033) ("gkbar" 0.027124836082684685))))))

For the l5pc the output is more comprehensive (obtained analogously with BluePyOpt/examples/l5pc/generate_acc.py).

$ tree <output-dir>
<output-dir>
├── C060114A7.asc
├── l5pc_decor.acc
├── l5pc.json
└── l5pc_label_dict.acc

with an analogous JSON and the same label_dict as above, but different decor,

(arbor-component
  (meta-data (version "0.1-dev"))
  (decor
    (default (membrane-potential -65))
    (default (temperature-kelvin 307.15))
    (default (membrane-capacitance 1))
    (paint (region "all") (density (mechanism "pas/e=-75" ("g" 3.0000000000000001e-05))))
    (paint (region "all") (axial-resistivity 100))
    (paint (region "apic") (ion-reversal-potential "na" 50))
    (paint (region "apic") (ion-reversal-potential "k" -85))
    (paint (region "apic") (membrane-capacitance 2))
    (paint (region "apic") (density (mechanism "NaTs2_t" ("gNaTs2_tbar" 0.026145000000000002))))
    (paint (region "apic") (density (mechanism "SKv3_1" ("gSKv3_1bar" 0.0042259999999999997))))
    (paint (region "apic") (density (mechanism "Im" ("gImbar" 0.00014300000000000001))))
    (paint (region "axon") (ion-reversal-potential "na" 50))
    (paint (region "axon") (ion-reversal-potential "k" -85))
    (paint (region "axon") (density (mechanism "NaTa_t" ("gNaTa_tbar" 3.1379679999999999))))
    (paint (region "axon") (density (mechanism "Nap_Et2" ("gNap_Et2bar" 0.0068269999999999997))))
    (paint (region "axon") (density (mechanism "K_Pst" ("gK_Pstbar" 0.97353800000000001))))
    (paint (region "axon") (density (mechanism "K_Tst" ("gK_Tstbar" 0.089259000000000005))))
    (paint (region "axon") (density (mechanism "SK_E2" ("gSK_E2bar" 0.0071040000000000001))))
    (paint (region "axon") (density (mechanism "SKv3_1" ("gSKv3_1bar" 1.0219450000000001))))
    (paint (region "axon") (density (mechanism "Ca_HVA" ("gCa_HVAbar" 0.00098999999999999999))))
    (paint (region "axon") (density (mechanism "Ca_LVAst" ("gCa_LVAstbar" 0.0087519999999999994))))
    (paint (region "axon") (density (mechanism "CaDynamics_E2" ("gamma" 0.0029099999999999998) ("decay" 287.19873100000001))))
    (paint (region "dend") (membrane-capacitance 2))
    (paint (region "dend") (density (mechanism "Ih" ("gIhbar" 8.0000000000000007e-05))))
    (paint (region "soma") (ion-reversal-potential "na" 50))
    (paint (region "soma") (ion-reversal-potential "k" -85))
    (paint (region "soma") (density (mechanism "NaTs2_t" ("gNaTs2_tbar" 0.98395500000000002))))
    (paint (region "soma") (density (mechanism "SKv3_1" ("gSKv3_1bar" 0.30347200000000002))))
    (paint (region "soma") (density (mechanism "SK_E2" ("gSK_E2bar" 0.0084069999999999995))))
    (paint (region "soma") (density (mechanism "Ca_HVA" ("gCa_HVAbar" 0.00099400000000000009))))
    (paint (region "soma") (density (mechanism "Ca_LVAst" ("gCa_LVAstbar" 0.00033300000000000002))))
    (paint (region "soma") (density (mechanism "CaDynamics_E2" ("gamma" 0.00060899999999999995) ("decay" 210.48528400000001))))

Once a cable cell is constructed in Arbor, it's possible to write it to ACC (arbor.write_component) and visually inspect it in the Arbor GUI. For the l5pc example, the ACC output is in l5pc_full_no_mechs.zip (mechanisms removed from decor) and looks as follows:
Screenshot from 2022-04-07 16-03-22

I'm also working on Arbor simulation examples that use these two exported cells.

For the code below, I'd like to mention that I slightly refactored create_hoc by adding two new function calls inside the create_hoc function, so that code from the existing module can be reused in create_acc (using _generate_template_params) and control flow is similar between the two (create_hoc._read_template/create_acc._read_templates). The logic/instructions in create_hoc are unchanged.

The tests intest_create_hoc.py are still succeeding and I've added analogous ones for the JSON/ACC output in test_create_acc.py.

If you have feedback, I'm interested to hear from you.

Copy link

@noraabiakar noraabiakar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Lukas!

bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
# Define BluePyOpt to Arbor region mapping (relabeling locations to SWC convention)
# Remarks:
# - using SWC convetion: 'dend' for basal dendrite, 'apic' for apical dendrite
# - myelinated is unsupported in Arbor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add support for myelinated in Arbor? Do you know how these section are defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not completely sure where this is used (it doesn't seem to be in l5pc). A quick search finds it in several .hoc files in examples/stochkv. Does somebody else have insights on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'myelinated' is a sectionlist we're using in our latest models. It's a cylinder attached to the end of the AIS to prevent boundary effects. It doesn't have channels but just represent a myelinated chunk of axon

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @wvangeit for the explanation. I assume AIS means axon initial segment. Is there an example/morphology with myelinated? Otherwise, I'd suggest to throw an exception for now until we can properly test that in Arbor.

Copy link
Contributor

@wvangeit wvangeit Jun 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have this in open source models yet. But it's fairly simple code though. It's not specified in the morphology file itself, but used in the replace_axon function when constructing the model:

        sim.neuron.h.execute('create myelin[1]', icell)                                                                                                                                                                                 
        icell.myelinated.append(sec=icell.myelin[0])                                                                                                                                                                                    
        icell.all.append(sec=icell.myelin[0])                                                                                                                                                                                           
        icell.myelin[0].nseg = 5                                                                                                                                                                                                        
        icell.myelin[0].L = 1000                                                                                                                                                                                                        
        icell.myelin[0].diam = diams[count-1]                                                                                                                                                                                           
        icell.myelin[0].connect(icell.axon[1], 1.0, 0.0)         

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested - it works with your code above added to replace_axon. I've added the necessary changes to c0af192, but they're currently commented out as I have no way to figure out if the myelin section exists without crashing in Neuron.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, but i wonder if hasattr():
https://www.w3schools.com/python/ref_func_hasattr.asp
would work on icell?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works on myelin and the len(self.icell.myelin) == 1 looks like a bug given that NEURON crashes, complaining that the section was deleted upon accessing e.g. self.icell.myelin[0]. I've added safe support for myelin now in 2c67258.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's look at this in a separate issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #419.

bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
bluepyopt/ephys/create_hoc.py Show resolved Hide resolved
bluepyopt/ephys/models.py Outdated Show resolved Hide resolved
bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
# Define BluePyOpt to Arbor region mapping (relabeling locations to SWC convention)
# Remarks:
# - using SWC convetion: 'dend' for basal dendrite, 'apic' for apical dendrite
# - myelinated is unsupported in Arbor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'myelinated' is a sectionlist we're using in our latest models. It's a cylinder attached to the end of the AIS to prevent boundary effects. It doesn't have channels but just represent a myelinated chunk of axon

bluepyopt/ephys/create_hoc.py Show resolved Hide resolved
bluepyopt/ephys/create_hoc.py Show resolved Hide resolved
bluepyopt/ephys/models.py Show resolved Hide resolved
bluepyopt/ephys/models.py Show resolved Hide resolved
bluepyopt/tests/test_ephys/test_create_acc.py Show resolved Hide resolved
examples/simplecell/simplecell_model.py Show resolved Hide resolved
@wvangeit
Copy link
Contributor

wvangeit commented Apr 8, 2022

Ok, thank you, that already looks nice.
One thing I think would be useful is to have a test that actually runs arbor on the generated code and compares the output with a NEURON simulation.

@lukasgd
Copy link
Contributor Author

lukasgd commented May 16, 2022

Thank you @wvangeit for the review! The tests should pass now. Please let me know if there are open issues. I'll have to prepare an example comparing Arbor with NEURON simulation output (analogous to the Allen tutorial mentioned above).

@wvangeit
Copy link
Contributor

@AurelienJaquier @DrTaDa , after merging master into this PR, some test failed. But I think it's something we recently added?

@DrTaDa
Copy link
Contributor

DrTaDa commented Jun 23, 2022

@wvangeit Indeed, I hardcoded a value for the a test for CMA but it seems that I should use a rtol or atol on the test instead of an equality:
diff: 0.10525059698894752 != 0.10525059698894745

@DrTaDa DrTaDa mentioned this pull request Jun 23, 2022
…ACC-export, demo of simulating protocols in Arbor on simple cell example and validation with Neuron
@lukasgd
Copy link
Contributor Author

lukasgd commented Jul 28, 2022

Ok, thank you, that already looks nice. One thing I think would be useful is to have a test that actually runs arbor on the generated code and compares the output with a NEURON simulation.

The validation of Arbor simulation results with those obtained from Neuron is done for the simple cell example in simplecell_arbor.ipynb. It demonstrates how to run protocols on a cable cell in Arbor, analyzes the obtained voltage traces with eFEL/Arbor's internal spike detector and compares them to Neuron. They seem to agree well both with and without axon replacement. Note that the simulations with axon replacement depend on features that are not yet in an official release of Arbor.

bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
setup.py Outdated Show resolved Hide resolved
bluepyopt/ephys/morphologies.py Outdated Show resolved Hide resolved
@anilbey anilbey closed this Nov 8, 2022
@anilbey anilbey mentioned this pull request Nov 8, 2022
@wvangeit
Copy link
Contributor

wvangeit commented Nov 8, 2022

@lukasgd could you please restore this PR to the state after @anilbey latest changes, or create new PR based on that state. It seems you have overwritten the history and squashed some commits. We should keep the history of this branch intact.
I also think have atomic commits like @anilbey used is a good idea. As a maintainer he will have to maintain the code in the future, so he can decide how he prefers to apply his commits.

@anilbey
Copy link
Contributor

anilbey commented Nov 8, 2022

Hi @lukasgd

which is why I've integrated your ideas in a new commit built on 4148974

Thanks for taking care of the code but we have to respect the principles of this repository (and, in general, OSS development expects that the community respect the maintainers process). The PR author makes the suggestions and the maintainers decide whether to apply them. Each organisation has different ways of working. You cannot enforce them to change their principles. Otherwise people could not have maintained large repositories if each PR author introduced their rules.

(I don't understand how your import function makes a difference and importing Arbor in the bluepyopt

Here making it a function makes a difference. It prevents side-effect caused by the global scope import. Before it was in the global scope. It means it was getting executed whenever someone imports something from the module. E.g. if someone imports from utils import NPEncoder in a repositry, they expect only the NPEncoder to be imported, not some global scope code to be executed. This effect should be avoided.

Before making changes to one, in my opinion a strategy is needed about how to evolve both (e.g. with a common exporter framework).

Having an interface that both hoc and acc adheres to would be good indeed. But the code was not there. Before making changes, first this code must be readable, maintainable, unit testable. I had made some changes to begin us along that path, but by squashing them, this has made the maintenance side of things more difficult - for instance the CI is failing, and it's difficult to track down why.The last state of the repository I left was "good enough" for me to merge for the time being. It means for now this much structuring is enough for the code to be readable and maintainable. In the future when new features come and BluePyOpt becomes more complex, more refactorings will be needed but for now it's okay.

This being said, future improvements are welcome but please respect the style of the repository and the maintainer's time.

Thus, please strive for:

  • Atomic commits
  • Each commit should communicate a single message. (if commit messages contain "and", "also", "as well", that is suspicious)
  • Include unit tests or code that is unit testable so it can be added.

The code you submitted reintroduced some old bugs there.

Although the unit test coverage increased, of course it is possible that my changes might have introduced bugs. If there's a bug, ideally the tests should be catching it, not visual inspection. That's why the unit test coverage must be high. Please inform me on the bug and how to reproduce it so that I can test it and fix it.

You can of course start with the ACC exporter, but it seems inconsistent to only apply it to part of the codebase.

In the future I would like to apply the same exception raising strategy (if it's a python built-in exception like type error then use it. If it's something very specific, then define it) in the other modules as well. However it's not within the scope of this already large PR.

Your contribution is split into very many commits, which made it difficult for me to build on them within reasonable time. Please consolidate your changes into fewer commits in the future (moving large code blocks in a separate commit is helpful, but tens of commits with self-explanatory few-line changes not so much).

It's the maintainers who decide this. Some large repositories even demand machine readable commit messages that includes certain keywords and structure. When I make a PR to a large code-base they have much stricter rules than this and I have to abide their rules because it's their system.

By the way, our small commits idea is not our invention. It comes from the literature and it's widely applicable. Kent Beck, Martin Fowler, Bob Martin etc. have expressed this idea of small, testable, revertible steps (commits) in various books, articles and talks. They are interesting resources.

I once again would like to thank you for your valuable contributions. Apologies if this comment appears overboard. I wanted to clarify our responsibilities to collaborate better.

I created #422 from the previous state of code. The tests pass there. They currently fail here with the newest changes. I think #422 is ready to be merged. You mentioned a bug, what is it? With that fix I can merge #422. Is there something critical you think should be added to #422? For the newer features of course we can have new PRs.

@wvangeit wvangeit reopened this Dec 14, 2022
@anilbey anilbey self-requested a review December 14, 2022 16:59
Copy link
Contributor

@anilbey anilbey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully the final review :)
Overall good.
@brenthuisman, @thorstenhater please see to the feedback.

bluepyopt/ephys/create_acc.py Show resolved Hide resolved
bluepyopt/ephys/create_acc.py Show resolved Hide resolved
bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
point_loc=param.point_loc,
value=cls._param_value(param))
else:
raise CreateAccException(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeError not CreateAccException.

bluepyopt/ephys/create_acc.py Outdated Show resolved Hide resolved
bluepyopt/ephys/create_hoc.py Outdated Show resolved Hide resolved
Comment on lines +322 to +325
def __init__(self, message):
"""Constructor"""

super(CreateHocException, self).__init__(message)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, nothing special is done in init.

bluepyopt/ephys/locations.py Outdated Show resolved Hide resolved
bluepyopt/ephys/locations.py Outdated Show resolved Hide resolved
bluepyopt/ephys/simulators.py Show resolved Hide resolved
@brenthuisman
Copy link

Hi @anilbey thanks for the review! I'm probably not going to get round to addressing it before the break, so I plan to get started first thing next year.

@lukasgd
Copy link
Contributor Author

lukasgd commented Dec 21, 2022

Thanks for the review @anilbey. Please double-check the Arbor import mechanism at bluepyopt/ephys/acc.py. You may want to move it to bluepyopt/ephys/__init__.py or similar according to the previous discussion.

Also, the L5PC create_acc test with axon-replacement is currently failing for me again due to 6th digit after the dot difference in the axon replacement coordinates. This happens when the entire testsuite is run with tox, not when the create_acc tests are run in isolation (then they all pass).

@anilbey
Copy link
Contributor

anilbey commented Dec 23, 2022

Thanks @lukasgd for the changes. I am okay with the import mechanisms.

Also, the L5PC create_acc test with axon-replacement is currently failing for me again due to 6th digit after the dot difference in the axon replacement coordinates. This happens when the entire testsuite is run with tox, not when the create_acc tests are run in isolation (then they all pass).

I see, this happens often with NEURON. One test leaves some global state and the other tests are affected by that state. In tests using NEURON we tolerate it because we know that it is due to NEURON's design. I guess it's also ok for Arbor tests to differ in precision at the 6th digit when not isolated.

This issue can be more important for Arbor, than for us. I.e. if it is not expected that independent runs affect each other, maybe it is something to look at. I don't know.

Like @brenthuisman I will also leave for holidays, let's continue finishing it next year.
Happy holidays :)

@lukasgd
Copy link
Contributor Author

lukasgd commented Jan 4, 2023

Thanks for the feedback, @anilbey. The test suite is fixed now - the altered coordinates in the L5PC morphology with axon replacement instantiated with Neuron were introduced with a version bump of Neuron (v8 to 9) causing test_write_acc_l5pc to fail. I've updated the test reference data to Neuron v9 now.

The main remaining point now that I'm aware of is to integrate the recent updates from the master branch. If the above things need any more work, please let me know.

Copy link
Contributor

@anilbey anilbey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me thanks @lukasgd for the changes

@lukasgd
Copy link
Contributor Author

lukasgd commented Jan 10, 2023

I'm uploading a proposal for merging master here. There are few things that I came across.

First, setting tox' minversion to 4 causes this error for me

dev/BluePyOpt$ tox
ERROR: venv '.tox' in /home/lukasd/src/arbor/dev/BluePyOpt would delete project
Traceback (most recent call last):
  File "/home/lukasd/src/arbor/dev/venv/bin/tox", line 8, in <module>
    sys.exit(cmdline())
  File "/home/lukasd/src/arbor/dev/venv/lib/python3.8/site-packages/tox/session/__init__.py", line 44, in cmdline
    main(args)
  File "/home/lukasd/src/arbor/dev/venv/lib/python3.8/site-packages/tox/session/__init__.py", line 69, in main
    exit_code = session.runcommand()
  File "/home/lukasd/src/arbor/dev/venv/lib/python3.8/site-packages/tox/session/__init__.py", line 186, in runcommand
    provision_tox_venv = self.getvenv(self.config.provision_tox_env)
  File "/home/lukasd/src/arbor/dev/venv/lib/python3.8/site-packages/tox/session/__init__.py", line 137, in getvenv
    raise tox.exception.ConfigError("envdir must not equal toxinidir")
tox.exception.ConfigError: ConfigError: envdir must not equal toxinidir

I didn't set any of these dirs - how do I fix this?

Regarding the updates from master I found the following:

  • it seems to me that create_hoc.py was not updated to account for the newly added param_dependencies. What was the motiavtion for this feature? It seems to come from the LFPy PR, but I can't find any example nor a test with it. Looking at the parameter-scalers code, the dependencies of a parameter can't themselves be inhomogeneous parameters in a semantically correct program, but this is not enforced. Also, the param_dependencies' locations are not used in param.instantiate(), but there is no immediate check that they are the same like the locations of the actual parameter. Are these things checked/documented somewhere?

  • Regarding parameters - I think a clearer distinction between homogeneous and inhomogeneous parameters (or parameter-scalers) would be helpful. NrnSectionParameters are used as homogeneous parameters, whereas NrnRangeParameters are used as inhomogeneous ones (in create_hoc and e.g. the L5PC example). Yet, it seems possible to parameterize a NrnSectionParameter with a NrnSegmentSomaDistanceScaler (resulting in an inhomogeneous parameter) and a NrnRangeParameter with a NrnSegmentLinearScaler (-> homogeneous parameter), correct? Also, NrnSegmentLinearScaler can be invoked with a parameter with nontrivial param_dependencies, which are then ignored though, which seems counterintuitive.

  • I've renamed the newly introduced simulator method sim.set_neuron_variables() to sim.initialize() to be simulator-agnostic as it caused errors in Arbor tests (it even shows up in the optimization library, so I believe it makes sense to have it simulator agnostic).

  • In the future, I think it will be helpful to take care to clearly separate frontend and backend objects. There's a few simulator-specific abstractions exposed to the user now that represent a seemingly equivalent electrophysiological concept like an original Neuron abstraction, though, with the implementation for another simulator. Yet, they're not all combinable. This is probably fine for now, but may become of interest when more simulators/features get added.

@AurelienJaquier
Copy link
Collaborator

@lukasgd about tox, I usually have this error when I have installed a tox with version < 4, while having minversion set to 4 in the tox.ini. Have you tried updating tox to the latest version?

@lukasgd
Copy link
Contributor Author

lukasgd commented Jan 15, 2023

Thanks, @AurelienJaquier - indeed, upgrading tox solved it. I've uploaded new validation runs here. Note that I've used different random parameter samples compared to the ones before, but the findings remain the same.

@lukasgd
Copy link
Contributor Author

lukasgd commented Jan 15, 2023

The tests should pass now as far as my internet connection allows to check. From my side, the PR is ready. Is there anything more that needs to be addressed?

@wvangeit
Copy link
Contributor

Thank you @lukasgd, the tests are indeed working.

@thorstenhater @brenthuisman , one last check, you're ok with the current implementation? Then I'll merge the PR.

@brenthuisman
Copy link

If you are happy and all breakage is addressed, you have my blessing :) Thanks everyone!

@wvangeit wvangeit merged commit af06928 into BlueBrain:master Jan 17, 2023
@wvangeit
Copy link
Contributor

wvangeit commented Jan 17, 2023

Finally merged :-)

Thank you for all the hard work @lukasgd et al.

@lukasgd
Copy link
Contributor Author

lukasgd commented Jan 17, 2023

Thank you for accepting it @wvangeit and thanks to everyone for their contribution and guidance!

brenthuisman pushed a commit to arbor-sim/arbor that referenced this pull request Jan 17, 2023
This is a small PR to track updates in the BluePyOpt API (cf.
BlueBrain/BluePyOpt#393) compared to the v0.8
release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants