Skip to content

Commit 7aae0e4

Browse files
Implementation of jacobian and invjacobian for the integrals
1 parent 12c4588 commit 7aae0e4

3 files changed

Lines changed: 133 additions & 2 deletions

File tree

src/geometry/functional.c

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4334,21 +4334,113 @@ static value integral_cgfn(vm *v, int nargs, value *args) {
43344334
return out;
43354335
}
43364336

4337+
/* -------------------
4338+
* Jacobian
4339+
* ------------------- */
4340+
4341+
/*
4342+
* A reference triangle is mapped to a target triangle through a
4343+
* linear transformation (the pushforward); an inverse transformation (the pullback)
4344+
* exists if the triangle is not degenerate. This function computes the forward
4345+
* and inverse jacobians.
4346+
*/
4347+
4348+
int jacobianhandle; // TL storage handle for Jacobian
4349+
int invjacobianhandle; // TL storage handle for inverse Jacobian
4350+
4351+
void _fetchvertices(objectintegralelementref *elref, objectmesh *mesh, int nv, elementid *vid, double **x) {
4352+
// Fetch reference vertices
4353+
for (int j=0; j<nv; j++) matrix_getcolumn(elref->iref->mref->vert, vid[j], &x[j]);
4354+
}
4355+
4356+
void _edgevectors(grade g, int dim, double **x, double *out) {
4357+
for (int i=0; i<g; i++) functional_vecsub(dim, x[i+1], x[0], out + i*dim);
4358+
}
4359+
4360+
/** Evaluates the jacobian and inverse jacobian; returns either of these as requested */
4361+
void integral_evaluatejacobian(vm *v, value *jac, value *invjac) {
4362+
objectintegralelementref *elref = integral_getelementref(v);
4363+
4364+
if (!elref) {
4365+
morpho_runtimeerror(v, INTEGRAL_SPCLFN, JACOBIAN_FUNCTION); return;
4366+
}
4367+
4368+
int dim = elref->mesh->dim; // Dimension of the mesh
4369+
4370+
// Allocate matrices
4371+
objectmatrix *J=object_newmatrix(dim, dim, true);
4372+
objectmatrix *Jinv=object_newmatrix(dim, dim, true);
4373+
4374+
if (J) vm_settlvar(v, jacobianhandle, MORPHO_OBJECT(J));
4375+
if (Jinv) vm_settlvar(v, invjacobianhandle, MORPHO_OBJECT(Jinv));
4376+
4377+
if (!J || !Jinv) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return; }
4378+
4379+
// Now compute them
4380+
grade g = elref->g; // Grade of the element
4381+
int nv = elref->nv; //
4382+
4383+
double **X = elref->vertexposn; // Vertex positions of the target element
4384+
double *x[nv]; // Vertex positions of the reference element
4385+
4386+
objectmesh *mref = elref->iref->mref; // Reference mesh
4387+
if (mref) _fetchvertices(elref, mref, nv, elref->vid, x);
4388+
4389+
// Construct matrix of edge vectors for target and reference elements
4390+
double starget[dim*dim], sref[dim*dim], sinv[dim*dim];
4391+
objectmatrix St = MORPHO_STATICMATRIX(starget, dim, dim),
4392+
Sr = MORPHO_STATICMATRIX(sref, dim, dim),
4393+
Sinv = MORPHO_STATICMATRIX(sinv, dim, dim);
4394+
4395+
_edgevectors(g, dim, X, starget);
4396+
if (mref) {
4397+
_edgevectors(g, dim, x, sref);
4398+
matrix_inverse(&Sr, &Sinv);
4399+
} else {
4400+
matrix_identity(&Sinv); // If no reference, the reference is the unit triangle
4401+
}
4402+
4403+
matrix_mul(&St, &Sinv, J); // J = S . s^-1
4404+
4405+
matrix_inverse(J, Jinv); // Compute J^-1
4406+
4407+
if (jac) *jac = MORPHO_OBJECT(J);
4408+
if (invjac) *invjac = MORPHO_OBJECT(Jinv);
4409+
}
4410+
4411+
static value integral_jacobian(vm *v, int nargs, value *args) {
4412+
value out=MORPHO_NIL;
4413+
4414+
vm_gettlvar(v, jacobianhandle, &out);
4415+
if (MORPHO_ISNIL(out)) integral_evaluatejacobian(v, &out, NULL);
4416+
4417+
return out;
4418+
}
4419+
4420+
static value integral_invjacobian(vm *v, int nargs, value *args) {
4421+
value out=MORPHO_NIL;
4422+
4423+
vm_gettlvar(v, invjacobianhandle, &out);
4424+
if (MORPHO_ISNIL(out)) integral_evaluatejacobian(v, NULL, &out);
4425+
4426+
return out;
4427+
}
4428+
43374429
/* ----------------------
43384430
* General initialization
43394431
* ---------------------- */
43404432

43414433
/** Clears threadlocal storage */
43424434
void integral_cleartlvars(vm *v) {
4343-
int handles[] = { elementhandle, normlhandle, tangenthandle, cauchygreenhandle, -1 };
4435+
int handles[] = { elementhandle, normlhandle, tangenthandle, cauchygreenhandle, jacobianhandle, invjacobianhandle, -1 };
43444436

43454437
for (int i=0; handles[i]>=0; i++) {
43464438
vm_settlvar(v, handles[i], MORPHO_NIL);
43474439
}
43484440
}
43494441

43504442
void integral_freetlvars(vm *v) {
4351-
int handles[] = { normlhandle, tangenthandle, cauchygreenhandle, -1 };
4443+
int handles[] = { normlhandle, tangenthandle, cauchygreenhandle,jacobianhandle, invjacobianhandle, -1 };
43524444

43534445
for (int i=0; handles[i]>=0; i++) {
43544446
value val;
@@ -4952,6 +5044,8 @@ void functional_initialize(void) {
49525044
builtin_addfunction(NORMAL_FUNCTION, integral_normal, BUILTIN_FLAGSEMPTY);
49535045
builtin_addfunction(GRAD_FUNCTION, integral_gradfn, BUILTIN_FLAGSEMPTY);
49545046
builtin_addfunction(CGTENSOR_FUNCTION, integral_cgfn, BUILTIN_FLAGSEMPTY);
5047+
builtin_addfunction(JACOBIAN_FUNCTION, integral_jacobian, BUILTIN_FLAGSEMPTY);
5048+
builtin_addfunction(INVJACOBIAN_FUNCTION, integral_invjacobian, BUILTIN_FLAGSEMPTY);
49555049

49565050
morpho_defineerror(VOLUMEENCLOSED_ZERO, ERROR_HALT, VOLUMEENCLOSED_ZERO_MSG);
49575051
morpho_defineerror(FUNC_INTEGRAND_MESH, ERROR_HALT, FUNC_INTEGRAND_MESH_MSG);
@@ -4990,6 +5084,8 @@ void functional_initialize(void) {
49905084
tangenthandle=vm_addtlvar();
49915085
normlhandle=vm_addtlvar();
49925086
cauchygreenhandle=vm_addtlvar();
5087+
jacobianhandle=vm_addtlvar();
5088+
invjacobianhandle=vm_addtlvar();
49935089

49945090
morpho_addfinalizefn(functional_finalize);
49955091
}

src/geometry/functional.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#define NORMAL_FUNCTION "normal"
6161
#define GRAD_FUNCTION "grad"
6262
#define CGTENSOR_FUNCTION "cgtensor"
63+
#define JACOBIAN_FUNCTION "jacobian"
64+
#define INVJACOBIAN_FUNCTION "invjacobian"
6365

6466
/* Functional names */
6567
#define LENGTH_CLASSNAME "Length"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Test the jacobian() function
2+
3+
import meshtools
4+
5+
// Create the reference triangle
6+
var mb = MeshBuilder()
7+
mb.addvertex([0,0])
8+
mb.addvertex([1,0])
9+
mb.addvertex([0,1])
10+
mb.addedge([0,1])
11+
mb.addedge([1,2])
12+
mb.addedge([2,0])
13+
mb.addface([0,1,2])
14+
15+
var mref = mb.build()
16+
17+
// Make the target triangle by cloning the reference..
18+
var m = mref.clone()
19+
m.setvertexmatrix(2*m.vertexmatrix()) // ... and scaling by 2
20+
21+
fn integrand(x) {
22+
var F = jacobian()
23+
//var Jinv = invjacobian()
24+
var Ft = F.transpose()
25+
26+
return (F*Ft).trace()
27+
}
28+
29+
var a=AreaIntegral(integrand, reference=mref, weightByReference=true).total(m)
30+
31+
print a
32+
// expect: 4
33+
// because Tr(F*Ft)=8; and the area of the reference tri. is 1/2

0 commit comments

Comments
 (0)