EnhancedSolver port complete

This commit is contained in:
2024-07-27 02:19:56 +02:00
parent 8091c714e2
commit d81313f293
199 changed files with 16030 additions and 310 deletions

View File

@@ -22,6 +22,7 @@ SRC = $(filter-out $(wildcard $(SRC_DIR)/*-*.c),$(wildcard $(SRC_DIR)/*.c)
ASM = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.s, $(SRC))
OBJ = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC))
OBJ += $(BUILD_DIR)/comm-$(COMM_TYPE).o
OBJ += $(BUILD_DIR)/solver-$(SOLVER).o
SOURCES = $(SRC) $(wildcard $(SRC_DIR)/*.h)
CPPFLAGS := $(CPPFLAGS) $(DEFINES) $(OPTIONS) $(INCLUDES)
@@ -38,9 +39,20 @@ $(BUILD_DIR)/%.s: %.c
$(info ===> GENERATE ASM $@)
$(CC) -S $(CPPFLAGS) $(CFLAGS) $< -o $@
.PHONY: clean distclean tags info asm format
.PHONY: clean distclean vis vis_clean tags info asm format
clean:
vis:
$(info ===> GENERATE VISUALIZATION)
@gnuplot -e "filename='pressure.dat'" ./surface.plot
@gnuplot -e "filename='velocity.dat'" ./vector.plot
@gnuplot -e "filename='residual.dat'" ./residual.plot
vis_clean:
$(info ===> CLEAN VISUALIZATION)
@rm -f *.dat
@rm -f *.png
clean: vis_clean
$(info ===> CLEAN)
@rm -rf $(BUILD_DIR)
@rm -f tags

View File

@@ -7,10 +7,10 @@
name canal # name of flow setup
bcN 1 # flags for boundary conditions
bcE 3 # 1 = no-slip 3 = outflow
bcS 1 # 2 = free-slip 4 = periodic
bcW 3 #
bcTop 1 # flags for boundary conditions
bcBottom 1 # 1 = no-slip 3 = outflow
bcLeft 3 # 2 = free-slip 4 = periodic
bcRight 3 #
gx 0.0 # Body forces (e.g. gravity)
gy 0.0 #
@@ -27,15 +27,22 @@ p_init 0.0 # initial value for pressure
xlength 30.0 # domain size in x-direction
ylength 4.0 # domain size in y-direction
imax 200 # number of interior cells in x-direction
jmax 50 # number of interior cells in y-direction
jmax 40 # number of interior cells in y-direction
# Time Data:
# ---------
te 100.0 # final time
te 60.0 # final time
dt 0.02 # time stepsize
tau 0.5 # safety factor for time stepsize control (<0 constant delt)
# Multigrid data:
# ---------
levels 2 # Multigrid levels
presmooth 5 # Pre-smoothning iterations
postsmooth 5 # Post-smoothning iterations
# Pressure Iteration Data:
# -----------------------

View File

@@ -1,7 +1,11 @@
# Supported: GCC, CLANG, ICC
TAG ?= CLANG
TAG ?= ICC
# Supported: true, false
ENABLE_MPI ?= true
ENABLE_OPENMP ?= false
# Supported: rb, mg
SOLVER ?= mg
# Supported: v1, v2, v3
COMM_TYPE ?= v3
#Feature options

View File

@@ -26,21 +26,28 @@ p_init 0.0 # initial value for pressure
xlength 1.0 # domain size in x-direction
ylength 1.0 # domain size in y-direction
imax 80 # number of interior cells in x-direction
jmax 80 # number of interior cells in y-direction
imax 128 # number of interior cells in x-direction
jmax 128 # number of interior cells in y-direction
# Time Data:
# ---------
te 10.0 # final time
dt 0.02 # time stepsize
tau 0.5 # safety factor for time stepsize control (<0 constant delt)
dt 0.02 # time stepsize
tau 0.5 # safety factor for time stepsize control (<0 constant delt)
# Multigrid data:
# ---------
levels 2 # Multigrid levels
presmooth 20 # Pre-smoothning iterations
postsmooth 5 # Post-smoothning iterations
# Pressure Iteration Data:
# -----------------------
itermax 1000 # maximal number of pressure iteration in one time step
eps 0.001 # stopping tolerance for pressure iteration
omg 1.9 # relaxation parameter for SOR iteration
omg 1.7 # relaxation parameter for SOR iteration
gamma 0.9 # upwind differencing factor gamma
#===============================================================================

View File

@@ -0,0 +1,9 @@
set terminal png size 1800,768 enhanced font ,12
set output 'residual.png'
set datafile separator whitespace
set xlabel "Timestep"
set ylabel "Residual"
set logscale y 2
plot 'residual.dat' using 1:2 title "Residual"

View File

@@ -14,7 +14,7 @@ static int sum(int* sizes, int position)
{
int sum = 0;
for (int i = 0; i < position; i++) {
for (int i = 0; i < position; i += position) {
sum += sizes[i];
}
@@ -67,6 +67,7 @@ int commIsBoundary(Comm* c, int direction)
void commExchange(Comm* c, double* grid)
{
// printf("Rank : %d In exchange \n", c->rank);
#ifdef _MPI
MPI_Request requests[4] = { MPI_REQUEST_NULL,
MPI_REQUEST_NULL,
@@ -173,9 +174,61 @@ void commPartition(Comm* c, int jmax, int imax)
{
#ifdef _MPI
c->imaxLocal = imax;
c->jmaxLocal = sizeOfRank(c->rank, c->size, jmax);
c->jmaxLocal = sizeOfRank(c->coords[JDIM], c->size, jmax);
c->neighbours[BOTTOM] = c->rank == 0 ? -1 : c->rank - 1;
c->neighbours[TOP] = c->rank == (c->size - 1) ? -1 : c->rank + 1;
c->neighbours[LEFT] = -1;
c->neighbours[RIGHT] = -1;
c->coords[IDIM] = 0;
c->coords[JDIM] = c->rank;
c->dims[IDIM] = 1;
c->dims[JDIM] = c->size;
#else
c->imaxLocal = imax;
c->jmaxLocal = jmax;
#endif
}
void commUpdateDatatypes(Comm* oldcomm, Comm* newcomm, int imaxLocal, int jmaxLocal)
{
#if defined _MPI
newcomm->comm = MPI_COMM_NULL;
int result = MPI_Comm_dup(MPI_COMM_WORLD, &newcomm->comm);
if (result == MPI_ERR_COMM) {
printf("\nNull communicator. Duplication failed !!\n");
}
newcomm->rank = oldcomm->rank;
newcomm->size = oldcomm->size;
newcomm->imaxLocal = imaxLocal / 2;
newcomm->jmaxLocal = jmaxLocal / 2;
newcomm->neighbours[BOTTOM] = newcomm->rank == 0 ? -1 : newcomm->rank - 1;
newcomm->neighbours[TOP] = newcomm->rank == (newcomm->size - 1) ? -1 : newcomm->rank + 1;
newcomm->neighbours[LEFT] = -1;
newcomm->neighbours[RIGHT] = -1;
newcomm->coords[IDIM] = 0;
newcomm->coords[JDIM] = newcomm->rank;
newcomm->dims[IDIM] = 1;
newcomm->dims[JDIM] = newcomm->size;
#endif
newcomm->imaxLocal = imaxLocal;
newcomm->jmaxLocal = jmaxLocal;
}
void commFreeCommunicator(Comm* comm)
{
#ifdef _MPI
MPI_Comm_free(&comm->comm);
#endif
}

View File

@@ -4,18 +4,18 @@
* Use of this source code is governed by a MIT style
* license that can be found in the LICENSE file.
*/
#include "comm.h"
#include <stdio.h>
#include <stdlib.h>
#include "comm.h"
#include <string.h>
#ifdef _MPI
// subroutines local to this module
static int sum(int* sizes, int position)
static int sum(int* sizes, int init, int offset, int coord)
{
int sum = 0;
for (int i = 0; i < position; i++) {
for (int i = init - offset; coord > 0; i -= offset, --coord) {
sum += sizes[i];
}
@@ -79,8 +79,8 @@ static void assembleResult(Comm* c, double* src, double* dst, int imax, int jmax
int newSizes[NDIMS] = { newSizesJ[i], newSizesI[i] };
int coords[NDIMS];
MPI_Cart_coords(c->comm, i, NDIMS, coords);
int starts[NDIMS] = { sum(newSizesJ, coords[JDIM]),
sum(newSizesI, coords[IDIM]) };
int starts[NDIMS] = { sum(newSizesJ, i, 1, coords[JDIM]),
sum(newSizesI, i, c->dims[JDIM], coords[IDIM]) };
printf(
"Rank: %d, Coords(i,j): %d %d, Size(i,j): %d %d, Target Size(i,j): %d %d "
"Starts(i,j): %d %d\n",
@@ -252,8 +252,8 @@ void commPartition(Comm* c, int jmax, int imax)
MPI_Cart_shift(c->comm, JDIM, 1, &c->neighbours[BOTTOM], &c->neighbours[TOP]);
MPI_Cart_get(c->comm, NDIMS, c->dims, periods, c->coords);
int imaxLocal = sizeOfRank(c->rank, dims[IDIM], imax);
int jmaxLocal = sizeOfRank(c->rank, dims[JDIM], jmax);
int imaxLocal = sizeOfRank(c->coords[IDIM], dims[IDIM], imax);
int jmaxLocal = sizeOfRank(c->coords[JDIM], dims[JDIM], jmax);
c->imaxLocal = imaxLocal;
c->jmaxLocal = jmaxLocal;
@@ -285,3 +285,58 @@ void commPartition(Comm* c, int jmax, int imax)
c->jmaxLocal = jmax;
#endif
}
void commUpdateDatatypes(Comm* oldcomm, Comm* newcomm, int imaxLocal, int jmaxLocal)
{
#if defined _MPI
newcomm->comm = MPI_COMM_NULL;
int result = MPI_Comm_dup(oldcomm->comm, &newcomm->comm);
if (result == MPI_ERR_COMM) {
printf("\nNull communicator. Duplication failed !!\n");
}
newcomm->rank = oldcomm->rank;
newcomm->size = oldcomm->size;
memcpy(&newcomm->neighbours, &oldcomm->neighbours, sizeof(oldcomm->neighbours));
memcpy(&newcomm->coords, &oldcomm->coords, sizeof(oldcomm->coords));
memcpy(&newcomm->dims, &oldcomm->dims, sizeof(oldcomm->dims));
newcomm->imaxLocal = imaxLocal/2;
newcomm->jmaxLocal = jmaxLocal/2;
MPI_Datatype jBufferType;
MPI_Type_contiguous(imaxLocal, MPI_DOUBLE, &jBufferType);
MPI_Type_commit(&jBufferType);
MPI_Datatype iBufferType;
MPI_Type_vector(jmaxLocal, 1, imaxLocal + 2, MPI_DOUBLE, &iBufferType);
MPI_Type_commit(&iBufferType);
newcomm->bufferTypes[LEFT] = iBufferType;
newcomm->bufferTypes[RIGHT] = iBufferType;
newcomm->bufferTypes[BOTTOM] = jBufferType;
newcomm->bufferTypes[TOP] = jBufferType;
newcomm->sdispls[LEFT] = (imaxLocal + 2) + 1;
newcomm->sdispls[RIGHT] = (imaxLocal + 2) + imaxLocal;
newcomm->sdispls[BOTTOM] = (imaxLocal + 2) + 1;
newcomm->sdispls[TOP] = jmaxLocal * (imaxLocal + 2) + 1;
newcomm->rdispls[LEFT] = (imaxLocal + 2);
newcomm->rdispls[RIGHT] = (imaxLocal + 2) + (imaxLocal + 1);
newcomm->rdispls[BOTTOM] = 1;
newcomm->rdispls[TOP] = (jmaxLocal + 1) * (imaxLocal + 2) + 1;
#else
newcomm->imaxLocal = imaxLocal;
newcomm->jmaxLocal = jmaxLocal;
#endif
}
void commFreeCommunicator(Comm* comm)
{
#ifdef _MPI
MPI_Comm_free(&comm->comm);
#endif
}

View File

@@ -11,11 +11,11 @@
#ifdef _MPI
// subroutines local to this module
static int sum(int* sizes, int position)
static int sum(int* sizes, int init, int offset, int coord)
{
int sum = 0;
for (int i = 0; i < position; i++) {
for (int i = init - offset; coord > 0; i -= offset, --coord) {
sum += sizes[i];
}
@@ -79,8 +79,8 @@ static void assembleResult(Comm* c, double* src, double* dst, int imax, int jmax
int newSizes[NDIMS] = { newSizesJ[i], newSizesI[i] };
int coords[NDIMS];
MPI_Cart_coords(c->comm, i, NDIMS, coords);
int starts[NDIMS] = { sum(newSizesJ, coords[JDIM]),
sum(newSizesI, coords[IDIM]) };
int starts[NDIMS] = { sum(newSizesJ, i, 1, coords[JDIM]),
sum(newSizesI, i, c->dims[JDIM], coords[IDIM]) };
printf(
"Rank: %d, Coords(i,j): %d %d, Size(i,j): %d %d, Target Size(i,j): %d %d "
"Starts(i,j): %d %d\n",
@@ -139,7 +139,6 @@ void commExchange(Comm* c, double* grid)
{
#ifdef _MPI
int counts[NDIRS] = { 1, 1, 1, 1 };
MPI_Neighbor_alltoallw(grid,
counts,
c->sdispls,
@@ -233,8 +232,8 @@ void commPartition(Comm* c, int jmax, int imax)
MPI_Cart_shift(c->comm, JDIM, 1, &c->neighbours[BOTTOM], &c->neighbours[TOP]);
MPI_Cart_get(c->comm, NDIMS, c->dims, periods, c->coords);
int imaxLocal = sizeOfRank(c->rank, dims[IDIM], imax);
int jmaxLocal = sizeOfRank(c->rank, dims[JDIM], jmax);
int imaxLocal = sizeOfRank(c->coords[IDIM], dims[IDIM], imax);
int jmaxLocal = sizeOfRank(c->coords[JDIM], dims[JDIM], jmax);
c->imaxLocal = imaxLocal;
c->jmaxLocal = jmaxLocal;
@@ -267,3 +266,55 @@ void commPartition(Comm* c, int jmax, int imax)
c->jmaxLocal = jmax;
#endif
}
void commUpdateDatatypes(Comm* oldcomm, Comm* newcomm, int imaxLocal, int jmaxLocal)
{
#if defined _MPI
int result = MPI_Comm_dup(oldcomm->comm, &newcomm->comm);
if (result == MPI_ERR_COMM) {
printf("\nNull communicator. Duplication failed !!\n");
}
newcomm->rank = oldcomm->rank;
newcomm->size = oldcomm->size;
newcomm->imaxLocal = imaxLocal / 2;
newcomm->jmaxLocal = jmaxLocal / 2;
MPI_Datatype jBufferType;
MPI_Type_contiguous(imaxLocal, MPI_DOUBLE, &jBufferType);
MPI_Type_commit(&jBufferType);
MPI_Datatype iBufferType;
MPI_Type_vector(jmaxLocal, 1, imaxLocal + 2, MPI_DOUBLE, &iBufferType);
MPI_Type_commit(&iBufferType);
newcomm->bufferTypes[LEFT] = iBufferType;
newcomm->bufferTypes[RIGHT] = iBufferType;
newcomm->bufferTypes[BOTTOM] = jBufferType;
newcomm->bufferTypes[TOP] = jBufferType;
newcomm->sdispls[LEFT] = (imaxLocal + 2) + 1;
newcomm->sdispls[RIGHT] = (imaxLocal + 2) + imaxLocal;
newcomm->sdispls[BOTTOM] = (imaxLocal + 2) + 1;
newcomm->sdispls[TOP] = jmaxLocal * (imaxLocal + 2) + 1;
newcomm->rdispls[LEFT] = (imaxLocal + 2);
newcomm->rdispls[RIGHT] = (imaxLocal + 2) + (imaxLocal + 1);
newcomm->rdispls[BOTTOM] = 1;
newcomm->rdispls[TOP] = (jmaxLocal + 1) * (imaxLocal + 2) + 1;
#else
newcomm->imaxLocal = imaxLocal;
newcomm->jmaxLocal = jmaxLocal;
#endif
}
void commFreeCommunicator(Comm* comm)
{
#ifdef _MPI
MPI_Comm_free(&comm->comm);
#endif
}

View File

@@ -41,6 +41,8 @@ extern void commExchange(Comm*, double*);
extern void commShift(Comm* c, double* f, double* g);
extern void commReduction(double* v, int op);
extern int commIsBoundary(Comm* c, int direction);
extern void commUpdateDatatypes(Comm*, Comm*, int, int);
extern void commFreeCommunicator(Comm*);
extern void commCollectResult(Comm* c,
double* ug,
double* vg,

View File

@@ -273,17 +273,18 @@ void setSpecialBoundaryCondition(Discretization* s)
if (commIsBoundary(&s->comm, LEFT)) {
double ylength = s->grid.ylength;
double dy = s->grid.dy;
int rest = s->grid.jmax % s->comm.size;
int yc = s->comm.rank * (s->grid.jmax / s->comm.size) +
int rest = s->grid.jmax % s->comm.dims[JDIM];
int yc = s->comm.rank * (s->grid.jmax / s->comm.dims[JDIM]) +
MIN(rest, s->comm.rank);
double ys = dy * (yc + 0.5);
double y;
/* printf("RANK %d yc: %d ys: %f\n", solver->rank, yc, ys); */
// printf("RANK %d yc: %d ys: %f\n", s->comm.rank, yc, ys);
for (int j = 1; j < jmaxLocal + 1; j++) {
y = ys + dy * (j - 0.5);
U(0, j) = y * (ylength - y) * 4.0 / (ylength * ylength);
}
}
}

View File

@@ -26,7 +26,9 @@ static void writeResults(Discretization* s)
double* pg = allocate(64, bytesize);
commCollectResult(&s->comm, ug, vg, pg, s->u, s->v, s->p, s->grid.imax, s->grid.jmax);
writeResult(s, ug, vg, pg);
if (commIsMaster(&s->comm)) {
writeResult(s, ug, vg, pg);
}
free(ug);
free(vg);
@@ -47,6 +49,9 @@ int main(int argc, char** argv)
commInit(&d.comm, argc, argv);
initParameter(&p);
FILE* fp;
if (commIsMaster(&d.comm)) fp = initResidualWriter();
if (argc != 2) {
printf("Usage: %s <configFile>\n", argv[0]);
exit(EXIT_SUCCESS);
@@ -77,16 +82,21 @@ int main(int argc, char** argv)
double tau = d.tau;
double te = d.te;
double t = 0.0;
double res = 0.0;
timeStart = getTimeStamp();
while (t <= te) {
if (tau > 0.0) computeTimestep(&d);
setBoundaryConditions(&d);
setSpecialBoundaryCondition(&d);
computeFG(&d);
computeRHS(&d);
solve(&s, d.p, d.rhs);
res = solve(&s, d.p, d.rhs);
adaptUV(&d);
if (commIsMaster(&d.comm)) writeResidual(fp, t, res);
t += d.dt;
#ifdef VERBOSE
@@ -104,7 +114,7 @@ int main(int argc, char** argv)
if (commIsMaster(s.comm)) {
printf("Solution took %.2fs\n", timeStop - timeStart);
}
if (commIsMaster(&d.comm)) fclose(fp);
writeResults(&d);
commFinalize(s.comm);
return EXIT_SUCCESS;

View File

@@ -14,13 +14,16 @@
void initParameter(Parameter* param)
{
param->xlength = 1.0;
param->ylength = 1.0;
param->imax = 100;
param->jmax = 100;
param->itermax = 1000;
param->eps = 0.0001;
param->omg = 1.8;
param->xlength = 1.0;
param->ylength = 1.0;
param->imax = 100;
param->jmax = 100;
param->itermax = 1000;
param->eps = 0.0001;
param->omg = 1.8;
param->levels = 5;
param->presmooth = 5;
param->postsmooth = 5;
}
void readParameter(Parameter* param, const char* filename)
@@ -72,6 +75,9 @@ void readParameter(Parameter* param, const char* filename)
PARSE_INT(bcRight);
PARSE_INT(bcBottom);
PARSE_INT(bcTop);
PARSE_INT(levels);
PARSE_INT(presmooth);
PARSE_INT(postsmooth);
PARSE_REAL(u_init);
PARSE_REAL(v_init);
PARSE_REAL(p_init);

View File

@@ -18,6 +18,7 @@ typedef struct {
char* name;
int bcLeft, bcRight, bcBottom, bcTop;
double u_init, v_init, p_init;
int levels, presmooth, postsmooth;
} Parameter;
void initParameter(Parameter*);

View File

@@ -8,7 +8,7 @@
#include <mpi.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "progress.h"
static double _end;
@@ -49,3 +49,22 @@ void stopProgress()
printf("\n");
fflush(stdout);
}
FILE* initResidualWriter()
{
FILE* fp;
fp = fopen("residual.dat", "w");
if (fp == NULL) {
printf("Error!\n");
exit(EXIT_FAILURE);
}
return fp;
}
void writeResidual(FILE* fp, double ts, double res)
{
fprintf(fp, "%f, %f\n", ts, res);
}

View File

@@ -10,5 +10,6 @@
extern void initProgress(double);
extern void printProgress(double);
extern void stopProgress();
extern FILE* initResidualWriter(void);
extern void writeResidual(FILE*, double, double);
#endif

View File

@@ -0,0 +1,302 @@
/*
* Copyright (C) NHR@FAU, University Erlangen-Nuremberg.
* All rights reserved. This file is part of nusif-solver.
* Use of this source code is governed by a MIT style
* license that can be found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include "allocate.h"
#include "solver.h"
#include "util.h"
#define FINEST_LEVEL 0
#define COARSEST_LEVEL (s->levels - 1)
// #define S(i, j) s[(j) * (imaxLocal + 2) + (i)]
#define E(i, j) e[(j) * (imaxLocal + 2) + (i)]
#define R(i, j) r[(j) * (imaxLocal + 2) + (i)]
#define OLD(i, j) old[(j) * (imaxLocal + 2) + (i)]
static void restrictMG(Solver* s, int level, Comm* comm)
{
int imaxLocal = comm->imaxLocal;
int jmaxLocal = comm->jmaxLocal;
double* r = s->r[level + 1];
double* old = s->r[level];
#ifdef _MPI
commExchange(comm, old);
#endif
for (int j = 1; j < (jmaxLocal / 2) + 1; j++) {
for (int i = 1; i < (imaxLocal / 2) + 1; i++) {
R(i, j) = (OLD(2 * i - 1, 2 * j - 1) + OLD(2 * i, 2 * j - 1) * 2 +
OLD(2 * i + 1, 2 * j - 1) + OLD(2 * i - 1, 2 * j) * 2 +
OLD(2 * i, 2 * j) * 4 + OLD(2 * i + 1, 2 * j) * 2 +
OLD(2 * i - 1, 2 * j + 1) + OLD(2 * i, 2 * j + 1) * 2 +
OLD(2 * i + 1, 2 * j + 1)) /
16.0;
}
}
}
static void prolongate(Solver* s, int level, Comm* comm)
{
int imaxLocal = comm->imaxLocal;
int jmaxLocal = comm->jmaxLocal;
double* old = s->r[level + 1];
double* e = s->r[level];
for (int j = 2; j < jmaxLocal + 1; j += 2) {
for (int i = 2; i < imaxLocal + 1; i += 2) {
E(i, j) = OLD(i / 2, j / 2);
}
}
}
static void correct(Solver* s, double* p, int level, Comm* comm)
{
double* e = s->e[level];
int imaxLocal = comm->imaxLocal;
int jmaxLocal = comm->jmaxLocal;
for (int j = 1; j < jmaxLocal + 1; ++j) {
for (int i = 1; i < imaxLocal + 1; ++i) {
P(i, j) += E(i, j);
}
}
}
static void setBoundaryCondition(Solver* s, double* p, int imaxLocal, int jmaxLocal)
{
#ifdef _MPI
if (commIsBoundary(s->comm, BOTTOM)) { // set bottom bc
for (int i = 1; i < imaxLocal + 1; i++) {
P(i, 0) = P(i, 1);
}
}
if (commIsBoundary(s->comm, TOP)) { // set top bc
for (int i = 1; i < imaxLocal + 1; i++) {
P(i, jmaxLocal + 1) = P(i, jmaxLocal);
}
}
if (commIsBoundary(s->comm, LEFT)) { // set left bc
for (int j = 1; j < jmaxLocal + 1; j++) {
P(0, j) = P(1, j);
}
}
if (commIsBoundary(s->comm, RIGHT)) { // set right bc
for (int j = 1; j < jmaxLocal + 1; j++) {
P(imaxLocal + 1, j) = P(imaxLocal, j);
}
}
#else
for (int i = 1; i < imaxLocal + 1; i++) {
P(i, 0) = P(i, 1);
P(i, jmaxLocal + 1) = P(i, jmaxLocal);
}
for (int j = 1; j < jmaxLocal + 1; j++) {
P(0, j) = P(1, j);
P(imaxLocal + 1, j) = P(imaxLocal, j);
}
#endif
}
static double smooth(Solver* s, double* p, double* rhs, int level, Comm* comm)
{
int imaxLocal = comm->imaxLocal;
int jmaxLocal = comm->jmaxLocal;
int imax = s->grid->imax;
int jmax = s->grid->jmax;
double dx2 = s->grid->dx * s->grid->dx;
double dy2 = s->grid->dy * s->grid->dy;
double idx2 = 1.0 / dx2;
double idy2 = 1.0 / dy2;
double factor = s->omega * 0.5 * (dx2 * dy2) / (dx2 + dy2);
double* r = s->r[level];
double res = 1.0;
int pass, jsw, isw;
jsw = 1;
for (pass = 0; pass < 2; pass++) {
isw = jsw;
#ifdef _MPI
commExchange(comm, p);
#endif
for (int j = 1; j < jmaxLocal + 1; j++) {
for (int i = isw; i < imaxLocal + 1; i += 2) {
P(i, j) -= factor *
(RHS(i, j) -
((P(i + 1, j) - 2.0 * P(i, j) + P(i - 1, j)) * idx2 +
(P(i, j + 1) - 2.0 * P(i, j) + P(i, j - 1)) * idy2));
}
isw = 3 - isw;
}
jsw = 3 - jsw;
}
}
static double calculateResidual(Solver* s, double* p, double* rhs, int level, Comm* comm)
{
int imax = s->grid->imax;
int jmax = s->grid->jmax;
int imaxLocal = comm->imaxLocal;
int jmaxLocal = comm->jmaxLocal;
double dx2 = s->grid->dx * s->grid->dx;
double dy2 = s->grid->dy * s->grid->dy;
double idx2 = 1.0 / dx2;
double idy2 = 1.0 / dy2;
double factor = s->omega * 0.5 * (dx2 * dy2) / (dx2 + dy2);
double* r = s->r[level];
double res = 1.0;
int pass, jsw, isw;
jsw = 1;
for (pass = 0; pass < 2; pass++) {
isw = jsw;
#ifdef _MPI
commExchange(comm, p);
#endif
for (int j = 1; j < jmaxLocal + 1; j++) {
for (int i = isw; i < imaxLocal + 1; i += 2) {
R(i, j) = RHS(i, j) -
((P(i + 1, j) - 2.0 * P(i, j) + P(i - 1, j)) * idx2 +
(P(i, j + 1) - 2.0 * P(i, j) + P(i, j - 1)) * idy2);
res += (R(i, j) * R(i, j));
}
isw = 3 - isw;
}
jsw = 3 - jsw;
}
#ifdef _MPI
commReduction(&res, SUM);
#endif
res = res / (double)(imax * jmax);
#ifdef DEBUG
if (commIsMaster(s->comm)) {
printf("%d Residuum: %e\n", it, res);
}
#endif
return res;
}
static double multiGrid(Solver* s, double* p, double* rhs, int level, Comm* comm)
{
double res = 0.0;
// coarsest level
if (level == COARSEST_LEVEL) {
for (int i = 0; i < 5; i++) {
smooth(s, p, rhs, level, comm);
}
return res;
}
// pre-smoothing
for (int i = 0; i < s->presmooth; i++) {
smooth(s, p, rhs, level, comm);
if (level == FINEST_LEVEL)
setBoundaryCondition(s, p, comm->imaxLocal, comm->jmaxLocal);
}
// calculate residuals
res = calculateResidual(s, p, rhs, level, comm);
// restrict
restrictMG(s, level, comm);
Comm newcomm;
commUpdateDatatypes(s->comm, &newcomm, comm->imaxLocal, comm->jmaxLocal);
// MGSolver on residual and error.
multiGrid(s, s->e[level + 1], s->r[level + 1], level + 1, &newcomm);
commFreeCommunicator(&newcomm);
// prolongate
prolongate(s, level, comm);
// correct p on finer level using residual
correct(s, p, level, comm);
if (level == FINEST_LEVEL)
setBoundaryCondition(s, p, comm->imaxLocal, comm->jmaxLocal);
// post-smoothing
for (int i = 0; i < s->postsmooth; i++) {
smooth(s, p, rhs, level, comm);
if (level == FINEST_LEVEL)
setBoundaryCondition(s, p, comm->imaxLocal, comm->jmaxLocal);
}
return res;
}
void initSolver(Solver* s, Discretization* d, Parameter* p)
{
s->eps = p->eps;
s->omega = p->omg;
s->itermax = p->itermax;
s->levels = p->levels;
s->grid = &d->grid;
s->comm = &d->comm;
s->presmooth = p->presmooth;
s->postsmooth = p->postsmooth;
int imax = s->grid->imax;
int jmax = s->grid->jmax;
int levels = s->levels;
printf("Using Multigrid solver with %d levels\n", levels);
s->r = malloc(levels * sizeof(double*));
s->e = malloc(levels * sizeof(double*));
size_t size = (imax + 2) * (jmax + 2) * sizeof(double);
for (int j = 0; j < levels; j++) {
s->r[j] = allocate(64, size);
s->e[j] = allocate(64, size);
for (int i = 0; i < (imax + 2) * (jmax + 2); i++) {
s->r[j][i] = 0.0;
s->e[j][i] = 0.0;
}
}
}
double solve(Solver* s, double* p, double* rhs)
{
double res = multiGrid(s, p, rhs, 0, s->comm);
#ifdef VERBOSE
if (commIsMaster(s->comm)) {
printf("Residuum: %.6f\n", res);
}
#endif
return res;
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) NHR@FAU, University Erlangen-Nuremberg.
* All rights reserved. This file is part of nusif-solver.
* Use of this source code is governed by a MIT style
* license that can be found in the LICENSE file.
*/
#include <math.h>
#include <stdio.h>
#include "allocate.h"
#include "comm.h"
#include "discretization.h"
#include "parameter.h"
#include "solver.h"
#include "util.h"
void initSolver(Solver* s, Discretization* d, Parameter* p)
{
s->grid = &d->grid;
s->eps = p->eps;
s->omega = p->omg;
s->itermax = p->itermax;
s->comm = &d->comm;
}
double solve(Solver* s, double* p, double* rhs)
{
int imax = s->grid->imax;
int jmax = s->grid->jmax;
int imaxLocal = s->comm->imaxLocal;
int jmaxLocal = s->comm->jmaxLocal;
double eps = s->eps;
int itermax = s->itermax;
double dx2 = s->grid->dx * s->grid->dx;
double dy2 = s->grid->dy * s->grid->dy;
double idx2 = 1.0 / dx2;
double idy2 = 1.0 / dy2;
double factor = s->omega * 0.5 * (dx2 * dy2) / (dx2 + dy2);
double epssq = eps * eps;
int pass, jsw, isw;
int it = 0;
double res = 1.0;
while ((res >= epssq) && (it < itermax)) {
jsw = 1;
for (pass = 0; pass < 2; pass++) {
isw = jsw;
commExchange(s->comm, p);
for (int j = 1; j < jmaxLocal + 1; j++) {
for (int i = isw; i < imaxLocal + 1; i += 2) {
double r = RHS(i, j) -
((P(i + 1, j) - 2.0 * P(i, j) + P(i - 1, j)) * idx2 +
(P(i, j + 1) - 2.0 * P(i, j) + P(i, j - 1)) * idy2);
P(i, j) -= (factor * r);
res += (r * r);
}
isw = 3 - isw;
}
jsw = 3 - jsw;
}
if (commIsBoundary(s->comm, BOTTOM)) { // set bottom bc
for (int i = 1; i < imaxLocal + 1; i++) {
P(i, 0) = P(i, 1);
}
}
if (commIsBoundary(s->comm, TOP)) { // set top bc
for (int i = 1; i < imaxLocal + 1; i++) {
P(i, jmaxLocal + 1) = P(i, jmaxLocal);
}
}
if (commIsBoundary(s->comm, LEFT)) { // set left bc
for (int j = 1; j < jmaxLocal + 1; j++) {
P(0, j) = P(1, j);
}
}
if (commIsBoundary(s->comm, RIGHT)) { // set right bc
for (int j = 1; j < jmaxLocal + 1; j++) {
P(imaxLocal + 1, j) = P(imaxLocal, j);
}
}
commReduction(&res, SUM);
res = res / (double)(imax * jmax);
#ifdef DEBUG
if (commIsMaster(s->comm)) {
printf("%d Residuum: %e\n", it, res);
}
#endif
it++;
}
#ifdef VERBOSE
if (commIsMaster(s->comm)) {
printf("Solver took %d iterations to reach %f\n", it, sqrt(res));
}
#endif
return res;
}

View File

@@ -9,6 +9,7 @@
#include "comm.h"
#include "discretization.h"
#include "grid.h"
#include "mpi.h"
#include "parameter.h"
typedef struct {
@@ -17,10 +18,12 @@ typedef struct {
/* parameters */
double eps, omega;
int itermax;
int levels, presmooth, postsmooth;
double **r, **e;
/* communication */
Comm* comm;
} Solver;
void initSolver(Solver*, Discretization*, Parameter*);
void solve(Solver*, double*, double*);
double solve(Solver*, double*, double*);
#endif