# About this Documentation

This documentation describes the [Open Systems Pharmacology Codebase](https://github.com/Open-Systems-Pharmacology). Its main aim is to facilitate easier onboarding of new developers to OSPSuite platform. Additionally, it functions as a documentation of the design decisions and provides an overview of the Suite.

However, the goal is not to document the implementation per se, developers should be able to use Visual Studio or RStudio to understand those details. Therefore, the goal of this repository is not to duplicate the details of the implementation in written form, but to provide enough detail that a developer starting on the project should be able to more quickly understand the design decisions. That should make it easier to understand the implementation through reading the code itself.


# Initial Resources

You can find an overview of the Open Systems Pharmacology Project [here](https://github.com/Open-Systems-Pharmacology/Suite/blob/develop/README.md). If you want to contribute to OSPSuite, you can find out about ways to do that and instructions on how to submit changes in our [Contribution Guidelines](https://github.com/Open-Systems-Pharmacology/Suite/blob/develop/CONTRIBUTING.md). Also please make sure that you adhere to our [Code of Conduct](https://github.com/Open-Systems-Pharmacology/Suite/blob/develop/CODE_OF_CONDUCT.md).


# OSPSuite Architecture

## Introduction

In this part we will describe the Open Systems Pharmacology Suite, a set of powerful and easy-to-use modeling & simulation tools for pharmaceutical and other life-sciences applications. Qualified and accepted by the scientific community including academia, regulatory agencies and industry. This includes the main parts of the Suite and their architecture. Namely we have the following main components:

* [OSPSuite Core](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core) where the main functionalities of the Suite reside that are common in all other applications.
* [PK-Sim](https://github.com/Open-Systems-Pharmacology/PK-Sim), a comprehensive software tool for whole-body physiologically based pharmacokinetic modeling
* [MoBi](https://github.com/Open-Systems-Pharmacology/MoBi), a software tool for multiscale physiological modeling and simulation that offers more freedom for the user to import and set up models from scratch.

Additionally, [OSPSuite-R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R) is a package that provides the functionality of loading, manipulating, and simulating the simulations created in the Open Systems Pharmacology Software tools PK-Sim and MoBi in the R programming language. There are additional parts to the OSPSuite universe, f.e. [OSPSuite.SimModel](https://github.com/Open-Systems-Pharmacology/OSPSuite.SimModel) that reads the model description in its XML format, creates a differential equations system from it and solves it.

The structure of the OSPSuite Architecture can be visualised as follows:

![The OSPSuite Suite structure](/files/SUPwurzPfA2IyXTP47Of)

## Technology used

The Core of the OSPSuite as well as PKSim and MoBi are written using the .NET Framework currently in version 4.8. The language used is C# 7.3. The architecture is based on the “onion architecture” and the view pattern used is the MVP pattern (Model-View-Presenter, Model-View-ViewModel etc.) The underlying view engine is using Winforms.

Severals third party components are being used in the application:

* DevExpress .Net WinForm Suite. The DevExpress components are used in all views, even for the simplest UI elements such as button or label in order to support skins.
* NHibernate. The ORM is used to serialize the pksim project into a SQLite database.
* Castle. Excellent inversion of control container implementation.
* NUnit. Simple yet powerful unit test framework.
* Npoi. Used to read from and write to xml files.
* FakeItEasy. Used in conjunction with NUnit to mock objects used in tests.
* Microsoft Extensions Logging. Used to log any warnings or error to a log file or to the console when debugging.

## Architecture

The architecture used in PKSim IS NOT based on the traditional layered infrastructure. The traditional layer creates per construction a tight coupling between layers, as each layers depends on the layer beneath it and in general all layers depends on some cross-layer concerns such as security, logging etc usually defined in some kind of “infrastructure” layer.

![Traditional Layered Architecture (image from https://lorifpeterson.com/?p=64)](/files/h3BTXdBwcMIBWqskSBOc)

Instead, an infrastructure pattern was used called “Onion architecture”, that at the time of design of the OSPSuite was quite new and has been gaining popularity ever since.

![Onion Architecture (image from https://medium.com/expedia-group-tech/onion-architecture-deed8a554423)](/files/uFa4SST8c9BWflOoa1Sw)

The idea behind this pattern is fairly simple: In a nutshell, ALL CODE CAN DEPEND ON LAYERS MORE CENTRAL, BUT CODE CANNOT DEPEND ON LAYER FURTHER OUT. The coupling is directed to the center of the architecture. The domain model is always the center of the architecture and thus has no dependencies whatsoever on other layers. In the layer Domain Services, we would typically find interfaces providing serialization behavior. The implementation however would be on the outside of the architecture (Infrastructure) as the serialization involved databases or xml manipulations that have no place in the core.

![Onion Architecture (image from https://jeffreypalermo.com/2008/07/the-onion-architecture-part-2/)](/files/qZnrxjK4TkNdIApHawVG)

In this example, the `IConferenceRepository` interface is defined as a DomainServices that can thus be accessed from all presenters of the application. The implementation however resides in Infrastructure.

This architecture relies HEAVILY on the use of the [Dependency Inversion Principle](http://en.wikipedia.org/wiki/Dependency_inversion_principle).

The application core needs implementation of core interfaces, and if those implementing classes reside at the edges of the application, we need some mechanism for injecting that code at runtime so the application can do something useful.

In OSPSuite, we did not have the need to separate Application Services from Domain Services. We just use services. But the concept remains the same.

You can refer to the description of the onion architecture from the time of the original design of OSPSuite [part1](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/) , [part2](http://jeffreypalermo.com/blog/the-onion-architecture-part-2/) , [part3](http://jeffreypalermo.com/blog/the-onion-architecture-part-3/) and [part4](https://jeffreypalermo.com/2013/08/onion-architecture-part-4-after-four-years/) for more information on this design patterns. Since the adoption of the onion architecture from OSPSuite, it has become ever more popular. You can also refer to the 2022 article about the onion architecture [here](https://medium.com/expedia-group-tech/onion-architecture-deed8a554423).

## OSPSuite.Core Project Structure

As discussed above the OSPSuite is mainly divided between three solutions. We will begin with [OSPSuite Core](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core) that contains all the common functionalities. The OSPSuite.Core solution has been separated in several projects reflecting the different concerns of the application:

![The OSPSuite.Core solution structure](/files/lgancJ3wYweX9WCPEUuU)

### OSPSuite.Assets

All strings displayed in the UI (captions, menus, tooltips, errors, warning, messages) and are common to both PK-Sim and MoBi. They are stored in one file call UIConstants. Although not implemented yet, this structure would enable the application to be used in different languages. It is required however to always define new strings in this file, and NEVER in the designer.

### OSPSuite.Assets.Images

In this project we define all the icons and images that are common to both PK-Sim and MoBi.This component has no other dependencies. It provides two static classes, ApplicationIcons and ApplicationImages that can be accessed throughout the presenter or UI layer to display icons and images.

### OSPSuite.Core

![The OSPSuite.Core project structure](/files/ckwwU9Sx6QLCSAauZxaj)

This is the central component of the infrastructure. It contains various namespaces:

* The namespace Commands contains all the commands that can be executed in OSPSuite and are common to both PK-Sim and MoBi. The command can be added in the history
* The namespace Events contains the application wide events that will be thrown using the EventPublisher.
* The namespace Extensions contains extension method that are not defined for specific ospsuite objects(methods on strings or object etc..)
* The namespace Mappers contains mapping object converting one core object into another core one.
* The namespace Import contains functionalities necessary for the importing of Excel and .csv files.
* The namespace Model contains the business objects of the application such as Simulation,Compound , Individual etc.
* The namespace Reporting contains the report items objects used to generate on the fly reports and tool tips for mode objects
* The namespace Services contains the services and tasks defined in the application and acting on the domain objects. All services interfaces are defined in this namespace. Implementation however can be found in another project. (see onion architecture). For instance, the ILazyLoadTask is defined in Services. The implementation LazyLoadTask is found in the infrastructure.

Objects defined in OSPSuite.Core are registered in the IoC container using a special PKSimRegistrationConvention convention: The code is well commented and should be studied for more information.

### OSPSuite.Infrastructure and OSPSuite.Infrastructure.\* projects

This layers contains all serialization code, from database initialization, Export and Import of Excel files, to ORM Mapping with NHibernate. It is divided in multiple projects named accordingly. The serializers for commands and model objects are also defined in this assembly as well as the project converter specifics. You can find more detailed documentation of the Serialization and its uses [here](/.net-code-specifics/serialization) and also for the Commands [here](/.net-code-specifics/commands).

### OSPSuite.Presentation

![The OSPSuite.Presentation project structure](/files/aJGbnMdHRHEOBiCsbWMi)

This is our presentation layer. It contains of course our presenters, but also the UICommands, DTOs and DTOMappers Charts Diagrams, View interfaces and more.

### OSPSuite.R

![The OSPSuite.R project structure](/files/ZWZfG7ozF7lKw2rVPOHT)

Here we have all our functionalities for the interfacing with R programming language, through OSPSuite.R. As part of the necessary preparation of this communication, it contains some side-effect-free classes and also minimal implementations of interfaces necessary for the software to run, that are never going to be called in the R context, as well as their registrations. The minimal implementations are all contained in the MinimalImplementations folder. An obvious example for this is the `OSPSuite.R.MinimalImplementations.DialogCreator` minimal implementation of `IDialogCreator`.

### OSPSuite.Starter

This is a test project that you can set as a startup project and run as a desktop application. It should be used to user test functionalities that exist in OSPSuite.Core, without needing to open one of the solutions.

### OSPSuite.UI

![The OSPSuite.UI project structure](/files/47u4tr0yJdtw1NxBmL1F)

All Views and controls used in OSPSuite and common to both PK-Sim and MoBi are defined in this layer. No business logic whatsoever should be defined in this component. Any advance UI Logic should be moved to the presenter. Each view should be associated with a presenter, even the most basic view, as again, NO LOGIC SHOULD BE DEFINED IN THE VIEW.

### Unit tests in OSPSuite

Unit testing is an integral part of our software practices and we keep the code that we write well covered by tests. All the solutions contain multiple tests, that are mainly divided into unit tests and integration tests. Apart from the brief description of the OSPSuite.Core unit test projects in the following paragraphs, you can find a comprehensive documentation of our unit testing methods and best practices [here](/.net-code-specifics/unit-and-integration-testing).

### OSPSuite.InfrastructureTests

This project contains unit tests for the functionalities in all the Infrastructure projects. The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`.

### OSPSuite.PresentationTests

This project contains unit tests for the functionalities in the infrastructure layer. The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`.

### OSPSuite.UITests

This project contains unit tests for the functionalities in the UI layer. The tests in this project also implement the `OSPSuite.BDDHelper.ContextSpecification<T>`

### OSPSuite.IntegrationTests

This project contains all the integration tests ever written for OSPSuite. The folder Data contains some external files (mainly excel and pkml files) that are used in the Integration tests.

In the tests of this project we are extending `OSPSuite.Core.ContextForIntegration<T>`. It registers almost all dependencies as the real OSPSuite applications would do, with the exception of a few objects like license or dialog creator. It is the perfect base class to use when testing real uses cases using the database etc… Execution time is much longer than a standard unit test.

## PKSim Project Structure

![The PKSim solution structure](/files/AHXuDRxnyZ6WPgEumTnB)

In this solution we have the code that is exclusive for the PK-Sim application.

### PKSim.Assets and PKSim.Assets.Images

Just like the equivalent projects in OSPSuite.Core, these two projects contain the UI strings, images and icons that are used exclusively for the PK-Sim application. Any new string used in the UI should be defined here.

### PKSim.Core

Contains the main functionalities of the PK-Sim application.

### PKSim.Infrastructure

This layers contains all code on serialization, project conversion, ORM Mapping with NHibernate and reporting that is specific to PKSim and is not included in OSPSuite.Core.Infrastructure and the OSPSuite.Core.Infrastructure.\* projects.

### PKSim.Presentation

It is the Presentation Layer specific for the PK-Sim application. Just like its equivalent in OSPSuite.Core, contains presenters, but also View Interfaces, DTOs and DTO mappers, UICommands and more. It has to be stressed that here should only be present the aforementioned elements that are unique to PK-Sim - elements of that type that are also common for MoBi should be added in OSPSuite.Core.Presentation.

### PKSim.UI

Contains all Views and Controls specific only to the PK-Sim application. UI elements shared with MoBi exist in OSPSuite.Core.UI.

### PKSim.CLI

In this project we have code that enables the PKSim to be used from the command line. This can be used f.e. for task automatizations using projects and snapshots as input. It is also being used by the [InstallationValidator](https://github.com/Open-Systems-Pharmacology/InstallationValidator).

### PKSim.CLI.Core

Contains code of the main functionalities of the CLI. Here we also have the minimal implementations of interfaces that are necessary for the OSPSuite code to run, but that we know that we are not going to be using in the command line scenario and thus they are not fully implemented. An obvious example for that would be the `CLIDialogCreator` minimal implementation of `IDialogCreator`.

### PKSim.BatchTool

Contains all the code related to the Batch Tool, that provides a graphic interface for the user to run PK-Sim tasks on json based PK-Sim simulations in batches. It can also be used to create a new project from snapshots and vice versa. It contains the necessary presenters, views and DTOs for this.

### PKSim.R

This project contains the code necessary for the communication between PK-Sim and R through the [ospsuite-R package](https://github.com/Open-Systems-Pharmacology/OSPSuite-R).

### PKSim.Tests

This projects contains unit tests for various aspects of the PKSim sourcecode, such as Infrastructure, Presentation, PKSim.Core etc. The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`, except for the Integration Tests that implement `PKSim.IntegrationTests.ContextForIntegration<T>` which is written specifically for setting up an environment and registering all the dependencies necessary to run integration tests in PK-Sim.

### PKSim.UI.Tests

Contains tests for the UI elements of PK-Sim. The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`.

### PKSim.Matlab

This dll should be used directly from Matlab to automate some PKSim tasks such as individual or population creation etc.

## MoBi Project Structure

![The MoBi solution structure](/files/etgeq1XuakMBIsI7Kbkc)

### MoBi project

Here we have the entry point of the MoBi application and some other things, like pkml Templates and Chart Layouts.

### MoBi.Assets

This project contains UI strings, images and icons that are used exclusively for the Mobi application. Any new string used in the UI should be defined here.

### MoBi.Core

Contains the main functionalities of the MoBi application, that are distinct from what is defined in OSPSuite.Core.

### MoBi.Engine

Contains the [SBML](https://sbml.org/) importer and engine for MoBi.

### MoBi.Presentation

It is the Presentation Layer specific for the MoBi application. Just like its equivalent in OSPSuite.Core, contains presenters, but also View Interfaces, DTOs and DTO mappers, UICommands and more. It has to be stressed that here should only be present the aforementioned elements that are unique to MoBi - elements of that type that are also common for MoBi should be added in OSPSuite.Core.Presentation.

### MoBi.UI

Contains all Views and Controls specific only to the MoBi application. UI elements shared with MoBi exist in OSPSuite.Core.UI.

### MoBi.Tests

This projects contains unit tests for various aspects of the MoBi sourcecode, such as Infrastructure, Presentation, PKSim.Core etc. The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`, except for the Integration Tests that implement PKSim.MoBi.IntegrationTests.ContextForIntegration which is written specifically for setting up an environment and registering all the dependencies necessary to run integration tests in MoBi. Also contains helper functions for those tests, mainly for creating objects to be used in the tests, like f.e. a `DimensionFactory`.

### MoBi.UI.Tests

Contains tests for the UI elements of MoBi The tests in this project implement the `OSPSuite.BDDHelper.ContextSpecification<T>`.

## PK-Sim Database

PK-Sim uses an SQLite database to store species, population etc. You can find a thorough documentation of the database and its tables [here](/pk-sim-database/db).

## Additional components and further reading

Additionally to these three main solutions, more components are being used in the OSPSuite as mentioned above.

You can read more about the [OSPSuite.SimModel](https://github.com/Open-Systems-Pharmacology/OSPSuite.SimModel) ( that as mentioned above reads the model description in its XML format, creates a differential equations system from it and solves it), and specifically about how to find memory leaks in it here:

[Finding Memory Leaks](/sim-model/finding-memory-leaks)

You can read about the algorithm used for the creation of an individual in this part of the documentation:

[Algorithm for Individual Creation](/algorithms/algorithm-for-individual-creation)

The functionalities of OSPSuite can be used in the R programming language through the [OSPSuite-R package](https://www.open-systems-pharmacology.org/OSPSuite-R/). You can go through a comprehensive documentation of how to install and use the package [here](https://www.open-systems-pharmacology.org/OSPSuite-R/). You can also find a more detailed description of the code structure for the package as part of this documentation [here](/r-development-resources/r-code-structure).For installing under various systems you can also refer to the current \[documentation]:

[Setup OSPSuite-R on Windows Or Ubuntu](/ospsuite-r-setup/setup-ospsuite-r-on-windows-or-ubuntu)

Concerning the data binding, there are two separate OSPSuite solutions that contain functionality that enables us to bind data to UI elements. You can read all about that [here](/.net-code-specifics/data-binding).


# Git Workflow

## Git Workflow

### Introduction

In this part of the documentation we will present the internal structure of the git repositories of OSPSuite, as well as the strategy for naming the branches and creating releases.

## General

The proposed workflow will use `git merge` and `git rebase` for different tasks. Our goal is to establish a workflow that will ensure a clean and useful public history graph. The public history should be concise yet clear and reflect the work of the team in a cohesive way.

We will use `git merge` to incorporate the entire set of commit of one branch (typically the `develop` branch) into another one (typically `master`).

We will use `git rebase` for all other type of code integration (sub tasks of a given swim lane etc..).

## Definition

* The `master` branch is the ultimate source of truth. It should always be possible to use the code on `master` and create a production setup.
* The `develop` branch is the branch where the development is taking place. Ultimately, when a new release is created, the commits in `develop` will be merged back into `master`.
* A `feature` branch is a short lived branch that is used during the implementation of a given task. It will be deleted once the feature is implemented and merged into `develop`.
* The git version to use is `1.8.5` or newer. This will allow the setting of the configuration option `git pull -rebase = preserve`. This option specify that *on pull, rebase should be used instead of merge*. But incoming merge commit should be preserved.
* Unless required otherwise, all work should be performed on a fork of the repository. A *Pull Request (PR)*, will be used to incorporate changes into the `develop` branch.

## Use Case: Implementing Task "426 it should be possible to delete observed data"

*Note:* A task is a cohesive unit of work. This can be part of a bigger feature or a bug fix. We assume that a fork of the repository has already been created.

1. Create a `feature` branch with a **meaningful name**, **starting with the id of the task**. We will need to acquire the latest changes from the remote `develop` branch first and then create the feature branch

* With option git pull -rebase = preserve

```
git checkout develop
git pull upstream #<= git fetch upstream develop && git rebase -p upstream/develop
git checkout -b 426-delete-observed-data
```

* Without option git pull -rebase = preserve

```
git checkout develop
git fetch upstream develop
git rebase -p upstream/develop
git checkout -b 426-delete-observed-data
```

2. Do work in your `feature` branch, committing early and often.
3. Rebase frequently to incorporate any upstream changes in the `develop` branch (to resolve conflicts as early as possible)

```
git fetch upstream develop
git rebase -p upstream/develop
```

4. Once work on the feature is complete, you are ready to create a PR. The first step is to push the code to your own repo and then create a PR onto the original repo for review:

```
git fetch upstream develop
git rebase -p upstream/develop
git push -u origin 426-delete-observed-data
```

At that stage, your local branch `426-delete-observed-data` is set to track the remote branch `426-delete-observed-data` so you will be able to use the simple `git push` command from now on to update your repo.

5. Create pull request on github so that your change may be reviewed. The pull request should be between the `develop` branch on the `upstream` repo and the `feature` branch on your `fork`. The PR message **should** use the task id and the whole description of the task. For example `Fixes #426 it should be possible to delete observed data`.
6. Upon code review, you may have to change the code slightly to take reviewer comments and concerns into account. If so just continue committing your work on your local `426-delete-observed-data` branch and repeat the steps above.
7. Once the latest push has been accepted and all tests are passing, the reviewer can accept the pull request by using the `Squash and Merge` option. This will effectively squash all your commit into one and rebase the one commit from `426-delete-observed-data` onto `develop`.
8. Delete your remote branch `426-delete-observed-data` as it is not required anymore
9. Locally you can now repeat the synchronization of your develop branch

```
git checkout develop
git pull upstream
```

10. Your local `426-delete-observed-data` can also be deleted.

```
git branch -d 426-delete-observed-data
```

11. Optionally you may wish to remove any pointers locally to remote branch that do not exist anymore

```
git remote prune origin
```

12. A useful alias can be created in git to avoid repeating the same commands again and again for synchronizing remote `develop` branch with local `feature` branch.

```
[alias]
 sync  = !git fetch upstream $1 && git rebase upstream/$1
 syncd = !git sync develop
```

Simply call `git syncd` to synchronize changes with the `develop` branch. To synchronize with an hypothetical other branch called `experience`, use `git sync experience`

## Use Case: Creating a new release 6.5.1

The work on the `develop` branch is finished and we are ready to tag the version officially. A tagged version will be a version that has been approved for work in production.

This is extremely simple with github using the concept of release.

1. Click on the `releases` section from the `Code` tab
2. Click on `Draft new release`
3. Pick the `develop` branch or the latest commit on `develop` corresponding to the commit to tag
4. Name the tag `v6.5.1`.
5. Give a meaningful name to the release `Release 6.5.1`
6. Optionally enter a description in the description field. This is typically where release notes should be written using the power of markdown. Files can also be attached to the description (manual, notes etc)
7. Publish release! *Great job*

## Use Case: Creating a hot fix

Release 6.5.1 has been out for a few weeks and a nasty bug (issue 756 on the bug tracking system) was reported that can corrupt a project file. We need to create a hot fix asap to address the issue. The hot fix should be applied to 6.5.1 obviously, but the actual fix should also be pushed to other branches such as `develop`

1. Create a branch based on the tag and create a new branch to collect all fixes for the hotfix

```
git fetch upstream
git checkout tags/v6.5.1 -b hotfix/6.5.2
git push -u upstream hotfix/6.5.2
```

2. Create a branch for the one issue to solve

```
git checkout -b 756-project-corrupted
```

3. Implement hot fix in this local branch
4. Push commit to start the code review process

```
git sync hotfix/6.5.2
git push origin 756-project-corrupted
```

5. After completed review, rebase PR into `hotfix/6.5.2`
6. Repeat for all issues that will be part of the hotfix (one or more)
7. Create release off of `hotfix/6.5.2` called Release `6.5.2` with tag `v6.5.2`
8. Merge branch `hotfix/6.5.2` into `develop` (fixing potential conflicts if any)
9. Delete branch `hotfix/6.5.2`


# C# Coding Standards

## Visual Studio Settings

* Use indentation of 3.
* Use spaces instead of tabs.
* If using Resharper, make sure a Resharper settings file is available to format your code.

## Naming Convention

Use meaningful and understandable names. Code should read as a story and only some well known abbreviations such as DTO, PK etc. should be used.

### Classes and Methods

* Use **Pascal Casing** for class name `public class SomeClass`.
* Use **Pascal Casing** for public and protected method name `public void SomeMethod()`.
* Use **Camel Casing** for private method name `private int somePrivateMethod()`.
* Prefix interface with I `public interface IMyInterface`.
* Suffix exception classes with Exception `public class SBSuiteException: Exception`.

### Variables

* Prefix private/protected member variable with `_` (underscore): `private int _parentContainerId`.
* Use **ALL\_CAPS Casing** for constant variables: `public const double DEFAULT_PERCENTILE = 0.5;`.
* Use **Camel Casing** for local variable names and method arguments: `int ingredientNode`.
* All members variable should be declared at one place of a class definition.
* Prefer variables initialization at the point of declaration .
* Do not use public members. Use properties instead.
* Do not use Hungarian notation (e.g. b for boolean, s for strings etc.).
* Except for program constants, never use global variables.

### Comments

* Do not comment the obvious
* Indent comment at the same level of indentation as the code you are documenting
* All comments must be written in English
* Do not generate comments automatically
* Do comment algorithm specifics. For example, why your loop starts at index 1 and not at 0.
* If a lot of comments are required to make a method easier to understand, break down the method in smaller methods
* Really, do not comment the obvious

## Coding Style

* No hard coded strings and magic number should be used. Declare a constant instead.
* Method with return values should not have side effects unless absolutely required.
* Exit early instead of having nested if statements.

  For example, instead of

  ```
  public void UpdateValue(bool isVisible, bool isEditable, double value)
  {
    if(isVisible)
    {
      if(isEditable)
      {
        _value = value;
      }
    }
  }
  ```

  use

  ```
  public void UpdateValue(bool isVisible, bool isEditable, double value)
  {
    if(!isVisible || !isEditable)
      return;

    _value = value;
  }
  ```
* Do not write `if` statements in one line.
* Do not write `for` and `forEach` statements in one line.
* Always use block `{}` for `for` and `forEach` statements.
* Always have a default case for `switch` statement, potentially throwing an exception if the default is unreachable.

## **Best Practices**

### DOs

* Use IReadOnlyList/IReadOnlyCollection as return type or parameter of your public APIs instead of IEnumerable.
* Create methods such as *Add*, *Remove* in your class if you need to modify an internal list instead of exposing the list to the outside world.

### DON'Ts

* Do not use IList/List as a return type or parameter of public APIs (methods or class member). By using those, you are breaking encapsulation and anyone can modify the list which makes debugging very hard.
* Do not use ICache/IDictionary as return type or parameter of public APIs. By doing so, you are duplicating the knowledge of how the key is constructed. This is also a break in encapsulation. Create your own class derived from Cache if you need to use a Cache construct as part of API.


# Setting up the developer environment for C\#

## Installing the prerequisites

1. Install the latest Visual Studio Community Edition or better. [Visual Studio Install](https://www.visualstudio.com/downloads/)
2. Install Ruby and Rake. [Ruby Install](https://rubyinstaller.org/downloads/)
3. Obtain Devexpress License and Install
   * DevExpress WinForms Controls and Libraries is used in the graphical user interface of the suite. You will need to obtain a license in order to work with the user interface.
   * DevExpress only provides trials on their current product offering, so you may have to acquire the license prior to downloading an older version if that's required to build the suite.
   * Obtain your license from DevExpress [DevExpress Order](https://www.devexpress.com/Support/Order/). Then get the installer for the version mentioned above that's required [DevExpress Install](https://www.devexpress.com/ClientCenter/DownloadManager/)
4. Install nuget.exe and ensure that it is in your `PATH` variable [NuGet Install](https://dist.nuget.org/index.html)
5. Add `OSPSuite.Core` as a nuget source using the following command

```
  nuget sources add -name OSP-GitHub-Packages -source https://nuget.pkg.github.com/Open-Systems-Pharmacology/index.json
```

## Building and Running

1. Clone the repository locally (either from the open-systems-pharmacology organization or from your own fork)
2. For PK-Sim and MoBi, run the `postclean.bat` command

   There are several requirements to running the software that are not automatically performed when building with Visual Studio. An automated `postclean` batch file is used to take care of these tasks.
3. Compile Source
4. Run Tests
5. Run the Application

## Useful Tips

1. The suite is using GitHub Actions as a CI server which also provides a nuget feed that should be registered on your system. This will prevent you from having to enter GitHub password with each new instance of Visual Studio.

```
nuget sources add -Name OSP-GitHub-Packages -source https://nuget.pkg.github.com/Open-Systems-Pharmacology/index.json -User <GITHUB USERNAME> -Password <PERSONAL ACCESS TOKEN>
```

or

```
dotnet nuget add source --username <GITHUB USERNAME> --password <PERSONAL ACCESS TOKEN> --store-password-in-clear-text --name OSP-GitHub-Packages "https://nuget.pkg.github.com/Open-Systems-Pharmacology/index.json"
```


# Setup OSPSuite-R on Windows Or Ubuntu

Follow the instructions provided in the [repository README](https://github.com/Open-Systems-Pharmacology/OSPSuite-R#ospsuite-r-package). Be sure to follow instructions for the prerequisites


# R Development Collaboration Guide

This guide describes how to contribute to, review, and release OSPS R packages. It is intended for contributors, reviewers, and maintainers of the OSPS R projects.

## Contents

* [Rules](#rules)
* [Prerequisites](#prerequisites)
* [Contributing changes](#contributing-changes)
* [Reviewing a pull request](#reviewing-a-pull-request)
* [Releasing versions](#releasing-versions)

## Rules

The following set of rules should be followed by all contributors and checked by all reviewers of the OSPS R projects.

1. Each change made to the codebase should have a clear purpose and exist in an isolated context.\
   1.1 Each change should be related to an issue created on the project's repository.\
   1.2 Each change should be made in a separate branch.\
   1.3 Each change should be proposed through a pull request.
2. Each change or addition to the code should be documented and controlled.\
   2.1 Each change that affects **user experience or outputs** should be reflected in the documentation. If documentation is not present, then it should be created.\
   2.2 Each change should be tested. If new cases emerge, then they should be tested, even if some tests are already present. If no tests are present, then they should be created.
3. Each change should be easily reviewable, understandable, and traceable.\
   3.1 Each change that affects **user experience or outputs** should have a corresponding entry in the `NEWS.md` file.\
   3.2 Each change should be associated with a pull request whose scope is limited to the change itself.
4. Each change must respect the coding style of the project.\
   4.1 Each change must respect the coding style of the project as defined in the [R Coding Standards](/r-development-resources/coding_standards_r).\
   4.2 Each change must be processed by the [`air`](https://posit-dev.github.io/air/) formatter before being proposed.
5. Each change should be reviewed before being merged.\
   5.1 Each change should be reviewed by at least one other contributor through its associated pull request.\
   5.2 Each change should be functional and comply with these rules before its associated pull request is set as "ready for review". If not ready or reviewer inputs are needed, the pull request should be marked as "draft".

## Prerequisites

The workflows in this guide assume that:

* R and RStudio are installed.
* A GitHub account is available and set up to work with RStudio.
* The `{usethis}` package is installed.
* A local clone (from the original repository or from a fork) has been created.

Releasing a version additionally assumes that the current branch is the default branch (usually `main`).

## Contributing changes

Contributions to the OSPS R projects use the [`{usethis}`](https://usethis.r-lib.org) package and its family of [`pr_*()`](https://usethis.r-lib.org/articles/pr-functions.html) functions.

1. Initialize the branch with `usethis::pr_init("my-branch-name")`.
2. Apply changes in the codebase and save with commits.
3. Add or update tests covering the change.
4. Update `NEWS.md` if the change affects user experience or outputs.
5. Format edited `.R` files with `air format` (or the `air` RStudio addin).
6. Run `devtools::check()` locally and resolve any errors, warnings, or notes.
7. Make a pull request with `usethis::pr_push()`.
8. Address reviewer feedback with new commits, then run `usethis::pr_push()` again.
9. Once the pull request is merged, clean up the local branch with `usethis::pr_finish()`.

**Tips:**

* Get back to the default branch at any moment with `usethis::pr_pause()`.
* Retrieve an open pull request locally with `usethis::pr_fetch(XX)`, where `XX` is the pull request's numerical identifier.

## Reviewing a pull request

Reviewers should verify the following before approving:

* [ ] The pull request is linked to an issue and its scope is limited to that issue (Rules 1.1, 3.2).
* [ ] CI checks pass.
* [ ] Code follows the [R Coding Standards](/r-development-resources/coding_standards_r) and is formatted with `air` (Rules 4.1, 4.2).
* [ ] Tests cover the change and pass locally (Rule 2.2).
* [ ] Documentation (roxygen, vignettes, pkgdown site) reflects user-facing changes (Rule 2.1).
* [ ] `NEWS.md` has an entry when the change affects user experience or outputs (Rule 3.1).
* [ ] The pull request description is clear and the commit history is readable.
* [ ] In the case of an automated AI review of a pull request (e.g., CodeRabbit or GitHub Copilot), all improvements suggested by the AI reviewer must either be fixed or set to "Resolved" with a comment.

## Releasing versions

### Versioning model

OSPS R packages use a two-state versioning model automated by the [`description_manager.yaml`](https://github.com/Open-Systems-Pharmacology/Workflows/blob/main/.github/workflows/description_manager.yaml) reusable GitHub workflow. The workflow runs on each push to the default branch and updates the `DESCRIPTION` file:

* **Release versions** (for example, `0.2.0`) — the version is left untouched, a `v0.2.0` git tag is created, and entries in the `Remotes` field are pinned to `@*release` so the released package depends on released versions of other OSPS packages.
* **Development versions** (for example, `0.2.0.9000`) — the fourth component is auto-incremented on every push to the default branch (`.9000` → `.9001` → ...), no tag is created, and `Remotes` entries remain unpinned.

The `.9000`+ suffix distinguishes in-development builds from released versions; see the [R Packages versioning guide](https://r-pkgs.org/lifecycle.html#sec-lifecycle-version-number) for background.

Because version bumps are automated, contributors **must not** manually edit the version field in `DESCRIPTION` outside of the release workflow described later in this section.

### Pre-release checklist

Before releasing, verify the following on the default branch:

* [ ] All CI checks pass on the latest commit.
* [ ] `devtools::check()` runs locally with no errors, warnings, or notes.
* [ ] The pkgdown site builds cleanly (`pkgdown::build_site()`).
* [ ] `NEWS.md` is up to date and reflects all user-facing changes since the last release.
* [ ] The chosen version number is consistent with [semantic versioning](https://r-pkgs.org/lifecycle.html#sec-lifecycle-version-number) and the nature of the changes (major / minor / patch).

### Creating the release

1. Pick the new version number.

   ```r
   new_version <- usethis:::choose_version("What should the new version be?")
   ```
2. Create a dedicated branch.

   ```r
   usethis::pr_init(branch = paste0("release-v", new_version))
   ```
3. Set the release version in `DESCRIPTION`. Follow the interactive prompts to accept and commit the changes.

   ```r
   usethis::use_version(which = labels(new_version))
   ```
4. Push the local branch and create the pull request.

   ```r
   usethis::pr_push()
   ```
5. Once the pull request is approved and merged, clean up the local branch.

   ```r
   usethis::pr_finish()
   ```

### Publishing the release

1. Wait until all CI/CD actions on the merge commit are validated and completed. The `description_manager.yaml` workflow will:
   * Detect the release version (no `.9000`+ suffix).
   * Pin `Remotes` entries to `@*release`.
   * Create the `v<version>` git tag.
   * Commit the result back to the default branch.
2. Switch to the default branch and pull the latest changes.

   ```r
   usethis::pr_pause()  # if on another branch
   git pull             # from the terminal
   ```
3. Create the release on GitHub.

   ```r
   usethis::use_github_release()
   ```
4. Download the built packages from the GitHub Actions run triggered by the PR merge and attach them to the release. The new version is now fully released.

### Restoring development mode

After the release tag is created, set the next development version. Subsequent pushes to the default branch will be auto-incremented by `description_manager.yaml`.

1. Pick the development version number. Development versions end with `.9000` so that developers and users can easily distinguish them from release versions.

   ```r
   new_version <- usethis:::choose_version(which = "dev")
   ```
2. Create a dedicated branch.

   ```r
   usethis::pr_init(branch = paste0("dev-v", new_version))
   ```
3. Set the development version in `DESCRIPTION`. Follow the interactive prompts to accept and commit the changes.

   ```r
   usethis::use_version(which = labels(new_version))
   ```
4. Push the local branch and create the pull request.

   ```r
   usethis::pr_push()
   ```
5. Once the pull request is approved and merged, clean up the local branch.

   ```r
   usethis::pr_finish()
   ```

From this point on, `description_manager.yaml` auto-bumps the `.9000`+ suffix on every push to the default branch until the next release.


# R Coding Standards

## Coding Standards for R

We will follow the <https://style.tidyverse.org/> style guide with very few changes to benefit from tools supporting this style guide:

* [`air`](https://posit-dev.github.io/air/) — the project formatter.
* [`{lintr}`](https://github.com/jimhester/lintr) — linting.

These coding standards outline the more important aspects of the aforementioned style.

## Modifications from tidyverse Coding Standards

* Naming will use `camelCase` instead of `snake_case`.
* Favor usage of `return()` even when the return value does not need to be specified explicitly.

## RStudio IDE Settings

* Indentation of 2
* Use spaces instead of tabs
* Use UTF-8 text encoding (Ref: <https://yihui.org/en/2018/11/biggest-regret-knitr/>)&#x20;

  <img src="/files/1x9foHZgcX9KQTmdNme8" alt="drawing" width="300">
* Use `{tinytex}` for `LaTeX` compilation (Ref: <https://yihui.org/tinytex/pain/>)&#x20;

  <img src="/files/Cu7ZpaWbxFPhmzo1HO8A" alt="drawing" width="300">
* Use AGG graphics device (Ref: <https://www.tidyverse.org/blog/2021/02/modern-text-features/>)&#x20;

  <img src="/files/AAhdTk2EBUyVvGJu6kVY" alt="drawing" width="300">
* Use a blank slate (there should not be any residue from previous session when you start a new session to ensure long-term reproducibility of the software)&#x20;

  <img src="/files/nfJ5HqQal5sAHzu5VjaM" alt="drawing" width="300">

## Naming Convention

Use meaningful and understandable names. Code should read as a story and only some well known abbreviations (such as pk) should be used.

### Files

File names containing both source code (`/R`) and tests (`/tests`) should follow the kebab-case naming convention and should have `.R` extension.

Do not use special characters (e.g. “µ”, “ß”, …) or blanks in the file names

```r
# bad
DataCombined.R
test-DataCombined.R

# good
data-combined.R
test-data-combined.R
```

### Object names

* Variable and function names should use only lowercase letters and numbers. Use **camelCase** to separate words within a name.
* Class names on the other hand should use **Pascal Casing**.
* True constant variables should use **ALL\_CAPS Casing**.

```r
# Class

Parameter <- R6Class("Parameter", ....)

# Variable

parameterToDelete <- ...

# Method and function

performSimulation <- function (...)

# Constant variables

DEFAULT_PERCENTILE <- 0.5
```

* Do not use Hungarian notation (e.g., g for global, b for Boolean, s for strings, etc.)

### Functions

Prefer using `return()` for explicitly returning result, although you can rely on R to implicitly return the result of the last evaluated expression in a function.

### Comments

* Do not comment the obvious.
* Use comments to explain the **why**, and not the **what** or **how**.
* Indent comment at the same level of indentation as the code you are documenting.
* All comments must be written in English.
* Do not generate comments automatically.
* Do comment algorithm specifics. For example, why would you start a loop at index 1 and not at 0, etc.
* If a lot of comments are required to make a method easier to understand, break down the method in smaller methods.
* Really, do not comment the obvious.

### Documentation

* Use roxygen comments (`#'`) as described [here](http://r-pkgs.had.co.nz/man.html#roxygen-comments).
* Do not include empty lines between the function code and its documentation.

```r
# Good
#' @export
weekend <- list("Saturday", "Sunday")

# Bad
#' @export

weekend <- list("Saturday", "Sunday")
```

* Internal functions, if documented, should use the tag `#' @keywords internal`. This makes sure that package websites don't include these internal functions.
* Prefer using `markdown` syntax to write roxygen documentation (e.g. use `**` instead of `\bold{}`).
* To automate the conversion of existing documentation to use `markdown` syntax, install [roxygen2md](https://roxygen2md.r-lib.org/) package and run `roxygen2md::roxygen2md()` in the package root directory and carefully check the conversion.

### Conventions

* Function names as code with parentheses (good: `dplyr::mutate()`, `mutate()`; bad: *mutate*, **mutate**)
* Variable and (`R6`/`S3`/`S4`) object names as code (good: `x`; bad: x, *x*, **x**)
* Package names as code with `{` (good: `{dplyr}`; bad: `dplyr`, *dplyr*, **dplyr**)
* Programming language names as code (e.g. `markdown`, `C++`)

Note that these conventions are adopted to facilitate (auto-generated) cross-linking in `{pkgdown}` websites.

#### Documenting functions

<http://r-pkgs.had.co.nz/man.html#man-functions>

#### Documenting classes

Reference classes are different across `S3` and `S4` because methods are associated with classes, not generics. RC also has a special convention for documenting methods: the docstring. The docstring is a string placed inside the definition of the method which briefly describes what it does. This makes documenting RC simpler than `S4` because you only need one roxygen block per class.

```r
#' This is my Person class
#' @title Person Class
#' @docType class
#' @description Person class description
#' @field name Name of the person
#' @field hair Hair colour
#'
#' @section Methods:
#' \describe{
#' \item{set_hair Set the hair color}
#' }
#'
#' @examples
#' Person$new(name="Bill", hair="Blond")
#' @export
Person <- R6::R6Class("Person",
  public = list(
    name = NULL,
    hair = NULL,
    initialize = function(name = NA, hair = NA) {
      self$name <- name
      self$hair <- hair
    },

    set_hair = function(val) {
      self$hair <- val
    },
  )
)
```

When referring to the class property (`$name`) or method (`$set_hair()`) in package vignettes, use the `$` sign to highlight that they belong to an object. Note that the method always has parentheses to distinguish it from a property.

If a class has a private method, its name should start with `.` to highlight this (e.g. `$.set_hair_color()`).

## Syntax

### Spacing

Run `air format` (or the `air` RStudio addin) to apply the project's spacing rules. For background on the underlying style, see the [tidyverse style guide on spacing](https://style.tidyverse.org/syntax.html#spacing).

### Global Variables and Constants

* Except for program constants or truly global states, never use global variables. If a global object is required, this should be absolutely discussed with the team.
* No hard coded strings and magic number should be used. Declare a constant instead.

### Booleans

* Avoid using boolean abbreviations (`T` and `F`). Instead, use `TRUE` and `FALSE` (respectively).

### Style

#### Long Lines

Strive to limit your code (including comments and roxygen documentation) to 80 characters per line.

#### Assignments

Use `<-`, not `=`, for assignment.

#### Semicolons

Don't put `;` at the end of a line, and don't use `;` to put multiple commands on one line.

**Note:** All these styling issues, and much more, are corrected automatically by `air format`.

#### Code blocks

* `{` should be the last character on the line. Related code (e.g., an `if` clause, a function declaration, a trailing comma, etc.) must be on the same line as the opening brace.
* The contents should be indented.
* `}` should be the first character on the line.
* It is OK to drop the curly braces for very simple statements that fit on one line, **as long as they don't have side-effects**.

```r
# Good
y <- 10
x <- if (y < 20) "Too low" else "Too high"

# Bad
if (y < 0) stop("Y is negative")

if (y < 0)
  stop("Y is negative")

find_abs <- function(x) {
  if (x > 0) return(x)
  x * -1
}
```

## Tests

Refer to chapter [Tests](https://style.tidyverse.org/tests.html)

## Error messages

Refer to chapter [Errors](https://style.tidyverse.org/errors.html)

## Rmarkdown

Package vignettes are written using `{rmarkdown}` package. Here are some good practices to follow while writing these documents:

* It is strongly recommended that only alphanumeric characters (`a-z`, `A-Z` and `0-9`) and dashes (`-`) are used in chunk labels, because they are not special characters and will surely work for all output formats. Other characters, spaces and underscores in particular, may cause trouble in certain packages, such as `{bookdown}`. Ref: <https://bookdown.org/yihui/rmarkdown/r-code.html>

````
# bad

```{r load theme, echo=FALSE}
```

# good

```{r load-theme, echo=FALSE}
```
````

* Let your rmarkdown breathe. You should use blank lines to separate different elements to avoid ambiguity. Ref: <https://yihui.org/en/2021/06/markdown-breath/>

````
# bad -----------------

My line is right above my chunk.
```{r}
```
# and the next section right below

# good -----------------

There is a line between text and chunk.

```{r}
```

# and the next section is separated by line as well
````

## Code complexity

R provides some quality checking tools, which can also investigate the complexity of code. E.g. the R package cyclocomp allows the calculation of cyclomatic complexity of a function or a package, s. <https://en.wikipedia.org/wiki/Cyclomatic_complexity> )

* `cyclocomp::cyclocomp(<function_name>)` OR
* `cyclocomp::cyclocomp_package(<package_name>)` OR
* `cyclocomp::cyclocomp_q(<R_expression>)` Example:

![](/files/PA7Wl5u4o7EiNN3dY0C3)

General advice is: **cyclomatic complexity of a function should not exceed the value of 15** <https://en.wikipedia.org/wiki/Cyclomatic_complexity#Limiting_complexity_during_development>

## See also

A more comprehensive list of tools helpful for package development can be found in this [resource](https://github.com/IndrajeetPatil/awesome-r-pkgtools/blob/master/README.md).


# Best Practices R

## theme

If you like vscode theme, use [`https://github.com/anthonynorth/rscodeio`](https://github.com/anthonynorth/rscodeio)

## dev\_mode

`devtools::dev_mode` function switches your version of R into "development mode". This is useful to avoid clobbering the existing versions of CRAN packages that you need for other tasks. Calling dev\_mode() again will turn development mode off, and return you to your default library setup.

```r
# This will install the package in the folder C:/Rpackages
devtools::dev_mode(path="C:/Rpackages")
```

## Reload the package

```r
devtools::load_all()
```

or `Ctrl + Shift + L`

## Add or update script files

`.R` files defined in `tests\dev\` will be removed from the package and can be used to simulate interaction with the package. See [scripts.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/wiki/tests/dev/scripts.R)

## Coding standards

Coding standards are described [here](/r-development-resources/coding_standards_r)

## Useful literature

* [**Advanced R** by Hadley Wickham](https://adv-r.hadley.nz/)

## Examples of "good" packages

Examples of packages that can serve as inspiration:

* [tidyverse](https://github.com/tidyverse)
* [PKPDsim](https://github.com/InsightRX/PKPDsim)

## Useful shortcuts

* Show all shortcuts: `Alt+Shift+K`
* Reload package: `Cmd + Shift + L`
* Navigate to: `Ctrl + .`
* Generate Doc: `Ctrl + Shift + D`
* Run unit tests: `Ctrl + Shift + T`
* Navigate to implementation: `Mouse over + F2` or `CTRL + Mouse Click`
* Un-/Comment line/selection: `Ctrl + Shift + C`
* Multi-select: `CTRL+SHIFT+ALT+M`

## Profiling with R-Studio

Profiling of code can be done within R-Studio with the package `profvis`, a description of the process is given [here](https://support.rstudio.com/hc/en-us/articles/218221837-Profiling-with-RStudio). In short, pass the code to be profiled as argument to the function `profvis`:

```
profvis({
  data(diamonds, package = "ggplot2")

  plot(price ~ carat, data = diamonds)
  m <- lm(price ~ carat, data = diamonds)
  abline(m, col = "red")
})
```

## Graphics

* [Export to SVG](https://stackoverflow.com/questions/12226822/how-to-save-a-plot-made-with-ggplot2-as-svg)

## Snapshot testing

* `{ospsuite}` uses snapshots to test the behavior of plot functions. Read [Introduction to snapshot testing in R](https://github.com/IndrajeetPatil/intro-to-snapshot-testing/#/title-slide) for information on how to.
* Short summary:
  * The first time a test with snapshot is executed, it creates a snapshot file that will be considered **the truth**. Therefore it is important to check this file for its validity.
  * If the behavior of the tested function changes, the test will fail, as the new output will differ from the snapshot.
  * Run `snapshot_review()` to compare the new output with the snapshot.
  * If the new behavior is correct, accept the snapshot by calling `snapshot_accept()`.
* If build fails because of failing snapshot tests, **never** accept new snapshots without manual review.

## Setting up Linux environment for R development

As an example, a Hyper-V Virtual Machine under Windows 10 is used. Currently tested with Ubuntu 19.10

1. **Install Ubuntu**

* Download Ubuntu from <https://ubuntu.com/download/desktop>
* Tutorial: <https://www.youtube.com/watch?v=oyNjjzg-UXo> = >This is a very good intro to get ubuntu installed from scratch

2. **Install git**

* `sudo apt install git`

3. **Install nuget**

* `sudo apt install nuget`

4. **Install R**

* `sudo apt install r-base`

5. **Install R Studio**

* Download R studio from [here](https://www.rstudio.com/products/rstudio/download/#download)

6. **Install OSPSuite-R**

* [Prerequisites](https://github.com/Open-Systems-Pharmacology/rSharp?tab=readme-ov-file#ubuntu)
* [Main Package](https://github.com/Open-Systems-Pharmacology/OSPSuite-R#ospsuite-r-package)


# R Code structure

## Introduction

This document describes the [OSPSuite-R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R) package structure. The package provides OSPSuite functionality in the R programming language. This document covers the package elements, code structure, and components that interface between the OSPSuite .NET codebase and R.

## OSPSuite-R communication with .NET

The `OSPSuite-R` package provides access to OSPSuite functionality implemented in .NET. The [`{rsharp}` package](https://github.com/Open-Systems-Pharmacology/rsharp) enables communication between R and .NET using C++ as an intermediate layer. .NET communicates with C++ through a custom native host. C++ then communicates with R through the R `.C` interface. Use `{rsharp}` to load libraries compiled from the .NET code.

On the .NET side, the [OSPSuite.R project in OSPSuite.Core](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/tree/develop/src/OSPSuite.R) serves as the main entry point for R. This entry point provides access to required Core libraries, including OSPSuite.Core and OSPSuite.Infrastructure. To access PK-Sim functionality, use the separate entry point in the PK-Sim codebase: [PKSim.R](https://github.com/Open-Systems-Pharmacology/PK-Sim/tree/develop/src/PKSim.R).

## OSPSuite-R code structure

The package follows R package best practices for file and code structure. Unlike most R packages, OSPSuite-R uses an object-oriented design. This design reflects the object-oriented structure of PK-Sim and OSPSuite.Core in .NET.

### Initializing the package

R loads package files [alphabetically](https://roxygen2.r-lib.org/articles/collate.html#:~:text=R%20loads%20files%20in%20alphabetical,t%20matter%20for%20most%20packages.), so [zzz.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/zzz.R) is evaluated last. This file calls `.onLoad()` to ensure all functions in other files are evaluated first. The `zzz.R` file checks that R is running the x64 version, then calls `.initPackage()`. The [init-package.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/init-package.R) file uses `{rsharp}` to call the OSPSuite-R package entry point in OSPSuite.Core.

### Object oriented design and `{rsharp}` encapsulation

OSPSuite-R uses an object-oriented design. The package uses the [R6](https://r6.r-lib.org/) framework to create and work with objects. Calls through `{rsharp}` create objects in the .NET environment. Access these objects through getters, setters, and methods. Encapsulate objects passed from .NET to R in wrapper classes. The base wrapper class is [DotNetWrapper](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/dot-net-wrapper.R). All specific wrapper classes (for example, for simulations) inherit from `DotNetWrapper`.

The class handles basic object initialization. The `initialize` method (the R6 equivalent of a C# constructor) saves a reference to the .NET object internally:

[DotNetWrapper](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/dot-net-wrapper.R):

```
#' Initialize a new instance of the class
#' @param ref Instance of the `.NET` object to wrap.
#' @return A new `DotNetWrapper` object.
initialize = function(ref) {
    private$.ref <- ref
}
```

Wrapper classes encapsulate `{rsharp}` calls that work on objects. Users should never call `{rsharp}` directly. All `{rsharp}` calls are encapsulated in wrapper classes or their utility functions (see utilities files below).

Wrap each .NET class with a corresponding wrapper class. Define wrapper classes in separate files named after the R class. For example, the R `Simulation` class wraps an OSPSuite simulation and is defined in [simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/simulation.R).

The `Simulation` class derives from `ObjectBase`. `ObjectBase` extends `DotNetWrapper` by adding `Name` and `Id` properties:

[simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/simulation.R):

```
Simulation <- R6::R6Class(
  "Simulation",
  cloneable = FALSE,
  inherit = ObjectBase,
  ...

```

[object-base.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/object-base.R):

```
#' @title ObjectBase
#' @docType class
#' @description  Abstract wrapper for an OSPSuite.Core ObjectBase.
#'
#' @format NULL
#' @keywords internal
ObjectBase <- R6::R6Class(
  "ObjectBase",
  cloneable = FALSE,
  inherit = DotNetWrapper,
  active = list(
    #' @field name The name of the object. (read-only)
    name = function(value) {
      private$.wrapReadOnlyProperty("Name", value)
    },
    #' @field id The id of the .NET wrapped object. (read-only)
    id = function(value) {
      private$.wrapReadOnlyProperty("Id", value)
    }
  )
)
```

Access simulation properties (for example, the Output Schema) through `DotNetWrapper` functionality:

[simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/simulation.R)

```
#' @field outputSchema outputSchema object for the simulation (read-only)
outputSchema = function(value) {
  private$.readOnlyProperty(
    "outputSchema",
    value,
    private$.settings$outputSchema
  )
}
```

R wrapper classes must implement a meaningful `print` function. Example:

[simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/simulation.R)

```
#' @description
#' Print the object to the console
#' @param ... Rest arguments.
print = function(...) {
  ospsuite.utils::ospPrintClass(self)
  ospsuite.utils::ospPrintItems(list(
    "Name" = self$name,
    "Source file" = self$sourceFile
  ))
}
```

Basic access to object methods and properties is often insufficient. Create utility functions for additional functionality and place them in separate utilities files. For example, see [utilities-simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/utilities-simulation.R). Utilities files contain R code that works on class objects. These files can also include `{rsharp}` calls to .NET functions that operate on objects. Don't place `{rsharp}` calls that only expose object properties or methods in utilities files. Put those in the R wrapper class.

By convention, prefix internal package functions with a dot. For example, use `.runSingleSimulation` instead of `runSingleSimulation`:

[utilities-simulation.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/utilities-simulation.R)

```
.runSingleSimulation <- function(
  simulation,
  simulationRunOptions,
  population = NULL,
  agingData = NULL
) { ... }
```

Communication between R and .NET has performance overhead. Minimize cross-language calls when possible.

### Tasks and task caching

Tasks are reusable objects defined on the .NET side that provide functionality for other objects. Access tasks through [Api.cs](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.R/Api.cs) in OSPSuite.Core. The OSPSuite side creates tasks through the [IoC container](https://en.wikipedia.org/wiki/Inversion_of_control).

The following example shows how to use the `hasDimension` utility function to check if a dimension (provided as a string) is supported:

[utilities-units.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/utilities-units.R):

```
#' Dimension existence
#'
#' @param dimension String name of the dimension.
#' @details Returns `TRUE` if the provided dimension is supported otherwise `FALSE`
#' @export
hasDimension <- function(dimension) {
  validateIsString(dimension)
  dimensionTask <- .getNetTaskFromCache("DimensionTask")
  dimensionTask$call("HasDimension", dimension)
}
```

The example calls the internal function `.getNetTaskFromCache` to retrieve the Dimension Task. To avoid repeated retrieval from .NET, tasks are cached on the R side. See [get-net-task.R](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/R/get-net-task.R):

```
#' @title .getNetTaskFromCache
#' @description Get an instance of the specified `.NET` Task that is retrieved
#' from cache if already initiated. Otherwise a new task will be initiated and
#' cached in the `tasksEnv`.
#'
#' @param taskName The name of the task to retrieve (**without** `Get` prefix).
#'
#' @return returns an instance of of the specified `.NET` task.
#'
#' @keywords internal
.getNetTaskFromCache <- function(taskName) {
  if (is.null(tasksEnv[[taskName]])) {
    tasksEnv[[taskName]] <- .getNetTask(taskName)
  }
  return(tasksEnv[[taskName]])
}
```

Tasks are cached in the `tasksEnv[]` list. If a task is not found in the cache, retrieve it from .NET through an `{rsharp}` call and add it to the cache for future use.

### Tests

The OSPSuite-R package includes comprehensive tests. Find test code in [testthat](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/tree/main/tests/testthat). Tests ensure correct and consistent package functioning. They also serve as examples for understanding how objects are created and used.

## Updating Core DLLs

The R package stores local copies of DLLs from OSPSuite.Core and PK-Sim in [`inst/lib/`](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/tree/main/inst/lib). Update these DLLs when a newer version of the .NET codebase is released.

### Run the update workflow

Use the `update-core-files.yaml` GitHub Actions workflow to update the Core DLLs. The workflow automates downloading files and creating a Pull Request.

To run the workflow:

1. Open the [workflow page](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/actions/workflows/update-core-files.yaml) on GitHub.
2. Click **Run workflow**.
3. Select the branch to run the workflow on (typically `main`).
4. (Optional) Configure workflow inputs:
   * **Branch name**: Specify a custom branch name (default: `update-core-files-YYYYMMDD-HHMMSS`)
   * **PR title**: Specify the Pull Request title (default: "Update Core Files")
   * **PR body**: Specify the Pull Request description (default: auto-generated)
5. Click **Run workflow**.

### What the workflow does

The workflow performs these steps:

1. Runs the R script `.github/scripts/update_core_files.R` to download core files from the latest PK-Sim build artifacts.
2. Checks for changes in the `inst/lib/` directory.
3. If changes are detected:
   * Creates a new branch.
   * Commits the updated files.
   * Creates a Pull Request.
   * Builds SQLite libraries for macOS (arm64).

The workflow file is located at [`.github/workflows/update-core-files.yaml`](https://github.com/Open-Systems-Pharmacology/OSPSuite-R/blob/main/.github/workflows/update-core-files.yaml).


# Serialization

## Serialization

### Introduction

In this part of the documentation we will talk about the serialization deserialization of classes and other data to xml. This serialization is used to save and load projects and pkmls.

### General

The XML serialization engine used in the Open Systems Pharmacology Project can be found in the [OSPSuite.Serializer solution](https://github.com/Open-Systems-Pharmacology/OSPSuite.Serializer). The way the xml mapping works is pretty straightforward, mapping objects to xml elements and keeping the treelike structure where it exists, storing object names and serializing and deserializing according to Ids. This actually makes the xml for a project (a .pkml file for PKSim e.g.) intelligible, and one can even go through the contents of a project.

```
  <Simulation id="XMVCOCRQwky6ttpq36MONA" name="Simple">
    <BuildConfiguration>
      <Molecules id="dJRCM06S7UG-ZbT3H6GNAQ" name="Simple" bbVersion="0">
        <Builders>
          <MoleculeBuilder id="jrKhlw58IkeRn6kWO6UYFA" name="C1" icon="Drug" mode="Logical" containerType="Other" isFloating="1" quantityType="Drug" isXenobiotic="1" defaultStartFormula="jjQg_fgKKkOJLrMEuyOC5g">
            <Children>
              <Parameter id="QR9mTPJCvU69y38G4q-big" name="pKa_pH_WS_sol_K7" description="Supporting parameter for calculation of pKa- and pH- dependent solubilty scale factor at refPH" persistable="0" isFixedValue="0" dim="Dimensionless" quantityType="Parameter" formula="CompoundAcidBase_PKSim.PARAM_pKa_pH_WS_sol_K7" buildMode="Property" visible="0" canBeVaried="0" />
              <Parameter id="UliE_UU0c0uWAKtlM8vFqg" name="pKa_pH_WS_sol_F3" description="Supporting parameter for calculation of pKa- and pH- dependent solubilty scale factor at refPH" persistable="0" isFixedValue="0" dim="Dimensionless" quantityType="Parameter" formula="CompoundAcidBase_PKSim.PARAM_pKa_pH_WS_sol_F3" buildMode="Property" visible="0" canBeVaried="0" />
              .
              .
              .
              </Children>
            <UsedCalculationMethods>
              <UsedCalculationMethod category="DistributionCellular" calculationMethod="Cellular partition coefficient method - PK-Sim Standard" />
              .
              .
              .
            </UsedCalculationMethods>
          </MoleculeBuilder>
```

The only case where things are a bit more complicated is the Formula Cache. If you open the xml segment of the Formula Cache in a .pkml file you will see something like the following:

```
 <FormulaCache>
          <Formulas>
            <Formula id="nyGiXWaSW0OYhQJ__lyZhg" name="Concentration_formula" dim="Concentration (molar)" formula="M/V">
              <Paths>
                <Path path="0" as="1" dim="2" />
                <Path path="3" as="4" dim="5" />
              </Paths>
            </Formula>
            <Formula id="Jv7-T-BLjEKUKypb2n2YIA" name="PLnL_zu_MFormula" dim="Concentration (molar)" formula="1e15/6.02214179e23" />
            <Formula id="lU8mEpGab0-unqhumPvr6g" name="PLFormula" dim="Concentration (molar)" formula="dilutionFactor*S_PL*PLnL_zu_M">
              <Paths>
                <Path path="6" as="7" />
                <Path path="8" as="9" />
                <Path path="10" as="11" />
              </Paths>
            </Formula>
            .
            .
            .
         </Formulas>
```

The above excerpt is a simple simulation created in PK-Sim and exported to pkml, and more specifically the [S1\_concentrBased.pkml](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/tests/PKSim.Tests/Data/S1_concentrBased.pkml) that is part of the test data of PKSim codebase. As you can see, in the Formula Cache, instead of having the actual formula strings, we have path numbers that refer to the StringMap that follows:

```
 <StringMap>
            <Map s=".." id="0" />
            <Map s="M" id="1" />
            <Map s="Amount" id="2" />
            <Map s="..|..|Volume" id="3" />
            <Map s="V" id="4" />
            <Map s="Volume" id="5" />
            <Map s="..|PL|dilutionFactor" id="6" />
            <Map s="dilutionFactor" id="7" />
            <Map s="..|PL|S_PL" id="8" />
            <Map s="S_PL" id="9" />
            .
            .
            .
 </StringMap>
```

This has occurred historically in order to avoid duplication of strings in bigger project files and thus help reduce the project file size.

### Xml Attribute Mapping

The functionality of mapping to specific xml attributes is handled by AttributeMappers that are added to the AttributeMapperRepository either in [OSPSuiteXmlSerializerRepository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Serialization/Xml/OSPSuiteXmlSerializerRepository.cs) in OSPSuite.Core or in the individual solutions in [PKSimXmlSerializerRepository](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/Serialization/Xml/Serializers/PKSimXmlSerializerRepository.cs) and [MoBiXmlSerializerRepository](https://github.com/Open-Systems-Pharmacology/MoBi/blob/develop/src/MoBi.Presentation/Serialization/Xml/Serializer/MoBiXmlSerializerRepository.cs). This is how for example you can specify for the `Species` in PK-Sim the name gets serialized in the xml and the rest gets saved in the database.

### Project (De)Serialization

Let's talk first for a PK-Sim project. In [ProjectMetaDataToProjectMapper.cs](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/Serialization/ORM/Mappers/ProjectMetaDataToProjectMapper.cs) of the PK-Sim solution the order of (de)serialization is defined. When starting the application e.g. we get the project structure from the database and then we further load the contents from the project file. In MoBi correspondingly the project (de)serialization is also defined in [ProjectMetaDataToProjectMapper.cs](https://github.com/Open-Systems-Pharmacology/MoBi/blob/develop/src/MoBi.Core/Serialization/ORM/Mappers/ProjectMetaDataToProjectMapper.cs) of the MoBi solution. The main difference between the two is that the entities in PK-Sim are lazy loaded, whereas in MoBi we load everything on startup.

### Writing a serializer for a new class

When creating a new class in OSPSuite of an object that will then need to be saved to the project file, a new serializer will also have to be written for that class. Let's call our new class `NewClass`. If the class gets created in OSPSuite.Core and is not implementing an interface that already has an abstract serializer, the convention would be to write a serializer called `NewClassSerializer : OSPSuiteXmlSerializer<NewClass>`.

You will then have to write a an override for the `PerformMapping()` function, that serializes the properties of the class:

For example:

```
public class NewClass
{
   public string Name { get; set; }

}
```

```
public class NewClassSerializer : OSPSuiteXmlSerializer<NewClass>
{
   public override void PerformMapping()
   {
      Map(x => x.Name);
   }
}
```

In case your new class implements an interface that already has an abstract serializer, it is that one that you will need to extend. For example if you are writing a new Building Block class (that would be implementing the interface IBuildingBlock), the serializer signature would be

```
public class NewClassSerializer : BuildingBlockXmlSerializer<NewClass>
```

Now let's talk a bit about the mapping a classes properties in the `PerformMapping()` override. The most frequent use cases would be:

## Map(...)

When you want to serialize a property of a class and a serializer already exists for the type of property you want to serialize (as is e.g. for string, int and the other basic types, or in case there is a serializer already written for this object in the solution), you only need to use Map function like in the above example with `Map(x => x.Name);`. You do not need to explicitly define what needs to be deserialized or how, the framework will take care of that for you. Additionally, you can use the mapping extensions to specify the xml element name to which your property will be mapped by calling `Map(x => x.Name).WithMappingName(mappingName);`, where mappingName is a string.

## MapEnumerable(...)

If the class property that you need to serialize is an IEnumerable (a list, a OSPSuite Cache collection,), and there exists a serializer for the type of objects stored in th IEnumerable, you need to define the serialization of that property with the MapEnumerable() function, where you pass the enumerable and an method used to add objects to the defined IEnumerable. As an example, with an readonly list:

```
public class NewClass
{
   private readonly List<object> _allData;

   public IReadOnlyList<object> AllData
   {
      get { return _allData; }
   }

   public void Add(object singleData)
   {
      _allData.Add(singleData);
   }
}

.
.
.
public class NewClassSerializer : OSPSuiteXmlSerializer<NewClass>
{
   public override void PerformMapping()
   {
      MapEnumerable(x => x.AllData, x => x.Add);
   }
}

```

For 90% of the cases when creating a serializer for a new class, the above should be adequate and writing the serializer should be pretty straightforward: just adding the corresponding `Map(...)` and `MapEnumerable(...)` calls for the class properties that need to be serialized to the `PerformMapping(...)` override of the serializer.

## MapReference(...)

Moving now to a more complicated use case: sometimes we have a class that has a reference to another object. Take the class [WeightedObservedData](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Domain/WeightedObservedData.cs) in OSPSuite.Core for example:

```
   public class WeightedObservedData
   {
      public virtual DataRepository ObservedData { get; }
      .
      .
      .
      public WeightedObservedData(DataRepository observedData)
      {
         ObservedData = observedData;
         .
         .
      }
      .
      .
   }
```

and its [serializer](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Serialization/Xml/WeightedObservedDataXmlSerializer.cs):

```
   public class WeightedObservedDataXmlSerializer : OSPSuiteXmlSerializer<WeightedObservedData>
   {
      public override void PerformMapping()
      {
         .
         .
         .
         MapReference(x => x.ObservedData);
      }
   }
```

In such a case the `Datarepository` that is `ObservedData` also exists in the Project and gets serialized and deserialized separately. We would not like to keep multiple copies of the same object in our project file, and therefore what we are going to write in the xml is a reference to that `ObservedData`. It is important though in this case to keep in mind than when deserializing we have to make sure the `ObservedData` is available when deserializing the corresponding `WeightedObservedData`, otherwise we might end up with an exception. That would mean that either the `ObservedData` has been (de)serialized before the (de)serialization of `WeightedObservedData` or within the same (de)serialization action (meaning that a `WeightedObservedData` object references an `ObservedData` object and both objects are withing the root note and the action is (de)serializing that common root node).

The observed data of a project is a very good example of this, since they are referenced in many different places of a project. Note for example that if you write a new class that has a `WeightedObservedData` member, when you are serializing it you would also be implicitly keeping a reference to the Observed Data underneath that object - and therefore will have to be careful that the (de)serialization in your project is correct.

## TypedSerialize(...) - TypedDeserialize(...)

In case the above functionalities do not cover your use case, you can also use `TypedSerialize(TObject objectToSerialize, TContext context)` and `TypedDeserialize(TObject objectToDeserialize, XElement outputToDeserialize, TContext context)` to be able to specify the actions that should happen before and after (de)serialization. This is the functionality used e.g. for the (de)serialization of the FormulaCache and its corresponding StringMap (as discussed in the xml structure section above).

A simple example for the use of these two functions in a class in Core is the [DisplayUnitMapXmlSerializer](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Serialization/Xml/DisplayUnitsManagerXmlSerializer.cs). There we have a `OSPSuite.Core.Domain.UnitSystem.Unit` as DisplayUnit member and we want to serialize the unit name as a string. We also serialize the dimension. When we deserialize we want to get from the created `DisplayUnitMap` dimension the actual Unit and not just a string.

```
   public class DisplayUnitMapXmlSerializer : OSPSuiteXmlSerializer<DisplayUnitMap>
   {
      public override void PerformMapping()
      {
         Map(x => x.Dimension);
      }

      protected override void TypedDeserialize(DisplayUnitMap displayUnitMap, XElement element, SerializationContext serializationContext)
      {
         base.TypedDeserialize(displayUnitMap, element, serializationContext);
         element.UpdateDisplayUnit(displayUnitMap);
      }

      protected override XElement TypedSerialize(DisplayUnitMap displayUnitMap, SerializationContext serializationContext)
      {
         var element = base.TypedSerialize(displayUnitMap, serializationContext);
         return element.AddDisplayUnitFor(displayUnitMap);
      }
   }
```

For that we are also using the following extension methods on the xml element:

```
public static XElement AddDisplayUnitFor(this XElement element, IWithDisplayUnit withDisplayUnit)
{
   return AddDisplayUnit(element, withDisplayUnit.DisplayUnit);
}

public static XElement AddDisplayUnit(this XElement element, Unit unit)
{
   if (unit == null || string.IsNullOrEmpty(unit.Name))
      return element;

   element.AddAttribute(Constants.Serialization.Attribute.DISPLAY_UNIT, unit.Name);
   return element;
}

.
.
.

public static void UpdateDisplayUnit(this XElement element, IWithDisplayUnit withDisplayUnit)
{
   withDisplayUnit.DisplayUnit = GetDisplayUnit(element, withDisplayUnit);
}

public static Unit GetDisplayUnit(this XElement element, IWithDimension withDimension)
{
   return GetDisplayUnit(element, withDimension.Dimension);
}

public static Unit GetDisplayUnit(this XElement element, IDimension dimension)
{
   if (dimension == null)
      return null;

   var displayUnit = element.GetAttribute(Constants.Serialization.Attribute.DISPLAY_UNIT);
   return dimension.UnitOrDefault(displayUnit);
}

```


# Unit and Integration Testing

## Unit and Integration Testing

### Introduction

In this part of the documentation we will present the structure of existing unit tests, as well as the abstract classes, helpers, contexts and other resources that have already been created to facilitate the creation and running of unit tests.

## General

Unit testing is an integral part of our software practices and we keep the code that we write well covered by tests. Currently Pull Requests are only being accepted if they contain at least one unit test ( with the logical exceptions e.g. a PR containing only package updates ) and the code can be considered well covered by unit tests. We try when possible to implement a Test-Driven-Development (TDD) approach, and specifically for fixing bugs it is strongly suggested to first write a failing test according to the error description and then fix the issue, to ensure the correct and permanent elimination of the bug.

For the C# solutions to write unit tests we are using [NUnit](https://nunit.org/) in combination with [FakeItEasy](https://fakeiteasy.github.io/) to mock objects and intercept calls and our own [BDDHelper](https://github.com/Open-Systems-Pharmacology/OSPSuite.BDDHelper) comprising of extension methods to write and structure unit tests in a Behavior-Driven Development manner.

## Test Outline

### The abstract class

We usually create one test class file for every class we want to test. Let's take for example a newly created class, let's call it NewClass: `public class NewClass`. When writing the unit tests for it, we would start with an abstract class which will be the parent to all the specific test case classes:

```
public abstract class concern_for_NewClass : ContextSpecification<NewClass>
{
    protected override void Context()
    {}
}
```

Please follow this naming convention for the abstract unit test classes of calling them `concern_for_NewClass` where `NewClass` the class to be tested.

Usually in this abstract class we would define the `Context() override` and also some protected members that would be common to all the test cases (even if their value would not stay constant for every test case).

The `Context()` is the setup of the test, where the environment and necessary objects are created. Functionalities that will be used overall in the test class should be defined and created here. As part of this `Context()` we could assign the `sut` (System Under Test) - alternatively this could be part of the `Because()` that we will see in the next segment, specifically if our test case concerns the instantiation of the object.

Apart from this `Context()` that would then be called (and if necessary also overridden) for every test case which inherits from this abstract class, we can also create a GlobalContext() override, where we instantiate resource-heavy objects that are used overall in the test class, since objects in the GlobalContext() are only instantiated once per test class.

### The individual test cases

Continuing with our example, we write an individual unit test class for `NewClass`:

```
public class When_changing_a_NewClass_property_value : concern_for_NewClass
{
    protected override void Context()
    {
        base.Context();
        .
        .
        .
    }

    protected override void Because()
    {
        ...
    }

    [Observation]
    public void should_have_updated_the_value_correctly()
    {
        ...
    }

    [Observation]
    public void should_notify_about_the_change()
    {
        ...
    }
}
```

Please note the convention of naming the unit test classes using complete sentences in lowercase separated with underscores instead of whitespaces. The BDDHelper then replaces the underscores with whitespaces for the test reports. The same naming logic applies to the Observations. Unit test classes usually ( but of course not necessarily ) start with "When\_.." and Observations with "should\_...". It is important that both the unit test class name as well as the observation fully and correctly describe the behaviour that gets tested and the expected outcome. The length of the name is in this case of no big concern.

#### Because() and Observations

Instead of packing both the behaviour that leads to a result that we want to test and the assertion of the correct outcome in one code segment, we prefer to separate those two in a `Because()` function where we have the behaviour that will be tested and an `Observation` that tests the outcome.

## Creation of Objects and Mocking

It is suggested to avoid mocking as far as possible. In our experience this can lead to a situation where too much mocking results in a green test where the actual functionality is not correct and also to more difficulty in maintenance. Instead, it is generally suggested to create real objects where possible and ideally to use helper functions for this task, in order to make the creation of the real objects reusable and avoid code duplication.

Before writing your own function for the creation of an object necessary for testing, please note that in the [HelpersForSpecs](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/tree/develop/tests/OSPSuite.HelpersForTests) folder you can find functions for the creations of many frequently used objects, like e.g. individuals or simulations. When writing a function to create an object that could be needed overall in the tests, it is these classes exactly that should be extended. Especially helpful are the DomainHelperForSpecs (in all the solutions: Core, PK-Sim and MoBi) where you can find functionalities to create domain objects (you can get e.g. the path to test files, create a new test simulation, create a new test individual, test observed data etc.).

### FakeItEasy

As discussed, to mock objects we use FakeItEasy. On the documentation of the [package](https://fakeiteasy.github.io/) you can find a quite detailed documentation of its usage. Still we will present here some of the functionalities that we use more often:

You can create a fake object of type `MyClass` or `IMyInterface` very simply:

```
var _fake = A.Fake<MyClass>();
```

It is easily possible to intercept calls to fake objects to return specific objects:

```
var _input = new InputValue();
var _value = new MyValue();
A.CallTo(() => _fake.GetValueForInput(_input)).Returns(_value);
```

making the mocked object return `_value` when `GetValueForInput()` is called with `_input` as parameter. Alternatively you can return the same value regardless of the input parameter using `A<Type>.Ignored` like this:

```
A.CallTo(() => _fake.GetValueForInput(A<InputValue>.Ignored)).Returns(_value);
```

Finally we often use the fakes to ensure a call to them has happened or not in our Observation segment, e.g. :

```
A.CallTo(() => _fake.GetValueForInput(A<InputValue>.Ignored)).MustHaveHappened();
```

or

```
A.CallTo(() => _fake.GetValueForInput(A<InputValue>.Ignored)).MustNotHaveHappened();
```

## BDDHelper

As discussed in the introduction, we use also use the extensions from [BDDHelper](https://github.com/Open-Systems-Pharmacology/OSPSuite.BDDHelper) in our tests. It is strongly recommended to use the hereby available functionalities instead of simple NUnit Asserts, for consistency, but also because some things are centrally implemented in these functions, like comparison tolerance for values for example.

So please write:

```
[Observation]
public void values_should_set_correctly()
{
    _myObject.DataValue.ShouldBeEqualTo(3);
}
```

instead of:

```
[Observation]
public void values_should_set_correctly()
{
    Assert.AreEqual(_myObject.DataValue, 3);
}
```

## Integration Tests

We use integration tests to test functionality that requires the loading of resource-heavy real objects and are generally oriented towards scenarios that run longer, open whole projects, load the whole context etc. There is also a difference in how we handle integration tests compared to normal unit tests in our Continuous Integration pipeline. Unit tests are run on every build, but integration tests are only run on the nightly builds since they are regarded as more time- and resource- consuming.

Specifically for integration tests we extend the usual `ContextSpecification<T>` of normal unit tests in `ContextForIntegration<T> : ContextSpecification<T>`. There we create and mock a few more things to begin with, the main one being an IoC container that we also fill with registrations.

### DataBaseUpdateSpecs

In PK-Sim we have a specific kind of integration tests that make sure that the database gets correctly updated and stays consistent with code and version changes.

## Constants for Tests

In order not to fill up the constant definitions that are used for the actual application, constants used only for tests should be defined in the dedicated classes [ConstantsForSpecs](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/tests/OSPSuite.HelpersForTests/ConstantsForSpecs.cs) in OSPSuite.Core or [CoreConstantsForSpecs](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/tests/PKSim.Tests/CoreConstantsForSpecs.cs) in PK-Sim.

## TestCaseSource()

You can use [TestCaseSource()](https://docs.nunit.org/articles/nunit/writing-tests/attributes/testcasesource.html) to avoid code duplication and create parameterized tests. Examples of unit tests that take advantage of this functionality can be found in the [OSPSuite.FuncParser repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.FuncParser), for example in the [DimensionParserSpecs](https://github.com/Open-Systems-Pharmacology/OSPSuite.FuncParser/blob/master/tests/OSPSuite.FuncParser.Tests/DimensionParserSpecs.cs).

## Unit Test Explorer

A helpful tip is to use the Unit Test Explorer of Visual Studio:

![The Visual Studio Unit Test Explorer.](/files/xBB5dHTnO3PE1DAJKps4)

or of Resharper:

![The Resharper Unit Test Explorer.](/files/x2AOhOMHHoPR7aO6OHBW)

To run or debug a single unit test, or all the selected or even all the unit tests in a solution. Specifically for Resharper, you can refer to its [documentation about starting, debugging and analysing tests](https://www.jetbrains.com/help/resharper/Executing_Analyzing_Tests.html) .

## Test Files

Sometimes test files are necessary for the unit tests, such as .xlsx files as input for example. These files should be saved in the "Data" folder of the respective project, e.g. in <https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/tree/develop/tests/OSPSuite.Presentation.Tests/Data> for `OSPSuite.Presentation.Tests.csproj`. When adding a new test file make sure you set its `Copy to Output Directory` property in Visual Studio to `Copy if newer`, otherwise the file will not be found when running the test.

![The Visual Studio "Copy to Output Directory" property.](/files/ve4OGuZfIsgwgqyNGgcf)

Additionally, in the PK-Sim `DomainHelperForSpecs` you can find functionalities to easily get the full path just from the name. For example, if you have a "TestData.csv" file you can get the full path like this:

```
var fullPath = DomainHelperForSpecs.DataFilePathFor("TestData.csv");
```


# Commands

## Commands

### Introduction

In this part of the documentation we will present the `Command` classes that are used to changed the values of the domain objects and its usages.

### General

When changing the values of domain objects in OSPSuite, instead of writing the values directly we are using Commands that change these objects. We do this for a few reasons. Firstly because we want to use the Commands to keep a history of changes that has happened to our data. This history also serves a regulatory purpose.

![The user can see the history of changes in the history view.](/files/AU8J1s6KYSIWFnAsEGFI)

Additionally those commands give us the possibility to reverse the actions that have happened. The user can do this by selecting the command from the history and clicking undo.

![Undoing commands.](/files/OUL26nDqZhdzsI1yigUl)

### Structure of the class and writing a new command

When you want to create a new action that changes the data, you will need to write a new command.

## Command Execution

The execution of a command is defined in the ExecuteWith(...) function override:

```
protected override void ExecuteWith(IOSPSuiteExecutionContext context)
```

Note: If the command is defined in PK-Sim or MoBi, the context would be the context interface more specific to the project, e.g. in PK-Sim

```
IExecutionContext : IOSPSuiteExecutionContext<PKSimProject> 
```

In the body of this override we define the execution steps of the command. The context serves two purposes:

````
The first is to give the command the possibility to resolve objects it might need from it, instead of having everything needed explicitly passed to it. For example, in the case of adding a new object to the project, the command will need a reference to the project. This reference gets resolved from the context. The execution of the command might even be dependant on a task or a service that can be resolved from the project. Additionally we can use the context to publish events when a change has happened that requires a global notification event. We can see this e.g. in the [command used to change Observed Data MetaData](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Commands/ChangeObservedDataMetaDataCommand.cs) in Core, where after changing the MetaData a new event notifying about that change has to be published:

```
context.PublishEvent(new ObservedDataMetaDataChangedEvent(_observedData));
```

Secondly we use the context to store data that we will need to reverse the command, even for data that we initially receive in the command explicitly. After the command is executed, the steps defined in the `ClearReferences()` are executed to clear the memory. Then with the `RestoreExecutionData(IExecutionContext context)` override we can restore the data from the context. An example here would be the [SetTransportTypeCommand](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Core/Commands/SetTransportTypeCommand.cs) in PK-Sim, where we get the `IndividualTransporter` as an argument in the constructor of the Command class:

```
public SetTransportTypeCommand(IndividualTransporter individualTransporter, TransportType transportType, IExecutionContext context)
  {
     .
     _individualTransporter = individualTransporter;
     .
     .
     .
     _transporterId = _individualTransporter.Id;
     
  }
```

the `_individualTransporter` object reference is then cleared in `ClearReferences()` 

```
protected override void ClearReferences()
{
    _individualTransporter = null;
    .
    .
}
```
 
and then restore it through the context in `RestoreExecutionData(..)` by just using its Id. `RestoreExecutionData(..)` is called before the inverse command. 

```
public override void RestoreExecutionData(IExecutionContext context)
{
    .
    .
    _individualTransporter = context.Get<IndividualTransporter>(_transporterId);
}
```
In other cases we might need to explicitly register an object to the context in the `ExecuteWith(...)` function.
````

## Inverse Command

In order to be able to reverse the execution of a command we need inverse commands. Which command we use for this is specified in the `GetInverseCommand(IOSPSuiteExecutionContext context)` function override part of a command. There are cases when we do not really need a new command to reverse the actions, e.g. when we have changed a value, we simply need to use the same command with different parameters to reset the values. We can find an example for that in the [ChangeObservedDataMetaDataCommand](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Commands/ChangeObservedDataMetaDataCommand.cs). Usually though a separate new command will have to be written to reverse the actions of the original command. For example if we have added observed data to the project, in reversing the command we need to remove exactly that observed data. [AddObservedDataToProjectCommand](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Commands/AddObservedDataToProjectCommand.cs) has [RemoveObservedDataFromProjectCommand](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Commands/RemoveObservedDataFromProjectCommand.cs) as its inverse - and vice versa of course.

## Further properties

The [ICommand interface](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Commands/Core/Command.cs) defines further properties, like the Description and ObjectType (type of object on which the command has been executed) that will also end up in the history view.

### MacroCommands

Macro Commands are a collection of separate commands. They keep the list of subcommands to which commands can be added, and the execution of a MacroCommand is the execution of each subcommand individually. Hence they do not have additional data of their own (ObjectType, Comment etc.). Clearing, restoring the execution data or getting the inverse of macro commands is the simply performing the corresponding action for each one of the subcommands.

### EmptyCommands

EmptyCommand is an implementation of the [Null Object Pattern](https://en.wikipedia.org/wiki/Null_object_pattern). We are using it as a return object in the cases when we do not want something to happen, instead of returning null and having then to check for null all the time down the execution path.

### Name similarity with UICommands

In the OSPSuite there also exist the interface IUICommand that is NOT the same as ICommand. The UICommands actually refer to specific UI actions (buttons, context menus etc) and either get executed directly or using tasks and without being reversible or being written in history. Otherwise they also need to invoke a separate command that takes care of executing the actions on the data.


# Debugging

## Debugging

### Introduction

In this part of the documentation we will talk about debugging in both the C# and R language worlds of OSPSuite. We will present some strategies, but also existing resources that facilitate debugging.

## Debugging in OSPSuite.Core

In order to be able to test some of the functionalities of the OSPSuite that reside in [OSPSuite.Core](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core) there has been created in Core the OSPSuite.Starter project. You simply have to set it up as a startup project:

![Right click on OSPSuite.Starter project and select "Setup as startup project".](/files/BtfpVpeomLqkNkx6KAC7)

Then you can start with the debugger in Visual Studio:

![Start debugging.](/files/nVRibwgme8I5snPfRnqp)

As you can see in the window that appears you can test various Core functionalities both as a user and through breakpoints in code.

![The starter view.](/files/xSl3jo9HWB2wb6Th6xmh)

### Developing between solutions

For some tasks, it's necessary to implement partially in OSPSuite.Core and partially in MoBi or PK-Sim. In those cases, it can be tedious to create pull requests in OSPSuite.Core and get them merged, so you can use them to implement the feature in MoBi or PK-Sim. Then, if you find bugs or additional requirements as you code, you need to create more pull requests and wait for them to be merged.

To accommodate an all local workflow of creating local OSPSuite.Core and using it directly in your local PK-Sim or MoBi Visual Studio solutions, the following steps are needed once to set up your local environment:

1. Create a `nuget_repo` folder in the same directory as the `OSPSuite.Core.sln` file.
2. Add the nuget\_repo folder as a nuget source in Visual Studio. To do that go to Tools -> Options -> NuGet Package Manager -> Package Sources and add the nuget\_repo folder as a new source.
3. Arrange your working directories for `MoBi`, `PK-Sim` and `OSPSuite.Core` so they are all contained in the same parent directory.
4. Make sure the directories for `MoBi`, `PK-Sim` and `OSPSuite.Core` are named `MoBi`, `PK-Sim` and `OSPSuite.Core` respectively.

Then you can always update one or both applications with local versions of OSPSuite.Core using scripts:

1. mobi\_nuget.bat to update only MoBi
2. mobi\_pksim.bat to update only PK-Sim
3. nuget\_to\_both.bat to update both MoBi and PK-Sim
4. Rebuild the application solution with the new dependencies.

This workflow will change the .csproj files in the application solutions to use the local version of OSPSuite.Core. Those OSPSuite.Core builds will not be available for other users of course, so you need a new OSPSuite.Core build from GitHub packages repository to finalize development.

First create a pull request in OSPSuite.Core and get it merged. Then you need to update the dependencies in the application .csproj to use the new version of OSPSuite.Core as built by GitHub Actions.

### Debugging between solutions

Beyond directly using the newly implemented code in OSPSuite.Core, you can also use the debugger to debug the code in Core from the other solutions. To do that you need to:

1. Set up your environment as above once
2. Update dependencies as above as needed
3. Start the application from Visual Studio without debugging
4. Attach the Visual Studio debugger from the OSPSuite.Core solution to the application process. You can now set breakpoints and debug the code in Core from the other solutions.

## Debugging from R script

You can also debug the OSPSuite.Core code from an R script. To do that you need to

1. Build Core in the "Debug" configuration.
2. Copy the created dlls and associated .pdb files from "OSPSuite.Core\src\OSPSuite.R\bin\Debug\netstandard2.0" to your OSPSuite.R installation directory and specifically in the "OSPSuite-R\inst\lib" folder.
3. Start the OSPSuite.R project in R !\[Ospsuite.R RStudio project file.]\(../assets/images/![The starter view.](/files/jlX10RD0QDXvgI9unysK)
4. Attach the Visual Studio debugger from the OSPSuite.Core solution to the RSession. Make sure to attach to rsession NOT to rstudio.exe. !\[Attach to rsession.]\(../assets/images/![The starter view.](/files/fwpcH391V89PvEAekkDz)
5. Load using devtools and load\_all to make sure the symbol files also get loaded:

```
devtools::load_all(".")
```

Now you can continue debugging. Note that if you have set a breakpoint in the part of the OSPSuite.Core code that gets called during the loading of OSPSuite.R, the debugger will already stop on it when you call `load_all(".")`.

### Creating local nuget packages from Core

Sometimes just copying the dlls from Core to PK-Sim or MoBi is not enough. This is the case when you write e.g. a new interface in Core that you need to implement in PK-Sim or MoBi. So let's say you have done such a change to your local OSPSuite.Core code and now you want to continue coding in MoBi, but you are not yet finished or for some other reason you do not yet want to merge your changes to the `develop` branch of Core and then update your MoBi nuget packages from the CI build. For such cases you can create nuget packages from your edited OSPSuite.Core codebase and install them to the other solutions or to OSPSuite.R.

In order for this to work a few scripts have been developed that create the nuget packages locally under "OSPSuite.Core\nuget\_repo" and also apply the changes in the respective solutions, provided that the repository folders are under the same root folder. Using the "pksim\_nuget" batch file will create the nuget packages from the local OSPSuite.Core source code and update PK-Sim, "mobi\_nuget" will do the same for MoBi, "nuget\_to\_both" creates nuget packages for and updates both PK-Sim and MoBi.


# Data Binding

## Data Binding

### Introduction

In this part of the documentation we will talk about the OSPSuite UI and the binding of data to graphic elements. We will present the elements that we are using to achieve this binding - either external like Devexpress or internal to OSPSuite, like the OSPSuite.DataBinding repository.

## Data Binding Overview

The graphical user interface of OSPSuite uses [Winforms](https://en.wikipedia.org/wiki/Windows_Forms) as its UI framework and the [Devexpress Winforms Component](https://docs.devexpress.com/WindowsForms/7874/winforms-controls) to provide additional controls and functionalities. In order to display the data on the controls, a data binding framework has been developed. The data binding is part of two separate repositories, [OSPSuite.DataBinding](https://github.com/Open-Systems-Pharmacology/OSPSuite.DataBinding) and the DevExpress specific [OSPSuite.DataBinding.DevExpress](https://github.com/Open-Systems-Pharmacology/OSPSuite.DataBinding.DevExpress). In almost all cases, simple bindings can be created to implement two way updating of view and objects.

## Data Binding Example

### DTO (Data Transfer Object)

Although we could bind to the properties of an object directly, we generally prefer to use DTOs [Data Transfer Object](https://en.wikipedia.org/wiki/Data_transfer_object) as an intermediate step, in order to be able to structure our data in a manner that makes more sense in displaying. Let's take as an example the binding to a simple TextEdit. We are going to base our example initially to binding a simple float value to the text edit:

So let's say we have defined in our view a TextEdit.

```
private DevExpress.XtraEditors.TextEdit myValueTextEdit;
```

In this example we want to bind the TextEdit to a `float` value. We will create a very simple DTO to hold that value - later on we will also add a validation check for this value. But let's start with the simplest possible form:

```
public class MyValueDTO
{
      public float MyValue { get; set; }
}
```

### Screenbinder

The next step after creating this is to define a screenbinder that would take care of the binding for us. It inherits from the class OSPSuite.DataBinding.ScreenBinder defined in [OSPSuite.DataBinding](https://github.com/Open-Systems-Pharmacology/OSPSuite.DataBinding/blob/master/src/OSPSuite.DataBinding/ScreenBinder.cs).

So moving back to the view, we define a screenbinder for this newly created DTO:

```
private readonly ScreenBinder<MyValueDTO> _screenBinder;
```

Since our view is extending `BaseView` (or even as part of the `IView` interface), we have a base virtual function `void InitializeBinding()`. This function should take care of the initializing of the binding, so in our case:

```
public override void InitializeBinding()
{
      base.InitializeBinding();
      _screenBinder.Bind(x => x.MyValue).To(myValueTextEdit); 
}
```

In order to bind to the actual DTO object, we need a `void BindTo(MyValueDTO myValueDTO)` function as part of the interface of the view. This function can then be called from the presenter to provide the DTO object for the actual binding.

So in the view we will have the implementation of this function:

```
public void BindTo(MyValueDTO myValueDTO)
{
      _screenBinder.BindToSource(myValueDTO);
}
```

Like this, the binding is complete. Similarly we could expand the DTO with more fields and use it to bind to various UI elements. In the case we had f.e. a form that would consist of a drop-down, a color selector, and two TextEdits for value input, we would usually create a single DTO that would encapsulate all those values and bind to the separate visual elements. An example of such a more complex binding can be found in [ParameterIdentificationConfigurationView.cs](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.UI/Views/ParameterIdentifications/ParameterIdentificationConfigurationView.cs), both in the initialization and the binding segments.

When using the screenbinder it is important to remember to dispose it at the end. Usually this is done in the `Dispose()` function of the view - usually located in the designer part of the view (...MyView\.Designer.cs):

```
protected override void Dispose(bool disposing)
{
      .
      .
      .

      _screenBinder.Dispose();
      base.Dispose(disposing);
}
```

When having more than one binders, it would be more reasonable to create a method called something like `disposeBinders()` and then just call from the `Dispose(bool disposing)` function above.

### Validation

Going back to the simple example that we are presenting here. If we want to add validation to the values that come as input by the user for the TextEdit, we need to implement in the DTO the `IValidatable` interface. Then we have to define the rule that we need validated. Let's say that we need the float value that we are reading to be greater than 2.

```
public class MyValueDTO : IValidatable
{
      public float MyValue { get; set; }

      public MyValueDTO()
      {
         Rules.Add(AllRules.myValueGreaterThanTwo);
      }

      private static class AllRules
      {
            private static IBusinessRule myValueGreaterThanTwo
            {
                  get
                  {
                        return CreateRule.For<MyValueDTO>()
                              .Property(item => item.MyValue)
                              .WithRule((x, value) => value > 2.0)
                              .WithError("Value must be greater than 2");
                  }
            }
      }
}
```

As you can see in the above example, we can also define an error text to be displayed to the user in case that the validation for the input value fails. Important Note: of course in the case of actual OSPSuite code, it has to be stressed that the error string should not be hard coded, but would rather be define in `UIConstants.Error`.

To finalize the validation, we should also expand the binding initialization to also register the validation:

```
public override void InitializeBinding()
{
      base.InitializeBinding();
      _screenBinder.Bind(x => x.MyValue).To(myValueTextEdit); 
      RegisterValidationFor(_screenBinder, NotifyViewChanged);
}
```

### Formatting

Additionally, we can use a formatter to specifically format the data displayed in the view. We can use an existing formatter, like the [DateTimeFormatter](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Services/DateTimeFormatter.cs) in order to fix the displaying format when we are binding to a frequently used type like in this case `DateTime`. Alternatively there is of course the possibility to create a custom formatter. Let's say for example we have a class `MyClass` that has a member function `string GetName()` that returns the name of the object. If we want to bind objects of this type to a 'ComboBoxEdit' we cannot do it directly - we will have to use a custom formatter to access the string name of the object. Additionally let's assume we want to display a specific string in case the bound value is `null`. To achieve all this we would write the following formatter:

```
public class MyClassFormatter : IFormatter<MyClass>
{
      public string Format(MyClass valueToFormat)
      {
            if (valueToFormat == null)
                  return "No value selected";

            return valueToFormat.GetName();
      }
}
```

Again please note that the hard coded string only exists in the above example for simplicity - in the real OSPSuite code it would be part of `Captions`.

Then when performing the actual binding:

```
private OSPSuite.UI.Controls.UxComboBoxEdit myComboBoxEdit;

.
.
.

//Here we are assuming we have created a DTO, the .MyClass returns an object of type MyClass 
private readonly ScreenBinder<MyDTO> _screenBinder = new ScreenBinder<MyDTO>;

private readonly IFormatter<MyClass> _myClassFormatter = new MyClassFormatter();

_screenBinder.Bind(x => x.MyClass)
      .To(myComboBoxEdit)
      .WithFormat(_myClassFormatter);
```

### Further possibilities

There are further functionalities that can be achieved using the binding framework. For example using the `_screenBinder.WithValues(...)` a set of values can be specified as possible values for the UI element ( drop-down menu f.e. ).

Actions like `_screenBinder.Changed()`, `_screenBinder.OnValueUpdating` and more can be used for the View to be subscribed to them and handle them accordingly when they happen. `RegisterValidationFor(....)` is already using events like that to handle the validation.

### DTO Mappers

Concerning the creation and transfer of data to and from the DTO, when we have a complicated scenario we usually create a separate mapper class. We do this to avoid having all the code in the presenter. F.e. you can refer to the mapping of the `JournalPage` to `JournalPageDTO` in [JournalPageToJournalPageDTOMapper](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Presentation/Mappers/JournalPageToJournalPageDTOMapper.cs).

## Binding to a Grid

When using a Grid as a visual element, a special type of binder can be used to bind data to the contents of the grid :

```
OSPSuite.DataBinding.DevExpress.XtraGrid.GridViewBinder<T>
```

The logic of using this binder is pretty similar to what we have described above. Since in the grid we have multiple lines we would usually use repositories to bind to, like `RepositoryItemComboBox` , `RepositoryItemCheckedComboBoxEdit`, or even button repositories of `UxRepositoryItemButtonEdit` type if we want to fill a column with clickable buttons. For example assuming we have defined a DTO class `myDTO` with members `Name` , `Type` etc:

```
private readonly GridViewBinder<myDTO> _gridViewBinder;

public override void InitializeBinding()
{
      _gridViewBinder.AutoBind(x => x.Name)
            .WithCaption("Name");

      _gridViewBinder.AutoBind(x => x.Type)
            .WithCaption("Type");

      _gridViewBinder.Changed += NotifyViewChanged;
}
```

The `.WithCaption(...)` (that same as above in real world code would be called with captions and not hard coded strings in the call), defines the title of the column. Please note that we are using `.AutoBind(...)` instead of simple `.Bind(...)` to do the binding. In the case of `.Bind(...)` we are doing the binding, whereas in the case of `.AutoBind(...)` it is the .NET framework that is doing it. If we were to use the `.Bind(...)` we would not get the 'x' error symbol that comes from the validation refreshed when the data changes. Note also that we are subscribing to the event of the grid data changing.

### Unbound Column in a Grid

Sometimes we want to add to our Grid a column that is not bound to the DTO. In the simplest case that could be a column with a constant value. A more interesting example for that would be a column that contains clickable buttons. We can do this f.e. like this:

```
public override void InitializeBinding()
{
      private readonly UxRepositoryItemButtonEdit _buttonRepository;

      //devexpress predefined buttons can f.e. be used in the button repository. Here we are using th predifined "Clear" button
      _buttonRepository = new UxRepositoryItemButtonEdit(ButtonPredefines.Clear);
      .
      .
      .

      _gridViewBinder.AddUnboundColumn()
            .WithCaption("")
            .WithRepository(x => _buttonRepository)
            .WithShowButton(ShowButtonModeEnum.ShowAlways)
            .WithFixedWidth(UIConstants.Size.EMBEDDED_BUTTON_WIDTH);
      
      .
      .
      .

      //call the presenter to handle the clicking of the button
      _buttonRepository.ButtonClick += (o, e) => OnEvent(() => _presenter.HandleButtonClick(_gridViewBinder.FocusedElement));
}
```

Please also note the subscription to the `ButtonClick` of the button repository, to handle the clicking of one of the buttons of the grid.


# PK-Sim Database Description

## Introduction

PK-Sim uses an [SQLite](https://www.sqlite.org/index.html) database to store data models and templates. In this part of the developer documentation we will present this database with a thorough description of its structure and tables.

More specifically, in the PK-Sim DB, we store:

* Structural models for PBPK modeling of small and large molecules:
* Anatomical and physiological parameters in different animal species and human populations for **healthy** individuals
  * For details regarding parameterization of **diseased** individuals please refer to [tab\_population\_disease\_states](#tab_population_disease_states).
* Templates for small and large molecules.
* Templates for optional processes like
  * Metabolizing pathways
  * Different active transporter types (influx, efflux, bidirectional)
  * Protein binding partners
* Templates for various administration routes and formulations
* Prediction models for
  * Tissue partition coefficients
  * Cellular permeabilities
  * Intestinal permeability
* Templates for events (meals etc.)

The database can be found in the [PK-Sim repository under **src/Db/PKSimDB.sqlite**](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/Db/PKSimDB.sqlite).

### DB Schema Diagrams

For this documentation segment, database schema diagrams were created using the [SchemaCrawler](https://www.schemacrawler.com/). You can find a short description of how to install and use the *SchemaCrawler* for creating schema diagrams [here](https://github.com/Open-Systems-Pharmacology/developer-docs/wiki/Using-SchemaCrawler-for-creating-of-database-schema-diagrams).

## General remarks

When a database value describes a numeric property of a quantity (e.g., parameter value, allowed value range, etc.), the value is always stored in the **base unit of the dimension of the quantity**.

Check the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml) to see what the base unit of a dimension is!

Some of the common properties used in many tables:

* **display\_name** The name of the entity to be used in the UI in PK-Sim.

  NOTE: MoBi does not support the "display name" concept, so all entities are displayed with their internal name. Also within a model all objects are stored with their internal name. It is therefore advisable to keep the display name the same as the internal name. Exceptions are e.g. special characters like "\*", "|" etc. which cannot be used in internal names.
* **description** Longer description of the entity, which is displayed as a tooltip in PK-Sim and can be edited in MoBi.
* **sequence** Used to sort objects in the UI (unless another sorting algorithm applies, e.g. alphabetical).
* **icon\_name** Defines which icon is used for the entity.

  If not empty: the icon with the given name must be present in the `OSPSuite.Assets.Images`
* {**min\_value**, **min\_isallowed**, **max\_value**, **max\_isallowed**} specifies the allowed range of values for a numeric quantity.
  * **min\_isallowed** and **max\_isallowed** define whether the corresponding bounded value range is open or closed.
  * **min\_value** can be empty. In this case the lower bound is `-Infinity`. The value of **min\_isallowed** will then be ignored.
  * **max\_value** can be empty. In this case the upper bound is `+Infinity`. The value of **max\_isallowed** will then be ignored.

Boolean values are always represented as **integers restricted to {0, 1}**.

:grey\_exclamation: Before renaming or removing basic entities (parameters, containers, observers): you should always **check if the modified entity is explicitly used by its name in PK-Sim or in the OSPSuite.Core**. If so, further code changes are required to reflect the database change! In some cases, the database objects that appear to be unused (when looking only at the database) are actually used in PK-Sim to create objects on the fly.

## Overview diagrams

Each of the following subsections focuses on one aspect and shows only a **subset** of the database tables relevant to that topic. The last subsection shows the complete schema with all tables.

### Containers

A *container* is a model entity that can have children. In the context of PK-Sim, everything except parameters and observers is a container.

![](/files/g0GrVKPDBFdpfIIZ5oep)

#### tab\_container\_names

Describes an abstract container (e.g. "Plasma"), which can be inserted at various places in the container structure defined in [*tab\_containers*](#tab_containers).

* **container\_type** is used, for example, to map a container to the correct container class in PK-Sim.
* **extension** is not used by PK-Sim and is only useful for some database update scripts.
* **icon\_name** defines which icon is used for a container.

There are some "special" containers defined in *tab\_container\_names* that are not used in the container hierarchy defined in [*tab\_containers*](#tab_containers). These containers are only used for **referential integrity when defining some relative object paths** (see the [Formulas](#formulas) section for more details).

#### tab\_container\_types

Defines available container types.

#### tab\_organ\_types

Classifies containers of type `ORGAN`. This classification is used in PK-Sim to group organs in different views (e.g. *Tissue Organs* vs. *Vascular System* vs. *GI Tract* etc.).

* **container\_type** is always set to "ORGAN".
* **organ\_name** is the name of the organ.
* **organ\_type** can be one of the values defined in [enum OrganType](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Core/Model/OrganType.cs).

#### tab\_containers

Defines the container hierarchy and includes **all possible containers** which can appear in a model. When a model is created, some containers are filtered out based on the information in [*tab\_model\_containers*](#tab_model_containers) and [*tab\_population\_containers*](#tab_population_containers) (s. below)

* Each container within a hierarchy is identified by the combination `{container_id, container_type, container_name}`.
  * `container_id` is unique across all containers. In principle, it would be sufficient to use only the *container id* as the primary key. Container type and container name have been included in the primary key for convenience (e.g. when querying data from other tables, it is not always necessary to include *tab\_containers* and *tab\_container\_names* etc.).
* Each container can have a parent container defined by the combination `{parent_container_id, parent_container_type, parent_container_name}`.
  * Containers that appear at the top level of the *Spatial Structure* are defined as children of the special `ROOT` container. The `ROOT` container itself has no parent.

    | container\_id | container\_type | container\_name    | parent\_container\_id | parent\_container\_type | parent\_container\_name |
    | ------------- | --------------- | ------------------ | --------------------- | ----------------------- | ----------------------- |
    | 146           | ORGANISM        | Organism           | 145                   | SIMULATION              | ROOT                    |
    | 777           | GENERAL         | Neighborhoods      | 145                   | SIMULATION              | ROOT                    |
    | 1026          | GENERAL         | MoleculeProperties | 145                   | SIMULATION              | ROOT                    |
    | 4205          | GENERAL         | Events             | 145                   | SIMULATION              | ROOT                    |
  * Top containers of other building blocks (Passive Transports, Reactions, Events, Formulations, ...) are all defined as containers without a parent.
* **tab\_containers.visible** defines if a container is shown in PK-Sim in hierarchy view (TODO rename column to **is\_visible**).
* **tab\_containers.is\_logical** defines if a container is *physical* or *logical* (s. the [OSP documentation](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/spatial-structures-bb) for details).

#### tab\_container\_tags

Describes which additional tags are added to a container.

* the **name** of a container is always added as a tag programmatically and does not need to be added here.

#### tab\_neighborhoods

Defines 2 neighbor containers for each neighborhood of a spatial structure

* There are no rules or restrictions as to which of 2 adjacent containers must be defined as the first and which as the second container. For example, passive transports are defined by the container criteria of their source and target containers, and changing the first and second neighbour containers does not affect the later creation of the transport. Care should only be taken when using the keywords FIRST\_NEIGHBOR and SECOND\_NEIGHBOR in the formulas.
  * Even in the latter case, swapping neighbors may not be critical. E.g. if both neighbor containers have **the same parent container** and the formula uses the path `FIRST_NEIGHBOR|..|Parameter1`, then swapping the formula path with `SECOND_NEIGHBOR|..|Parameter1`would result in the same formula, because F`IRST_NEIGHBOR|..` and `SECOND_NEIGHBOR|..` both point to the same container, making the formula invariant with respect to neighbor switching.
  * But if the formula refers e.g. to `FIRST_NEIGHBOR|Parameter1` - then the neighbor order is relevant.

#### tab\_population\_containers

Defines which containers are created in individual/population building blocks in PK-Sim. For each population, this is a subset of the containers defined in [*tab\_containers*](#tab_containers).

#### tab\_model\_containers

Defines which containers **can** be included into the final model. Whether a container is included into the model is estimated based on the value of the column **usage\_in\_individual** as following:

* if `usage_in_individual = REQUIRED`
  * if the container is available in the individual/population building block used for the model creation: container is added to the model
  * otherwise: error, model cannot be created
* if `usage_in_individual = OPTIONAL`
  * if the container is available in the individual/population building block used for the model creation: container is added to the model
  * otherwise: container is NOT added to the model
* if `usage_in_individual = EXTENDED`
  * container is added to the model in any case
  * containers of this type usually should not be defined in [*tab\_population\_containers*](#tab_population_containers)

### Processes

*Processes* are defined as containers with `container_type="PROCESS"` and must be inserted into [*tab\_container\_names*](#tab_container_names) first; once done they can be inserted into [*tab\_processes*](#tab_processes) and further process-specific tables.

![](/files/2LCAUQ9dY5G3UUkoOVST)

#### tab\_processes

Contains the following information about a process:

* **template** defines whether a process is always added to the selected model or only on demand.
  * For example, all passive transports or FcRn binding reactions in a protein model have `template = 0`
  * For example, active transports or metabolization reactions which are added only if the corresponding process was configured in a simulation in PK-Sim have `template = 1`
* **group\_name** is used to identify where (in which building blocks or simulations) the processes are used in PK-Sim.
  * Processes with the **parent** group *COMPOUND\_PROCESSES* are templates for active processes (active transport, specific binding, elimination, metabolization, inhibition, induction, ...) used in the compound building block of PK-Sim.
  * Processes with the group *APPLICATION* are application transports.
  * Processes with the group *INDIVIDUAL\_ACTIVE\_PROCESS* are templates for *active transports*, used in an *Expression Profile* building block. These templates have no parameters and are further specified in [*tab\_transports*](#tab_transports) (s. below).
  * Processes with the group *PROTEIN* describe *production* and *degradation* of proteins (enzymes, transporters, binding partners).
  * Processes with the group *SIMULATION\_ACTIVE\_PROCESS* describe the processes which are created in a simulation from both compound process template and individual (expression profile) process template.
  * Processes with the group *UNDEFINED* are processes where the group is not relevant (typically all *passive* processes).

    | GROUP\_NAME                     | PARENT\_GROUP       |
    | ------------------------------- | ------------------- |
    | ACTIVE\_TRANSPORT               | COMPOUND\_PROCESSES |
    | ACTIVE\_TRANSPORT\_INTRINSIC    | COMPOUND\_PROCESSES |
    | APPLICATION                     |                     |
    | ENZYMATIC\_STABILITY            | COMPOUND\_PROCESSES |
    | ENZYMATIC\_STABILITY\_INTRINSIC | COMPOUND\_PROCESSES |
    | INDIVIDUAL\_ACTIVE\_PROCESS     |                     |
    | INDUCTION\_PROCESSES            | COMPOUND\_PROCESSES |
    | INHIBITION\_PROCESSES           | COMPOUND\_PROCESSES |
    | PROTEIN                         |                     |
    | SIMULATION\_ACTIVE\_PROCESS     |                     |
    | SPECIFIC\_BINDING               | COMPOUND\_PROCESSES |
    | SYSTEMIC\_PROCESSES             | COMPOUND\_PROCESSES |
    | UNDEFINED                       |                     |
* **kinetic\_type** is used for the mapping `{Compound process template, Individual process template} ▶️ Simulation process`

  Example: active transports

  * for the active transports there are currently 2 compound templates:

    | process                       | group\_name       | kinetic\_type |
    | ----------------------------- | ----------------- | ------------- |
    | ActiveTransportSpecific\_Hill | ACTIVE\_TRANSPORT | Hill          |
    | ActiveTransportSpecific\_MM   | ACTIVE\_TRANSPORT | MM            |
  * there are different individual active transport templates - specified by their source and target (Interstitial<=>Intracellular, Interstitial<=>Plasma, Blood Cells <=> Plasma etc.) (kinetic type is not specified on the individual building block level and thus is set to "*Undefined*")

    | process                                         | group\_name                 | kinetic\_type |
    | ----------------------------------------------- | --------------------------- | ------------- |
    | ActiveEffluxSpecificIntracellularToInterstitial | INDIVIDUAL\_ACTIVE\_PROCESS | Undefined     |
    | ActiveInfluxSpecificInterstitialToIntracellular | INDIVIDUAL\_ACTIVE\_PROCESS | Undefined     |
    | ActiveEffluxSpecificInterstitialToPlasma        | INDIVIDUAL\_ACTIVE\_PROCESS | Undefined     |
    | ActiveInfluxSpecificPlasmaToInterstitial        | INDIVIDUAL\_ACTIVE\_PROCESS | Undefined     |
    | ...                                             | ...                         | ...           |
  * In the simulation

    * `ActiveTransportSpecific_MM (Compound) + ActiveEffluxSpecificIntracellularToInterstitial (Individual) ▶️ ActiveEffluxSpecificIntracellularToInterstitial_MM (Simulation)`
    * `ActiveTransportSpecific_Hill (Compound) + ActiveEffluxSpecificIntracellularToInterstitial (Individual) ▶️ ActiveEffluxSpecificIntracellularToInterstitial_Hill (Simulation)`

    | process                                               | group\_name                 | kinetic\_type |
    | ----------------------------------------------------- | --------------------------- | ------------- |
    | ActiveEffluxSpecificIntracellularToInterstitial\_Hill | SIMULATION\_ACTIVE\_PROCESS | Hill          |
    | ActiveEffluxSpecificIntracellularToInterstitial\_MM   | SIMULATION\_ACTIVE\_PROCESS | MM            |
    | ActiveInfluxSpecificInterstitialToIntracellular\_Hill | SIMULATION\_ACTIVE\_PROCESS | Hill          |
    | ActiveInfluxSpecificInterstitialToIntracellular\_MM   | SIMULATION\_ACTIVE\_PROCESS | MM            |
    | ActiveEffluxSpecificInterstitialToPlasma\_Hill        | SIMULATION\_ACTIVE\_PROCESS | Hill          |
    | ActiveEffluxSpecificInterstitialToPlasma\_MM          | SIMULATION\_ACTIVE\_PROCESS | MM            |
    | ActiveInfluxSpecificPlasmaToInterstitial\_Hill        | SIMULATION\_ACTIVE\_PROCESS | Hill          |
    | ActiveInfluxSpecificPlasmaToInterstitial\_MM          | SIMULATION\_ACTIVE\_PROCESS | MM            |
    | ...                                                   | ...                         | ...           |
* **process\_type** is used for more detailed process specification within a group and is used for various purposes in PK-Sim (s. e.g. [FlatProcessToCompoundProcessMapper](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/Mappers/FlatProcessToCompoundProcessMapper.cs), [FlatProcessToActiveProcessMapper](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/Mappers/FlatProcessToActiveProcessMapper.cs),etc.)

  | group\_name                     | process\_type            |
  | ------------------------------- | ------------------------ |
  | ACTIVE\_TRANSPORT               | ActiveTransport          |
  | ACTIVE\_TRANSPORT\_INTRINSIC    | ActiveTransport          |
  | APPLICATION                     | Application              |
  | ENZYMATIC\_STABILITY            | Metabolization           |
  | ENZYMATIC\_STABILITY\_INTRINSIC | Metabolization           |
  | INDIVIDUAL\_ACTIVE\_PROCESS     | BiDirectional            |
  | INDIVIDUAL\_ACTIVE\_PROCESS     | Efflux                   |
  | INDIVIDUAL\_ACTIVE\_PROCESS     | Influx                   |
  | INDIVIDUAL\_ACTIVE\_PROCESS     | PgpLike                  |
  | INDUCTION\_PROCESSES            | Induction                |
  | INHIBITION\_PROCESSES           | CompetitiveInhibition    |
  | INHIBITION\_PROCESSES           | IrreversibleInhibition   |
  | INHIBITION\_PROCESSES           | MixedInhibition          |
  | INHIBITION\_PROCESSES           | NoncompetitiveInhibition |
  | INHIBITION\_PROCESSES           | UncompetitiveInhibition  |
  | PROTEIN                         | Creation                 |
  | SIMULATION\_ACTIVE\_PROCESS     | BiDirectional            |
  | SIMULATION\_ACTIVE\_PROCESS     | Efflux                   |
  | SIMULATION\_ACTIVE\_PROCESS     | Induction                |
  | SIMULATION\_ACTIVE\_PROCESS     | Influx                   |
  | SIMULATION\_ACTIVE\_PROCESS     | IrreversibleInhibition   |
  | SIMULATION\_ACTIVE\_PROCESS     | PgpLike                  |
  | SPECIFIC\_BINDING               | SpecificBinding          |
  | SYSTEMIC\_PROCESSES             | Elimination              |
  | SYSTEMIC\_PROCESSES             | EliminationGFR           |
  | SYSTEMIC\_PROCESSES             | Metabolization           |
  | SYSTEMIC\_PROCESSES             | Secretion                |
  | UNDEFINED                       | Passive                  |
* **action\_type** is one of {`APPLICATION`, `INTERACTION`, `REACTION`, `TRANSPORT`} (s. [enum ProcessActionType](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/FlatObjects/ProcessActionType.cs)).
* **create\_process\_rate\_parameter** defines if the `Process Rate` parameter should be created for transport or reaction (s. OSP Suite documentation [molecules](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/molecules-bb) or [reactions](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/reactions-bb) for details.)

#### tab\_process\_types

Defines available process types.

#### tab\_kinetic\_types

Defines available process kinetic types.

#### tab\_process\_descriptor\_conditions

Describes source and target container criteria for transports and source container criteria for reactions

* **tag\_type** can be one of `{SOURCE, TARGET}`

#### tab\_process\_molecules

Describes the reactions which are **always** part of a model (like e.g. *FcRn binding* in the large molecules model) (TODO rename the table, s. the issue <https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309>)

* **direction** can be of `IN` (educt), `OUT` (product) or `MODIFIER`

#### tab\_process\_rates

Describes the rate (kinetic) of a process

* Template processes with the **parent** group **COMPOUND\_PROCESSES** and processes with the group **INDIVIDUAL\_ACTIVE\_PROCESS** always have `Zero_Rate` formula, because they are used in the corresponding building blocks where the process rate does not matter. The real rate is then set for the corresponding **simulation** process, e.g.

  | process                                             | calculation\_method | formula\_rate                                   |
  | --------------------------------------------------- | ------------------- | ----------------------------------------------- |
  | ActiveTransportSpecific\_MM                         | LinksCommon         | Zero\_Rate                                      |
  | ActiveEffluxSpecificIntracellularToInterstitial     | LinksCommon         | Zero\_Rate                                      |
  | ActiveEffluxSpecificIntracellularToInterstitial\_MM | LinksCommon         | ActiveEffluxSpecificWithTransporterInTarget\_MM |

#### tab\_model\_transport\_molecule\_names

Restricts which molecules are transported by a passive transport for particular model. As per default, passive transport will transfer all floating molecules from its source container to the target container. In this table, some molecules can be excluded (`should_transport=0`) or transport can be restricted only to the specific molecules (`should_transport=1`). S. the [Passive Transports documentation](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/passive-transports-bb) (TODO rename the table, s. the issue <https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309>)

#### tab\_transports

Defines which active transports can be created in the model. (TODO rename the table, s. the issue <https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309>)

#### tab\_transport\_directions

Defines all available transport directions (TODO rename the table, s. the issue <https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309>)

#### tab\_known\_transporters

Defines a *global* transporter direction for a `{Species, Gene}` combination. When adding a transporter in PK-Sim that is not available in this data table: the transporter direction is set to default and the user is informed that the transporter was not found in the database. See [Localizations, directions, and initial concentrations of transport proteins](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-expression-profile#localizations-directions-and-initial-concentrations-of-transport-proteins) in the OSP Suite documentation.

#### tab\_known\_transporters\_containers

The *global* transporter direction defines the default transporter direction and polarity in each organ. However, some organs may have different transporter properties. To account for this, the *local* transporter direction and/or polarity can be overridden in some organs by entries in this table. See [Localizations, directions, and initial concentrations of transport proteins](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-expression-profile#localizations-directions-and-initial-concentrations-of-transport-proteins) in the OSP Suite documentation.

#### tab\_active\_transport\_types

Defines available **active** transport types (which is a subset of all transport types defined in [enum TransportType](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Domain/TransportType.cs)).

### Species and populations

*Species* defines the type of an individual (Human, Dog, Rat, Mouse, ...)

*Population* defines a subtype of a species. For each species, 1 or more populations can be defined.

![](/files/1TWFclsrBeoyVZHUl1so)

**tab\_population\_containers** specifies which containers are available for the given population and is described in detail [here](#tab_population_containers). See the [Containers](#containers) section for the explanation how this information is used when creating a simulation).

#### tab\_species

Defines a species.

* **user\_defined**
* **is\_human**

#### tab\_populations

Defines which populations are available for a given species.

* **is\_age\_dependent** Specifies whether some population parameters have age-dependent information (such parameters are then defined in [*tab\_container\_parameter\_curves*](#tab_container_parameter_curves)). If a population is age dependent:
  * Age must be provided as an input when creating an individual
  * Age range must be provided as an input when creating a population
  * *Aging* option is available when creating a simulation
  * Age dependent *ontogeny information* will be used for proteins etc.
* **is\_height\_dependent** Specifies whether height information is available for the given population. If a population is height dependent:
  * Height must be provided as an input when creating an individual
  * Height range must be provided as an input when creating a population
  * Organ volumes and some other anatomical parameters are scaled with the height when creating an individual, in simulations with aging etc.
  * Body surface area can be calculated

#### tab\_genders

Provides definition of all available genders.

#### tab\_population\_genders

Define genders available for a population. If no gender-specific data is available: gender is set to `UNKNOWN`.

#### tab\_population\_age

Defines the age range and the default age for the newly created individuals for all age-dependent populations.

* **default\_age\_unit** is the default *user interface* unit used when creating individuals/populations for the given population.

#### tab\_species\_calculation\_methods

If a parameter is defined by **formula** - this formula must be described by a *calculation method* (s. the [Calculation methods and parameter value versions](#calculation-methods-and-parameter-value-versions) section for details). In such a case, this calculation method must be assigned to the species, which happens in *tab\_species\_calculation\_methods*.

* E.g. the calculation method `Lumen_Geometry` describes the calculation of some GI-related parameters based on the age and body height, which is currently applicable only to the species `Human`. Thus this calculation method is defined only for `Human` in the table

#### tab\_species\_parameter\_value\_versions

Is the counterpart of *tab\_species\_calculation\_methods* for parameters defined by a **constant value**. All constant values must be described by a *parameter value version* (s. the [Calculation methods and parameter value versions](#calculation-methods-and-parameter-value-versions) section for details).

One of the reasons for introducing calculation methods and parameter value versions is that sometimes we have **more than one possible alternative** for defining a set of parameters.

* E.g. we have several alternatives for the calculation of body surface area in humans. The corresponding entries in the table [*tab\_species\_calculation\_methods*](#tab_species_calculation_methods) are shown below.

  | species | calculation\_method           |
  | ------- | ----------------------------- |
  | Human   | Body surface area - Du Bois   |
  | Human   | Body surface area - Mosteller |

  The fact that the above calculation methods are **alternatives** is defined by the fact that both have the same **category** defined in [*tab\_calculation\_methods*](#tab_calculation_methods) (see section [Calculation Methods and Parameter Value Versions](#calculation-methods-and-parameter-value-versions) for details). In PK-Sim, the user then has to select exactly one of these calculation methods (in the above example - during the individual creation, because the described parameters belong to the individual building block).

  ![](/files/RLUoH9PmAwvJZkptUS5y)

#### tab\_model\_species

Defines which species can be used in combination with the given model.

#### tab\_population\_disease\_states

The PK-Sim database stores information for **healthy** individuals. For some populations, additional information is available for some disease states. This table indicates which disease states are available for a population. If any:

* User can choose between healthy and one of the diseased states
* If a disease state has been selected: additional input parameters may be required. In the database, these parameters are specified in a parentless container whose name is identical to the name of the selected disease state and with `container_type=DISEASE_STATE`, e.g:

  | container\_id | container\_type | container\_name | parameter\_name | group\_name     | building\_block\_type | is\_input | … |
  | ------------- | --------------- | --------------- | --------------- | --------------- | --------------------- | --------- | - |
  | 5954          | DISEASE\_STATE  | CKD             | eGFR            | DISEASE\_STATES | INDIVIDUAL            | 1         | … |
* Disease-specific parameter values are currently NOT stored in the PK-Sim database. Instead, PK-Sim provides a "DiseaseState" class for each available disease state. In this class, a healthy individual is taken and then modified according to the specification of the given disease state. Examples:

  * CKD (Chronic Kidney Disease) disease state: [CKDDiseaseStateImplementation.cs](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Core/Services/CKDDiseaseStateImplementation.cs)
  * HI (Hepatic Impairment) disease state: [HIDiseaseStateImplementation.cs](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Core/Services/HIDiseaseStateImplementation.cs)

  ![](/files/041VO2iLqpu10yydAJrX)

#### tab\_disease\_states

Describes all currently available disease states.

#### tab\_ontogenies

Defines ontogeny factors for some known proteins for a combination of `{Protein, Species}` (s. the [Documentation](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-compounds-definition-and-work-flow#basic-physico-chemistry) for details)

* **molecule** name of the protein.
* **species** name of the species
* **group\_name** specifies the localization of the ontogeny information:
  * `ONTOGENY_PLASMA` is used to set ontogeny factor for the plasma protein binding (s. [Documentation](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-compounds-definition-and-work-flow#basic-physico-chemistry) for details)
  * For enzymes, transporters and binding partners (other than plasma binding partners), ontogeny information can be stored in 2 different ways:
    * Either the same (global) ontogeny factor for all containers. In this case, the group name is set to `ONTOGENY_LIVER_ALL`
    * Or two ontogeny factors: the first one for the intestine and the second one for the rest of the body. In this case, the group name for these 2 factors is set to `ONTOGENY_DUODENUM` and `ONTOGENY_LIVER_NO_GI`, respectively.
* For for a combination of `{Protein, Species, Group}`, ontogeny information is stored in the form of the supporting points `{Postmenstrual age (PMA), Ontogeny factor, Geometric Standard Deviation}`.
  * If the individual's PMA is equal to one of the supporting points: the corresponding ontogeny factor value is used for the calculation.
  * If the PMA of the individual is less than the minimum PMA of the supporting points: the ontogeny factor corresponding to the minimum PMA is used.
  * If the PMA of the individual is greater than the maximum PMA of the supporting points: the ontogeny factor corresponding to the maximum PMA is used.
  * In other cases, the ontogeny factor is calculated by linear interpolation from two supporting points.

### Container parameters

This section describes the definition of `{Container, Parameter}` combinations. Another (dynamic) way to define parameters is described in the section [Calculation method parameters](#calculation-method-parameters) below.

![](/files/je5We06nrp0El1pOpAjI)

#### tab\_parameters

Describes an abstract parameter (e.g. "Volume"), which can be inserted in various containers.

* **dimension** must be one of the dimensions defined in the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml).
* **default\_unit** \[OPTIONAL] The default unit to use in the UI (unless the user specifies otherwise). Must be one of the units defined for the parameter dimension in the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml). If empty: the default unit from the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml) for the parameter dimension is used.

#### tab\_dimensions

Lists the available dimensions.

* **dimension** must be one of the dimensions defined in the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml).
* **kernel\_unit** is not used. Is only helpful when creating some database reports etc. Must be identical with the base unit of the corresponding dimension defined in the [OSP Dimensions Repository](https://github.com/Open-Systems-Pharmacology/OSPSuite.Dimensions/blob/master/OSPSuite.Dimensions.xml).

#### tab\_container\_parameters

Specifies a `{Container, Parameter}` combination.

* {**container\_id**, **container\_type**, **container\_name**} specifies the container.
* **parameter\_name** specifies the parameter.
* **visible** specifies if the parameter is shown in the PK-Sim UI (when sent to MoBi, this flag is translated into the *Advanced parameter* property.)
* **read\_only** specifies if the parameter can be edited by user in the PK-Sim UI
* **can\_be\_varied** is used to allow the variation of some read-only parameters outside of PK-Sim (e.g. in MoBi or via the R interface).

  Example: for the Arterial Blood container, the following parameters are defined in PK-Sim:

  | container\_name | parameter\_name                | can\_be\_varied | read\_only | visible |
  | --------------- | ------------------------------ | --------------- | ---------- | ------- |
  | ArterialBlood   | Allometric scale factor        | 0               | 1          | 0       |
  | ArterialBlood   | Density (tissue)               | 1               | 1          | 0       |
  | ArterialBlood   | Fraction vascular              | 1               | 1          | 1       |
  | ArterialBlood   | Peripheral blood flow fraction | 1               | 0          | 1       |
  | ArterialBlood   | Volume                         | 1               | 0          | 1       |
  | ArterialBlood   | Weight (tissue)                | 1               | 1          | 0       |

  If we create a sensitivity analysis in PK-Sim, only the parameters `Peripheral Blood Flow Fraction` and `Volume` will be available for variation because of the flag combination `{visible=1, read_only=0, can_be_varied=1}`.

  However, if we send the simulation to MoBi and create a sensitivity analysis there, all parameters from the table above, except `Allometric Scale Factor`, will be available for variation (in *Advanced Mode*), due to `can_be_varied=1`.
* **can\_be\_varied\_in\_population** specifies (together with **is\_changed\_by\_create\_individual** - s. below) if a parameter defined by value or by formula (s. below) can be used for the [User Defined Variability‌](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-creating-populations#user-defined-variability) in populations or population simulations.
* **group\_name** defines how parameters are displayed in the PK-Sim UI (s. below and also see the description in the [OSP documentation](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-simulations#running-a-simulation-in-an-individual)).
* **build\_mode** can be one of the following: `LOCAL`, `GLOBAL`, or `PROPERTY` (s. the [OSP documentation](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags) for details).
* **building\_block\_type** can be one of the following: `COMPOUND`, `EVENT`, `FORMULATION`, `INDIVIDUAL`, `PROTOCOL`, `SIMULATION`. Used to determine which parameters can be added to a container at the building block level and which at the simulation level.
* **is\_input** is used to specify whether a parameter that has NOT been changed by the user should be exported to the project snapshot or not.

  Why we need this: some parameters have default values **just for user convenience**. In principle, these values should be empty/NaN by default. However, to reduce the amount of user input required, the parameters have been set to some value.

  For example, when creating a new compound, the default value is "`Is small molecule = 1`". When the user creates a new small molecule compound, this value is apparently kept AS IS. But in fact it's a user input, which is implicit here, meaning that the value of "`Is small molecule`" must be exported to the snapshot in any case.
* **is\_changed\_by\_create\_individual** indicates whether a parameter is changed by the *Create Individual algorithm*. This includes both *directly* modified parameters (= age-dependent parameters specified in [*tab\_container\_parameter\_curves*](#tab_container_parameter_curves), see below) and *indirectly* modified parameters (such as the blood flows). Parameters with `is_changed_by_create_individual = 1` always appear in the *Distribution* tab of PK-Sim and are not available for user-defined variability.

#### tab\_groups

Defines the group hierarchy. In the parameter view of individuals/populations/simulations in PK-Sim, each visible parameter is displayed within its group. (s. [OSP Suite documentation](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-creating-individuals#anatomy-and-physiology) for details)

* **parent\_group** specifies the parent group (if any). Groups without a parent are displayed at the top level.
* **is\_advanced** defines whether the group is displayed in the simple view or only in the advanced view.
* **visible** determines whether the group is visible in the parameter view. If a parameter is visible but belongs to a hidden group, it can still be displayed in either the Hierarchy View mode or in the "All" Parameters group.
* **pop\_display\_name** \[OPTIONAL] is used to display parameters in the "User Defined Variability" and "Distribution" tabs of populations and population simulations. If empty: the **display\_name** of the group is used.
* **full\_name** is not used by PK-Sim. Shown in MoBi when a simulation is sent from PK-Sim (MoBi does not provide hierarchical parameter view by group like PK-Sim).
* **unique\_id** Unique group id used to identify a group in MoBi or when importing a simulation from pkml in PK-Sim. Should never be changed in the DB! With each new OSP release a **GroupRepository.xml** file is generated by PK-Sim and placed under **C:\ProgramData\Open Systems Pharmacology\MoBi\X.Y**. Here the complete group information (display name, description, icon, ..) is stored. In pkml files, only the unique group ID is stored.

#### tab\_molecule\_parameters

Describes some global protein parameters (like "Reference concentration" etc.)

The value of a container parameter can be defined in one of three possible ways:

1. By a *formula* specified in [*tab\_container\_parameter\_rates*](#tab_container_parameter_rates).

   A formula is neither species nor population dependent.
2. By *constant value* specified in [*tab\_container\_parameter\_values*](#tab_container_parameter_values).

   A constant value is species dependent but not population dependent.
3. By *age-dependent probability distribution* specified in [*tab\_container\_parameter\_curves*](#tab_container_parameter_curves).

It is possible, that for a combination {`container_id, container_type, container_name, parameter_name`} we have *several entries* in different tables (e.g. several formulas or formula and value etc.).

When creating a building block or simulation, some entries are filtered out because the calculation method or parameter value version of the entry does not belong to the species/population/model of the created building block/simulation.

If we still have more than one entry - the corresponding calculation methods or parameter value versions must be of the **same category** (i.e. they represent possible **alternatives** for the parameter definition). See the sections [Species and Populations](#species-and-populations) and [Calculation Methods and Parameter Value Versions](#calculation-methods-and-parameter-value-versions) for more details.

#### tab\_container\_parameter\_rates

Defines a formula for the given parameter in the given container.

* **container\_id**, **container\_type**, **container\_name** defines the container.
* **parameter\_name** defines the parameter in the given container.
* **calculation\_method**, **formula\_rate** defines the formula (s. the section [Formulas](#formulas) for more details on formulas).

#### tab\_container\_parameter\_values

Defines a constant value for the combination {*Container*, *Parameter*, *Species*, *Parameter Value Version*}.

* **container\_id**, **container\_type**, **container\_name** defines the container.
* **parameter\_name** defines the parameter in the given container.
* **species** defines the species.
* **parameter\_value\_version** defines which parameter value version the given value belongs to (s. the section [Calculation methods and parameter value versions](#calculation-methods-and-parameter-value-versions) for more details).
* **default\_value** parameter value for the combination of the properties above.

#### tab\_container\_parameter\_curves

Describes age-dependent and/or distributed parameters.

How does it work (all bullet points below apply for a combination {`parameter_value_version, species, container_id, container_type, container_name, parameter_name, population, gender, gestational_age`}):

* N supporting age points are defined (N>=1): *Age\_min*, … , *Age\_max*
* For an individual of given age: *mean* and *sd* value are interpolated based on the mean and sd of defined supported points
  * For `Age < Age_min`: `mean(Age) = mean(Age_min)` and `sd(Age) = sd(Age_min)`
  * For `Age > Age_max`: `mean(Age) = mean(Age_max)` and `sd(Age) = sd(Age_max)`
  * For `Age_min ≤ Age ≤ Age_max`: both *mean* and *sd* are linearly interpolated between their 2 adjacent supporting points (if the *Age* is one of the supporting points, then *mean* and *sd* are obviously taken from it without interpolation).
* Distribution type must be always the same for all ages.
* If we have only age dependency but no distribution, we set `distribution_type=”discrete”` (constant) and `sd = 0` for all supporting points.
* If both *mean* and *sd* are constant for all ages: we define only 1 supporting point (usually with `Age = 0`).

#### tab\_distribution\_types

Lists all available probability distributions.

#### tab\_compound\_process\_parameter\_mapping

When creating a process in a compound building block, the values of the *Calculation parameters* of this process are taken from the mapped parameters of the **default individual** for the **default population** (the latter is specified in the PK-Sim options) of the species defined by the user during the process creation (see the [OSP Suite documentation](https://docs.open-systems-pharmacology.org/working-with-pk-sim/pk-sim-documentation/pk-sim-compounds-definition-and-work-flow#adme-properties) for details).

#### tab\_container\_parameter\_rhs

If a parameter is defined by a differential equation, the right-hand side (RHS) of that equation is given in this table.

#### tab\_container\_parameter\_descriptor\_conditions

Is used to restrict the creation of local protein parameters to specific containers.

* **tag** Tag of a container in which the parameter should (or should not) be created.
* **condition** Criteria condition for the tag.
* **operator** Specifies how to combine single criteria conditions for the combination {`container_id, container_type, container_name, parameter_name`}. Must be the same for all entries in this combination. Possible values are 'And' and 'Or'.

#### tab\_conditions (container parameters)

Specifies available (container) criteria conditions. Values must be the same as defined by the [`enum CriteriaCondition`](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/FlatObjects/CriteriaCondition.cs) in PK-Sim.

<details>

<summary>Currently not used by PK-Sim</summary>

There is another way to describe the value of a container parameter: by an age-dependent probability distribution specified in [*tab\_container\_parameter\_fcurves*](#tab_container_parameter_fcurves). However, this is currently not used by PK-Sim.

The difference to the [*tab\_container\_parameter\_curves*](#tab_container_parameter_curves) is: the age-dependent parameter value and distribution are not defined by the table of support points, but by 2 analytical functions:

$$Mean\ value = f\_1(Age,\ ...)$$

$$Standard\ deviation = f\_2(Age,\ ...)$$

![](/files/zPVYpD5nw7ZKtUZzwzQI)

#### tab\_container\_parameter\_fcurves

* **calculation\_method**, **mean\_value\_rate** define the age-dependent function of the parameter mean value.
* **calculation\_method**, **standard\_deviation\_rate** define the age-dependent function of the parameter standard deviation.
* all other columns have the same meaning as in the [*tab\_container\_parameter\_curves*](#tab_container_parameter_curves).

</details>

### Calculation method parameters

Apart from the container parameters described above, some parameters are created *dynamically* when the model uses a particular calculation method.

Some calculation methods rely on a large number of **supporting parameters**, which are only used to create other parameters and are of no interest once the "main" parameters are created.

To avoid adding tons of supporting parameters for all possible combinations of calculation methods, the concept of "Calculation method parameters" was introduced, which allows adding supporting parameters on demand.

To enable calculation method parameters also in MoBi: with each new OSP release a **AllCalculationMethods.pkml** file is generated by PK-Sim and placed under **C:\ProgramData\Open Systems Pharmacology\MoBi\X.Y**. Here the complete supporting parameter information (parameter properties, location, formula) is stored.

![](/files/wayD1Xfm7GyZ4XG6idPt)

#### tab\_calculation\_method\_parameter\_rates

Defines which parameters are added dynamically. Another task of this table is to dynamically assign formulas to the "main" parameters initially defined by a *black-box formula*. The latter is described in more detail in the section [Black Box Formulas](#black-box-formulas).

* **parameter\_id** unique id, only used internally in the database.
* **parameter\_name** name of the supporting parameter to add.
* **group\_name**, **can\_be\_varied**, **can\_be\_varied\_in\_population**, **read\_only**, **visible** have the same meaning as for the container parameters.
* {**calculation\_method**, **rate**} define for which calculation method and with which formula the parameter will be added.

#### tab\_calculation\_method\_parameter\_descr\_conditions

Defines the containers in which a supporting parameter should be created. Containers are described by their tags; single criteria conditions for a parameter id are combined by `AND`.

### Formulas

This section describes the formulas defined in the PK-Sim database. This includes:

* formulas defined by an analytical equation (*explicit formulas*)
* *sum formulas*
* table formulas with offset
* table formulas with X argument

An **explicit formula** is defined by the equation $$f(P\_1, ... P\_n; M\_1, ..., M\_k; C\_1, ... C\_j; TIME)$$ where:

* $$f$$ is an analytical function
* $$P\_1, ... P\_n$$ ($$n \geq 0$$) are model parameters
* $$M\_1, ..., M\_k$$ ($$k \geq 0$$) are molecule amounts
* $$C\_1, ... C\_j$$ ($$j \geq 0$$) are molecule concentrations
* $$TIME$$ is the current time (related to the begin of the simulation run)

A **sum formula** is defined by the equation $$f(P\_1, ... P\_n; M\_1, ..., M\_k; C\_1, ... C\_j; TIME;$$ `Q_#i` $$)$$ where:

* `Q_#i` is a *control variable* (parameter, molecule amount, etc.) defined by certain conditions
* all other arguments have the same meaning as in an explicit formula

A **table formula with offset** is defined by 2 quantities (see the [OSP documentation](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#table-formulas-with-offset) for details):

* **table object** with the `Table_formula` (defined by the support points { $$time\_i;value\_i$$} )
* **offset object** with the `Offset_formula`.

The X argument of the table object is always the (simulation) time, and the formula returns the value `Table_formula(Time - Offset_formula(Time;...))`.

A **table formula with X argument** is a generalization of *table formula with offset* and is defined by 2 quantities

* **table object** with the `Table_formula` (defined by the support points { $$x\_i;value\_i$$} ).
* **X argument object** with the `XArgument_formula`.

The table's X argument is arbitrary, and the formula returns the value $$Table\_formula(XArgument\_formula(...))$$.

S. the OSP Suite documentation: [Working with Formulas‌](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas) and [Sum Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#sum-formulas) for more details on formulas.

![](/files/yMWXq2PhrujLJImDg6x7)

#### tab\_rates

Describes an abstract formula.

#### tab\_calculation\_methods

Describes a calculation method. A calculation method describes how a **group of quantities** (parameters, molecule initial values, etc.) are defined by their formulas. A decision about which quantities should be described by the same calculation method is usually based on information about which formulas would change when the user switches from one (sub)model to another. For example, if the user chooses a different method for calculating the *Body Surface Area* (BSA) - only the BSA parameter itself is affected, and thus only this parameter is described by the corresponding calculation methods. If the user chooses another method for calculating the surface area between the plasma and the interstitial space - the *Surface Area (Plasma/Interstitial)* parameters in all tissues organs are affected: thus all these parameters are grouped in the same calculation method.

* **category** calculation methods belonging to the same category are alternatives, which can be selected by user (s. also the section [Container Parameters](#container-parameters))

#### tab\_categories

Specifies the categories of calculation methods.

* **category\_type** describes for which building block or simulation all calculation methods of the given category are valid. For example, if the category type of a calculation method is "Individual" - the calculation method will be used when creating an individual. Valid values of the category type are defined by the [`enum CategoryType`](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Core/Model/Category.cs).

#### tab\_calculation\_method\_rates

Defines the formula equation for the combination {`calculation_method, formula_rate`}.

* **calculation\_method** defines the calculation method. Some calculation methods have a special meaning and are described in more detail in the next subsections:
  * `BlackBox_CalculationMethod`
  * `DynamicSumFormulas`
  * `DiseaseStates`
* **formula\_rate** defines the formula.
  * For some frequently used constant rates specific formulas were defined:
    * `Zero_Rate`
    * `One_Rate`
    * `Thousand_Rate`
    * `NaN_Rate`
  * Some calculation methods have a special meaning and are described in more detail in the next subsections:
    * `TableFormulaWithOffset_*`
    * `TableFormulaWithXArgument_*`
* **formula** defines the equation for the combination {`calculation_method, formula_rate`}. Which operators, standard functions, etc. are allowed is described in the [OSP Suite documentation - Working with Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas).
  * It is allowed to leave the **formula** field empty. Quantity with empty formula becomes mandatory user input in PK-Sim UI. This means that only **visible and editable quantities** are allowed to have an empty formula.
  * Formula can be set to $$\pm \infty$$. Valid values for this are:
    * `Inf` or `Infinity`
    * `-Inf` or `-Infinity`
  * It is important to write **efficient formulas**. Check the [WIKI **Writing efficient formulas**](https://github.com/Open-Systems-Pharmacology/OSPSuite.FuncParser/wiki/Writing-efficient-formulas) for details.
  * Constant values in equations should be avoided. It is always better to define a new parameter, set it to the constant value, and then use that parameter in the equation. Exceptions are constants whose meaning is immediately clear (e.g. `1`, `0`, `ln(2)`, etc.). Because:
    * In the parameter definition, we can add description, value origin, etc. All of this information is missing when you use a constant directly in an equation.
    * Unit information is lost and this can easily lead to errors (happens quite often in MoBi, when users add constants to their formulas, see e.g. [this discussion](https://github.com/Open-Systems-Pharmacology/Forum/issues/491)).
* **dimension** the dimension of the formula. Used e.g. by the dimension check in MoBi to make sure that the quantities using the given formula have the same dimension.

#### tab\_rate\_container\_parameters

Parameters referenced by the formula of the combination {`calculation_method, formula_rate`}. Parameters are given by the combination of {`container_id, container_type, container_name, parameter_name`}.

* **alias** is the alias of the referenced parameter used in the calculation. The rules for defining aliases are
  * Aliases of all quantities referenced in the formula must be unique and not empty.
  * Alias cannot be a number.
  * Alias must not contain any of the characters `+ - * \ / ^ . , < > = ! ( ) [ ] { } ' " ? : ¬ | & ;`
  * Alias must not contain blanks.
  * Alias cannot be one of the predefined *standard constants* (s. the [OSP Suite documentation - Working with Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas)).
  * Alias cannot be one of the predefined *standard functions* (s. the [OSP Suite documentation - Working with Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas)).
  * Alias cannot be one of the predefined *logical operators* (s. the [OSP Suite documentation - Working with Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas)).

#### tab\_rate\_container\_molecules

Molecules referenced by the formula of the combination {`calculation_method, formula_rate`}. Molecules are given by the combination of {`container_id, container_type, container_name, molecule`}.

* **alias** is the alias of the referenced parameter used in the calculation. Alias rules apply (s. above).
* **use\_amount** specifies whether the *amount* or *concentration* of the given molecule is used.

#### tab\_rate\_generic\_parameters

Parameters referenced by the formula of the combination {`calculation_method, formula_rate`}. Parameters are given by the combination of {`path_id, parameter_name`}.

* **path\_id** refers to the (relative) object path stored in the table [*tab\_object\_paths*](#tab_object_paths) (s. below).
* **alias** is the alias of the referenced parameter used in the calculation. Alias rules apply (s. above).

#### tab\_rate\_generic\_molecules

Parameters referenced by the formula of the combination {`calculation_method, formula_rate`}. Parameters are given by the combination of {`path_id, molecule`}.

* **path\_id** refers to the (relative) object path stored in the table [*tab\_object\_paths*](#tab_object_paths) (s. below).
* **alias** is the alias of the referenced molecule used in the calculation. Alias rules apply (s. above).
* **use\_amount** specifies whether the *amount* or *concentration* of the given molecule is used.

There are some "special" containers defined in [*tab\_container\_names*](#tab_container_names) that are not used in the container hierarchy defined in [*tab\_containers*](#tab_containers). These containers are only used for **referential integrity when defining some relative object paths**. (TODO s. [the issue](https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2692))

<details>

<summary>Special containers</summary>

| ref\_container\_name     | description                                                 |
| ------------------------ | ----------------------------------------------------------- |
| .                        | Me                                                          |
| ..                       | Parent                                                      |
| \<COMPLEX>               | Dummy, will be replaced by complex name in PK-Sim           |
| \<FormulationName>       | \<FormulationName>                                          |
| \<MOLECULE>              | Dummy, will be replaced by compound name in PK-Sim          |
| \<PROCESS>               | Template for Compound process in simulation                 |
| \<PROTEIN>               | Template for protein                                        |
| \<REACTION>              | Dummy, will be replaced by reaction name in PK-Sim          |
| ALL\_FLOATING\_MOLECULES | Path entry referencing all floating molecules (Assignments) |
| FIRST\_NEIGHBOR          | Path entry for the first neighbor                           |
| FcRn                     | FcRn                                                        |
| FcRn\_Complex            | FcRn\_Complex                                               |
| LigandEndo               | LigandEndo                                                  |
| LigandEndo\_Complex      | LigandEndo\_Complex                                         |
| NEIGHBORHOOD             | Path entry for the neighborhood                             |
| SECOND\_NEIGHBOR         | Path entry for the second neighbor                          |
| SOURCE                   | Path entry for source amount                                |
| TARGET                   | Path entry for target amount                                |
| TRANSPORT                | Path entry for the transport                                |

</details>

#### tab\_object\_paths

Describes (relative) paths of quantities used in a formula (see the [OSP Suite documentation - Working with Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#formulas) for details). Each entry of an object path is stored separately, with its own id and the id of its parent path entry. Tables *tab\_rate\_generic\_XXX* have the reference to the **bottom element of the object path** (see the example below).

* **path\_id** is the unique id of the path entry.
* **parent\_path\_id** is the id of the parent path entry. If there is no parent path entry: the parent path id is set equal to the path id!
* {**ref\_container\_type**, **ref\_container\_name**} name and type of the container which is referenced by the path entry.

Example:

*tab\_object\_paths* contains the following path entries:

| path\_id | parent\_path\_id | ref\_container\_type | ref\_container\_name   |
| -------- | ---------------- | -------------------- | ---------------------- |
| 260      | 259              | GENERAL              | MOLECULE               |
| 259      | 2078             | NEIGHBORHOOD         | Brain\_pls\_Brain\_int |
| 2078     | 2078             | GENERAL              | Neighborhoods          |

These entries represent the path `Neighborhoods|Brain_pls_Brain_int|MOLECULE`.

In [*tab\_rate\_generic\_parameters*](#tab_rate_generic_parameters) the path is referenced like this:

| calculation\_method                                 | formula\_rate                      | path\_id | parameter\_name                             | alias       |
| --------------------------------------------------- | ---------------------------------- | -------- | ------------------------------------------- | ----------- |
| Interstitial partition coefficient method - Schmitt | PARAM\_K\_water\_int\_brn\_Schmitt | **260**  | Partition coefficient (interstitial/plasma) | K\_int\_pls |

With this, the full path to the referenced parameter is:\
`Neighborhoods|Brain_pls_Brain_int|MOLECULE|Partition coefficient (interstitial/plasma)`

**Sum formulas**

See the [OSP Suite documentation - Sum Formulas](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/parameters-formulas-tags#sum-formulas) for more details.

Sum formulas in the PK-Sim database must have the calculation method **DynamicSumFormulas**.

Compared to the full flexibility of the sum formulas provided in MoBi, there are some restrictions:

* *Control variable* (`Q` in the screenshot below) can only be defined **with 1 letter**.
* Quantity references **relative to the summed object** (the highlighted part of the definition below) are not possible.
* The operator for combining the conditions of each criterion is always \`And'.

![](/files/TCiQL2iwZXJeX2TZiGmt)

#### tab\_calculation\_method\_rate\_descriptor\_conditions

Defines the criteria of the quantities to be summed up for the combination {`calculation_method, rate`}.

* **condition** criteria condition for the target container.
* **tag** the tag of the single condition.

#### tab\_conditions (formulas)

Specifies available (container) criteria conditions. Values must be the same as defined by the [`enum CriteriaCondition`](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/FlatObjects/CriteriaCondition.cs) in PK-Sim.

**"Black box" formulas**

Some molecule-dependent parameters defined within the spatial structure have a formula that depends on the calculation methods of the specific molecule. Examples of such parameters are partition coefficients, cellular permeabilities, etc.

Within the spatial structure, these parameters are defined by a dummy formula - *black-box formula* - which is replaced by a concrete formula for each molecule.

All black box formulas are combined within the calculation method \`BlackBox\_CalculationMethod'.

The concrete (calculation method dependent) formulas are then defined in the table [*tab\_calculation\_method\_parameter\_rates*](#tab_calculation_method_parameter_rates) (and exported to **AllCalculationMethods.pkml** for MoBi) - see the section [Calculation method parameters](#calculation-method-parameters).

Example of how black box parameters are displayed in MoBi:

![](/files/vx7y3pfV11LKBogBJAt6)

**Disease state parameters**

Parameters specific to disease states are grouped under the `DiseaseStates` calculation method.

**Table formulas with offset**

If a formula\_rate starts with the prefix **TableFormulaWithOffset\_** (e.g. `TableFormulaWithOffset_FractionDose`) - PK-Sim will create a table formula with offset.

PK-Sim then expects that **exactly 2 referenced quantities are defined for the formula**: one quantity with the alias `Table` and another quantity with the alias `Offset`. Example:

| calculation\_method  | formula\_rate                        | path\_id | parameter\_name | alias      |
| -------------------- | ------------------------------------ | -------- | --------------- | ---------- |
| ApplicationParameter | TableFormulaWithOffset\_FractionDose | 139      | Start time      | **Offset** |
| ApplicationParameter | TableFormulaWithOffset\_FractionDose | 253      | Fraction (dose) | **Table**  |

**Table formulas with X argument**

If a formula\_rate starts with the prefix **TableFormulaWithXArgument\_** (e.g. `TableFormulaWithXArgument_Solubility`) - PK-Sim will create a table formula with X Argument.

PK-Sim then expects, that **exactly 2 referenced quantities are defined for the formula**: one quantity with the alias `Table` and another quantity with the alias `XArg`. Example:

| calculation\_method | formula\_rate                         | path\_id | parameter\_name  | alias     |
| ------------------- | ------------------------------------- | -------- | ---------------- | --------- |
| Lumen\_PKSim        | TableFormulaWithXArgument\_Solubility | 140      | pH               | **XArg**  |
| Lumen\_PKSim        | TableFormulaWithXArgument\_Solubility | 240      | Solubility table | **Table** |

### Calculation methods and parameter value versions

![](/files/D9VzkcH1oEe2LNknz5zB)

**tab\_species\_calculation\_methods** defines which calculation methods are available for the given species and is described in detail [here](#tab_species_calculation_methods).

**tab\_species\_parameter\_value\_versions** is the counterpart of *tab\_species\_calculation\_methods* and defines which parameter value versions are available for the given species. It is described in detail [here](#tab_species_parameter_value_versions).

**tab\_categories** specifies the categories of calculation methods and parameter value versions and is described in detail [here](#tab_categories).

**tab\_calculation\_methods** defines a *calculation method* (**CM**) and is described in detail [here](#tab_calculation_methods). A calculation method describes how a **group of quantities** (parameters, molecule initial values, etc.) are defined by their formulas. A decision about which quantities should be described by the same CM is usually based on information about which formulas would change when the user switches from one (sub)model to another. For example, if the user chooses a different method for calculating the *Body Surface Area* (BSA) - only the BSA parameter itself is affected, and thus only this parameter is described by the corresponding calculation method. If the user chooses another method for calculating the surface area between the plasma and the interstitial space - the *Surface Area (Plasma/Interstitial)* parameters in all tissues organs are affected: thus all these parameters are grouped in the same calculation method. More details on calculation methods are provided in the section [Formulas](#formulas).

#### tab\_models

Defines available PBPK models, which can be selected during the simulation creation (e.g. "Small molecules model", "Large molecules model" etc.).

* **short\_display\_name** is used in some places in the UI, where the fully qualified model display name is too long.

#### tab\_parameter\_value\_versions

Defines a *parameter value version* (**PVV**). A parameter value version describes how a **group of parameters** are defined by their constant values or their distributions. A decision about which parameters should be described by the same PVV is usually based on information about which parameters would change when the user switches from one PVV to another. More details on parameter value versions are provided in the sections [Species and populations](#species-and-populations) and [Container parameters](#container-parameters).

#### tab\_model\_calculation\_methods

Defines which calculation methods are available for a model.

Now, when it comes to creating a building block or simulation, the algorithm for determining which CMs and PVVs to use is as follows:

1. Identify all PVVs with the category type corresponding to the type of the block/simulation.
2. If the building block type is "Individual": remove all PVVs that are not assigned to the species of the individual (via *tab\_species\_parameter\_value\_versions*).
3. Group all remaining PVVs according to their category.
   * For each group with $$\geq$$ 2 PVVs: these PVVs are **alternatives** and the user has to choose exactly one of them to be used in the building block/simulation.
4. Identify all CMs with the category type corresponding to the type of the block/simulation.
5. If the building block type is "Individual": remove all CMs that are not assigned to the species of the individual (via *tab\_species\_calculation\_methods*).
6. Group all remaining CMs according to their category.
   * For each group with $$\geq$$ 2 CMs: these CMs are **alternatives** and the user has to choose exactly one of them to be used in the building block/simulation.

### Applications and formulations

*Applications* are containers with container\_type="APPLICATION"\`.

*Formulations* are containers with container\_type="FORMULATION"\`.

![](/files/ZG18fSGag2j4PAMYFpKT)

In the container hierarchy (defined in [*tab\_containers*](#tab_containers)):

* Formulations are always top-level containers with no parent.
* Applications always have a formulation as parent container.
  * For applications that do not require a formulation (e.g. IV), `Formulation_Empty` is defined as the parent container.

| Id   | Type        | Name                    | ParentId | ParentType  | ParentName                   |
| ---- | ----------- | ----------------------- | -------- | ----------- | ---------------------------- |
| 1725 | APPLICATION | Intravenous             | 1718     | FORMULATION | Formulation\_Empty           |
| 1724 | APPLICATION | IntravenousBolus        | 1718     | FORMULATION | Formulation\_Empty           |
| 1722 | APPLICATION | Oral\_Dissolved         | 1717     | FORMULATION | Formulation\_Dissolved       |
| 5101 | APPLICATION | Oral\_Particles         | 5100     | FORMULATION | Formulation\_Particles       |
| 5268 | APPLICATION | Oral\_Table             | 5262     | FORMULATION | Formulation\_Table           |
| 5045 | APPLICATION | Oral\_Tablet\_Lint80    | 5044     | FORMULATION | Formulation\_Tablet\_Lint80  |
| 1728 | APPLICATION | Oral\_Tablet\_Weibull   | 1720     | FORMULATION | Formulation\_Tablet\_Weibull |
| 5344 | APPLICATION | UserDefined\_Dissolved  | 1717     | FORMULATION | Formulation\_Dissolved       |
| 5239 | APPLICATION | UserDefined\_FirstOrder | 1719     | FORMULATION | Formulation\_FirstOrder      |
| 5284 | APPLICATION | UserDefined\_Table      | 5262     | FORMULATION | Formulation\_Table           |
| ...  | ...         | ...                     | ...      | ...         | ...                          |

Each application has a `ProtocolSchemaItem` subcontainer which stores some parameters common to all applications (e.g. `Start time`, `Dose`, etc.) and some application specific parameters (e.g. `Amount of water` for oral applications).

Each application also has an `Application_StartEvent` subcontainer that defines the application start event.

Most applications have an `Application_StopEvent` subcontainer that defines the application stop event.

Other application subcontainers are application specific (e.g. transport(s) *Application* ▶️ *Organism*, other subcontainers, etc.). For example, for the *Intravenous* (infusion) application has the following subcontainers:

| container\_id | container\_type | container\_name         | parent\_container\_id | parent\_container\_type | parent\_container\_name |
| ------------- | --------------- | ----------------------- | --------------------- | ----------------------- | ----------------------- |
| 1731          | GENERAL         | ProtocolSchemaItem      | 1725                  | APPLICATION             | Intravenous             |
| 1739          | EVENT           | Application\_StartEvent | 1725                  | APPLICATION             | Intravenous             |
| 1745          | EVENT           | Application\_StopEvent  | 1725                  | APPLICATION             | Intravenous             |
| 1748          | PROCESS         | Intravenous\_Transport  | 1725                  | APPLICATION             | Intravenous             |

#### tab\_formulation\_routes

Defines the formulations.

* **formulation** is the name of the formulation.
* **container\_type** is always "FORMULATION".
* **route** is the route of administration (IV, oral, dermal, ...) for which the formulation is intended.

#### tab\_applications

Defines the top container of an application.

* **application\_name** is the name of the application.
* **container\_type** is always "APPLICATION".
* **application\_type** is the route of administration (TODO rename, s. [the Issue](https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309))

#### tab\_application\_types

Defines all available administration routes (TODO rename, s. [the Issue](https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309))

* **application\_type** is the route of administration (TODO rename, s. [the Issue](https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2309))
* **is\_formulation\_required** indicates whether a formulation definition is required for the given route.

### Events

![](/files/bLjyEN6xRtdwmR7MWQUz)

*Events* are containers with `container_type="EVENT"`.

In the container hierarchy (defined in [*tab\_containers*](#tab_containers)) event are usually children of containers of type "`APPLICATION`" or "`EVENTGROUP`".

Each event is described by the event condition and the quantities that are changed by this event.

#### tab\_event\_conditions

Defines the event condition of an event.

* {**event\_id**, **event\_container\_type**, **event\_name**} are the id, type and name of the event container.
* {**calculation\_method**, **formula\_rate**} define the formula of the event condition (typically a boolean formula which can return only 0 or 1).
* **is\_one\_time** specifies whether the event is triggered *whenever the event condition is met* (`is_one_time=0`) or only at the *first simulation time point* when the event condition is met.

#### tab\_event\_changed\_container\_molecules

#### tab\_event\_changed\_container\_parameters

#### tab\_event\_changed\_generic\_molecules

#### tab\_event\_changed\_generic\_parameters

Define which parameters or molecule amounts are modified by an event. The referencing of the modified quantities of an event is done in the same way as the referencing of the quantities used in a formula and defined in the tables [*tab\_rate\_container\_molecules*](#tab_rate_container_molecules), [*tab\_rate\_container\_parameters*](#tab_rate_container_parameters), [*tab\_rate\_generic\_molecules*](#tab_rate_generic_molecules), [*tab\_rate\_generic\_parameters*](#tab_rate_generic_parameters) (s. the section [Formulas](#formulas)) for details.

* {**event\_id**, **event\_container\_type**, **event\_name**} are the id, type and name of the event container.
* {**calculation\_method**, **formula\_rate**} defines the formula that will be applied to the changed quantity when the event is triggered.
* **use\_as\_value** defines if the formula is assigned as a formula or as a value of the formula, calculated at the time point of the assignment.
* **use\_amount** (TODO delete - s. [the issue](https://github.com/Open-Systems-Pharmacology/PK-Sim/issues/2696))

S. the [OSP Documentation on events](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/events-bb#event-groups-and-events) for more details.

### Observers

![](/files/qAQrWqj9mKig9MEiMT1L)

#### tab\_observers

Specifies an observer.

* **observer** name of the observer.
* **observer\_type**
* **category** always set to `"Observer"`.
* **builder\_type** "`AMOUNT`" or "`CONTAINER`", which corresponds to "Molecule Observer" and "Container Observer in MoBi" (s. the [OSP Suite documentation](https://docs.open-systems-pharmacology.org/working-with-mobi/mobi-documentation/building-block-concepts#observers) for details).
* **is\_for\_all\_molecules**
* **dimension** dimension of the observer.

#### tab\_observer\_rates

Defines the monitor formula of the observer.

#### tab\_observer\_descriptor\_conditions

Defines criteria for containers where the observer will be created. Single container criteria are combined by "`AND`".

* **observer** name of the observer.
* **tag** is a tag of a container in which the observer should (or should not) be created.
* **tag\_type** Is always set to "`PARENT`"
* **should\_have** specifies whether the target container should or should not have the given tag..

### Entities defined by formulas

![](/files/73AQQXvCepYh5M89aSAy)

The picture above shows an overview of all quantities which are described by a formula. Most tables are explained in other sections.

#### tab\_container\_rates

Is currently not used. This table was introduced to define some conditions which cannot be described by the boundary criteria (min/max) of a quantity. E.g. for the condition "Sum of compartment fractions of an organ = 1".

### Proteins

![](/files/fd91dQtcI2M4plF807eo)

#### tab\_protein\_names

Stores the names of known proteins.

#### tab\_protein\_synonyms

Stores synonyms of the protein names.

**tab\_ontogenies** is described in detail [above](#tab_ontogenies).

**tab\_molecule\_parameters** is described in detail [above](#tab_molecule_parameters).

### Models

![](/files/0SsRvbLQzdwVrY5XIiiz)

**tab\_models** defines available PBPK models and is described [above](#tab_models).

**tab\_model\_calculation\_methods** is described [above](#tab_model_calculation_methods).

#### tab\_model\_observers

Defines which observers are available for the given model.

**tab\_model\_species** defines which species can be used in combination with the given model and is described [above](#tab_model_species).

**tab\_model\_containers** defines which containers **can** be included into the final model and is described [above](#tab_model_containers).

#### tab\_molecules

Defines the **default** properties (start amount, *IsPresent*, etc.) for administered compounds and endogenous molecules. For each model container, these default settings can be **overwritten** by entries in [*tab\_container\_molecule\_start\_formulas*](#tab_container_molecule_start_formulas) and [*tab\_model\_container\_molecules*](#tab_model_container_molecules) (s. below)

* **molecule** the name of the molecule.
* **default\_is\_present** is the molecule present as per default.
* **start\_formula\_calculation\_method**, **start\_formula\_rate** defined the default start formula for the molecule. E.g. for administered compounds start formula is always zero; etc.
* **is\_floating** defines whether the molecule is floating or stationary.
* **molecule\_type** type of the molecule (administered compound, Enzyme, Transporter, etc.)

**tab\_model\_transport\_molecule\_names** restricts which molecules are transported by a passive transport for particular model and is described [above](#tab_model_transport_molecule_names).

#### tab\_container\_molecules

Used for referential integrity only; not exposed to PK-Sim.

#### tab\_model\_container\_molecules

Overwrites some default (global) molecule properties on the model container level.

* **negative\_values\_allowed** overrides the default setting (**FALSE**; defined programmatically and not in the database).
* **is\_present** overrides the global molecule setting defined in [*tab\_molecules*](#tab_molecules).

#### tab\_container\_molecule\_start\_formulas

Overwrites some default (global) molecule properties on the model container level.

* **calculation\_method**, **formula\_rate** overrides the global molecule start amount formula in [*tab\_molecules*](#tab_molecules).

### Tags

The picture below describes for which objects *descriptor criteria* (*descriptor conditions*) are defined in the database.

![](/files/Hjh15xEljG40rD8PEbAl)

#### tab\_tags

Defines all possible tags. The *name* of each container is added as tag programmatically in **OSPSuite.Core**. So there is no need to insert all container names into *tab\_tags* or *tab\_container\_tags*.

#### tab\_criteria\_conditions

Describes all available conditions. Each condition must be available in the [`enum CriteriaCondition`](https://github.com/Open-Systems-Pharmacology/PK-Sim/blob/develop/src/PKSim.Infrastructure/ORM/FlatObjects/CriteriaCondition.cs) in PK-Sim.

All other tables are explained in the previous sections.

### Value origins

![](/files/NDQxMREG2ond5E40JqJ8)

Value origin describes the data source of a value or formula.

#### tab\_references

Describes a data source (e.g. publication).

#### tab\_value\_origins

Describes available value origins.

* **id** is the unique id of a value origin. This id is used in all referencing tables.
* **description** is either empty or refers an entry in *tab\_references*.
* **source** must be one of the values define in [enum ValueOriginSourceId](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Domain/ValueOriginSource.cs) (database default: "`Undefined`").
* **method** must be one of the values define in [enum ValueOriginDeterminationMethodId](https://github.com/Open-Systems-Pharmacology/OSPSuite.Core/blob/develop/src/OSPSuite.Core/Domain/ValueOriginDeterminationMethod.cs) (database default: "`Undefined`").

### Representation Info

![](/files/zNIEhYOUdpiiNU7QPRrp)

#### tab\_representation\_info

Defines the display properties (display name, description, icon) for some entities, which are not covered by other database tables.

## Full schema

![](/files/x0JCm4rZGYdKmFnklfbE)

## Tables reference

* [Containers](#containers)
  * [tab\_container\_names](#tab_container_names)
  * [tab\_container\_types](#tab_container_types)
  * [tab\_organ\_types](#tab_organ_types)
  * [tab\_containers](#tab_containers)
  * [tab\_container\_tags](#tab_container_tags)
  * [tab\_neighborhoods](#tab_neighborhoods)
  * [tab\_population\_containers](#tab_population_containers)
  * [tab\_model\_containers](#tab_model_containers)
* [Processes](#processes)
  * [tab\_processes](#tab_processes)
  * [tab\_process\_types](#tab_process_types)
  * [tab\_kinetic\_types](#tab_kinetic_types)
  * [tab\_process\_descriptor\_conditions](#tab_process_descriptor_conditions)
  * [tab\_process\_molecules](#tab_process_molecules)
  * [tab\_process\_rates](#tab_process_rates)
  * [tab\_model\_transport\_molecule\_names](#tab_model_transport_molecule_names)
  * [tab\_transports](#tab_transports)
  * [tab\_transport\_directions](#tab_transport_directions)
  * [tab\_known\_transporters](#tab_known_transporters)
  * [tab\_known\_transporters\_containers](#tab_known_transporters_containers)
  * [tab\_active\_transport\_types](#tab_active_transport_types)
* [Species and populations](#species-and-populations)
  * [tab\_species](#tab_species)
  * [tab\_populations](#tab_populations)
  * [tab\_genders](#tab_genders)
  * [tab\_population\_genders](#tab_population_genders)
  * [tab\_population\_age](#tab_population_age)
  * [tab\_species\_calculation\_methods](#tab_species_calculation_methods)
  * [tab\_species\_parameter\_value\_versions](#tab_species_parameter_value_versions)
  * [tab\_model\_species](#tab_model_species)
  * [tab\_population\_disease\_states](#tab_population_disease_states)
  * [tab\_disease\_states](#tab_disease_states)
  * [tab\_ontogenies](#tab_ontogenies)
* [Container parameters](#container-parameters)
  * [tab\_parameters](#tab_parameters)
  * [tab\_dimensions](#tab_dimensions)
  * [tab\_container\_parameters](#tab_container_parameters)
  * [tab\_groups](#tab_groups)
  * [tab\_molecule\_parameters](#tab_molecule_parameters)
  * [tab\_container\_parameter\_rates](#tab_container_parameter_rates)
  * [tab\_container\_parameter\_values](#tab_container_parameter_values)
  * [tab\_container\_parameter\_curves](#tab_container_parameter_curves)
  * [tab\_distribution\_types](#tab_distribution_types)
  * [tab\_compound\_process\_parameter\_mapping](#tab_compound_process_parameter_mapping)
  * [tab\_container\_parameter\_rhs](#tab_container_parameter_rhs)
  * [tab\_container\_parameter\_descriptor\_conditions](#tab_container_parameter_descriptor_conditions)
  * [tab\_conditions (container parameters)](#tab_conditions-container-parameters)
  * [tab\_container\_parameter\_fcurves](#tab_container_parameter_fcurves)
* [Calculation method parameters](#calculation-method-parameters)
  * [tab\_calculation\_method\_parameter\_rates](#tab_calculation_method_parameter_rates)
  * [tab\_calculation\_method\_parameter\_descr\_conditions](#tab_calculation_method_parameter_descr_conditions)
* [Formulas](#formulas)
  * [tab\_rates](#tab_rates)
  * [tab\_calculation\_methods](#tab_calculation_methods)
  * [tab\_categories](#tab_categories)
  * [tab\_calculation\_method\_rates](#tab_calculation_method_rates)
  * [tab\_rate\_container\_parameters](#tab_rate_container_parameters)
  * [tab\_rate\_container\_molecules](#tab_rate_container_molecules)
  * [tab\_rate\_generic\_parameters](#tab_rate_generic_parameters)
  * [tab\_rate\_generic\_molecules](#tab_rate_generic_molecules)
  * [tab\_object\_paths](#tab_object_paths)
    * [Sum formulas](#sum-formulas)
  * [tab\_calculation\_method\_rate\_descriptor\_conditions](#tab_calculation_method_rate_descriptor_conditions)
  * [tab\_conditions (formulas)](#tab_conditions-formulas)
    * ["Black box" formulas](#black-box-formulas)
    * [Disease state parameters](#disease-state-parameters)
    * [Table formulas with offset](#table-formulas-with-offset)
    * [Table formulas with X argument](#table-formulas-with-x-argument)
* [Calculation methods and parameter value versions](#calculation-methods-and-parameter-value-versions)
  * [tab\_models](#tab_models)
  * [tab\_parameter\_value\_versions](#tab_parameter_value_versions)
  * [tab\_model\_calculation\_methods](#tab_model_calculation_methods)
* [Applications and formulations](#applications-and-formulations)
  * [tab\_formulation\_routes](#tab_formulation_routes)
  * [tab\_applications](#tab_applications)
  * [tab\_application\_types](#tab_application_types)
* [Events](#events)
  * [tab\_event\_conditions](#tab_event_conditions)
  * [tab\_event\_changed\_container\_molecules](#tab_event_changed_container_molecules)
  * [tab\_event\_changed\_container\_parameters](#tab_event_changed_container_parameters)
  * [tab\_event\_changed\_generic\_molecules](#tab_event_changed_generic_molecules)
  * [tab\_event\_changed\_generic\_parameters](#tab_event_changed_generic_parameters)
* [Observers](#observers)
  * [tab\_observers](#tab_observers)
  * [tab\_observer\_rates](#tab_observer_rates)
  * [tab\_observer\_descriptor\_conditions](#tab_observer_descriptor_conditions)
* [Entities defined by formulas](#entities-defined-by-formulas)
  * [tab\_container\_rates](#tab_container_rates)
* [Proteins](#proteins)
  * [tab\_protein\_names](#tab_protein_names)
  * [tab\_protein\_synonyms](#tab_protein_synonyms)
* [Models](#models)
  * [tab\_model\_observers](#tab_model_observers)
  * [tab\_molecules](#tab_molecules)
  * [tab\_container\_molecules](#tab_container_molecules)
  * [tab\_model\_container\_molecules](#tab_model_container_molecules)
  * [tab\_container\_molecule\_start\_formulas](#tab_container_molecule_start_formulas)
* [Tags](#tags)
  * [tab\_tags](#tab_tags)
  * [tab\_criteria\_conditions](#tab_criteria_conditions)
* [Value origins](#value-origins)
  * [tab\_references](#tab_references)
  * [tab\_value\_origins](#tab_value_origins)
* [Representation Info](#representation-info)
  * [tab\_representation\_info](#tab_representation_info)


# Finding Memory Leaks

## Introduction

The [OSPSuite.SimModel](https://github.com/Open-Systems-Pharmacology/OSPSuite.SimModel) is a the component of the OSPSuite, written mainly in C++, that reads the model description in its XML format, creates a differential equations system from it and solves it. In this part of the documentation we will describe how to use the Visual Leak Detector to detect memory leaks in the C++ code.

## Using the Visual Leak Detector

Looking for memory leaks in SimModel when used in PK-Sim (MoBi, etc. - same procedure)

1. Install **Visual Leak Detector for Visual C++** (VLD) from \~\~<https://github.com/KindDragon/vld/releases~~\\>
   EDIT 2022: VLD development continues now here: <https://github.com/Azure/vld> (latest release: <https://github.com/Azure/vld/releases>)
2. Open SimModel solution in Visual Studio and uncomment the line `#include <vld.h>` in **src/OSPSuite.SimModelNative/src/Simulation.cpp**
3. If VLD was installed NOT into the default path: open project settings of **OSPSuite.SimModelNative** and adjust the paths in the Debug-configuration ![grafik](https://user-images.githubusercontent.com/25061876/74615676-4154c080-5123-11ea-9d2a-b8db8732d4cf.png)
4. Build the Debug version of **OSPSuite.SimModelNative**
5. Copy **OSPSuite.SimModelNative.dll** and **OSPSuite.SimModelNative.pdb** from *\<SimModel\_SolutionDir>\Build\\**Debug**\x64* into the PK-Sim folder
6. Copy the ***Debug*** version of **OSPSuite.FuncParserNative.dll** and **OSPSuite.FuncParserNative.pdb** from the corresponding Nuget package into the PK-Sim folder
7. Copy the ***Debug*** version of **OSPSuite.SimModelSolver\_CVODES.dll** and **OSPSuite.SimModelSolver\_CVODES.pdb** from the corresponding Nuget package into the PK-Sim folder
8. Open "**C:\Program Files (x86)\Visual Leak Detector\vld.ini**" in a text editor and set

* `AggregateDuplicates = yes`
* `ForceIncludeModules = <list of additional C++ libs to include>`\
  E.g. to profile FuncParser as well: `ForceIncludeModules = OSPSuite.FuncParserNative.dll`
* `ReportFile = <path to report file>` Leak report will be created here\
  E.g. `ReportFile = C:\Temp\SimModelLeaks.txt`
* `ReportTo = file` or `ReportTo = both`
* `StackWalkMethod = fast`

9. Start PK-Sim and perform actions you would like to profile (run individual/population simulations, perform sensitivity analysis, parameter identifications, ...)
10. Close PK-Sim. Leak report is now available in the `<path to report file>` defined in vld.ini

<details>

<summary>Example vld.ini</summary>

```
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Visual Leak Detector - Initialization/Configuration File
;;  Copyright (c) 2005-2017 VLD Team
;;
;;  This library is free software; you can redistribute it and/or
;;  modify it under the terms of the GNU Lesser General Public
;;  License as published by the Free Software Foundation; either
;;  version 2.1 of the License, or (at your option) any later version.
;;
;;  This library is distributed in the hope that it will be useful,
;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;  Lesser General Public License for more details.
;;
;;  You should have received a copy of the GNU Lesser General Public
;;  License along with this library; if not, write to the Free Software
;;  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
;;
;;  See COPYING.txt for the full terms of the GNU Lesser General Public License.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Any options left blank or not present will revert to their default values.
[Options]

; The main on/off switch. If off, Visual Leak Detector will be completely
; disabled. It will do nothing but print a message to the debugger indicating
; that it has been turned off.
;
;  Valid Values: on, off
;  Default: on
;
VLD = on

; If yes, duplicate leaks (those that are identical) are not shown individually.
; Only the first such leak is shown, along with a number indicating the total
; number of duplicate leaks.
;
;   Valid Values: yes, no
;   Default: no
;
AggregateDuplicates = yes

; Lists any additional modules to be included in memory leak detection. This can
; be useful for checking for memory leaks in debug builds of 3rd party modules
; which can not be easily rebuilt with '#include "vld.h"'. This option should be
; used only if absolutely necessary and only if you really know what you are
; doing.
;
;   CAUTION: Avoid listing any modules that link with the release CRT libraries.
;     Only modules that link with the debug CRT libraries should be listed here.
;     Doing otherwise might result in false memory leak reports or even crashes.
;
;   Valid Values: Any list containing module names (i.e. names of EXEs or DLLs)
;   Default: None.
;
ForceIncludeModules = OSPSuite.FuncParserNative.dll

; Maximum number of data bytes to display for each leaked block. If zero, then
; the data dump is completely suppressed and only call stacks are shown.
; Limiting this to a low number can be useful if any of the leaked blocks are
; very large and cause unnecessary clutter in the memory leak report.
;
;   Value Values: 0 - 4294967295
;   Default: 256
;
MaxDataDump = 

; Maximum number of call stack frames to trace back during leak detection.
; Limiting this to a low number can reduce the CPU utilization overhead imposed
; by memory leak detection, especially when using the slower "safe" stack
; walking method (see StackWalkMethod below).
;
;   Valid Values: 1 - 4294967295
;   Default: 64
;
MaxTraceFrames = 

; Sets the type of encoding to use for the generated memory leak report. This
; option is really only useful in conjuction with sending the report to a file.
; Sending a Unicode encoded report to the debugger is not useful because the
; debugger cannot display Unicode characters. Using Unicode encoding might be
; useful if the data contained in leaked blocks is likely to consist of Unicode
; text.
;
;   Valid Values: ascii, unicode
;   Default: ascii
;
ReportEncoding = ascii

; Sets the report file destination, if reporting to file is enabled. A relative
; path may be specified and is considered relative to the process' working
; directory.
;
;   Valid Values: Any valid path and filename.
;   Default: .\memory_leak_report.txt
;
ReportFile = C:\Temp\SimModelLeaks.txt

; Sets the report destination to either a file, the debugger, or both. If
; reporting to file is enabled, the report is sent to the file specified by the
; ReportFile option.
;
;   Valid Values: debugger, file, both
;   Default: debugger
;
ReportTo = both

; Turns on or off a self-test mode which is used to verify that VLD is able to
; detect memory leaks in itself. Intended to be used for debugging VLD itself,
; not for debugging other programs.
;
;   Valid Values: on, off
;   Default: off
;
SelfTest = off

; Selects the method to be used for walking the stack to obtain stack traces for
; allocated memory blocks. The "fast" method may not always be able to
; successfully trace completely through all call stacks. In such cases, the
; "safe" method may prove to more reliably obtain the full stack trace. The
; disadvantage is that the "safe" method is significantly slower than the "fast"
; method and will probably result in very noticeable performance degradation of
; the program being debugged.
;
;   Valid Values: fast, safe
;   Default: fast
; 
StackWalkMethod = fast

; Determines whether memory leak detection should be initially enabled for all
; threads, or whether it should be initially disabled for all threads. If set
; to "yes", then any threads requiring memory leak detection to be enabled will
; need to call VLDEnable at some point to enable leak detection for those
; threads.
;
;   Valid Values: yes, no
;   Default: no
;
StartDisabled = no

; Determines whether or not all frames, including frames internal to the heap,
; are traced. There will always be a number of frames internal to Visual Leak
; Detector and C/C++ or Win32 heap APIs that aren't generally useful for
; determining the cause of a leak. Normally these frames are skipped during the
; stack trace, which somewhat reduces the time spent tracing and amount of data
; collected and stored in memory. Including all frames in the stack trace, all
; the way down into VLD's own code can, however, be useful for debugging VLD
; itself.
;
;   Valid Values: yes, no
;   Default: no
;
TraceInternalFrames = no

; Determines whether or not report memory leaks when missing HeapFree calls.
;
;   Valid Values: yes, no
;   Default: no
;
SkipHeapFreeLeaks = no

; Determines whether or not report memory leaks generated from crt startup code.
; These are not actual memory leaks as they are freed by crt after the VLD object
; has been destroyed.
;
;   Valid Values: yes, no
;   Default: yes
;
SkipCrtStartupLeaks = yes
```

</details>

<details>

<summary>Example VLD report (no leaks)</summary>

```
Visual Leak Detector Version 2.5.1 installed.
    Aggregating duplicate leaks.
    Forcing inclusion of these modules in leak detection: ospsuite.simmodelnative.dll
    Outputting the report to the debugger and to C:\Temp\SimModelLeaks.txt
No memory leaks detected.
Visual Leak Detector is now exiting.
```

</details>

<details>

<summary>Example VLD report (leaks detected)</summary>

```
Visual Leak Detector Version 2.5.1 installed.
    Aggregating duplicate leaks.
    Forcing inclusion of these modules in leak detection: ospsuite.simmodelnative.dll
    Outputting the report to the debugger and to C:\Temp\SimModelLeaks.txt
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 2591982 at 0x00000000D10D0C40: 16 bytes ----------
  Leak Hash: 0x9F3C55E1, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!realloc()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Include\SimModel\TObjectVector.h (44): OSPSuite.SimModelNative.dll!SimModelNative::TObjectVector<SimModelNative::ValuePoint>::push_back() + 0x1E bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (413): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    30 20 7F F7    8C 01 00 00    90 20 7F F7    8C 01 00 00     0....... ........


---------- Block 2591983 at 0x00000000DC3CBA00: 16 bytes ----------
  Leak Hash: 0x109A42D6, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_array.cpp (29): OSPSuite.SimModelNative.dll!operator new[]()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (99): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::CacheValues() + 0x3A bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (416): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    00 00 00 00    00 00 00 00    00 00 00 00    10 0D 20 41     ........ .......A


---------- Block 2584297 at 0x00000000EFF88190: 176 bytes ----------
  Leak Hash: 0xAE6CF1B2, Count: 8, Total 1408 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (274): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    60 FE FC 45    FA 7F 00 00    FF FF FF FF    CD CD CD CD     `..E.... ........
    40 87 D6 F7    8C 01 00 00    00 CD CD CD    CD CD CD CD     @....... ........
    CD CD CD CD    CD CD CD CD    00 00 00 00    00 00 00 00     ........ ........
    0F 00 00 00    00 00 00 00    20 8E D6 F7    8C 01 00 00     ........ ........
    00 CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    00 00 00 00    00 00 00 00    0F 00 00 00    00 00 00 00     ........ ........
    70 89 D6 F7    8C 01 00 00    70 8E D6 F7    8C 01 00 00     p....... p.......
    78 8E D6 F7    8C 01 00 00    78 8E D6 F7    8C 01 00 00     x....... x.......
    00 CD CD CD    02 00 00 00    60 8A D6 F7    8C 01 00 00     ........ `.......
    60 85 D6 F7    8C 01 00 00    F0 86 D6 F7    8C 01 00 00     `....... ........
    B0 94 D6 F7    8C 01 00 00    02 00 00 00    CD CD CD CD     ........ ........


---------- Block 2591895 at 0x00000000F77EF330: 24 bytes ----------
  Leak Hash: 0xEF90F768, Count: 16, Total 384 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (412): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    00 00 00 00    00 00 00 00    00 10 05 D3    2E 92 99 3F     ........ .......?
    00 CD CD CD    CD CD CD CD                                   ........ ........


---------- Block 2584175 at 0x00000000F7D65EF0: 16 bytes ----------
  Leak Hash: 0xD6B4DD11, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (49): OSPSuite.SimModelNative.dll!std::_Default_allocate_traits::_Allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (178): OSPSuite.SimModelNative.dll!std::_Allocate<16,std::_Default_allocate_traits,0>() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (867): OSPSuite.SimModelNative.dll!std::allocator<std::_Container_proxy>::allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (1202): OSPSuite.SimModelNative.dll!std::_Container_base12::_Alloc_proxy<std::allocator<std::_Container_proxy> >() + 0xF bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xstring (2242): OSPSuite.SimModelNative.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >() + 0x39 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\ObjectBase.cpp (15): OSPSuite.SimModelNative.dll!SimModelNative::ObjectBase::ObjectBase() + 0x2A bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Formula.cpp (11): OSPSuite.SimModelNative.dll!SimModelNative::Formula::Formula() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (9): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::TableFormula() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (274): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints() + 0x21 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    A0 90 F8 EF    8C 01 00 00    00 00 00 00    00 00 00 00     ........ ........


---------- Block 2584177 at 0x00000000F7D65F40: 16 bytes ----------
  Leak Hash: 0x575112C8, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (49): OSPSuite.SimModelNative.dll!std::_Default_allocate_traits::_Allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (178): OSPSuite.SimModelNative.dll!std::_Allocate<16,std::_Default_allocate_traits,0>() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (867): OSPSuite.SimModelNative.dll!std::allocator<std::_Container_proxy>::allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (1202): OSPSuite.SimModelNative.dll!std::_Container_base12::_Alloc_proxy<std::allocator<std::_Container_proxy> >() + 0xF bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\vector (369): OSPSuite.SimModelNative.dll!std::vector<double,std::allocator<double> >::vector<double,std::allocator<double> >() + 0x26 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (9): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::TableFormula() + 0x2B bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (274): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints() + 0x21 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    F0 90 F8 EF    8C 01 00 00    00 00 00 00    00 00 00 00     ........ ........


---------- Block 2584184 at 0x00000000F7D65FE0: 8 bytes ----------
  Leak Hash: 0xE4893551, Count: 8, Total 64 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (49): OSPSuite.SimModelNative.dll!std::_Default_allocate_traits::_Allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (178): OSPSuite.SimModelNative.dll!std::_Allocate<16,std::_Default_allocate_traits,0>() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (867): OSPSuite.SimModelNative.dll!std::allocator<double>::allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\vector (697): OSPSuite.SimModelNative.dll!std::vector<double,std::allocator<double> >::_Emplace_reallocate<double const &>() + 0xF bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\vector (661): OSPSuite.SimModelNative.dll!std::vector<double,std::allocator<double> >::emplace_back<double const &>() + 0x1F bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\vector (671): OSPSuite.SimModelNative.dll!std::vector<double,std::allocator<double> >::push_back()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (124): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::CacheValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (416): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    00 00 00 00    00 00 00 00                                   ........ ........


---------- Block 2584176 at 0x00000000F7D66D50: 16 bytes ----------
  Leak Hash: 0x9FD38EF2, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): OSPSuite.SimModelNative.dll!operator new() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (49): OSPSuite.SimModelNative.dll!std::_Default_allocate_traits::_Allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (178): OSPSuite.SimModelNative.dll!std::_Allocate<16,std::_Default_allocate_traits,0>() + 0xA bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (867): OSPSuite.SimModelNative.dll!std::allocator<std::_Container_proxy>::allocate()
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xmemory (1202): OSPSuite.SimModelNative.dll!std::_Container_base12::_Alloc_proxy<std::allocator<std::_Container_proxy> >() + 0xF bytes
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905\include\xstring (2242): OSPSuite.SimModelNative.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >() + 0x39 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\ObjectBase.cpp (16): OSPSuite.SimModelNative.dll!SimModelNative::ObjectBase::ObjectBase()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Formula.cpp (11): OSPSuite.SimModelNative.dll!SimModelNative::Formula::Formula() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (9): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::TableFormula() + 0xA bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (274): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints() + 0x21 bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    C8 90 F8 EF    8C 01 00 00    00 00 00 00    00 00 00 00     ........ ........


---------- Block 2591998 at 0x00000000F7D68560: 16 bytes ----------
  Leak Hash: 0x09C82FE1, Count: 8, Total 128 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_array.cpp (29): OSPSuite.SimModelNative.dll!operator new[]()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (100): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::CacheValues() + 0x3A bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (416): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    7D DF 1D A2    2D 40 E8 3F    CB FE 56 62    38 3F E8 3F     }...-@.? ..Vb8?.?


---------- Block 2591999 at 0x00000000F7D686F0: 8 bytes ----------
  Leak Hash: 0x1E0D575D, Count: 8, Total 64 bytes
  Call Stack:
    ucrtbased.dll!malloc()
    d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_array.cpp (29): OSPSuite.SimModelNative.dll!operator new[]()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (138): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::CacheValues() + 0x3D bytes
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\TableFormula.cpp (416): OSPSuite.SimModelNative.dll!SimModelNative::TableFormula::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Parameter.cpp (283): OSPSuite.SimModelNative.dll!SimModelNative::Parameter::SetTablePoints()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\Src\Simulation.cpp (1332): OSPSuite.SimModelNative.dll!SimModelNative::Simulation::SetParametersValues()
    C:\SW-Dev\SimModel\src\OSPSuite.SimModelNative\src\PInvokeSimulation.cpp (841): OSPSuite.SimModelNative.dll!SetParameterValues()
    (Module name unavailable)!0x00007FFA2DD726FF()
  Data:
    AE 90 1C 18    06 8F EE BD                                   ........ ........


Visual Leak Detector detected 88 memory leaks (7264 bytes).
Largest number used: 28604617 bytes.
Total allocations: 203291523 bytes.
Visual Leak Detector is now exiting.

```

</details>

#### Remarks

* For additional included C++ modules: in order to get readable stack trace, *Whole Program Optimization* (**/GL**) Compiler option must be set


# Algorithm for Individual Creation

When OSPSuite creates a new individual given input data, there is one of two algorithms being used: There is the algorithm for species that are not age dependant and There is the more complicated algorithm for age dependant species that.

Both algorithms can be found in more detail here:

<https://github.com/Open-Systems-Pharmacology/OSPSuite.Documentation/wiki/Create-Individual-Algorithm>


# Overview


# User Roles and Responsibilities

## Management Team (**MT**)

* Community and OSP membership management
* Regular review, endorsement & publication of roadmap for OSP development
* Certification of software platform, models and other Systems Pharmacology content qualifications and trainings
* Release of certified platform versions
* Organization of contributions to scientific and regulatory community and publication of whitepapers

## Sounding Board (**SB**)

* Review of scientific and technical content
* Identification of scientific and regulatory trends
* Scientific and technical consultancy for the management team

## Core Developers (**DEV**)

* Development and testing of OSP software platform and tools
* Review of proposed software changes
* Integration of proposed software changes into the platform

## OSP Community Members (**OSP Members**)

* Development of Systems Pharmacology content, in particular
  * data and models
  * software requirements
  * methods
  * best practices and qualification frameworks
  * training material
* Development and testing of OSP software platform and tools
* Qualification of Systems Pharmacology applications
* Validation of OSP software platform
* Experience exchange and active contributions to OSP forum

## Users

* Use of OSP content and software platform and reporting of observations, needs and issues
* Experience exchange and active contributions to OSP forum (e.g. Q\&A)


# Software Engineering

The Open Systems Pharmacology Suite (OSP Suite) is the open-source platform. The OSP Suite is the result of over 20 years of effort from experts in software development, database management, mathematics, biology, physiology, pharmacokinetics, pharmacology, and systems biology. This multi-million dollar platform was made open-source in early 2017 to accelerate the development and application of PBPK models and systems modeling in the drug development process.

## Source Control

The OSP Suite uses GitHub as a source control platform.

![The OSPSuite GitHub Organization](/files/Zjc6xiMhmV12KKgRjRv8)

GitHub is a web-based hosting service for version control using Git. It offers all of the distributed version control and source code management (SCM) functionality of Git as well as adding its own features. It provides access control and several collaboration features such as bug tracking, feature requests, task management, and wikis for every project.

GitHub offers plans for both private repositories and free accounts, which are commonly used to host open-source software projects. All Repositories in the scope of the OSP Suite are public. As of January 2023, GitHub reports having over 100 million users and more than 420 million repositories (including at least 28 million public repositories), making it the largest host of source code in the world.

In addition to source code, GitHub supports the following formats and features:

* Documentation, including automatically rendered README files in a variety of Markdown-like file formats
* Issue tracking (including feature requests) with labels, milestones, assignees and a search engine
* Wikis
* [GitHub Codespaces](https://en.wikipedia.org/wiki/GitHub_Codespaces), an online Integrated Development Environment (IDE) providing users with a virtual machine intended to be a work environment to build and test code
* [Discussions](https://docs.github.com/en/discussions)
* Security Alerts of known [common vulnerabilities and exposures](https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures) in different packages
* Pull requests with code review and comments
* Commits history
* Graphs: pulse, contributors, commits, code frequency, punch card, network, members
* Email notifications and the option to subscribe someone to notifications by @ mentioning them
* GitHub Pages: small websites can be hosted from public repositories on GitHub. This is what we have done for the OSP Suite where the site <https://www.open-systems-pharmacology.org> is a user-friendly gateway to the OSP Platform
* PDF document viewer

## Issue Tracking

The OSP Suite uses GitHub as an issue tracker. Every user with a valid GitHub account can submit an issue and participate in discussions. Issues are related to bugs and features. They have a life cycle and different issues can be linked to each other. GitHub supports collaboration over issues such that members can comment and discuss publicly.

![The OSPSuite GitHub Issue Tracker](/files/3dB7D7XIdLIUr2tehQZJ)

## Forum

The Forum is used e.g. for scientific discussions related to the OSP platform and is realized as a [Discussion tab](https://docs.github.com/en/discussions) in a dedicated Forum repository. <https://github.com/Open-Systems-Pharmacology/Forum/discussions>

![The OSPSuite GitHub Forum](/files/MbnZoieXBB9kgQJWCsmk)

## Release Planning

Release planning is realized via the GitHub “Projects” feature. Issues are organized by milestones and effort estimates are proposed and tracked. Release planning is done by the OSP Management Team.

![OSP Suite Release Planning](/files/iAMrGtzde9yOOnel7nUU)

Approved “official” releases of the OSP Suite are published on the GitHub Platform and can be downloaded by any user (no GitHub account is required for this). Full release histories are available on GitHub and include any changes made in the release from the previous version and any Release Notes.

![OSP Suite Release Notes](/files/Vkkdxvim6qz7B8nQ3UiM)

## Continuous Integration

Continuous Integration (CI) is a software development practice that aims at preventing code integration problems and improving overall software quality. It requires developers to update their code (commit) into a code repository. Periodically or even after each commit, the code is verified by an automated build running on the Continuous Integration Server (CI Server). Upon build completion, teams are notified of any defects or issues that were found thus allowing developers to detect and fix problems early. The Continuous Integration Process (CI Process) describes the tasks to be performed by the automated build.

Continuous integration of the OSP Suite is realized through [GitHub Actions](https://github.com/features/actions). GitHub Actions is a hosted, distributed continuous integration service used to build and test projects hosted on GitHub for Windows, Linux, and macOS. It provides the following features:

* Test automation
  * Run unit tests on each commit of the source code
  * Run integration/module/systems tests periodically (e.g. nightly) because slower tests are run less frequently
  * Logging mechanism and test reports
  * Notify team when build or unit tests are failing
* Build automation
  * Setups of different OSP Platform tools as well as of the whole Suite are created nightly
* Code quality analysis (e.g. static code analysis, test coverage)
* Artifact repository (setup, reports): Nightly builds that incorporate any new features/fixes can be accessed by anyone for beta testing. Full testing and code coverage reports can be accessed and investigated by all for each build.
* Semantic code analysis with [Dependabot](https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide) and [CodeQL](https://codeql.github.com/docs/codeql-overview/about-codeql/) scanning for security vulnerabilities
  * Dependabot scans repository for known vulnerable dependencies
  * CodeQL scans the source code for known vulnerabilities
  * Both scanners alert developers to newly created, or newly added vulnerabilities and can create issues to be addressed or are reported in the security tab of the repository

## Validation

Validation of computerized system: Comprehensive library of test cases that grows with every newly released feature, including manual or automatic with validated programs.

1. Testing correct behavior of software modules. Tests triggered with every software build [(Unit Tests, Integration Tests …)](#continuous-integration).
2. Comparison of simulation outputs to verified standards for specific combinations of compounds, organisms, calculation methods, and model options.
3. Automated tests in different software environments (different operating systems etc.)
4. Test of new features by the scientific experts (e.g. via creation of various simulation scenarios and comparing of simulated results with published study data)

## General Qualification of the PBPK Platform

* Qualification of the model structure
  * Qualified by design
    * Based on biological structure (physiologically based) and relevant biological processes ( absorption, distribution, metabolism, excretion)
    * Only slight structural changes between species (human, monkey, dog, rat, mouse, beagle, rabbit, minipig)
  * Qualification of physiological parameters
    * Some of them qualified by design, e.g. input from studies (weight, height, …)
    * Others qualified by prior information: Literature values, different project experience, learning...
  * Qualification of proteins, enzyme, transporter parameters
    * From experiments, taken as a priori information
    * Inferred parameters from estimation based on data

## Qualification for intended use

The "qualification for intended use” introduced in the European Medicines Agency guideline translates into the following two major challenges:

1. The provision of a sufficient package of successful prediction case studies
2. Full transparency of the approach, processes, tools and models used

Automated qualification support is a built-in functionality of the OSP Suite.

A qualification repository consists of:

1. (references to) model project files and experimental data
2. formal qualification plan describing the simulations, visualizations, and reporting to be automatically generated by a qualification engine. Several qualification repositories for drug–drug interactions and pediatric applications have already been published on GitHub.

Details are given in:

* [Open Systems Pharmacology Community - An Open Access, Open Source, Open Science Approach to Modeling and Simulation in Pharmaceutical Sciences (https://doi.org/10.1002/psp4.12473)](https://doi.org/10.1002/psp4.12473)
* [OSP Software Release Management and (Re-)Qualification Framework](https://www.open-systems-pharmacology.org/assets/conference_2024/Session%209-1_Solodenko%20-%20OSP%20Software%20Release%20Management%20and%20\(Re-\)Qualification%20Framework.pdf)
* [OSP Suite online documentation: Qualification framework](https://docs.open-systems-pharmacology.org/shared-tools-and-example-workflows/qualification)
* [A generic framework for the physiologically-based pharmacokinetic platform qualification of PK-Sim and its application to predicting cytochrome P450 3A4-mediated drug-drug interactions (https://doi.org/10.1002/psp4.12636)](https://doi.org/10.1002/psp4.12636)


# Transparency and Security

## Source Code Modifications

The whole source code of the OSP Suite is stored and versioned on GitHub.

As of January 2023, GitHub reports having over 100 million users and more than 420 million repositories (including at least 28 million public repositories), making it the largest host of source code in the world.

Among others, GitHub is used by companies like Google or Microsoft for the code hosting, for example [Google](https://github.com/google) and [Microsoft](https://github.com/microsoft)

Source code on the OSP can be modified by the OSP Maintainers only. OSP Maintainers consist of a very limited number of people (and is a subset of OSP Management Team (MT), OSP Sounding Board (SB) and OSP Core Developers (DEV)).

When source code modifications must be done, the procedure is as follows:

* Any user can propose changes for the software by creating a so called [Pull Request (PR)](https://en.wikipedia.org/wiki/Distributed_version_control#Pull_requests)
* Those changes are not automatically accepted into the software
* Instead members of the SB and DEV team review this proposal and decide if proposed changes could be integrated
* In case of positive decision: revalidation of the software with integrated proposed changes is performed
* If the outcome of the revalidation is positive: proposed changes are accepted as part of the official release

This is a well-established procedure used particularly by GitHub for open source and closed source (commercial) software, used by millions of customers.

## Build Process

Building of the OSP Libraries and Setups is realized in a fully automated manner via GitHub Actions CI service [(s. section Software Engineering/Continuous Integration)](/software-engineering-transparency-and-security/overview/software-engineering#continuous-integration).

When building a library or a setup: the corresponding source code from the OSP is transferred into such a build environment and a build process is triggered; resulting build artifacts (libraries/setups) are stored in the GitHub cloud.

This process is fully automated. Particularly:

* Nobody (except core developers (DEV)) can change a standard build environment.
* Nobody can modify source code during build
* Nobody can modify produced build artifacts.

## Transparency

### Source Code

* All source code is public.
* All code changes are tracked and saved in the history, including:
  * Full list of changes
  * Date and time stamp
  * Names of the contributors
  * Names of the Reviewers
  * Name of the person who has integrated the changes (accepted the corresponding PR)
  * Links to associated validation reports

Example: <https://github.com/Open-Systems-Pharmacology/Suite/commits/master>

* Code changes history entries cannot be modified

### Software Builds

* All software builds are tracked and saved in the build history, including:
  * Link to the used version of the source code on GitHub
  * Date and time stamp
  * Full build log
  * Test protocols of all automated tests
  * All produced build artifacts

Example: <https://github.com/Open-Systems-Pharmacology/Suite/actions/workflows/build-and-publish.yml>

* Build history entries cannot be modified

### Software validation and qualification

An overview of validation steps and links to validation/test reports are published with every OSP Suite release on GitHub (<https://github.com/Open-Systems-Pharmacology/Suite/tree/master/validation%20and%20qualification>) E.g., the test reports of the OSP Suite version 8 contain more than 10,000 tests.

Qualification reports of the OSP platform are published on GitHub. Examples:

* <https://github.com/Open-Systems-Pharmacology/Pediatric_Qualification_Package_GFR_Ontogeny/releases>
* <https://github.com/Open-Systems-Pharmacology/Pediatric_Qualification_Package_CYP3A4_Ontogeny/releases>
* <https://github.com/Open-Systems-Pharmacology/Pediatric_Qualification_Package_CYP2C8_Ontogeny/releases>

## Security

### Branch protection

The **default** branch and the **main** branch (if different from the default) in the code repositories are protected using GitHub's [branch protection rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule).

* This prevents any user (including repository maintainers and organization administrators) from directly pushing code into a protected branch without first creating a pull request.
* Every pull request can only be merged after being approved by the repository maintainer(s).

  ![Branch Protection](/files/AKJ90F2NlfKAsylD6yec)

### Static Application Security Testing (SAST)

SAST is fully integrated into the OSP CI Pipeline via GitHub's [CodeQL](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning-with-codeql), which is part of *GitHub Advanced Security* (GHAS).

* Source code is scanned for vulnerabilities with every modification and before a pull request is merged into the code base.

  ![CodeQL Pull Request](/files/b6xrXEOiRbu7WHGGkg9t)
* Additionally, the existing code base is scanned weekly.
  * All found security alerts appear directly in the **Security** tab of a repository and can be quickly addressed by the development team.

    ![CodeQL Code Analysis](/files/surf944Ow0odCpmWJLzy)

### Software Composition Analysis (SCA)

The OSP codebase is protected by continuous Software Composition Analysis (SCA) using [GitHub Dependabot](https://docs.github.com/code-security/dependabot). Dependabot monitors open-source dependencies against the *GitHub Advisory Database* and *Common Vulnerabilities and Exposures (CVE)* database.

When a vulnerability is identified, Dependabot automatically notifies the developers and creates pull requests with safe, patched versions. The OSP developer team then reviews and merges these updates promptly.

![Dependabot Alerts](/files/TTF7qzUUiicScnM4uDGa)

### Release security: VirusTotal scanning and badges

To help you use the OSP Suite and its standalone tools (PK-Sim and MoBi) with confidence, every release is scanned for viruses and other threats before publication. All installer and archive formats (EXE, MSI and ZIP) are submitted to [VirusTotal](https://www.virustotal.com) for independent, multi-engine analysis. A badge is then added to each GitHub release that links directly to the corresponding VirusTotal scan results.

Example: [![](https://img.shields.io/badge/Scanned%20by%20VirusTotal-000000?style=for-the-badge\&logo=virustotal\&logoColor=white\&labelColor=blue\&color=green)](https://www.virustotal.com/gui/file/33f877bc926c5c3fe2634183a51938039b91664a23c545d201b2a6b8f061a531)

* What is VirusTotal?
  * [VirusTotal](https://www.virustotal.com/) is a file and URL scanning service that aggregates results from 60+ antivirus engines and reputation services. It also uses static and dynamic (sandbox) analysis.
  * Reports typically include:
    * A detection summary (e.g. 'No security vendors flagged this file' or 'The number of engines that flagged it').
    * Per-vendor verdicts and details.
    * Behavioral and sandbox observations (where applicable).
    * File metadata, such as hashes (SHA-256), size and first/last seen times.
* How to interpret the results:
  * A clean result across all engines indicates that the file is likely to be safe.
  * False positives can occur. Engine definitions evolve over time, so results may change as vendors update their signatures.
  * If you see any detections that concern you, review the per-engine details in VirusTotal and contact the OSP team with a link to the report.
* Notes and best practices:
  * Always download installers from the official OSP release pages.
  * The VirusTotal badge links to the scan performed at the time of release; you can also rescan on VirusTotal to see the latest vendor verdicts.


