@@ -3990,6 +3990,17 @@ objectintegralelementref *integral_getelementref(vm *v) {
39903990 return NULL ;
39913991}
39923992
3993+ /* ---------
3994+ * Elementid
3995+ * --------- */
3996+
3997+ static value integral_elementid (vm * v , int nargs , value * args ) {
3998+ objectintegralelementref * elref = integral_getelementref (v );
3999+ if (!elref ) { morpho_runtimeerror (v , INTEGRAL_SPCLFN , ELEMENTID_FUNCTION ); return MORPHO_NIL ; }
4000+
4001+ return MORPHO_INTEGER (elref -> id );
4002+ }
4003+
39934004/* --------
39944005 * Tangent
39954006 * -------- */
@@ -4036,6 +4047,7 @@ int normlhandle; // TL storage handle for normal vectors
40364047/** Evaluates the normal vector */
40374048void integral_evaluatenormal (vm * v , value * out ) {
40384049 objectintegralelementref * elref = integral_getelementref (v );
4050+
40394051 if (!elref ) { morpho_runtimeerror (v , INTEGRAL_SPCLFN , NORMAL_FUNCTION ); return ; }
40404052
40414053 int dim = elref -> mesh -> dim ;
@@ -4334,21 +4346,113 @@ static value integral_cgfn(vm *v, int nargs, value *args) {
43344346 return out ;
43354347}
43364348
4349+ /* -------------------
4350+ * Jacobian
4351+ * ------------------- */
4352+
4353+ /*
4354+ * A reference triangle is mapped to a target triangle through a
4355+ * linear transformation (the pushforward); an inverse transformation (the pullback)
4356+ * exists if the triangle is not degenerate. This function computes the forward
4357+ * and inverse jacobians.
4358+ */
4359+
4360+ int jacobianhandle ; // TL storage handle for Jacobian
4361+ int invjacobianhandle ; // TL storage handle for inverse Jacobian
4362+
4363+ void _fetchvertices (objectintegralelementref * elref , objectmesh * mesh , int nv , elementid * vid , double * * x ) {
4364+ // Fetch reference vertices
4365+ for (int j = 0 ; j < nv ; j ++ ) matrix_getcolumn (elref -> iref -> mref -> vert , vid [j ], & x [j ]);
4366+ }
4367+
4368+ void _edgevectors (grade g , int dim , double * * x , double * out ) {
4369+ for (int i = 0 ; i < g ; i ++ ) functional_vecsub (dim , x [i + 1 ], x [0 ], out + i * dim );
4370+ }
4371+
4372+ /** Evaluates the jacobian and inverse jacobian; returns either of these as requested */
4373+ void integral_evaluatejacobian (vm * v , value * jac , value * invjac ) {
4374+ objectintegralelementref * elref = integral_getelementref (v );
4375+
4376+ if (!elref ) {
4377+ morpho_runtimeerror (v , INTEGRAL_SPCLFN , JACOBIAN_FUNCTION ); return ;
4378+ }
4379+
4380+ int dim = elref -> mesh -> dim ; // Dimension of the mesh
4381+
4382+ // Allocate matrices
4383+ objectmatrix * J = object_newmatrix (dim , dim , true);
4384+ objectmatrix * Jinv = object_newmatrix (dim , dim , true);
4385+
4386+ if (J ) vm_settlvar (v , jacobianhandle , MORPHO_OBJECT (J ));
4387+ if (Jinv ) vm_settlvar (v , invjacobianhandle , MORPHO_OBJECT (Jinv ));
4388+
4389+ if (!J || !Jinv ) { morpho_runtimeerror (v , ERROR_ALLOCATIONFAILED ); return ; }
4390+
4391+ // Now compute them
4392+ grade g = elref -> g ; // Grade of the element
4393+ int nv = elref -> nv ; //
4394+
4395+ double * * X = elref -> vertexposn ; // Vertex positions of the target element
4396+ double * x [nv ]; // Vertex positions of the reference element
4397+
4398+ objectmesh * mref = elref -> iref -> mref ; // Reference mesh
4399+ if (mref ) _fetchvertices (elref , mref , nv , elref -> vid , x );
4400+
4401+ // Construct matrix of edge vectors for target and reference elements
4402+ double starget [dim * dim ], sref [dim * dim ], sinv [dim * dim ];
4403+ objectmatrix St = MORPHO_STATICMATRIX (starget , dim , dim ),
4404+ Sr = MORPHO_STATICMATRIX (sref , dim , dim ),
4405+ Sinv = MORPHO_STATICMATRIX (sinv , dim , dim );
4406+
4407+ _edgevectors (g , dim , X , starget );
4408+ if (mref ) {
4409+ _edgevectors (g , dim , x , sref );
4410+ matrix_inverse (& Sr , & Sinv );
4411+ } else {
4412+ matrix_identity (& Sinv ); // If no reference, the reference is the unit triangle
4413+ }
4414+
4415+ matrix_mul (& St , & Sinv , J ); // J = S . s^-1
4416+
4417+ matrix_inverse (J , Jinv ); // Compute J^-1
4418+
4419+ if (jac ) * jac = MORPHO_OBJECT (J );
4420+ if (invjac ) * invjac = MORPHO_OBJECT (Jinv );
4421+ }
4422+
4423+ static value integral_jacobian (vm * v , int nargs , value * args ) {
4424+ value out = MORPHO_NIL ;
4425+
4426+ vm_gettlvar (v , jacobianhandle , & out );
4427+ if (MORPHO_ISNIL (out )) integral_evaluatejacobian (v , & out , NULL );
4428+
4429+ return out ;
4430+ }
4431+
4432+ static value integral_invjacobian (vm * v , int nargs , value * args ) {
4433+ value out = MORPHO_NIL ;
4434+
4435+ vm_gettlvar (v , invjacobianhandle , & out );
4436+ if (MORPHO_ISNIL (out )) integral_evaluatejacobian (v , NULL , & out );
4437+
4438+ return out ;
4439+ }
4440+
43374441/* ----------------------
43384442 * General initialization
43394443 * ---------------------- */
43404444
43414445/** Clears threadlocal storage */
43424446void integral_cleartlvars (vm * v ) {
4343- int handles [] = { elementhandle , normlhandle , tangenthandle , cauchygreenhandle , -1 };
4447+ int handles [] = { elementhandle , normlhandle , tangenthandle , cauchygreenhandle , jacobianhandle , invjacobianhandle , -1 };
43444448
43454449 for (int i = 0 ; handles [i ]>=0 ; i ++ ) {
43464450 vm_settlvar (v , handles [i ], MORPHO_NIL );
43474451 }
43484452}
43494453
43504454void integral_freetlvars (vm * v ) {
4351- int handles [] = { normlhandle , tangenthandle , cauchygreenhandle , -1 };
4455+ int handles [] = { normlhandle , tangenthandle , cauchygreenhandle ,jacobianhandle , invjacobianhandle , -1 };
43524456
43534457 for (int i = 0 ; handles [i ]>=0 ; i ++ ) {
43544458 value val ;
@@ -4948,10 +5052,13 @@ void functional_initialize(void) {
49485052 builtin_addclass (NEMATIC_CLASSNAME , MORPHO_GETCLASSDEFINITION (Nematic ), objclass );
49495053 builtin_addclass (NEMATICELECTRIC_CLASSNAME , MORPHO_GETCLASSDEFINITION (NematicElectric ), objclass );
49505054
5055+ builtin_addfunction (ELEMENTID_FUNCTION , integral_elementid , BUILTIN_FLAGSEMPTY );
49515056 builtin_addfunction (TANGENT_FUNCTION , integral_tangent , BUILTIN_FLAGSEMPTY );
49525057 builtin_addfunction (NORMAL_FUNCTION , integral_normal , BUILTIN_FLAGSEMPTY );
49535058 builtin_addfunction (GRAD_FUNCTION , integral_gradfn , BUILTIN_FLAGSEMPTY );
49545059 builtin_addfunction (CGTENSOR_FUNCTION , integral_cgfn , BUILTIN_FLAGSEMPTY );
5060+ builtin_addfunction (JACOBIAN_FUNCTION , integral_jacobian , BUILTIN_FLAGSEMPTY );
5061+ builtin_addfunction (INVJACOBIAN_FUNCTION , integral_invjacobian , BUILTIN_FLAGSEMPTY );
49555062
49565063 morpho_defineerror (VOLUMEENCLOSED_ZERO , ERROR_HALT , VOLUMEENCLOSED_ZERO_MSG );
49575064 morpho_defineerror (FUNC_INTEGRAND_MESH , ERROR_HALT , FUNC_INTEGRAND_MESH_MSG );
@@ -4990,6 +5097,8 @@ void functional_initialize(void) {
49905097 tangenthandle = vm_addtlvar ();
49915098 normlhandle = vm_addtlvar ();
49925099 cauchygreenhandle = vm_addtlvar ();
5100+ jacobianhandle = vm_addtlvar ();
5101+ invjacobianhandle = vm_addtlvar ();
49935102
49945103 morpho_addfinalizefn (functional_finalize );
49955104}
0 commit comments