@@ -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 */
43424434void 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
43504442void 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}
0 commit comments