ITensorsOpenSystems.jl Developer Guide

This guide will help you get setup with all the tools you need to contribute to the development of the package. We'll assume you have Julia >= 1.9 installed, if you haven't, please see the installation guide.

Development environment

Clone the repo

For this section we'll assume you've been given access to the ITensorsOpenSystems.jl repository.

First clone the repository

$ git clone git@github.com:ITensor-opensystems/ITensorsOpenSystems.jl.git

Then move into the package

$ cd ITensorsOpenSystems.jl

Running the tests

Now you're setup you can try running the tests to make sure everthing required is installed and the tests pass on your system

First we'll start the Julia REPL, activate the package manager and activate the package

$ julia
julia> ]
(@v1.10) pkg> activate .
    Activating project at `~/Documents/ITensorsOpenSystems`

(ITensorsOpenSystems) pkg>

Now you're ready to run the tests

 (ITensorsOpenSystems) pkg> test

Install in dev mode

As you'll be modifying a local copy of the package during development you can install the package in dev mode. Make sure your terminal working directory is the root of the ITensorsOpenSystems.jl repository and then run

$ julia
julia> ]
(@v1.10) pkg> dev .

Pre-commit (optional)

We use pre-commit to ensure commits meet the standards we expect. This tool runs some pre-commit hooks to run linting and formatting checks on the changes being made.

To install the pre-commit hooks run

$ pre-commit install
pre-commit installed at .git/hooks/pre-commit

On the first commit after install you'll see messages telling you the pre-commit environment is being initialized, this will only happen once.

Bypassing pre-commit

If you find that pre-commit is causing issues you can bypass the hook by passing the -n flag when making a commit.

$ git commit -n -m "commit message"

Using Revise.jl

The Revise.jl package allows changes you've made to the source code to become available in you current Julia session. Without Revise you'll need to restart your Julia session each time you make changes. Install the package using the package manager.

julia> ]
(v1.10) pkg> add Revise

When you start a Julia REPL during development the first using statement should be using Revise. This will then enable Revise for the session. Alternatively if you're on Linux/macOS you can make sure Revise is started at the beginning of each Julia session by running

mkdir -p ~/.julia/config/ && echo "using Revise" >> ~/.julia/config/startup.jl

For more information see the documentation.

Contributing

Tutorial driven development

As we've developed ITensorsOpenSystems.jl we've worked with tutorial driven development approach. This means that for each piece of functionality we want to add to the package we first write a tutorial. To do this we write out the function calls we'd like to make and the objects we expect to be returned.

It doesn't matter that those functions don't exist yet, we'll create them once we'll finished a first pass of the tutorial. The interface to each function doesn't have to be perfect on the first pass, write an almost complete tutorial and then start writing the code. As you write the code you'll realise some of the tutorial will need changing.

Work in an iterative way, improving the tutorial and code with each iteration. Once you've completed the code you'll have a complete tutorial that covers all of the new functionality. There shouldn't be any functionality in the project that isn't covered by a tutorial as users have no way of knowing this functionality exists.

Feature branches

As we develop ITensorsOpenSystems we use feature branches as we develop new functionality. Each piece of work should have a GitHub issue associated with it. This makes it easy to track work and discuss design ideas and track progress of the work. Let's create a new feature branch for some work described in issue 42.

We use the devel branch as our development branch, we'll first check it out and pull any recent changes.

$ git checkout devel
$ git pull

Now we're ready to create our branch

$ git checkout -b Iss42/Foo

Here we've created a branch called Iss42/Foo. Starting the branch name with the issue number followed by a couple of descriptive words helps future us and our collaborators understand what's happening where.

Now we've created the branch make your commits, merging in the devel if the branch is longer lived, this helps prevent complicated merge conflicts further down the line.

Once you've finished the feature open a pull request on the ITensorsOpenSystems.jl repository and request a code review.

Adding documentation

All our documentation is contained in Markdown files in a folder structure expected by Documenter.jl.

docs/
    src/
        getting_started/            <- tutorials for users and developers
            installation.md         <- getting ITensorsOpenSystems.jl installed
            ...
        tutorials/                  <- in-depth end-to-end tutorials covering functionality
            tutorial1.md            <- Tutorial covering creating an open quantum system
            ...
        AnalyticSolutions.md        <- API documentation for ChainMappings submodule
        ChainMappings.md            <- API documentation for ChainMappings submodule
        Superfermions.md            <- API documentation for Superfermions submodule
        SplitVectorization.md       <- API documentation for SplitVectorization submodule
        Vectorization.md            <- API documentation for Vectorization submodule
        ...
    .gitignore                      <- tell Git to ignore built documentation
    make.jl                         <- Julia script containing build instructions
    Project.toml                    <- Contains libraries used to create documentation

Tutorials

If you're adding new functionality, create a new tutorial file in the tutorials folder.

API changes

If you're adding functions or objects that will be exported from the package you'll need add these to the API documentation in the file for that module. Let's add a new function to the Superfermions module.

Superfermions.rightapply
Superfermions.leftapply
Superfermions.my_new_function
...

The @docs tag in the Markdown file is part of the syntax used by Documenter.jl when building the documentation. You can read more about that in the documentation.

Building the documentation

Updating make.jl

If you've added any new files to the documentation you'll need to update the makedocs call in the make.jl file. This tells Documenter where to look for the API documentation and tutorials.

For example, to make Documenter.jl aware of a new tutorial you'll need to add it to the Tutorials section. Note that here we use ... to denote lines in the file not shown here.

...

makedocs(
    sitename = "ITensorsOpenSystems",
    format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
    modules = [ITensorsOpenSystems],
    pages = Any[
        "Introduction" => "index.md",
        "API" => [
            "AnalyticSolutions" => "AnalyticSolutions.md",
            "GlobalFunctionApproximation" => "GlobalFunctionApproximation.md",
            ...
        ],
        "Tutorials" => [
            "Open Spin Systems" => "tutorials/tutorial1.md",
            "My new tutorial" => "tutorials/my_tutorial.md",
        ]],
)

...

Build

We're now ready to build the documentation. Ensure your terminal working directory is the docs folder and then run

$ julia --project make.jl

This will build the documentation HTML files and write these to a build folder. Once it's finished you can open the documentation at build/index.html.

Dealing with errors

You may encounter errors such as

[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: ExpandTemplates: expanding markdown templates.
[ Info: CrossReferences: building cross-references.
[ Info: CheckDocument: running document checks.
┌ Error: 1 docstring not included in the manual:
│
│     ITensorsOpenSystems.MatrixConstruction.new_function :: Tuple{Any}
│
│ These are docstrings in the checked modules (configured with the modules keyword)
│ that are not included in canonical @docs or @autodocs blocks.
└ @ Documenter ~/.julia/packages/Documenter/2OZOh/src/utilities/utilities.jl:44

This means we've forgotten to add the MatrixConstruction.new_function function to the list of functions in the MatrixConstruction.md API documentation file.

Writing tests

We need to make sure that each function we add to the package behaves as we expect it to. We use the ReTestItems.jl package to run our tests. See their documentation for information on how to write tests using that framework.

Pull request and code review

GitHub allows use to easily review code that's being added to the project. We've setup the repository to only allow merging of changes if they've passed a code review and have been given approval by a maintainer. This is an important process to ensure that

  • code is understood by others
  • code adheres to the standards expected
  • code is well documented

This isn't meant to be a hurdle to contributing, it helps everyone better understand new features.

GitHub Actions CI/CD

As part of the pull request the GitHub Actions runners will run some checks to make sure the code meets the standards we expect and that all the tests pass. See the results of our GitHub Actions runners here.