# Parallel Simulations of the Sharp Wave-Ripples of the Hippocamp on Multicore CPUs and GPUs
## 2 Materials and Methods
### Parallel Simulations of the CA1 Network
#### 2.2.2 The Multicore Algorithm  
The multicore algorithm exploits the OpenMP (Open Multi Processing) paradigm. It is an Application Programming Interface (API) that facilitates multi-platform shared memory multiprocessing programming in C/C++. It is specifically designed to facilitate the development of parallel applications on multicore processors by providing a set of compiler directives, library routines, and environment variables. OpenMP provides a means for developers to write parallel code that can effectively utilise the capabilities of multicore systems by distributing tasks across multiple processing cores.  
One of the key advantages of OpenMP is its simplicity and ease of integration into existing codebases, which allows for incremental parallelisation without the necessity for extensive code restructuring. It supports both fine-grained and coarse-grained parallelism, thereby enabling the parallel execution of loops, sections, and tasks while maintaining a high level of control over thread creation, synchronisation, and workload distribution. The OpenMP shared memory model permits threads to communicate by reading and writing shared variables. Additionally, it provides mechanisms such as critical sections and atomic operations to circumvent race conditions.  
In multicore systems, OpenMP can markedly enhance performance by optimising the utilisation of available cores, thereby reducing execution times for compute-intensive applications. Its portability across different architectures also ensures that code written with OpenMP can run efficiently on a wide range of multicore processors, making it a crucial tool for developers aiming to optimise software for parallel execution.  
The serial code described in Section 2.2.1 has been annotated with OpenMP directives to indicate to the compiler which parts can be parallelized, without exploiting any numerical library. In particular, all the operations inside the main _for_ loop are intrinsically parallel since they are in the form of matrix-vector multiplications or equations describing the voltage update of single cells. It must be stressed that, for each time step of the simulation, the update of the voltage of each cell is dependent only on the network state at the previous time step, the actual inputs from the CA3 layer, and the background noise. Therefore, the four matrix-vector multiplications and the _for_ loops related to the excitatory and inhibitory cells can be performed in parallel. These code parts have been annotated with the _#pragma omp parallel_ for directive to indicate that the iterations of the _for_ loops should be equally divided on the available core of the processor. Moreover, the _private_ and _shared_ clauses have been used to indicate the variables that are private to the single thread and the structures that are shared among all the processing elements. Indeed, referring to Algorithm 1, the matrix-vector multiplications described in lines 3-6 have been parallelized with the aforementioned directives. Moreover, the _for_ loops in lines 8 and 11 have been annotated to be parallelized by the compiler.  
Finally, since the number of spikes occurring at each time step is needed to validate the simulation against the results of [5], a _reduction_ clause is used to accumulate the results of all the threads in a single variable that can be seen from the master thread.