Commit eec68ea7 authored by Jonathan Lambrechts's avatar Jonathan Lambrechts
Browse files

introduce FEElement and FEFields

parent b40fadaa
......@@ -23,6 +23,7 @@
set(SRC
fluid_problem.c
fluid_problem_concentration.c
fluid_problem_fem.c
mesh.c
mesh_find.c
../tools/quadtree.c
......
This diff is collapsed.
......@@ -26,6 +26,7 @@
#include "mesh.h"
#include "mesh_find.h"
#include "fluid_problem_fem.h"
#if DIMENSION==2
#define N_N 3
......@@ -35,7 +36,6 @@
typedef void BoundaryCallback(int n, const double *x, double *bnd);
typedef struct {
char *tag;
int row;
......@@ -101,6 +101,7 @@ struct FluidProblem {
int advection;
int temporal;
int drag_in_stab;
FEFields *fields, *field_porosity, *field_concentration;
};
// complete force on the particle (including gravity)
......@@ -144,7 +145,7 @@ void fluid_problem_set_stab_param(FluidProblem *p, double stab_param);
void fluid_problem_set_reduced_gravity(FluidProblem *p, int reduced_gravity);
int weak_boundary_n_values(const WeakBoundary *wbnd);
void weak_boundary_values(const FEFields *fields, const Mesh *mesh, const MeshBoundary *bnd, const WeakBoundary *wbnd, double *data);
double fluid_problem_a_integ_volume(FluidProblem *problem);
double fluid_problem_a_integ_bnd(FluidProblem *problem, double dt);
void weak_boundary_values(const Mesh *mesh, const MeshBoundary *bnd, const WeakBoundary *wbnd, double *data);
#endif
......@@ -19,6 +19,8 @@ int mesh_boundary_id_from_tag(const Mesh *mesh, const char *tag) {
}
void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
#if 0
const FEElement *element = problem->fields->element[0];
const Mesh *mesh = problem->mesh;
const int n_fields = fluid_problem_n_fields(problem);
double *velocity = malloc(D*problem->mesh->n_nodes*sizeof(double));
......@@ -40,10 +42,10 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
dxdxi[i][j] = mesh->x[el[j+1]*3+i] - mesh->x[el[0]*3+i];
const double detj = invDD(dxdxi, dxidx);
det[iel] = detj;
grad_shape_functions(dxidx, dphi);
element->df(QP[0], dxidx, dphi);
double da[D] = {0};
double divu = 0;
for (int i = 0; i < N_SF; ++i) {
for (int i = 0; i < element->nlocal; ++i) {
for (int id = 0; id < D; ++id) {
da[id] += dphi[i][id]*problem->concentration[iel*N_N+i];
divu += dphi[i][id]*problem->solution[el[i]*n_fields+id];
......@@ -51,13 +53,13 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
}
for (int iqp = 0; iqp< N_QP; ++iqp) {
double phi[N_SF];
shape_functions(QP[iqp],phi);
double phi[element->nlocal];
element->f(QP[iqp],phi);
double u[D] = {0};
double c = 0;
double cold = 0;
double a = 0;
for (int i = 0; i < N_SF; ++i) {
for (int i = 0; i < element->nlocal; ++i) {
a += phi[i]*problem->concentration[iel*N_N+i];
c += phi[i]*problem->porosity[el[i]];
cold += phi[i]*problem->oldporosity[el[i]];
......@@ -70,7 +72,7 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
r -= u[id]*da[id];
}
const double jw = QW[iqp]*detj;
for (int i = 0; i < N_SF; ++i) {
for (int i = 0; i < element->nlocal; ++i) {
rhs[iel*N_N+i] += r*phi[i]*jw;
}
}
......@@ -81,12 +83,12 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
const int iel0 = interface[0];
const int iel1 = interface[2];
if (iel1 < 0) continue;
const int *cl0 = elbnd[interface[1]];
const int *cl1 = elbnd[interface[3]];
double *x[N_LSF];
const int *cl0 = element->boundaries[interface[1]];
const int *cl1 = element->boundaries[interface[3]];
double *x[element->boundary_element->nlocal];
const int *el0 = &mesh->elements[iel0*N_N];
const int *el1 = &mesh->elements[iel1*N_N];
for (int i = 0; i < N_LSF; ++i){
for (int i = 0; i < element->boundary_element->nlocal; ++i){
x[i] = &mesh->x[el0[cl0[i]]*3];
}
double detbnd, n[D];
......@@ -94,9 +96,9 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
for (int iqp = 0; iqp < N_LQP; ++iqp) {
double a0 = 0, a1 = 0, un = 0;
double phil[N_LQP];
l_shape_functions(LQP[iqp],phil);
element->boundary_element->f(LQP[iqp],phil);
double c = 0;
for (int i = 0; i < N_LSF; ++i) {
for (int i = 0; i < element->boundary_element->nlocal; ++i) {
a0 += problem->concentration[iel0*N_N+cl0[i]]*phil[i];
a1 += problem->concentration[iel1*N_N+cl1[i]]*phil[i];
c += problem->porosity[el0[cl0[i]]]*phil[i];
......@@ -108,7 +110,7 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
const double r0 = -un*(a-a0);
const double r1 = un*(a-a1);
const double jw = LQW[iqp]*detbnd;
for (int i = 0; i < N_LSF; ++i){
for (int i = 0; i < element->boundary_element->nlocal; ++i){
rhs[iel0*N_N+cl0[i]] += phil[i]*r0*jw;
rhs[iel1*N_N+cl1[i]] += phil[i]*r1*jw;
}
......@@ -121,7 +123,7 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
if (wbnd->type == BND_WALL) continue;
int n_value = weak_boundary_n_values(wbnd);
double *data = malloc(N_LQP*n_value*bnd->n_interfaces*sizeof(double));
weak_boundary_values(mesh, bnd, wbnd, data);
weak_boundary_values(problem->fields, mesh, bnd, wbnd, data);
if (wbnd->aid<0){
printf("concentration should be specified on open boundary %s.",wbnd->tag);
exit(1);
......@@ -129,9 +131,9 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
for (int iinterface = 0; iinterface < bnd->n_interfaces; ++iinterface) {
const int *interface = &mesh->interfaces[bnd->interfaces[iinterface]*4];
const int iel = interface[0];
const int *cl = elbnd[interface[1]];
const int *cl = element->boundaries[interface[1]];
const int *el = &mesh->elements[iel*N_N];
double *x[N_LSF];
double *x[element->boundary_element->nlocal];
for (int i = 0; i < D; ++i){
x[i] = &mesh->x[el[cl[i]]*3];
}
......@@ -140,10 +142,10 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
for (int iqp = 0; iqp < N_LQP; ++iqp) {
const double *dataqp = &data[n_value*(iinterface*N_LQP+iqp)];
double phil[N_LQP];
l_shape_functions(LQP[iqp],phil);
element->boundary_element->f(LQP[iqp],phil);
double a = 0;
double c = 0;
for (int i = 0; i < N_LSF; ++i) {
for (int i = 0; i < element->boundary_element->nlocal; ++i) {
a += problem->concentration[iel*N_N+cl[i]]*phil[i];
c += problem->porosity[el[cl[i]]]*phil[i];
}
......@@ -153,14 +155,14 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
un += n[id]*dataqp[wbnd->vid+id];
}
else {
for (int i = 0; i < N_LSF; ++i) {
for (int i = 0; i < element->boundary_element->nlocal; ++i) {
un += phil[i]*problem->solution[el[cl[i]]*n_fields+id]*n[id];
}
}
}
const double jw = LQW[iqp]*detbnd;
double f0 = -un * (un > 0 ? 0 : dataqp[wbnd->aid]-a);
for (int iphi = 0; iphi < N_LSF; ++iphi){
for (int iphi = 0; iphi < element->boundary_element->nlocal; ++iphi){
rhs[iel*N_N+cl[iphi]] += phil[iphi]*f0*jw;
}
}
......@@ -173,9 +175,9 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
for (int iel = 0; iel < mesh->n_elements; ++iel) {
double m = 0;
const int *el = &mesh->elements[iel*N_N];
for (int in = 0; in < N_SF; ++in) {
for (int jn = 0; jn < N_SF; ++jn) {
problem->concentration[iel*N_SF+in] += invmassmatrix[in][jn]*rhs[iel*N_SF+jn]/det[iel]*dt;
for (int in = 0; in < element->nlocal; ++in) {
for (int jn = 0; jn < element->nlocal; ++jn) {
problem->concentration[iel*element->nlocal+in] += invmassmatrix[in][jn]*rhs[iel*element->nlocal+jn]/det[iel]*dt;
}
}
......@@ -220,6 +222,7 @@ void fluid_problem_advance_concentration(FluidProblem *problem, double dt) {
free(rhs);
free(det);
#endif
}
void fluid_problem_set_concentration_cg(FluidProblem *problem, double *concentration) {
......
#ifndef FLUID_PROBLEM_FEM_H
#define FLUID_PROBLEM_FEM_H
#define D DIMENSION
#include <math.h>
#include "mesh.h"
#define deps 1
#if D==2
struct FEElementStruct{
int nlocal;
int n[DIMENSION+1];
void (*f)(const double *xi, double *f);
void (*df)(const double *xi, const double dxidx[D][D], double f[][D]);
};
FEElement *fe_element_new(const char *etype);
void fe_element_free(FEElement *element);
#define N_SF 3
#define N_N 3
typedef struct {
int local_size;
int n;
int nd[DIMENSION+1];
FEElement **element;
}FEFields;
FEFields *fe_fields_new(const char **etypes);
void fe_fields_f(const FEFields *fields, const double *xi, double *f);
void fe_fields_df(const FEFields *fields, const double *xi, const double dxdidx[D][D], double df[][D]);
void fe_fields_eval_grad(const FEFields *fields, const Mesh *mesh, int iel, const double sf[], const double dsf[][DIMENSION], const double *v, double s[], double ds[][DIMENSION]);
void fe_fields_eval(const FEFields *fields, const Mesh *mesh, int iel, const double sf[], const double *v, double s[]);
void fe_fields_add_to_local_vector(const FEFields *fields, const double *f0, const double f1[][D], const double *sf, const double dsf[][D], double jw, double *local_vector);
static void fe_fields_add_to_local_matrix(const FEFields *fields, const double *f00, const double f01[][D], const double f10[][D], const double f11[][D][D], const double *sf, const double dsf[][D], double jw, double *local_matrix) {
int jc = 0;
for (int jfield = 0; jfield < fields->n; ++jfield) {
for (int jphi = 0; jphi < fields->element[jfield]->nlocal; ++jphi){
int ic = 0;
for (int ifield = 0; ifield < fields->n; ++ifield){
for (int iphi = 0; iphi < fields->element[ifield]->nlocal; ++iphi){
double m = 0;
if (f00) {
m += jw*sf[ic]*sf[jc]*f00[ifield*fields->n+jfield];
}
if (f10) {
for (int id = 0; id < D; ++id) {
m += jw*dsf[ic][id]*sf[jc]*f10[ifield*fields->n+jfield][id];
}
}
if (f11) {
for (int id = 0; id < D; ++id) {
for (int jd = 0; jd < D; ++jd) {
m += jw*dsf[ic][id]*dsf[jc][jd]*f11[ifield*fields->n+jfield][id][jd];
}
}
}
if (f01) {
for (int jd = 0; jd < D; ++jd) {
m += jw*sf[ic]*dsf[jc][jd]*f01[ifield*fields->n+jfield][jd];
}
}
local_matrix[(ifield*3+iphi)*9+jfield*3+jphi] += m;
ic ++;
}
}
jc ++;
}
}
}
void fe_fields_free(FEFields *fields);
#if D==2
#define N_QP 3
#define N_LQP 2
#define N_LSF 2
static double LQP[][1] = {{0.21132486540518713}, {0.7886751345948129}};
static double LQW[] = {0.5,0.5};
static double QP[][2] = {{1./6,1./6},{1./6,2./3},{2./3,1./6}};
static double QW[] = {1./6,1./6,1./6};
static void shape_functions(double *uvw, double *sf)
{
sf[0] = 1-uvw[0]-uvw[1];
sf[1] = uvw[0];
sf[2] = uvw[1];
}
static void grad_shape_functions(const double dxidx[2][2], double gsf[3][2])
{
for (int i = 0; i < 2; ++i) {
gsf[0][i] = -dxidx[0][i]-dxidx[1][i];
gsf[1][i] = dxidx[0][i];
gsf[2][i] = dxidx[1][i];
}
}
static double detDD(const double m[2][2])
{
return m[0][0]*m[1][1] - m[0][1]*m[1][0];
......@@ -41,10 +88,7 @@ static double invDD(const double m[2][2], double inv[2][2])
inv[1][1] = m[0][0]/d;
return d;
}
static void l_shape_functions(double *uvw, double *sf) {
sf[0] = 1-uvw[0];
sf[1] = uvw[0];
}
static const double invmassmatrix[3][3] = {
{18,-6,-6},
{-6,18,-6},
......@@ -55,6 +99,18 @@ static const double mass_matrix[3][3] = {
{1./24,1./12,1./24},
{1./24,1./24,1./12}
};
static double get_normal(const Mesh *mesh, const int *interface, double n[2]){
const int *tri = &mesh->elements[interface[0]*3];
const int *cl = elbnd2[interface[1]];
double *x[2] = {&mesh->x[tri[cl[0]]*3], &mesh->x[tri[cl[1]]*3]};
const double dx[2] = {x[1][0]-x[0][0], x[1][1]-x[0][1]};
const double detbnd = sqrt(dx[0]*dx[0] + dx[1]*dx[1]);
n[0] = dx[1]/detbnd;
n[1] = -dx[0]/detbnd;
return detbnd;
}
static void get_normal_and_det(double *x[2], double n[2], double *det){
const double dx[2] = {x[1][0]-x[0][0], x[1][1]-x[0][1]};
const double detbnd = sqrt(dx[0]*dx[0] + dx[1]*dx[1]);
......@@ -62,13 +118,11 @@ static void get_normal_and_det(double *x[2], double n[2], double *det){
n[1] = -dx[0]/detbnd;
*det = detbnd;
}
#else
#define N_SF 4
#define N_N 4
#define N_QP 5
#define N_LQP 3
#define N_LSF 3
static double QP[][3] = {
{0.25, 0.25, 0.25},
{0.5, 1./6, 1./6},
......@@ -79,22 +133,6 @@ static double QP[][3] = {
static double LQP[][2] = {{1./6,1./6},{1./6,2./3},{2./3,1./6}};
static double QW[] = {-16./120, 9./120, 9./120, 9./120, 9./120};
static double LQW[] = {1./6,1./6,1./6};
static void shape_functions(double *uvw, double *sf)
{
sf[0] = 1-uvw[0]-uvw[1]-uvw[2];
sf[1] = uvw[0];
sf[2] = uvw[1];
sf[3] = uvw[2];
}
static void grad_shape_functions(const double dxidx[3][3], double gsf[4][3])
{
for (int i = 0; i < 3; ++i) {
gsf[0][i] = -dxidx[0][i]-dxidx[1][i]-dxidx[2][i];
gsf[1][i] = dxidx[0][i];
gsf[2][i] = dxidx[1][i];
gsf[3][i] = dxidx[2][i];
}
};
static double detDD(const double m[3][3])
{
return m[0][0]*(m[1][1]*m[2][2]-m[2][1]*m[1][2])
......@@ -115,11 +153,6 @@ static double invDD(const double m[3][3], double inv[3][3]) {
return d;
};
static void l_shape_functions(double *uvw, double *sf) {
sf[0] = 1-uvw[0]-uvw[1];
sf[1] = uvw[0];
sf[2] = uvw[1];
}
static const double invmassmatrix[4][4] = {
{ 96,-24,-24,-24},
{-24, 96,-24,-24},
......@@ -145,5 +178,21 @@ static void get_normal_and_det(double *x[3], double n[3], double *det) {
*det = detbnd;
}
#endif
static double get_normal(const Mesh *mesh, const int *interface, double n[3]){
const int *tet = &mesh->elements[interface[0]*4];
const int *cl = elbnd2[interface[1]];
double *x[3] = {&mesh->x[tet[cl[0]]*3], &mesh->x[tet[cl[1]]*3], &mesh->x[tet[cl[2]]*3]};
const double dx[2][3] = {{x[1][0]-x[0][0], x[1][1]-x[0][1], x[1][2]-x[0][2]},{x[2][0]-x[0][0], x[2][1]-x[0][1], x[2][2]-x[0][2]}};
const double nn[3] = {
dx[0][1]*dx[1][2] - dx[0][2]*dx[1][1],
dx[0][2]*dx[1][0] - dx[0][0]*dx[1][2],
dx[0][0]*dx[1][1] - dx[0][1]*dx[1][0]};
const double detbnd = sqrt(nn[0]*nn[0] + nn[1]*nn[1] + nn[2]*nn[2]);
n[0] = -nn[0]/detbnd;
n[1] = -nn[1]/detbnd;
n[2] = -nn[2]/detbnd;
return detbnd;
}
#endif
#endif
......@@ -22,6 +22,7 @@
*/
#include "mesh.h"
#include "fluid_problem_fem.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -74,7 +75,7 @@ static void mesh_gen_edges(Mesh *m, int n_bnd_elements, int *bnd_elements, int *
for (int i=0; i<m->n_elements; ++i) {
for (int j = 0; j < DIMENSION+1; ++j) {
for (int k = 0; k < DIMENSION; ++k) {
he->n[k] = m->elements[i*(DIMENSION+1)+elbnd[j][k]];
he->n[k] = m->elements[i*(DIMENSION+1)+elbnd2[j][k]];
}
sort_edge_nodes(he->n);
he->element = i;
......@@ -139,10 +140,10 @@ static void mesh_gen_edges(Mesh *m, int n_bnd_elements, int *bnd_elements, int *
const int *e1 = &m->elements[e[2]*4];
e[3] += 12;
if (periodic) {
while (m->periodic_mapping[e0[elbnd[e[1]][0]]] != m->periodic_mapping[e1[elbnd[e[3]][k]]]) e[3] += 4;
while (m->periodic_mapping[e0[elbnd2[e[1]][0]]] != m->periodic_mapping[e1[elbnd2[e[3]][k]]]) e[3] += 4;
}
else {
while (e0[elbnd[e[1]][0]] != e1[elbnd[e[3]][k]]) e[3] += 4;
while (e0[elbnd2[e[1]][0]] != e1[elbnd2[e[3]][k]]) e[3] += 4;
}
#endif
}
......@@ -161,11 +162,17 @@ void mesh_free(Mesh *m)
free(m->boundary_names);
free(m->interfaces);
free(m->periodic_mapping);
fe_element_free(m->element);
free(m);
}
Mesh *mesh_new_from_elements(int n_nodes, double *x, int n_elements, int *elements, int n_boundaries, int *boundaries, int *boundary_tags,int n_physicals, char **physicals, const int *periodic) {
Mesh *m = malloc(sizeof(Mesh));
#if DIMENSION == 2
m->element = fe_element_new("triangle_p1");
#else
m->element = fe_element_new("tetrahedron_p1");
#endif
m->n_elements = n_elements;
m->elements = malloc(n_elements*sizeof(int)*(DIMENSION+1));
memcpy(m->elements,elements,(DIMENSION+1)*sizeof(int)*n_elements);
......@@ -212,7 +219,7 @@ MeshBoundary *mesh_boundaries_create(const Mesh *m) {
if (interface[2] == -1) {
int tag = interface[3];
int *el = m->elements + interface[0]*(DIMENSION+1);
int *cl = elbnd[interface[1]];
int *cl = elbnd2[interface[1]];
b[tag].interfaces[b[tag].n_interfaces++] = i;
for (int i = 0; i < DIMENSION; ++i) {
b[tag].nodes[b[tag].n_nodes++] = el[cl[i]];
......@@ -246,3 +253,26 @@ void mesh_boundaries_free(MeshBoundary *bs, int n)
}
void param_boundary_to_element(int cl, const double *xibnd, double *xiel) {
#if DIMENSION == 2
double x = xibnd[0];
switch(cl) {
case 0: xiel[0] = x; xiel[1] = 0; break;
case 1: xiel[0] = 1-x; xiel[1] = x; break;
case 2: xiel[0] = 0; xiel[1] = 1-x; break;
case 3: xiel[0] = 1-x; xiel[1] = 0; break;
case 4: xiel[0] = x; xiel[1] = 1-x; break;
case 5: xiel[0] = 0; xiel[1] = x; break;
}
#else
static double nodes[4][3] = {{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
double xi = xibnd[0], eta = xibnd[1];
double phi[3] = {1-xi-eta,xi,eta};
for (int i = 0; i < 3; ++i) {
xiel[i] =0;
for (int j = 0; j < 3; ++j) {
xiel[i] += phi[j] * nodes[elbnd2[cl][j]][i];
}
}
#endif
}
......@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdint.h>
typedef struct FEElementStruct FEElement;
typedef struct {
int n_nodes;
......@@ -36,10 +37,11 @@ typedef struct {
char **boundary_names;
int n_interfaces;
int *interfaces; // eid0, closure0, {(eid1, closure1),(-1,phys_id)}
int n_interfaces_periodic; // same as interfaces but taking into account the periodicity
int n_interfaces_periodic; // edges taking into account the
int *interfaces_periodic; // eid0, closure0, {(eid1, closure1),(-1,phys_id)}
int n_periodic;
int *periodic_mapping; // n_nodes
FEElement *element;
} Mesh;
void mesh_free(Mesh *m);
......@@ -55,15 +57,12 @@ typedef struct {
int *nodes;
} MeshBoundary;
MeshBoundary *mesh_boundaries_create(const Mesh *m);
void mesh_boundaries_free(MeshBoundary *mbnd, int n);
#if DIMENSION == 2
static int elbnd[6][2] = {
static int elbnd2[6][2] = {
{0,1},{1,2},{2,0},
{1,0},{2,1},{0,2}};
#else
static int elbnd[24][3] = {
static int elbnd2[24][3] = {
{0,1,2},{0,2,3},{0,3,1},{1,3,2},
{2,0,1},{3,0,2},{1,0,3},{2,1,3},
{1,2,0},{2,3,0},{3,1,0},{3,2,1},
......@@ -73,4 +72,8 @@ static int elbnd[24][3] = {
{1,0,2},{2,0,3},{3,0,1},{3,1,2}
};
#endif
void param_boundary_to_element(int cl, const double *xibnd, double *xiel);
MeshBoundary *mesh_boundaries_create(const Mesh *m);
void mesh_boundaries_free(MeshBoundary *mbnd, int n);
#endif
......@@ -50,8 +50,11 @@ class LinearSystem :
def local_to_global(self,localv,localm,rhs):
self.mat.zeroEntries()
np.add.at(rhs.reshape([-1]),self.idx,localv)
for e,m in zip(self.elements,localm.reshape([-1,self.localsize**2])) :
self.mat.setValuesBlocked(e,e,m,PETSc.InsertMode.ADD)
vmap = np.tile(self.elements*3,[1,3]) + np.repeat(np.arange(3,dtype=np.int32),3)[None,:]
for e,m in zip(vmap,localm.reshape([-1,self.localsize**2])) :
self.mat.setValues(e,e,m,PETSc.InsertMode.ADD)
#for e,m in zip(self.elements,localm.reshape([-1,self.localsize**2])) :
#self.mat.setValuesBlocked(e,e,m,PETSc.InsertMode.ADD)
self.mat.assemble()
def solve(self,rhs) :
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment