diff --git a/_quarto.yml b/_quarto.yml
index 606e6d9da7c95e1620eaa86fee23020f8588b220..0fe852244b687e738c476241e6d374a50c7c87b2 100644
--- a/_quarto.yml
+++ b/_quarto.yml
@@ -52,7 +52,7 @@ website:
           - "exercises/user-experience.qmd"
           # - "exercises/testing.qmd"
           # - "exercises/git2.qmd"
-          - "exercises/parallelism.qmd"
+          - "exercises/parallelism/parallelism.qmd"
           # - "exercises/hardware.qmd"
           # - "exercises/file_and_data_systems.qmd"
           # - "exercises/memory_hierarchies.qmd"
diff --git a/exercises/parallelism/main.c b/exercises/parallelism/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4a474945b39d363a17dcddfd727dd75936de571
--- /dev/null
+++ b/exercises/parallelism/main.c
@@ -0,0 +1,297 @@
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef _OPENMP
+#include <omp.h>
+#else
+#ifdef WRITE_DECOMP
+#error You cannot write the decomposition without OpenMP.
+#endif
+#endif
+
+//compile using (for example):
+//gcc -lm -fopenmp -g main.c
+
+//definition of constants
+//some values are given in meter
+//some in seconds
+//
+#define x_0 10000
+#define delta_x 1
+#define coeff_sech 0.01
+//depth of sea at deepest point
+#define b_0 1000
+//gravitational acceleration
+#define g 10
+#define delta_t 0.001
+
+
+double *h;
+double *h1;
+double *h2;
+double *u;
+double *u1;
+double *u2;
+
+int *point_to_thread;
+
+long count_points () {
+	return (int)(2*x_0/delta_x);
+}
+
+double get_x(long i){
+	return i*delta_x - x_0;
+}
+
+double waterdepth(long i){
+	double x = get_x(i);
+	return b_0*(x*x/(x_0*x_0)-1);
+}
+
+void initialise_h(double *h){
+	double x, tmp;
+	long i;
+	for(i=0; i < count_points(); i++){
+		x=get_x(i);
+		tmp = 2/(exp(coeff_sech*x)+exp(-coeff_sech*x));
+		if (tmp > 1e-10)
+			h[i] = tmp*tmp;
+		else
+			h[i] = 0;
+	}
+}
+
+void initialise_u(double *u){
+	long i;
+	for(i=0;i<count_points();i++){
+		u[i]=0;
+	}
+}
+
+
+
+void print_values(FILE *data, double *h, double *u){
+	long i;
+	fprintf(data, "#x\th\tu\tb\n");
+	for(i=0;i<count_points();i++){
+		fprintf(data, "%g\t%g\t%g\t%g\n", get_x(i), h[i], u[i], waterdepth(i));
+	}
+}
+
+double lu(double *h, double *u, long i){
+	return u[i]*(u[i+1]-u[i-1])+g*(h[i+1]-h[i-1]);
+}
+
+double lh(double *h, double *u, long i){
+	return u[i]*(h[i+1]-h[i-1])-u[i]*(waterdepth(i+1)-waterdepth(i-1))+(h[i]-waterdepth(i))*(u[i+1]-u[i-1]);
+}
+
+
+//sets h1,u1 using values (startconditions) from u2/h2
+void euler(double *h1, double *h2, double *u1, double *u2){
+	long i;
+	long npoints = count_points();
+	u1[0]=0;		//boundary value
+	h1[0]=0;		//boundary value
+	u1[npoints-1]=0;
+	h1[npoints-1]=0;
+	for(i=1;i<npoints-1;i++){
+		u1[i]=u2[i]-(delta_t/(2.*delta_x))*lu(h2,u2,i);
+		h1[i]=h2[i]-(delta_t/(2.*delta_x))*lh(h2,u2,i);
+	}
+}
+
+long findmax(double *h, long oldmaxi,long outputmth){
+	long i, maxi=oldmaxi-10;
+	for(i=oldmaxi-10;(i< oldmaxi+(int)(outputmth/delta_x)+30) && (i<count_points()) ;i++){
+		if(h[i]>h[maxi]){
+			maxi=i;
+		}
+	}
+	return maxi;
+}
+
+double maxval(double *h) {
+	long npoints = count_points();
+	long i;
+	double hmax = -10;
+// HOMEWORK: Parallelise this loop!
+	for(i = 0; i < npoints; i++){
+		if (h[i] > hmax)
+			hmax = h[i];
+	}
+	return hmax;
+}
+
+
+double ng_derivative(double xi, double xi_1, double deltax){
+	return (xi-xi_1)/deltax;
+}
+
+
+void siginthandler(){
+	print_values(stdout,h,u);
+	exit(0);
+}
+
+#ifdef _OPENMP
+void save_decomp(long i) {
+	point_to_thread[i] = omp_get_thread_num();
+}
+
+void print_decomp() {
+	int i,j;
+	int npoints = count_points();
+	for (i=0; i<omp_get_num_threads(); i++) {
+		#pragma omp barrier
+		if (i != omp_get_thread_num())
+			continue;
+		printf("%d\t", i);
+		int first=-1;
+		for (j=0; j<npoints+1; j++) {
+			if (j < npoints && point_to_thread[j] == i) {
+				if (first == -1)
+					first = j;
+			} else {
+				if (first == -1)
+					continue;
+				if (first == j-1)
+					printf("%d ", j);
+				else {
+					printf("%d-%d ", first, j-1);
+				}
+				first = -1;
+			}
+		}
+		printf("\n");
+	}
+}
+#endif
+
+
+void swap(double **var, double **var1, double **var2) {
+	double *temp;
+
+	temp  = *var2;
+	*var2 = *var1;
+	*var1 = *var;
+	*var  = temp;
+}
+
+void set_boundaries(double *var) {
+	long npoints = count_points();
+	var[0]         = 0;
+	var[npoints-1] = 0;
+}
+
+int main(int argc, char* argv){
+	long i;
+	long npoints = count_points();
+	h  = malloc(sizeof(double)*npoints);
+	h1 = malloc(sizeof(double)*npoints);
+	h2 = malloc(sizeof(double)*npoints);
+
+	u  = malloc(sizeof(double)*npoints);
+	u1 = malloc(sizeof(double)*npoints);
+	u2 = malloc(sizeof(double)*npoints);
+#ifdef WRITE_DECOMP
+	point_to_thread = malloc(sizeof(int)*count_points());
+#endif
+
+	if(h==NULL || h1==NULL || h2==NULL || u==NULL || u1==NULL || u2==NULL){
+		fprintf(stderr, "Insufficient memory");
+		exit(23);
+	}
+#if 0
+	signal(SIGINT, siginthandler);
+#endif
+
+	long maxi=((npoints)/2)+5;
+	long oldmaxi;
+	long oldmaxi_output=(npoints)/2;
+	int maximth=20;
+	double t=0;
+	long n=0;
+	int outputmth=1000; //write every mth set of values to stderr
+	int dataqth=200; //write every qth set of values to output#
+	char file[60]; //char pointer for filename
+	FILE* out;
+	double *temp;
+	int first = 1;
+
+	initialise_u(u2);
+	initialise_h(h2);
+	euler(h1,h2,u1,u2);
+#if 0
+        out = fopen("t-1.dat","w");
+        print_values(out,h1,u1);
+        out = fopen("t-2.dat","w");
+        print_values(out,h2,u2);
+#endif
+	time_t t_before = time(NULL);
+	fprintf(stderr, "#time	h_max\n");
+
+	//while ( t < 150 ){
+	while ( t < 50 ){
+		if (!first) {
+			swap(&h, &h1, &h2);
+			swap(&u, &u1, &u2);
+		} else
+			first = 0;
+
+		set_boundaries(u);
+		set_boundaries(h);
+
+		#pragma omp parallel for // schedule(dynamic, 10)
+		for(i=0;i<npoints;i++){
+#ifdef WRITE_DECOMP
+			save_decomp(i);
+#endif
+			if (i == 0 || i == npoints-1)
+				continue;
+			u[i]=u2[i]-(delta_t/delta_x)*lu(h1,u1,i);
+			h[i]=h2[i]-(delta_t/delta_x)*lh(h1,u1,i);
+		}
+
+		t+=delta_t;
+		if((n%maximth)==0){
+
+			oldmaxi=maxi;
+			maxi=findmax(h,oldmaxi,maximth);
+			if((n%outputmth)==0){
+				double maxh = maxval(h);
+				fprintf(stderr, "%g\t%g\n", t, maxh);
+
+#if 0
+				fprintf(stderr, "%g \t",t);
+				fprintf(stderr, "%g\t%g \t%g\n",get_x(maxi),h[maxi],ng_derivative(get_x(maxi),get_x(oldmaxi_output),outputmth*delta_t));
+				oldmaxi_output=maxi;
+#endif
+			}
+		}
+
+
+#if 0
+                  if((n%dataqth)==0){
+                        sprintf(file,"output%04ld.dat",n/dataqth);
+                        out = fopen(file,"w");
+                        print_values(out,h,u);
+                  }
+#endif
+		n++;
+	}
+	time_t t_after = time(NULL);
+	double duration = difftime(t_after, t_before);
+	printf("Run took %g seconds.\n", duration);
+
+	//print_values(stdout,h,u);
+#ifdef WRITE_DECOMP
+#pragma omp parallel
+	print_decomp();
+#endif
+
+	return 0;
+}
+
diff --git a/exercises/parallelism.qmd b/exercises/parallelism/parallelism.qmd
similarity index 100%
rename from exercises/parallelism.qmd
rename to exercises/parallelism/parallelism.qmd