From 02cf18f562b60fac7557ef3de341a527bef5bdbf Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Wed, 30 Mar 2022 17:23:43 -0400 Subject: [PATCH 01/13] Replaced the Flory-Huggins energy with a Hydrogel energy --- morpho5/geometry/functional.c | 3263 ++++++++++++++++++++------------- morpho5/geometry/functional.h | 146 +- 2 files changed, 2048 insertions(+), 1361 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index be0d2b56..8a4a514e 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -21,58 +21,59 @@ #include #ifndef M_PI - #define M_PI 3.14159265358979323846 +#define M_PI 3.14159265358979323846 #endif static value functional_gradeproperty; static value functional_fieldproperty; -//static value functional_functionproperty; +// static value functional_functionproperty; /** Symmetry behaviors */ -typedef enum { +typedef enum +{ SYMMETRY_NONE, SYMMETRY_ADD } symmetrybhvr; /** Integrand function */ -typedef bool (functional_integrand) (vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out); +typedef bool(functional_integrand)(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out); /** Gradient function */ -typedef bool (functional_gradient) (vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc); +typedef bool(functional_gradient)(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc); struct s_functional_mapinfo; // Resolve circular typedef dependency /** Dependencies function */ -typedef bool (functional_dependencies) (struct s_functional_mapinfo *info, elementid id, varray_elementid *out); - -typedef struct s_functional_mapinfo { - objectmesh *mesh; // Mesh to use - objectselection *sel; // Selection, if any - objectfield *field; // Field, if any - grade g; // Grade to use - functional_integrand *integrand; // Integrand function - functional_gradient *grad; // Gradient +typedef bool(functional_dependencies)(struct s_functional_mapinfo *info, elementid id, varray_elementid *out); + +typedef struct s_functional_mapinfo +{ + objectmesh *mesh; // Mesh to use + objectselection *sel; // Selection, if any + objectfield *field; // Field, if any + grade g; // Grade to use + functional_integrand *integrand; // Integrand function + functional_gradient *grad; // Gradient functional_dependencies *dependencies; // Dependencies - symmetrybhvr sym; // Symmetry behavior - void *ref; // Reference to pass on + symmetrybhvr sym; // Symmetry behavior + void *ref; // Reference to pass on } functional_mapinfo; - - /* ********************************************************************** * Utility functions * ********************************************************************** */ -static void functional_clearmapinfo(functional_mapinfo *info) { - info->mesh=NULL; - info->field=NULL; - info->sel=NULL; - info->g=0; - info->integrand=NULL; - info->grad=NULL; - info->dependencies=NULL; - info->ref=NULL; - info->sym=SYMMETRY_NONE; +static void functional_clearmapinfo(functional_mapinfo *info) +{ + info->mesh = NULL; + info->field = NULL; + info->sel = NULL; + info->g = 0; + info->integrand = NULL; + info->grad = NULL; + info->dependencies = NULL; + info->ref = NULL; + info->sym = SYMMETRY_NONE; } /** Validates the arguments provided to a functional @@ -80,41 +81,55 @@ static void functional_clearmapinfo(functional_mapinfo *info) { * @param[in] nargs - number of arguments * @param[in] args - the arguments * @param[out] info - mapinfo block */ -bool functional_validateargs(vm *v, int nargs, value *args, functional_mapinfo *info) { +bool functional_validateargs(vm *v, int nargs, value *args, functional_mapinfo *info) +{ functional_clearmapinfo(info); - for (unsigned int i=0; imesh = MORPHO_GETMESH(MORPHO_GETARG(args,i)); - } else if (MORPHO_ISSELECTION(MORPHO_GETARG(args,i))) { - info->sel = MORPHO_GETSELECTION(MORPHO_GETARG(args,i)); - } else if (MORPHO_ISFIELD(MORPHO_GETARG(args,i))) { - info->field = MORPHO_GETFIELD(MORPHO_GETARG(args,i)); - if (info->field) info->mesh = (info->field->mesh); // Retrieve the mesh from the field + for (unsigned int i = 0; i < nargs; i++) + { + if (MORPHO_ISMESH(MORPHO_GETARG(args, i))) + { + info->mesh = MORPHO_GETMESH(MORPHO_GETARG(args, i)); + } + else if (MORPHO_ISSELECTION(MORPHO_GETARG(args, i))) + { + info->sel = MORPHO_GETSELECTION(MORPHO_GETARG(args, i)); + } + else if (MORPHO_ISFIELD(MORPHO_GETARG(args, i))) + { + info->field = MORPHO_GETFIELD(MORPHO_GETARG(args, i)); + if (info->field) + info->mesh = (info->field->mesh); // Retrieve the mesh from the field } } - - if (info->mesh) return true; + if (info->mesh) + return true; morpho_runtimeerror(v, FUNC_INTEGRAND_MESH); return false; } - /* ********************************************************************** * Common routines * ********************************************************************** */ /** Internal function to count the number of elements */ -static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, objectsparse **s) { +static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, objectsparse **s) +{ /* How many elements? */ - if (g==MESH_GRADE_VERTEX) { - *n=mesh->vert->ncols; - } else { - *s=mesh_getconnectivityelement(mesh, 0, g); - if (*s) { - *n=(*s)->ccs.ncols; // Number of elements - } else { + if (g == MESH_GRADE_VERTEX) + { + *n = mesh->vert->ncols; + } + else + { + *s = mesh_getconnectivityelement(mesh, 0, g); + if (*s) + { + *n = (*s)->ccs.ncols; // Number of elements + } + else + { morpho_runtimeerror(v, FUNC_ELNTFND, g); return false; } @@ -122,9 +137,11 @@ static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, o return true; } -static int functional_symmetryimagelistfn(const void *a, const void *b) { - elementid i=*(elementid *) a; elementid j=*(elementid *) b; - return (int) i-j; +static int functional_symmetryimagelistfn(const void *a, const void *b) +{ + elementid i = *(elementid *)a; + elementid j = *(elementid *)b; + return (int)i - j; } /** Gets a list of all image elements (those that map onto a target element) @@ -132,39 +149,48 @@ static int functional_symmetryimagelistfn(const void *a, const void *b) { * @param[in] g - grade to look up * @param[in] sort - whether to sort othe results * @param[out] ids - varray is filled with image element ids */ -void functional_symmetryimagelist(objectmesh *mesh, grade g, bool sort, varray_elementid *ids) { - objectsparse *conn=mesh_getconnectivityelement(mesh, g, g); +void functional_symmetryimagelist(objectmesh *mesh, grade g, bool sort, varray_elementid *ids) +{ + objectsparse *conn = mesh_getconnectivityelement(mesh, g, g); - ids->count=0; // Initialize the varray + ids->count = 0; // Initialize the varray - if (conn) { - int i,j; - void *ctr=sparsedok_loopstart(&conn->dok); + if (conn) + { + int i, j; + void *ctr = sparsedok_loopstart(&conn->dok); - while (sparsedok_loop(&conn->dok, &ctr, &i, &j)) { + while (sparsedok_loop(&conn->dok, &ctr, &i, &j)) + { varray_elementidwrite(ids, j); } - if (sort) qsort(ids->data, ids->count, sizeof(elementid), functional_symmetryimagelistfn); + if (sort) + qsort(ids->data, ids->count, sizeof(elementid), functional_symmetryimagelistfn); } } /** Sums forces on symmetry vertices * @param[in] mesh - mesh object * @param frc - force object; updated if symmetries are present. */ -bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) { - objectsparse *s=mesh_getconnectivityelement(mesh, 0, 0); // Checking for vertex symmetries +bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) +{ + objectsparse *s = mesh_getconnectivityelement(mesh, 0, 0); // Checking for vertex symmetries - if (s) { - int i,j; + if (s) + { + int i, j; void *ctr = sparsedok_loopstart(&s->dok); double *fi, *fj, fsum[mesh->dim]; - while (sparsedok_loop(&s->dok, &ctr, &i, &j)) { + while (sparsedok_loop(&s->dok, &ctr, &i, &j)) + { if (matrix_getcolumn(frc, i, &fi) && - matrix_getcolumn(frc, j, &fj)) { + matrix_getcolumn(frc, j, &fj)) + { - for (unsigned int k=0; kdim; k++) fsum[k]=fi[k]+fj[k]; + for (unsigned int k = 0; k < mesh->dim; k++) + fsum[k] = fi[k] + fj[k]; matrix_setcolumn(frc, i, fsum); matrix_setcolumn(frc, j, fsum); } @@ -174,13 +200,19 @@ bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) { return s; } -bool functional_inlist(varray_elementid *list, elementid id) { - for (unsigned int i=0; icount; i++) if (list->data[i]==id) return true; +bool functional_inlist(varray_elementid *list, elementid id) +{ + for (unsigned int i = 0; i < list->count; i++) + if (list->data[i] == id) + return true; return false; } -bool functional_containsvertex(int nv, int *vid, elementid id) { - for (unsigned int i=0; imesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - objectsparse *s=NULL; - int n=0; + objectsparse *s = NULL; + int n = 0; - if (!functional_countelements(v, mesh, g, &n, &s)) return false; + if (!functional_countelements(v, mesh, g, &n, &s)) + return false; /* Find any image elements so we can skip over them */ varray_elementid imageids; varray_elementidinit(&imageids); functional_symmetryimagelist(mesh, g, true, &imageids); - if (n>0) { + if (n > 0) + { int vertexid; // Use this if looping over grade 0 - int *vid=(g==0 ? &vertexid : NULL), - nv=(g==0 ? 1 : 0); // The vertex indices - int sindx=0; // Index into imageids array - double sum=0.0, c=0.0, y, t, result; - - if (sel) { // Loop over selection - if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - - // Skip this element if it's an image element: - if ((imageids.count>0) && (sindxccs, i, &nv, &vid); - else vertexid=i; - - if (vid && nv>0) { - if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { - y=result-c; t=sum+y; c=(t-sum)-y; sum=t; // Kahan summation - } else goto functional_sumintegrand_cleanup; + int *vid = (g == 0 ? &vertexid : NULL), + nv = (g == 0 ? 1 : 0); // The vertex indices + int sindx = 0; // Index into imageids array + double sum = 0.0, c = 0.0, y, t, result; + + if (sel) + { // Loop over selection + if (sel->selected[g].count > 0) + for (unsigned int k = 0; k < sel->selected[g].capacity; k++) + { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) + continue; + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + + // Skip this element if it's an image element: + if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } + + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; + + if (vid && nv > 0) + { + if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) + { + y = result - c; + t = sum + y; + c = (t - sum) - y; + sum = t; // Kahan summation + } + else + goto functional_sumintegrand_cleanup; + } } - } - } else { // Loop over elements - for (elementid i=0; i0) && (sindxccs, i, &nv, &vid); - else vertexid=i; + if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } - if (vid && nv>0) { - if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { - y=result-c; t=sum+y; c=(t-sum)-y; sum=t; // Kahan summation - } else goto functional_sumintegrand_cleanup; + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; + + if (vid && nv > 0) + { + if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) + { + y = result - c; + t = sum + y; + c = (t - sum) - y; + sum = t; // Kahan summation + } + else + goto functional_sumintegrand_cleanup; } } } - *out=MORPHO_FLOAT(sum); + *out = MORPHO_FLOAT(sum); } - success=true; + success = true; functional_sumintegrand_cleanup: varray_elementidclear(&imageids); @@ -265,19 +333,21 @@ bool functional_sumintegrand(vm *v, functional_mapinfo *info, value *out) { * @param[in] info - map info * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) { +bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) +{ objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - objectsparse *s=NULL; - objectmatrix *new=NULL; - bool ret=false; - int n=0; + objectsparse *s = NULL; + objectmatrix *new = NULL; + bool ret = false; + int n = 0; /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) return false; + if (!functional_countelements(v, mesh, g, &n, &s)) + return false; /* Find any image elements so we can skip over them */ varray_elementid imageids; @@ -285,59 +355,92 @@ bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) { functional_symmetryimagelist(mesh, g, true, &imageids); /* Create the output matrix */ - if (n>0) { - new=object_newmatrix(1, n, true); - if (!new) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } + if (n > 0) + { + new = object_newmatrix(1, n, true); + if (!new) + { + morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); + return false; + } } - if (new) { + if (new) + { int vertexid; // Use this if looping over grade 0 - int *vid=(g==0 ? &vertexid : NULL), - nv=(g==0 ? 1 : 0); // The vertex indices - int sindx=0; // Index into imageids array + int *vid = (g == 0 ? &vertexid : NULL), + nv = (g == 0 ? 1 : 0); // The vertex indices + int sindx = 0; // Index into imageids array double result; - if (sel) { // Loop over selection - if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - - // Skip this element if it's an image element - if ((imageids.count>0) && (sindxselected[g].count > 0) + for (unsigned int k = 0; k < sel->selected[g].capacity; k++) + { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) + continue; + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + + // Skip this element if it's an image element + if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } - if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else vertexid=i; + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; - if (vid && nv>0) { - if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { - matrix_setelement(new, 0, i, result); - } else goto functional_mapintegrand_cleanup; + if (vid && nv > 0) + { + if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) + { + matrix_setelement(new, 0, i, result); + } + else + goto functional_mapintegrand_cleanup; + } } - } - } else { // Loop over elements - for (elementid i=0; i0) && (sindx 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } - if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else vertexid=i; + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; - if (vid && nv>0) { - if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { + if (vid && nv > 0) + { + if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) + { matrix_setelement(new, 0, i, result); - } else goto functional_mapintegrand_cleanup; + } + else + goto functional_mapintegrand_cleanup; } } } *out = MORPHO_OBJECT(new); - ret=true; + ret = true; } varray_elementidclear(&imageids); return ret; functional_mapintegrand_cleanup: - object_free((object *) new); + object_free((object *)new); varray_elementidclear(&imageids); return false; } @@ -347,137 +450,176 @@ bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) { * @param[in] info - map info structure * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapgradient(vm *v, functional_mapinfo *info, value *out) { +bool functional_mapgradient(vm *v, functional_mapinfo *info, value *out) +{ objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_gradient *grad = info->grad; void *ref = info->ref; symmetrybhvr sym = info->sym; - objectsparse *s=NULL; - objectmatrix *frc=NULL; - bool ret=false; - int n=0; + objectsparse *s = NULL; + objectmatrix *frc = NULL; + bool ret = false; + int n = 0; /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) return false; + if (!functional_countelements(v, mesh, g, &n, &s)) + return false; /* Create the output matrix */ - if (n>0) { - frc=object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); - if (!frc) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } + if (n > 0) + { + frc = object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); + if (!frc) + { + morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); + return false; + } } - if (frc) { + if (frc) + { int vertexid; // Use this if looping over grade 0 - int *vid=(g==0 ? &vertexid : NULL), - nv=(g==0 ? 1 : 0); // The vertex indices - - - if (sel) { // Loop over selection - if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; - - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else vertexid=i; - - if (vid && nv>0) { - if (!(*grad) (v, mesh, i, nv, vid, ref, frc)) goto functional_mapgradient_cleanup; + int *vid = (g == 0 ? &vertexid : NULL), + nv = (g == 0 ? 1 : 0); // The vertex indices + + if (sel) + { // Loop over selection + if (sel->selected[g].count > 0) + for (unsigned int k = 0; k < sel->selected[g].capacity; k++) + { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) + continue; + + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; + + if (vid && nv > 0) + { + if (!(*grad)(v, mesh, i, nv, vid, ref, frc)) + goto functional_mapgradient_cleanup; + } } - } - } else { // Loop over elements - for (elementid i=0; iccs, i, &nv, &vid); - else vertexid=i; - - if (vid && nv>0) { - if (!(*grad) (v, mesh, i, nv, vid, ref, frc)) goto functional_mapgradient_cleanup; + } + else + { // Loop over elements + for (elementid i = 0; i < n; i++) + { + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; + + if (vid && nv > 0) + { + if (!(*grad)(v, mesh, i, nv, vid, ref, frc)) + goto functional_mapgradient_cleanup; } } } - if (sym==SYMMETRY_ADD) functional_symmetrysumforces(mesh, frc); + if (sym == SYMMETRY_ADD) + functional_symmetrysumforces(mesh, frc); *out = MORPHO_OBJECT(frc); - ret=true; + ret = true; } functional_mapgradient_cleanup: - if (!ret) object_free((object *) frc); + if (!ret) + object_free((object *)frc); return ret; } /* Calculates a numerical gradient */ -static bool functional_numericalgradient(vm *v, objectmesh *mesh, elementid i, int nv, int *vid, functional_integrand *integrand, void *ref, objectmatrix *frc) { - double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here +static bool functional_numericalgradient(vm *v, objectmesh *mesh, elementid i, int nv, int *vid, functional_integrand *integrand, void *ref, objectmatrix *frc) +{ + double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here // Loop over vertices in element - for (unsigned int j=0; jdim; k++) { + for (unsigned int k = 0; k < mesh->dim; k++) + { matrix_getelement(frc, k, vid[j], &f0); matrix_getelement(mesh->vert, k, vid[j], &x0); - matrix_setelement(mesh->vert, k, vid[j], x0+eps); - if (!(*integrand) (v, mesh, i, nv, vid, ref, &fp)) return false; - matrix_setelement(mesh->vert, k, vid[j], x0-eps); - if (!(*integrand) (v, mesh, i, nv, vid, ref, &fm)) return false; + matrix_setelement(mesh->vert, k, vid[j], x0 + eps); + if (!(*integrand)(v, mesh, i, nv, vid, ref, &fp)) + return false; + matrix_setelement(mesh->vert, k, vid[j], x0 - eps); + if (!(*integrand)(v, mesh, i, nv, vid, ref, &fm)) + return false; matrix_setelement(mesh->vert, k, vid[j], x0); - matrix_setelement(frc, k, vid[j], f0+(fp-fm)/(2*eps)); + matrix_setelement(frc, k, vid[j], f0 + (fp - fm) / (2 * eps)); } } return true; } /* Calculates a numerical gradient for a remote vertex */ -static bool functional_numericalremotegradientold(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) { +static bool functional_numericalremotegradientold(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) +{ objectmesh *mesh = info->mesh; - double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here + double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here - int *rvid=(info->g==0 ? &remoteid : NULL), - rnv=(info->g==0 ? 1 : 0); // The vertex indices + int *rvid = (info->g == 0 ? &remoteid : NULL), + rnv = (info->g == 0 ? 1 : 0); // The vertex indices - if (conn) sparseccs_getrowindices(&conn->ccs, remoteid, &rnv, &rvid); + if (conn) + sparseccs_getrowindices(&conn->ccs, remoteid, &rnv, &rvid); // Loop over vertices in element - for (unsigned int j=0; jdim; k++) { + for (unsigned int k = 0; k < mesh->dim; k++) + { matrix_getelement(frc, k, vid[j], &f0); matrix_getelement(mesh->vert, k, vid[j], &x0); - matrix_setelement(mesh->vert, k, vid[j], x0+eps); - if (!(*info->integrand) (v, mesh, remoteid, rnv, rvid, info->ref, &fp)) return false; - matrix_setelement(mesh->vert, k, vid[j], x0-eps); - if (!(*info->integrand) (v, mesh, remoteid, rnv, rvid, info->ref, &fm)) return false; + matrix_setelement(mesh->vert, k, vid[j], x0 + eps); + if (!(*info->integrand)(v, mesh, remoteid, rnv, rvid, info->ref, &fp)) + return false; + matrix_setelement(mesh->vert, k, vid[j], x0 - eps); + if (!(*info->integrand)(v, mesh, remoteid, rnv, rvid, info->ref, &fm)) + return false; matrix_setelement(mesh->vert, k, vid[j], x0); - matrix_setelement(frc, k, vid[j], f0+(fp-fm)/(2*eps)); + matrix_setelement(frc, k, vid[j], f0 + (fp - fm) / (2 * eps)); } } return true; } -static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) { +static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) +{ objectmesh *mesh = info->mesh; - double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here + double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here // Loop over coordinates - for (unsigned int k=0; kdim; k++) { + for (unsigned int k = 0; k < mesh->dim; k++) + { matrix_getelement(frc, k, remoteid, &f0); matrix_getelement(mesh->vert, k, remoteid, &x0); - matrix_setelement(mesh->vert, k, remoteid, x0+eps); - if (!(*info->integrand) (v, mesh, i, nv, vid, info->ref, &fp)) return false; - matrix_setelement(mesh->vert, k, remoteid, x0-eps); - if (!(*info->integrand) (v, mesh, i, nv, vid, info->ref, &fm)) return false; + matrix_setelement(mesh->vert, k, remoteid, x0 + eps); + if (!(*info->integrand)(v, mesh, i, nv, vid, info->ref, &fp)) + return false; + matrix_setelement(mesh->vert, k, remoteid, x0 - eps); + if (!(*info->integrand)(v, mesh, i, nv, vid, info->ref, &fm)) + return false; matrix_setelement(mesh->vert, k, remoteid, x0); - matrix_setelement(frc, k, remoteid, f0+(fp-fm)/(2*eps)); + matrix_setelement(frc, k, remoteid, f0 + (fp - fm) / (2 * eps)); } return true; @@ -488,20 +630,22 @@ static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, * @param[in] info - map info * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out) { +bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out) +{ objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; symmetrybhvr sym = info->sym; - objectsparse *s=NULL; - objectmatrix *frc=NULL; - bool ret=false; - int n=0; + objectsparse *s = NULL; + objectmatrix *frc = NULL; + bool ret = false; + int n = 0; varray_elementid dependencies; - if (info->dependencies) varray_elementidinit(&dependencies); + if (info->dependencies) + varray_elementidinit(&dependencies); /* Find any image elements so we can skip over them */ varray_elementid imageids; @@ -509,147 +653,206 @@ bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out functional_symmetryimagelist(mesh, g, true, &imageids); /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) return false; + if (!functional_countelements(v, mesh, g, &n, &s)) + return false; /* Create the output matrix */ - if (n>0) { - frc=object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); - if (!frc) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } + if (n > 0) + { + frc = object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); + if (!frc) + { + morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); + return false; + } } - if (frc) { + if (frc) + { int vertexid; // Use this if looping over grade 0 - int *vid=(g==0 ? &vertexid : NULL), - nv=(g==0 ? 1 : 0); // The vertex indices - int sindx=0; // Index into imageids array - - if (sel) { // Loop over selection - if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; - - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else vertexid=i; - - // Skip this element if it's an image element - if ((imageids.count>0) && (sindx0) { - if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) goto functional_numericalgradient_cleanup; + int *vid = (g == 0 ? &vertexid : NULL), + nv = (g == 0 ? 1 : 0); // The vertex indices + int sindx = 0; // Index into imageids array + + if (sel) + { // Loop over selection + if (sel->selected[g].count > 0) + for (unsigned int k = 0; k < sel->selected[g].capacity; k++) + { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) + continue; + + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; + + // Skip this element if it's an image element + if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } - if (info->dependencies && // Loop over dependencies if there are any - (info->dependencies) (info, i, &dependencies)) { - for (int j=0; j 0) + { + if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) + goto functional_numericalgradient_cleanup; + + if (info->dependencies && // Loop over dependencies if there are any + (info->dependencies)(info, i, &dependencies)) + { + for (int j = 0; j < dependencies.count; j++) + { + if (!functional_numericalremotegradient(v, info, s, dependencies.data[j], i, nv, vid, frc)) + goto functional_numericalgradient_cleanup; + } + dependencies.count = 0; } - dependencies.count=0; } } - } - } else { // Loop over elements - for (elementid i=0; i0) && (sindx 0) && (sindx < imageids.count) && imageids.data[sindx] == i) + { + sindx++; + continue; + } - if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else vertexid=i; + if (s) + sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else + vertexid = i; - if (vid && nv>0) { + if (vid && nv > 0) + { - if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) goto functional_numericalgradient_cleanup; + if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) + goto functional_numericalgradient_cleanup; if (info->dependencies && // Loop over dependencies if there are any - (info->dependencies) (info, i, &dependencies)) { - for (int j=0; jdependencies)(info, i, &dependencies)) + { + for (int j = 0; j < dependencies.count; j++) + { + if (functional_containsvertex(nv, vid, dependencies.data[j])) + continue; + if (!functional_numericalremotegradient(v, info, s, dependencies.data[j], i, nv, vid, frc)) + goto functional_numericalgradient_cleanup; } - dependencies.count=0; + dependencies.count = 0; } } } } - if (sym==SYMMETRY_ADD) functional_symmetrysumforces(mesh, frc); + if (sym == SYMMETRY_ADD) + functional_symmetrysumforces(mesh, frc); *out = MORPHO_OBJECT(frc); - ret=true; + ret = true; } functional_numericalgradient_cleanup: varray_elementidclear(&imageids); - if (info->dependencies) varray_elementidclear(&dependencies); - if (!ret) object_free((object *) frc); + if (info->dependencies) + varray_elementidclear(&dependencies); + if (!ret) + object_free((object *)frc); return ret; } -bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value *out) { +bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value *out) +{ objectmesh *mesh = info->mesh; objectselection *sel = info->sel; objectfield *field = info->field; grade grd = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - //symmetrybhvr sym = info->sym; + // symmetrybhvr sym = info->sym; - double eps=1e-10; - bool ret=false; - objectsparse *conn=mesh_getconnectivityelement(mesh, 0, grd); // Connectivity for the element + double eps = 1e-10; + bool ret = false; + objectsparse *conn = mesh_getconnectivityelement(mesh, 0, grd); // Connectivity for the element /* Create the output field */ - objectfield *grad=object_newfield(mesh, field->prototype, field->dof); - if (!grad) return false; + objectfield *grad = object_newfield(mesh, field->prototype, field->dof); + if (!grad) + return false; field_zero(grad); /* Loop over elements in the field */ - for (grade g=0; gngrades; g++) { - if (field->dof[g]==0) continue; - int nentries=1, *entries, nv, *vid; - double fr,fl; - objectsparse *rconn=mesh_addconnectivityelement(mesh, grd, g); // Find dependencies for the grade - - for (elementid id=0; idngrades; g++) + { + if (field->dof[g] == 0) + continue; + int nentries = 1, *entries, nv, *vid; + double fr, fl; + objectsparse *rconn = mesh_addconnectivityelement(mesh, grd, g); // Find dependencies for the grade + + for (elementid id = 0; id < mesh_nelementsforgrade(mesh, g); id++) + { entries = &id; // if there's no connectivity matrix, we'll just use the id itself - if ((!rconn) || mesh_getconnectivity(rconn, id, &nentries, &entries)) { - for (int i=0; iccs, entries[i], &nv, &vid); - } else { - if (sel) if (!selection_isselected(sel, grd, id)) continue; - nv=1; vid=&id; + } + else + { + if (sel) + if (!selection_isselected(sel, grd, id)) + continue; + nv = 1; + vid = &id; } /* Loop over dofs in field entry */ - for (int j=0; jpsize*field->dof[g]; j++) { - int k=field->offset[g]+id*field->psize*field->dof[g]+j; - double fld=field->data.elements[k]; - field->data.elements[k]+=eps; + for (int j = 0; j < field->psize * field->dof[g]; j++) + { + int k = field->offset[g] + id * field->psize * field->dof[g] + j; + double fld = field->data.elements[k]; + field->data.elements[k] += eps; - if (!(*integrand) (v, mesh, id, nv, vid, ref, &fr)) goto functional_mapnumericalfieldgradient_cleanup; + if (!(*integrand)(v, mesh, id, nv, vid, ref, &fr)) + goto functional_mapnumericalfieldgradient_cleanup; - field->data.elements[k]=fld-eps; + field->data.elements[k] = fld - eps; - if (!(*integrand) (v, mesh, id, nv, vid, ref, &fl)) goto functional_mapnumericalfieldgradient_cleanup; + if (!(*integrand)(v, mesh, id, nv, vid, ref, &fl)) + goto functional_mapnumericalfieldgradient_cleanup; - field->data.elements[k]=fld; + field->data.elements[k] = fld; - grad->data.elements[k]+=(fr-fl)/(2*eps); + grad->data.elements[k] += (fr - fl) / (2 * eps); } } } } *out = MORPHO_OBJECT(grad); - ret=true; + ret = true; } functional_mapnumericalfieldgradient_cleanup: - if (!ret) object_free((object *) grad); + if (!ret) + object_free((object *)grad); return ret; } @@ -659,40 +862,51 @@ bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value * ********************************************************************** */ /** Calculate the difference of two vectors */ -void functional_vecadd(unsigned int n, double *a, double *b, double *out) { - for (unsigned int i=0; idim]; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); - *out=functional_vecnorm(mesh->dim, s0); + *out = functional_vecnorm(mesh->dim, s0); return true; } /** Calculate gradient */ -bool length_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool length_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x[nv], s0[mesh->dim], norm; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); - norm=functional_vecnorm(mesh->dim, s0); - if (normdim, s0); + if (norm < MORPHO_EPS) + return false; - matrix_addtocolumn(frc, vid[0], -1.0/norm, s0); - matrix_addtocolumn(frc, vid[1], 1./norm, s0); + matrix_addtocolumn(frc, vid[0], -1.0 / norm, s0); + matrix_addtocolumn(frc, vid[1], 1. / norm, s0); return true; } @@ -818,41 +1064,46 @@ FUNCTIONAL_TOTAL(Length, MESH_GRADE_LINE, length_integrand) MORPHO_BEGINCLASS(Length) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Length_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Length_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Length_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Length_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * Enclosed area - * ---------------------------------------------- */ - -/** Calculate area enclosed */ -bool areaenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Length_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Length_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Length_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * Enclosed area + * ---------------------------------------------- */ + + /** Calculate area enclosed */ + bool areaenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ double *x[nv], cx[mesh->dim]; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - *out=0.5*functional_vecnorm(mesh->dim, cx); + *out = 0.5 * functional_vecnorm(mesh->dim, cx); return true; } /** Calculate gradient */ -bool areaenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool areaenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x[nv], cx[mesh->dim], s[mesh->dim]; double norm; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - norm=functional_vecnorm(mesh->dim, cx); - if (normdim, cx); + if (norm < MORPHO_EPS) + return false; functional_veccross(x[1], cx, s); - matrix_addtocolumn(frc, vid[0], 0.5/norm, s); + matrix_addtocolumn(frc, vid[0], 0.5 / norm, s); functional_veccross(cx, x[0], s); - matrix_addtocolumn(frc, vid[1], 0.5/norm, s); + matrix_addtocolumn(frc, vid[1], 0.5 / norm, s); return true; } @@ -864,51 +1115,56 @@ FUNCTIONAL_TOTAL(AreaEnclosed, MESH_GRADE_LINE, areaenclosed_integrand) MORPHO_BEGINCLASS(AreaEnclosed) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, AreaEnclosed_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaEnclosed_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaEnclosed_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaEnclosed_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * Area - * ---------------------------------------------- */ - -/** Calculate area */ -bool area_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaEnclosed_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaEnclosed_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaEnclosed_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * Area + * ---------------------------------------------- */ + + /** Calculate area */ + bool area_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ double *x[nv], s0[mesh->dim], s1[mesh->dim], cx[mesh->dim]; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, cx); - *out=0.5*functional_vecnorm(mesh->dim, cx); + *out = 0.5 * functional_vecnorm(mesh->dim, cx); return true; } /** Calculate gradient */ -bool area_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool area_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x[nv], s0[3], s1[3], s01[3], s010[3], s011[3]; double norm; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, s01); - norm=functional_vecnorm(mesh->dim, s01); - if (normdim, s01); + if (norm < MORPHO_EPS) + return false; functional_veccross(s01, s0, s010); functional_veccross(s01, s1, s011); - matrix_addtocolumn(frc, vid[0], 0.5/norm, s011); - matrix_addtocolumn(frc, vid[2], 0.5/norm, s010); + matrix_addtocolumn(frc, vid[0], 0.5 / norm, s011); + matrix_addtocolumn(frc, vid[2], 0.5 / norm, s010); functional_vecadd(mesh->dim, s010, s011, s0); - matrix_addtocolumn(frc, vid[1], -0.5/norm, s0); + matrix_addtocolumn(frc, vid[1], -0.5 / norm, s0); return true; } @@ -920,42 +1176,46 @@ FUNCTIONAL_TOTAL(Area, MESH_GRADE_AREA, area_integrand) MORPHO_BEGINCLASS(Area) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Area_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Area_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Area_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Area_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * Enclosed volume - * ---------------------------------------------- */ - -/** Calculate enclosed volume */ -bool volumeenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Area_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Area_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Area_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * Enclosed volume + * ---------------------------------------------- */ + + /** Calculate enclosed volume */ + bool volumeenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ double *x[nv], cx[mesh->dim]; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - *out=fabs(functional_vecdot(mesh->dim, cx, x[2]))/6.0; + *out = fabs(functional_vecdot(mesh->dim, cx, x[2])) / 6.0; return true; } /** Calculate gradient */ -bool volumeenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool volumeenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x[nv], cx[mesh->dim], dot; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - dot=functional_vecdot(mesh->dim, cx, x[2]); - dot/=fabs(dot); + dot = functional_vecdot(mesh->dim, cx, x[2]); + dot /= fabs(dot); - matrix_addtocolumn(frc, vid[2], dot/6.0, cx); + matrix_addtocolumn(frc, vid[2], dot / 6.0, cx); functional_veccross(x[1], x[2], cx); - matrix_addtocolumn(frc, vid[0], dot/6.0, cx); + matrix_addtocolumn(frc, vid[0], dot / 6.0, cx); functional_veccross(x[2], x[0], cx); - matrix_addtocolumn(frc, vid[1], dot/6.0, cx); + matrix_addtocolumn(frc, vid[1], dot / 6.0, cx); return true; } @@ -967,19 +1227,21 @@ FUNCTIONAL_TOTAL(VolumeEnclosed, MESH_GRADE_AREA, volumeenclosed_integrand) MORPHO_BEGINCLASS(VolumeEnclosed) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, VolumeEnclosed_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, VolumeEnclosed_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, VolumeEnclosed_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, VolumeEnclosed_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * Volume - * ---------------------------------------------- */ - -/** Calculate enclosed volume */ -bool volume_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, VolumeEnclosed_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, VolumeEnclosed_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, VolumeEnclosed_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * Volume + * ---------------------------------------------- */ + + /** Calculate enclosed volume */ + bool volume_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ double *x[nv], s10[mesh->dim], s20[mesh->dim], s30[mesh->dim], cx[mesh->dim]; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s10); functional_vecsub(mesh->dim, x[2], x[0], s20); @@ -987,15 +1249,17 @@ bool volume_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, v functional_veccross(s20, s30, cx); - *out=fabs(functional_vecdot(mesh->dim, s10, cx))/6.0; + *out = fabs(functional_vecdot(mesh->dim, s10, cx)) / 6.0; return true; } /** Calculate gradient */ -bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x[nv], s10[mesh->dim], s20[mesh->dim], s30[mesh->dim]; double s31[mesh->dim], s21[mesh->dim], cx[mesh->dim], uu; - for (int j=0; jvert, vid[j], &x[j]); + for (int j = 0; j < nv; j++) + matrix_getcolumn(mesh->vert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s10); functional_vecsub(mesh->dim, x[2], x[0], s20); @@ -1004,19 +1268,19 @@ bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, vo functional_vecsub(mesh->dim, x[2], x[1], s21); functional_veccross(s20, s30, cx); - uu=functional_vecdot(mesh->dim, s10, cx); - uu=(uu>0 ? 1.0 : -1.0); + uu = functional_vecdot(mesh->dim, s10, cx); + uu = (uu > 0 ? 1.0 : -1.0); - matrix_addtocolumn(frc, vid[1], uu/6.0, cx); + matrix_addtocolumn(frc, vid[1], uu / 6.0, cx); functional_veccross(s31, s21, cx); - matrix_addtocolumn(frc, vid[0], uu/6.0, cx); + matrix_addtocolumn(frc, vid[0], uu / 6.0, cx); functional_veccross(s30, s10, cx); - matrix_addtocolumn(frc, vid[2], uu/6.0, cx); + matrix_addtocolumn(frc, vid[2], uu / 6.0, cx); functional_veccross(s10, s20, cx); - matrix_addtocolumn(frc, vid[3], uu/6.0, cx); + matrix_addtocolumn(frc, vid[3], uu / 6.0, cx); return true; } @@ -1028,29 +1292,32 @@ FUNCTIONAL_TOTAL(Volume, MESH_GRADE_VOLUME, volume_integrand) MORPHO_BEGINCLASS(Volume) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Volume_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Volume_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Volume_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Volume_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Volume_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Volume_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Volume_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ---------------------------------------------- - * Scalar potential - * ---------------------------------------------- */ + /* ---------------------------------------------- + * Scalar potential + * ---------------------------------------------- */ -static value scalarpotential_functionproperty; + static value scalarpotential_functionproperty; static value scalarpotential_gradfunctionproperty; /** Evaluate the scalar potential */ -bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { +bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ double *x; - value fn = *(value *) ref; + value fn = *(value *)ref; value args[mesh->dim]; value ret; matrix_getcolumn(mesh->vert, id, &x); - for (int i=0; idim; i++) args[i]=MORPHO_FLOAT(x[i]); + for (int i = 0; i < mesh->dim; i++) + args[i] = MORPHO_FLOAT(x[i]); - if (morpho_call(v, fn, mesh->dim, args, &ret)) { + if (morpho_call(v, fn, mesh->dim, args, &ret)) + { return morpho_valuetofloat(ret, out); } @@ -1058,20 +1325,25 @@ bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in } /** Evaluate the gradient of the scalar potential */ -bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { +bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) +{ double *x; - value fn = *(value *) ref; + value fn = *(value *)ref; value args[mesh->dim]; value ret; matrix_getcolumn(mesh->vert, id, &x); - for (int i=0; idim; i++) args[i]=MORPHO_FLOAT(x[i]); + for (int i = 0; i < mesh->dim; i++) + args[i] = MORPHO_FLOAT(x[i]); - if (morpho_call(v, fn, mesh->dim, args, &ret)) { - if (MORPHO_ISMATRIX(ret)) { - objectmatrix *vf=MORPHO_GETMATRIX(ret); + if (morpho_call(v, fn, mesh->dim, args, &ret)) + { + if (MORPHO_ISMATRIX(ret)) + { + objectmatrix *vf = MORPHO_GETMATRIX(ret); - if (vf->nrows*vf->ncols==frc->nrows) { + if (vf->nrows * vf->ncols == frc->nrows) + { return matrix_addtocolumn(frc, id, 1.0, vf->elements); } } @@ -1080,116 +1352,158 @@ bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int return false; } - /** Initialize a scalar potential */ -value ScalarPotential_init(vm *v, int nargs, value *args) { +value ScalarPotential_init(vm *v, int nargs, value *args) +{ objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_INTEGER(MESH_GRADE_VERTEX)); /* First argument is the potential function */ - if (nargs>0) { - if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 0))) { + if (nargs > 0) + { + if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 0))) + { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, MORPHO_GETARG(args, 0)); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); } /* Second argument is the gradient of the potential function */ - if (nargs>1) { - if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 1))) { + if (nargs > 1) + { + if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 1))) + { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, MORPHO_GETARG(args, 1)); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); } return MORPHO_NIL; } /** Integrand function */ -value ScalarPotential_integrand(vm *v, int nargs, value *args) { +value ScalarPotential_integrand(vm *v, int nargs, value *args) +{ functional_mapinfo info; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { + if (functional_validateargs(v, nargs, args, &info)) + { value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) + { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) { + if (MORPHO_ISCALLABLE(fn)) + { functional_mapintegrand(v, &info, &out); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else + morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } /** Evaluate a gradient */ -value ScalarPotential_gradient(vm *v, int nargs, value *args) { +value ScalarPotential_gradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { + if (functional_validateargs(v, nargs, args, &info)) + { value fn; // Check if a gradient function is available - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, &fn)) { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, &fn)) + { info.g = MESH_GRADE_VERTEX; info.grad = scalarpotential_gradient; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) { + if (MORPHO_ISCALLABLE(fn)) + { functional_mapgradient(v, &info, &out); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } else if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) + { // Otherwise try to use the regular scalar function - + value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) + { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) { + if (MORPHO_ISCALLABLE(fn)) + { functional_mapnumericalgradient(v, &info, &out); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); - - } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else + morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } + else + morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } /** Total function */ -value ScalarPotential_total(vm *v, int nargs, value *args) { +value ScalarPotential_total(vm *v, int nargs, value *args) +{ functional_mapinfo info; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { + if (functional_validateargs(v, nargs, args, &info)) + { value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) + { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) { + if (MORPHO_ISCALLABLE(fn)) + { functional_sumintegrand(v, &info, &out); - } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } + else + morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } + else + morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } return out; } MORPHO_BEGINCLASS(ScalarPotential) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, ScalarPotential_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, ScalarPotential_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, ScalarPotential_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, ScalarPotential_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, ScalarPotential_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, ScalarPotential_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, ScalarPotential_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ---------------------------------------------- - * Linear Elasticity - * ---------------------------------------------- */ + /* ---------------------------------------------- + * Linear Elasticity + * ---------------------------------------------- */ -static value linearelasticity_referenceproperty; + static value linearelasticity_referenceproperty; static value linearelasticity_poissonproperty; -typedef struct { +typedef struct +{ objectmesh *refmesh; grade grade; double lambda; // Lamé coefficients @@ -1197,94 +1511,114 @@ typedef struct { } linearelasticityref; /** Calculates the Gram matrix */ -void linearelasticity_calculategram(objectmatrix *vert, int dim, int nv, int *vid, objectmatrix *gram) { - int gdim=nv-1; // Dimension of Gram matrix - double *x[nv], // Positions of vertices - s[gdim][nv]; // Side vectors - - for (int j=0; j - for (int i=0; ielements[i+j*gdim]=functional_vecdot(dim, s[i], s[j]); + for (int i = 0; i < nv - 1; i++) + for (int j = 0; j < nv - 1; j++) + gram->elements[i + j * gdim] = functional_vecdot(dim, s[i], s[j]); } /** Calculate the linear elastic energy */ -bool linearelasticity_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - double weight=0.0; - linearelasticityref *info = (linearelasticityref *) ref; - int gdim=nv-1; // Dimension of Gram matrix +bool linearelasticity_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + double weight = 0.0; + linearelasticityref *info = (linearelasticityref *)ref; + int gdim = nv - 1; // Dimension of Gram matrix /* Construct static matrices */ - double gramrefel[gdim*gdim], gramdefel[gdim*gdim], qel[gdim*gdim], rel[gdim*gdim], cgel[gdim*gdim]; + double gramrefel[gdim * gdim], gramdefel[gdim * gdim], qel[gdim * gdim], rel[gdim * gdim], cgel[gdim * gdim]; objectmatrix gramref = MORPHO_STATICMATRIX(gramrefel, gdim, gdim); // Gram matrices objectmatrix gramdef = MORPHO_STATICMATRIX(gramdefel, gdim, gdim); // - objectmatrix q = MORPHO_STATICMATRIX(qel, gdim, gdim); // Inverse of Gram in source domain - objectmatrix r = MORPHO_STATICMATRIX(rel, gdim, gdim); // Intermediate calculations - objectmatrix cg = MORPHO_STATICMATRIX(cgel, gdim, gdim); // Cauchy-Green strain tensor + objectmatrix q = MORPHO_STATICMATRIX(qel, gdim, gdim); // Inverse of Gram in source domain + objectmatrix r = MORPHO_STATICMATRIX(rel, gdim, gdim); // Intermediate calculations + objectmatrix cg = MORPHO_STATICMATRIX(cgel, gdim, gdim); // Cauchy-Green strain tensor linearelasticity_calculategram(info->refmesh->vert, mesh->dim, nv, vid, &gramref); linearelasticity_calculategram(mesh->vert, mesh->dim, nv, vid, &gramdef); - if (matrix_inverse(&gramref, &q)!=MATRIX_OK) return false; - if (matrix_mul(&gramdef, &q, &r)!=MATRIX_OK) return false; + if (matrix_inverse(&gramref, &q) != MATRIX_OK) + return false; + if (matrix_mul(&gramdef, &q, &r) != MATRIX_OK) + return false; matrix_identity(&cg); matrix_scale(&cg, -0.5); matrix_accumulate(&cg, 0.5, &r); - double trcg=0.0, trcgcg=0.0; + double trcg = 0.0, trcgcg = 0.0; matrix_trace(&cg, &trcg); matrix_mul(&cg, &cg, &r); matrix_trace(&r, &trcgcg); - if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &weight)) return false; + if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &weight)) + return false; - *out=weight*(info->mu*trcgcg + 0.5*info->lambda*trcg*trcg); + *out = weight * (info->mu * trcgcg + 0.5 * info->lambda * trcg * trcg); return true; } /** Prepares the reference structure from the LinearElasticity object's properties */ -bool linearelasticity_prepareref(objectinstance *self, linearelasticityref *ref) { - bool success=false; - value refmesh=MORPHO_NIL; - value grade=MORPHO_NIL; - value poisson=MORPHO_NIL; +bool linearelasticity_prepareref(objectinstance *self, linearelasticityref *ref) +{ + bool success = false; + value refmesh = MORPHO_NIL; + value grade = MORPHO_NIL; + value poisson = MORPHO_NIL; if (objectinstance_getproperty(self, linearelasticity_referenceproperty, &refmesh) && objectinstance_getproperty(self, functional_gradeproperty, &grade) && MORPHO_ISINTEGER(grade) && objectinstance_getproperty(self, linearelasticity_poissonproperty, &poisson) && - MORPHO_ISNUMBER(poisson)) { - ref->refmesh=MORPHO_GETMESH(refmesh); - ref->grade=MORPHO_GETINTEGERVALUE(grade); + MORPHO_ISNUMBER(poisson)) + { + ref->refmesh = MORPHO_GETMESH(refmesh); + ref->grade = MORPHO_GETINTEGERVALUE(grade); double nu = MORPHO_GETFLOATVALUE(poisson); - ref->mu=0.5/(1+nu); - ref->lambda=nu/(1+nu)/(1-2*nu); - success=true; + ref->mu = 0.5 / (1 + nu); + ref->lambda = nu / (1 + nu) / (1 - 2 * nu); + success = true; } return success; } -value LinearElasticity_init(vm *v, int nargs, value *args) { +value LinearElasticity_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); /* First argument is the reference mesh */ - if (nargs>0) { - if (MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { + if (nargs > 0) + { + if (MORPHO_ISMESH(MORPHO_GETARG(args, 0))) + { objectinstance_setproperty(self, linearelasticity_referenceproperty, MORPHO_GETARG(args, 0)); objectmesh *mesh = MORPHO_GETMESH(MORPHO_GETARG(args, 0)); objectinstance_setproperty(self, functional_gradeproperty, MORPHO_INTEGER(mesh_maxgrade(mesh))); objectinstance_setproperty(self, linearelasticity_poissonproperty, MORPHO_FLOAT(0.3)); - } else morpho_runtimeerror(v, LINEARELASTICITY_REF); - } else morpho_runtimeerror(v, LINEARELASTICITY_REF); + } + else + morpho_runtimeerror(v, LINEARELASTICITY_REF); + } + else + morpho_runtimeerror(v, LINEARELASTICITY_REF); /* Second (optional) argument is the grade to act on */ - if (nargs>1) { - if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) { + if (nargs > 1) + { + if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) + { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_GETARG(args, 1)); } } @@ -1293,233 +1627,297 @@ value LinearElasticity_init(vm *v, int nargs, value *args) { } /** Integrand function */ -value LinearElasticity_integrand(vm *v, int nargs, value *args) { +value LinearElasticity_integrand(vm *v, int nargs, value *args) +{ functional_mapinfo info; linearelasticityref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { + if (functional_validateargs(v, nargs, args, &info)) + { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) + { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; functional_mapintegrand(v, &info, &out); - } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } + else + morpho_runtimeerror(v, LINEARELASTICITY_PRP); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } /** Total function */ -value LinearElasticity_total(vm *v, int nargs, value *args) { +value LinearElasticity_total(vm *v, int nargs, value *args) +{ functional_mapinfo info; linearelasticityref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { + if (functional_validateargs(v, nargs, args, &info)) + { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) + { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; functional_sumintegrand(v, &info, &out); - } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } + else + morpho_runtimeerror(v, LINEARELASTICITY_PRP); } return out; } /** Integrand function */ -value LinearElasticity_gradient(vm *v, int nargs, value *args) { +value LinearElasticity_gradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; linearelasticityref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { + if (functional_validateargs(v, nargs, args, &info)) + { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) + { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; info.sym = SYMMETRY_ADD; functional_mapnumericalgradient(v, &info, &out); - } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } + else + morpho_runtimeerror(v, LINEARELASTICITY_PRP); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(LinearElasticity) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LinearElasticity_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LinearElasticity_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LinearElasticity_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LinearElasticity_gradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * Flory-Huggins - * ---------------------------------------------- */ - -static value floryhuggins_aproperty; -static value floryhuggins_bproperty; -static value floryhuggins_cproperty; -static value floryhuggins_phi0property; - -typedef struct { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LinearElasticity_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LinearElasticity_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LinearElasticity_gradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * Hydrogel + * ---------------------------------------------- */ + + static value hydrogel_aproperty; +static value hydrogel_bproperty; +static value hydrogel_cproperty; +static value hydrogel_dproperty; +static value hydrogel_phirefproperty; +static value hydrogel_phi0property; + +typedef struct +{ objectmesh *refmesh; grade grade; - double a,b,c; // Flory-Huggins coefficients + double a, b, c, d, phiref; // Hydrogel coefficients + /* Add other parameters relevant to the elasticity term */ value phi0; // Can be a number or a field -} floryhugginsref; +} hydrogelref; /** Prepares the reference structure from the object's properties */ -bool floryhuggins_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, floryhugginsref *ref) { - bool success=false; - value refmesh=MORPHO_NIL, grade=MORPHO_NIL, phi0=MORPHO_NIL; - value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL; - +bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, hydrogelref *ref) +{ + bool success = false; + value refmesh = MORPHO_NIL, grade = MORPHO_NIL, phi0 = MORPHO_NIL; + value a = MORPHO_NIL, b = MORPHO_NIL, c = MORPHO_NIL, d = MORPHO_NIL, phiref = MORPHO_NIL; + /* Add other parameters relevant to the elasticity term */ if (objectinstance_getproperty(self, linearelasticity_referenceproperty, &refmesh) && objectinstance_getproperty(self, functional_gradeproperty, &grade) && MORPHO_ISINTEGER(grade) && - objectinstance_getproperty(self, floryhuggins_aproperty, &a) && + objectinstance_getproperty(self, hydrogel_aproperty, &a) && MORPHO_ISNUMBER(a) && - objectinstance_getproperty(self, floryhuggins_bproperty, &b) && + objectinstance_getproperty(self, hydrogel_bproperty, &b) && MORPHO_ISNUMBER(b) && - objectinstance_getproperty(self, floryhuggins_cproperty, &c) && + objectinstance_getproperty(self, hydrogel_cproperty, &c) && MORPHO_ISNUMBER(c) && - objectinstance_getproperty(self, floryhuggins_phi0property, &phi0) && - (MORPHO_ISNUMBER(phi0) || MORPHO_ISFIELD(phi0))) { - ref->refmesh=MORPHO_GETMESH(refmesh); - ref->grade=MORPHO_GETINTEGERVALUE(grade); - - if (ref->grade<0) ref->grade=mesh_maxgrade(mesh); + objectinstance_getproperty(self, hydrogel_dproperty, &d) && + MORPHO_ISNUMBER(d) && + objectinstance_getproperty(self, hydrogel_phirefproperty, &phiref) && + MORPHO_ISNUMBER(phiref) && + objectinstance_getproperty(self, hydrogel_phi0property, &phi0) && + (MORPHO_ISNUMBER(phi0) || MORPHO_ISFIELD(phi0))) + { + ref->refmesh = MORPHO_GETMESH(refmesh); + ref->grade = MORPHO_GETINTEGERVALUE(grade); + + if (ref->grade < 0) + ref->grade = mesh_maxgrade(mesh); if (morpho_valuetofloat(a, &ref->a) && morpho_valuetofloat(b, &ref->b) && - morpho_valuetofloat(c, &ref->c)) { + morpho_valuetofloat(c, &ref->c) && + morpho_valuetofloat(d, &ref->d) && + morpho_valuetofloat(phiref, &ref->phiref)) + { ref->phi0 = phi0; - success=true; + success = true; } } return success; } -/** Calculate the Flory-Huggins energy */ -bool floryhuggins_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - floryhugginsref *info = (floryhugginsref *) ref; +/** Calculate the Hydrogel energy */ +bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + hydrogelref *info = (hydrogelref *)ref; value vphi0 = info->phi0; - double V=0.0, V0=0.0, phi0=0.0; + double V = 0.0, V0 = 0.0, phi0 = 0.0; - if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) return false; - if (!functional_elementsize(v, mesh, info->grade, id, nv, vid, &V)) return false; + if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) + return false; + if (!functional_elementsize(v, mesh, info->grade, id, nv, vid, &V)) + return false; - if (V0<1e-8) printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); + if (V0 < 1e-8) + printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); - if (fabs(V)phi0)) { + if (MORPHO_ISFIELD(info->phi0)) + { objectfield *p = MORPHO_GETFIELD(info->phi0); field_getelement(p, info->grade, id, 0, &vphi0); } - if (MORPHO_ISNUMBER(vphi0)) { - if (!morpho_valuetofloat(vphi0, &phi0)) return false; + if (MORPHO_ISNUMBER(vphi0)) + { + if (!morpho_valuetofloat(vphi0, &phi0)) + return false; } - double phi = phi0/(V/V0); - - if (phi<0) printf("Warning: phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1-phi); - if (1-phi<0) printf("Warning: 1-phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1-phi); - - if (phi>1-MORPHO_EPS) phi = 1-MORPHO_EPS; - if (phia * phi*log(phi) + - info->b * (1-phi)*log(1-phi) + - info->c * phi*(1-phi))*V; - - if (phi<0 || 1-phi<0) return false; + double phi = phi0 / (V / V0); + double pr = info->phiref; + if (phi < 0) + printf("Warning: phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1 - phi); + if (1 - phi < 0) + printf("Warning: 1-phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1 - phi); + + if (phi > 1 - MORPHO_EPS) + phi = 1 - MORPHO_EPS; + if (phi < MORPHO_EPS) + phi = MORPHO_EPS; + /* Add other terms from the elasticity */ + *out = (info->a * phi * log(phi) + + info->b * (1 - phi) * log(1 - phi) + + info->c * phi * (1 - phi)) * + V + + info->d * (log(pr / phi) / 3.0 - pow((pr / phi), (2.0 / 3)) + 1.0) * V0; + + if (phi < 0 || 1 - phi < 0) + return false; return true; } -value FloryHuggins_init(vm *v, int nargs, value *args) { +value Hydrogel_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); int nfixed; - value grade=MORPHO_INTEGER(-1); - value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL, phi0=MORPHO_NIL; - - if (builtin_options(v, nargs, args, &nfixed, 5, - floryhuggins_aproperty, &a, - floryhuggins_bproperty, &b, - floryhuggins_cproperty, &c, - floryhuggins_phi0property, &phi0, - functional_gradeproperty, &grade)) { - - objectinstance_setproperty(self, floryhuggins_aproperty, a); - objectinstance_setproperty(self, floryhuggins_bproperty, b); - objectinstance_setproperty(self, floryhuggins_cproperty, c); - objectinstance_setproperty(self, floryhuggins_phi0property, phi0); + value grade = MORPHO_INTEGER(-1); + value a = MORPHO_NIL, b = MORPHO_NIL, c = MORPHO_NIL, d = MORPHO_NIL, phiref = MORPHO_NIL, phi0 = MORPHO_NIL; + + if (builtin_options(v, nargs, args, &nfixed, 6, + hydrogel_aproperty, &a, + hydrogel_bproperty, &b, + hydrogel_cproperty, &c, + hydrogel_dproperty, &d, + hydrogel_phirefproperty, &phiref, + hydrogel_phi0property, &phi0, + functional_gradeproperty, &grade)) + { + + objectinstance_setproperty(self, hydrogel_aproperty, a); + objectinstance_setproperty(self, hydrogel_bproperty, b); + objectinstance_setproperty(self, hydrogel_cproperty, c); + objectinstance_setproperty(self, hydrogel_dproperty, d); + objectinstance_setproperty(self, hydrogel_phirefproperty, phiref); + objectinstance_setproperty(self, hydrogel_phi0property, phi0); objectinstance_setproperty(self, functional_gradeproperty, grade); - if (nfixed==1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { + if (nfixed == 1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) + { objectinstance_setproperty(self, linearelasticity_referenceproperty, MORPHO_GETARG(args, 0)); - } else morpho_runtimeerror(v, FLORYHUGGINS_ARGS); - } else morpho_runtimeerror(v, FLORYHUGGINS_ARGS); + } + else + morpho_runtimeerror(v, HYDROGEL_ARGS); + } + else + morpho_runtimeerror(v, HYDROGEL_ARGS); return MORPHO_NIL; } -FUNCTIONAL_METHOD(FloryHuggins, integrand, (ref.grade), floryhugginsref, floryhuggins_prepareref, functional_mapintegrand, floryhuggins_integrand, NULL, FLORYHUGGINS_PRP, SYMMETRY_NONE) +FUNCTIONAL_METHOD(Hydrogel, integrand, (ref.grade), hydrogelref, hydrogel_prepareref, functional_mapintegrand, hydrogel_integrand, NULL, HYDROGEL_PRP, SYMMETRY_NONE) -FUNCTIONAL_METHOD(FloryHuggins, total, (ref.grade), floryhugginsref, floryhuggins_prepareref, functional_sumintegrand, floryhuggins_integrand, NULL, FLORYHUGGINS_PRP, SYMMETRY_NONE) +FUNCTIONAL_METHOD(Hydrogel, total, (ref.grade), hydrogelref, hydrogel_prepareref, functional_sumintegrand, hydrogel_integrand, NULL, HYDROGEL_PRP, SYMMETRY_NONE) -FUNCTIONAL_METHOD(FloryHuggins, gradient, (ref.grade), floryhugginsref, floryhuggins_prepareref, functional_mapnumericalgradient, floryhuggins_integrand, NULL, FLORYHUGGINS_PRP, SYMMETRY_ADD) +FUNCTIONAL_METHOD(Hydrogel, gradient, (ref.grade), hydrogelref, hydrogel_prepareref, functional_mapnumericalgradient, hydrogel_integrand, NULL, HYDROGEL_PRP, SYMMETRY_ADD) -MORPHO_BEGINCLASS(FloryHuggins) -MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, FloryHuggins_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, FloryHuggins_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, FloryHuggins_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, FloryHuggins_gradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS +MORPHO_BEGINCLASS(Hydrogel) +MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Hydrogel_init, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Hydrogel_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Hydrogel_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Hydrogel_gradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ---------------------------------------------- - * Equielement - * ---------------------------------------------- */ + /* ---------------------------------------------- + * Equielement + * ---------------------------------------------- */ -static value equielement_weightproperty; + static value equielement_weightproperty; -typedef struct { +typedef struct +{ grade grade; - objectsparse *vtoel; // Connect vertices to elements - objectsparse *eltov; // Connect elements to vertices + objectsparse *vtoel; // Connect vertices to elements + objectsparse *eltov; // Connect elements to vertices objectmatrix *weight; // Weight field double mean; } equielementref; /** Prepares the reference structure from the Equielement object's properties */ -bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, equielementref *ref) { - bool success=false; - value grade=MORPHO_NIL; - value weight=MORPHO_NIL; +bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, equielementref *ref) +{ + bool success = false; + value grade = MORPHO_NIL; + value weight = MORPHO_NIL; if (objectinstance_getproperty(self, functional_gradeproperty, &grade) && - MORPHO_ISINTEGER(grade) ) { - ref->grade=MORPHO_GETINTEGERVALUE(grade); - ref->weight=NULL; + MORPHO_ISINTEGER(grade)) + { + ref->grade = MORPHO_GETINTEGERVALUE(grade); + ref->weight = NULL; - int maxgrade=mesh_maxgrade(mesh); - if (ref->grade<0 || ref->grade>maxgrade) ref->grade = maxgrade; + int maxgrade = mesh_maxgrade(mesh); + if (ref->grade < 0 || ref->grade > maxgrade) + ref->grade = maxgrade; - ref->vtoel=mesh_addconnectivityelement(mesh, ref->grade, 0); - ref->eltov=mesh_addconnectivityelement(mesh, 0, ref->grade); + ref->vtoel = mesh_addconnectivityelement(mesh, ref->grade, 0); + ref->eltov = mesh_addconnectivityelement(mesh, 0, ref->grade); - if (ref->vtoel && ref->eltov) success=true; + if (ref->vtoel && ref->eltov) + success = true; } if (objectinstance_getproperty(self, equielement_weightproperty, &weight) && - MORPHO_ISMATRIX(weight) ) { - ref->weight=MORPHO_GETMATRIX(weight); - if (ref->weight) { - ref->mean=matrix_sum(ref->weight); - ref->mean/=ref->weight->ncols; + MORPHO_ISMATRIX(weight)) + { + ref->weight = MORPHO_GETMATRIX(weight); + if (ref->weight) + { + ref->mean = matrix_sum(ref->weight); + ref->mean /= ref->weight->ncols; } } @@ -1527,44 +1925,59 @@ bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, obj } /** Calculate the linear elastic energy */ -bool equielement_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *r, double *out) { - equielementref *ref = (equielementref *) r; +bool equielement_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *r, double *out) +{ + equielementref *ref = (equielementref *)r; int nconn, *conn; - if (sparseccs_getrowindices(&ref->vtoel->ccs, id, &nconn, &conn)) { - if (nconn==1) { *out = 0; return true; } + if (sparseccs_getrowindices(&ref->vtoel->ccs, id, &nconn, &conn)) + { + if (nconn == 1) + { + *out = 0; + return true; + } - double size[nconn], mean=0.0, total=0.0; + double size[nconn], mean = 0.0, total = 0.0; - for (int i=0; ieltov->ccs, conn[i], &nv, &vid); functional_elementsize(v, mesh, ref->grade, conn[i], nv, vid, &size[i]); - mean+=size[i]; + mean += size[i]; } - mean /= ((double) nconn); + mean /= ((double)nconn); - if (fabs(mean)weight || fabs(ref->mean)weight || fabs(ref->mean) < MORPHO_EPS) + { + for (unsigned int i = 0; i < nconn; i++) + total += (1.0 - size[i] / mean) * (1.0 - size[i] / mean); + } + else + { + double weight[nconn], wmean = 0.0; - for (int i=0; iweight, 0, conn[i], &weight[i]); - wmean+=weight[i]; + wmean += weight[i]; } - wmean /= ((double) nconn); - if (fabs(wmean)selection=sel; + ref->selection = sel; ref->lineel = mesh_getconnectivityelement(mesh, MESH_GRADE_VERTEX, MESH_GRADE_LINE); - if (ref->lineel) success=sparse_checkformat(ref->lineel, SPARSE_CCS, true, false); + if (ref->lineel) + success = sparse_checkformat(ref->lineel, SPARSE_CCS, true, false); - if (success) { + if (success) + { objectsparse *s = mesh_getconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); - if (!s) s=mesh_addconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); - success=s; + if (!s) + s = mesh_addconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); + success = s; } - if (success) { - value integrandonly=MORPHO_FALSE; + if (success) + { + value integrandonly = MORPHO_FALSE; objectinstance_getproperty(self, curvature_integrandonlyproperty, &integrandonly); - ref->integrandonly=MORPHO_ISTRUE(integrandonly); + ref->integrandonly = MORPHO_ISTRUE(integrandonly); } return success; } /** Finds the points that a point depends on */ -bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { +bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) +{ objectmesh *mesh = info->mesh; curvatureref *cref = info->ref; - bool success=false; + bool success = false; varray_elementid nbrs; varray_elementidinit(&nbrs); - if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs)>0) { - for (unsigned int i=0; i 0) + { + for (unsigned int i = 0; i < nbrs.count; i++) + { int nentries, *entries; // Get the vertices for this edge - if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) goto linecurvsq_dependencies_cleanup; - for (unsigned int j=0; jlineel->ccs, nbrs.data[i], &nentries, &entries)) + goto linecurvsq_dependencies_cleanup; + for (unsigned int j = 0; j < nentries; j++) + { + if (entries[j] == id) + continue; varray_elementidwrite(out, entries[j]); } } } - success=true; + success = true; /*printf("Vertex %u: ", id); for (int k=0; kcount; k++) printf("%u ", out->data[k]); printf("\n");*/ @@ -1670,51 +2099,64 @@ bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elem } /** Calculate the integral of the curvature squared */ -bool linecurvsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - curvatureref *cref = (curvatureref *) ref; +bool linecurvsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + curvatureref *cref = (curvatureref *)ref; double result = 0.0; varray_elementid nbrs; varray_elementid synid; varray_elementidinit(&nbrs); varray_elementidinit(&synid); - double s0[mesh->dim], s1[mesh->dim], *s[2] = { s0, s1}, sgn=-1.0; + double s0[mesh->dim], s1[mesh->dim], *s[2] = {s0, s1}, sgn = -1.0; - if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs)>0 && - mesh_getsynonyms(mesh, MESH_GRADE_VERTEX, id, &synid)) { - if (nbrs.count!=2) goto linecurvsq_integrand_cleanup; + if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs) > 0 && + mesh_getsynonyms(mesh, MESH_GRADE_VERTEX, id, &synid)) + { + if (nbrs.count != 2) + goto linecurvsq_integrand_cleanup; - for (unsigned int i=0; i<2; i++) { + for (unsigned int i = 0; i < 2; i++) + { int nentries, *entries; // Get the vertices for this edge - if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) break; + if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) + break; double *x0, *x1; if (mesh_getvertexcoordinatesaslist(mesh, entries[0], &x0) && - mesh_getvertexcoordinatesaslist(mesh, entries[1], &x1)) { + mesh_getvertexcoordinatesaslist(mesh, entries[1], &x1)) + { functional_vecsub(mesh->dim, x0, x1, s[i]); } - if (!(entries[0]==id || functional_inlist(&synid, entries[0]))) sgn*=-1; + if (!(entries[0] == id || functional_inlist(&synid, entries[0]))) + sgn *= -1; } - double s0s0=functional_vecdot(mesh->dim, s0, s0), - s0s1=functional_vecdot(mesh->dim, s0, s1), - s1s1=functional_vecdot(mesh->dim, s1, s1); + double s0s0 = functional_vecdot(mesh->dim, s0, s0), + s0s1 = functional_vecdot(mesh->dim, s0, s1), + s1s1 = functional_vecdot(mesh->dim, s1, s1); - s0s0=sqrt(s0s0); s1s1=sqrt(s1s1); + s0s0 = sqrt(s0s0); + s1s1 = sqrt(s1s1); - if (s0s0integrandonly) result /= len; // Get the bare curvature. + result = u * u / len; + if (cref->integrandonly) + result /= len; // Get the bare curvature. } linecurvsq_integrand_cleanup: - + *out = result; varray_elementidclear(&nbrs); varray_elementidclear(&synid); @@ -1729,36 +2171,41 @@ FUNCTIONAL_METHOD(LineCurvatureSq, gradient, MESH_GRADE_VERTEX, curvatureref, cu MORPHO_BEGINCLASS(LineCurvatureSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineCurvatureSq_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineCurvatureSq_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * LineTorsionSq - * ---------------------------------------------- */ - -/** Return a list of vertices that an element depends on */ -bool linetorsionsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineCurvatureSq_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * LineTorsionSq + * ---------------------------------------------- */ + + /** Return a list of vertices that an element depends on */ + bool linetorsionsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) +{ objectmesh *mesh = info->mesh; curvatureref *cref = info->ref; - bool success=false; + bool success = false; varray_elementid nbrs; varray_elementid synid; varray_elementidinit(&nbrs); varray_elementidinit(&synid); - if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs)>0) { - for (unsigned int i=0; i 0) + { + for (unsigned int i = 0; i < nbrs.count; i++) + { int nentries, *entries; // Get the vertices for this edge - if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) goto linetorsionsq_dependencies_cleanup; - for (unsigned int j=0; jlineel->ccs, nbrs.data[i], &nentries, &entries)) + goto linetorsionsq_dependencies_cleanup; + for (unsigned int j = 0; j < nentries; j++) + { varray_elementidwriteunique(out, entries[j]); } } } - success=true; + success = true; linetorsionsq_dependencies_cleanup: varray_elementidclear(&nbrs); @@ -1767,63 +2214,86 @@ bool linetorsionsq_dependencies(functional_mapinfo *info, elementid id, varray_e return success; } - /** Calculate the integral of the torsion squared */ -bool linetorsionsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - curvatureref *cref = (curvatureref *) ref; - int tmpi; elementid tmpid; - bool success=false; - - //double result = 0.0; +bool linetorsionsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + curvatureref *cref = (curvatureref *)ref; + int tmpi; + elementid tmpid; + bool success = false; + + // double result = 0.0; varray_elementid nbrs; varray_elementid synid; varray_elementidinit(&nbrs); varray_elementidinit(&synid); elementid vlist[6]; // List of vertices in order n int type[6]; - for (unsigned int i=0; i<6; i++) type[i]=-1; + for (unsigned int i = 0; i < 6; i++) + type[i] = -1; /* We want an ordered list of vertex indices: * v the element * 0 --- 1/2 --- 3/4 --- 5 * Where 1/2 and 3/4 are the same vertex, but could have different indices due to symmetries */ - vlist[2] = vid[0]; vlist[3] = vid[1]; // Copy the current element into place + vlist[2] = vid[0]; + vlist[3] = vid[1]; // Copy the current element into place /* First identify neighbors and get the vertex ids for each element */ - if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs)>0) { - if (nbrs.count<2) { - *out = 0; success=true; + if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs) > 0) + { + if (nbrs.count < 2) + { + *out = 0; + success = true; goto linecurvsq_torsion_cleanup; } - for (unsigned int i=0; ilineel->ccs, nbrs.data[i], &nentries, &entries)) goto linecurvsq_torsion_cleanup; - for (unsigned int j=0; jlineel->ccs, nbrs.data[i], &nentries, &entries)) + goto linecurvsq_torsion_cleanup; + for (unsigned int j = 0; j < nentries; j++) + { // Copy the vertexids + vlist[4 * i + j] = entries[j]; } } } /* The vertex ids are not yet in the right order. Let's identify which vertex is which */ - for (int i=0; i<2; i++) { - if (mesh_getsynonyms(mesh, 0, vid[i], &synid)) { - for (int j=0; j<6; j++) if (vlist[j]==vid[i] || functional_inlist(&synid, vlist[j])) type[j]=i; + for (int i = 0; i < 2; i++) + { + if (mesh_getsynonyms(mesh, 0, vid[i], &synid)) + { + for (int j = 0; j < 6; j++) + if (vlist[j] == vid[i] || functional_inlist(&synid, vlist[j])) + type[j] = i; } } /* The type array now contains either 0,1 depending on which vertex we have, or -1 if the vertex is not a synonym for the element's vertices */ -#define SWAP(var, i, j, tmp) { tmp=var[i]; var[i]=var[j]; var[j]=tmp; } - if (type[0]==1 || type[1]==1) { // Make sure the first segment corresponds to the first vertex - SWAP(vlist, 0, 4, tmpid); SWAP(vlist, 1, 5, tmpid); - SWAP(type, 0, 4, tmpi); SWAP(type, 1, 5, tmpi); - } - - if (type[1]==-1) { // Check order of first segment +#define SWAP(var, i, j, tmp) \ + { \ + tmp = var[i]; \ + var[i] = var[j]; \ + var[j] = tmp; \ + } + if (type[0] == 1 || type[1] == 1) + { // Make sure the first segment corresponds to the first vertex + SWAP(vlist, 0, 4, tmpid); + SWAP(vlist, 1, 5, tmpid); + SWAP(type, 0, 4, tmpi); + SWAP(type, 1, 5, tmpi); + } + + if (type[1] == -1) + { // Check order of first segment SWAP(vlist, 0, 1, tmpid); SWAP(type, 0, 1, tmpi); } - if (type[4]==-1) { // Check order of first segment + if (type[4] == -1) + { // Check order of first segment SWAP(vlist, 4, 5, tmpid); SWAP(type, 4, 5, tmpi); } @@ -1832,7 +2302,8 @@ bool linetorsionsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int /* We now have an ordered list of vertices. Get the vertex positions */ double *x[6]; - for (int i=0; i<6; i++) matrix_getcolumn(mesh->vert, vlist[i], &x[i]); + for (int i = 0; i < 6; i++) + matrix_getcolumn(mesh->vert, vlist[i], &x[i]); double A[3], B[3], C[3], crossAB[3], crossBC[3]; functional_vecsub(3, x[1], x[0], A); @@ -1842,17 +2313,19 @@ bool linetorsionsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int functional_veccross(A, B, crossAB); functional_veccross(B, C, crossBC); - double normB=functional_vecnorm(3, B), - normAB=functional_vecnorm(3, crossAB), - normBC=functional_vecnorm(3, crossBC); + double normB = functional_vecnorm(3, B), + normAB = functional_vecnorm(3, crossAB), + normBC = functional_vecnorm(3, crossBC); - double S = functional_vecdot(3, A, crossBC)*normB; - if (normAB>MORPHO_EPS) S/=normAB; - if (normBC>MORPHO_EPS) S/=normBC; + double S = functional_vecdot(3, A, crossBC) * normB; + if (normAB > MORPHO_EPS) + S /= normAB; + if (normBC > MORPHO_EPS) + S /= normBC; - S=asin(S); - *out=S*S/normB; - success=true; + S = asin(S); + *out = S * S / normB; + success = true; linecurvsq_torsion_cleanup: varray_elementidclear(&nbrs); @@ -1868,49 +2341,56 @@ FUNCTIONAL_METHOD(LineTorsionSq, gradient, MESH_GRADE_LINE, curvatureref, curvat MORPHO_BEGINCLASS(LineTorsionSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineTorsionSq_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineTorsionSq_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineTorsionSq_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineTorsionSq_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * MeanCurvatureSq - * ---------------------------------------------- */ - -typedef struct { - objectsparse *areael; // Areas + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineTorsionSq_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineTorsionSq_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineTorsionSq_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * MeanCurvatureSq + * ---------------------------------------------- */ + + typedef struct +{ + objectsparse *areael; // Areas objectselection *selection; // Selection - bool integrandonly; // Output integrated curvature or 'bare' curvature. + bool integrandonly; // Output integrated curvature or 'bare' curvature. } areacurvatureref; -bool areacurvature_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, areacurvatureref *ref) { +bool areacurvature_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, areacurvatureref *ref) +{ bool success = true; - ref->selection=sel; + ref->selection = sel; ref->areael = mesh_getconnectivityelement(mesh, MESH_GRADE_VERTEX, MESH_GRADE_AREA); - if (ref->areael) success=sparse_checkformat(ref->areael, SPARSE_CCS, true, false); + if (ref->areael) + success = sparse_checkformat(ref->areael, SPARSE_CCS, true, false); - if (success) { + if (success) + { objectsparse *s = mesh_getconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); - if (!s) s=mesh_addconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); - success=s; + if (!s) + s = mesh_addconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); + success = s; } - if (success) { - value integrandonly=MORPHO_FALSE; + if (success) + { + value integrandonly = MORPHO_FALSE; objectinstance_getproperty(self, curvature_integrandonlyproperty, &integrandonly); - ref->integrandonly=MORPHO_ISTRUE(integrandonly); + ref->integrandonly = MORPHO_ISTRUE(integrandonly); } return success; } /** Return a list of vertices that an element depends on */ -bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { +bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) +{ objectmesh *mesh = info->mesh; areacurvatureref *cref = info->ref; - bool success=false; + bool success = false; varray_elementid nbrs; varray_elementid synid; @@ -1923,16 +2403,20 @@ bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray /* Loop over synonyms of the element id */ mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) goto meancurvsq_dependencies_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) + goto meancurvsq_dependencies_cleanup; - for (unsigned int j=0; jcount; k++) if (synid->data[k]==vids[i]) { posn = i; break; } +bool curvature_ordervertices(varray_elementid *synid, int nv, int *vids) +{ + int posn = -1; + for (unsigned int i = 0; i < nv && posn < 0; i++) + { + for (unsigned int k = 0; k < synid->count; k++) + if (synid->data[k] == vids[i]) + { + posn = i; + break; + } } - if (posn>0) { // If the desired vertex isn't in first position, move it there. - int tmp=vids[posn]; - vids[posn]=vids[0]; vids[0]=tmp; + if (posn > 0) + { // If the desired vertex isn't in first position, move it there. + int tmp = vids[posn]; + vids[posn] = vids[0]; + vids[0] = tmp; } - return (posn>=0); + return (posn >= 0); } /** Calculate the integral of the mean curvature squared */ -bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - areacurvatureref *cref = (areacurvatureref *) ref; +bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + areacurvatureref *cref = (areacurvatureref *)ref; double areasum = 0; - bool success=false; + bool success = false; varray_elementid nbrs; varray_elementid synid; @@ -1971,20 +2465,25 @@ bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in varray_elementidwriteunique(&synid, id); double frc[mesh->dim]; // This will hold the total force due to the triangles present - for (unsigned int i=0; idim; i++) frc[i]=0.0; + for (unsigned int i = 0; i < mesh->dim; i++) + frc[i] = 0.0; mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) goto meancurvsq_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) + goto meancurvsq_cleanup; /* Order the vertices */ - if (!curvature_ordervertices(&synid, nvert, vids)) goto meancurvsq_cleanup; + if (!curvature_ordervertices(&synid, nvert, vids)) + goto meancurvsq_cleanup; double *x[3], s0[3], s1[3], s01[3], s101[3]; double norm; - for (int j=0; j<3; j++) matrix_getcolumn(mesh->vert, vids[j], &x[j]); + for (int j = 0; j < 3; j++) + matrix_getcolumn(mesh->vert, vids[j], &x[j]); /* s0 = x1-x0; s1 = x2-x1 */ functional_vecsub(mesh->dim, x[1], x[0], s0); @@ -1992,18 +2491,20 @@ bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in /* F(v0) = (s1 x s0 x s1)/|s0 x x1|/2 */ functional_veccross(s0, s1, s01); - norm=functional_vecnorm(mesh->dim, s01); - if (normdim, s01); + if (norm < MORPHO_EPS) + goto meancurvsq_cleanup; - areasum+=norm/2; + areasum += norm / 2; functional_veccross(s1, s01, s101); - functional_vecaddscale(mesh->dim, frc, 0.5/norm, s101, frc); + functional_vecaddscale(mesh->dim, frc, 0.5 / norm, s101, frc); } - *out = functional_vecdot(mesh->dim, frc, frc)/(areasum/3.0)/4.0; - if (cref->integrandonly) *out /= (areasum/3.0); - success=true; + *out = functional_vecdot(mesh->dim, frc, frc) / (areasum / 3.0) / 4.0; + if (cref->integrandonly) + *out /= (areasum / 3.0); + success = true; meancurvsq_cleanup: varray_elementidclear(&nbrs); @@ -2019,20 +2520,21 @@ FUNCTIONAL_METHOD(MeanCurvatureSq, gradient, MESH_GRADE_VERTEX, areacurvatureref MORPHO_BEGINCLASS(MeanCurvatureSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, MeanCurvatureSq_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, MeanCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, MeanCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, MeanCurvatureSq_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * GaussCurvature - * ---------------------------------------------- */ - -/** Calculate the integral of the gaussian curvature */ -bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - areacurvatureref *cref = (areacurvatureref *) ref; + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, MeanCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, MeanCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, MeanCurvatureSq_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * GaussCurvature + * ---------------------------------------------- */ + + /** Calculate the integral of the gaussian curvature */ + bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ + areacurvatureref *cref = (areacurvatureref *)ref; double anglesum = 0, areasum = 0; - bool success=false; + bool success = false; varray_elementid nbrs; varray_elementid synid; @@ -2043,19 +2545,24 @@ bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int varray_elementidwriteunique(&synid, id); double frc[mesh->dim]; // This will hold the total force due to the triangles present - for (unsigned int i=0; idim; i++) frc[i]=0.0; + for (unsigned int i = 0; i < mesh->dim; i++) + frc[i] = 0.0; mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) goto gausscurv_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) + goto gausscurv_cleanup; /* Order the vertices */ - if (!curvature_ordervertices(&synid, nvert, vids)) goto gausscurv_cleanup; + if (!curvature_ordervertices(&synid, nvert, vids)) + goto gausscurv_cleanup; double *x[3], s0[3], s1[3], s01[3]; - for (int j=0; j<3; j++) matrix_getcolumn(mesh->vert, vids[j], &x[j]); + for (int j = 0; j < 3; j++) + matrix_getcolumn(mesh->vert, vids[j], &x[j]); /* s0 = x1-x0; s1 = x2-x0 */ functional_vecsub(mesh->dim, x[1], x[0], s0); @@ -2063,14 +2570,15 @@ bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int functional_veccross(s0, s1, s01); double area = functional_vecnorm(mesh->dim, s01); - anglesum+=atan2(area, functional_vecdot(mesh->dim, s0, s1)); + anglesum += atan2(area, functional_vecdot(mesh->dim, s0, s1)); - areasum+=area/2; + areasum += area / 2; } - *out = 2*M_PI-anglesum; - if (cref->integrandonly) *out /= (areasum/3.0); - success=true; + *out = 2 * M_PI - anglesum; + if (cref->integrandonly) + *out /= (areasum / 3.0); + success = true; gausscurv_cleanup: varray_elementidclear(&nbrs); @@ -2086,16 +2594,17 @@ FUNCTIONAL_METHOD(GaussCurvature, gradient, MESH_GRADE_VERTEX, areacurvatureref, MORPHO_BEGINCLASS(GaussCurvature) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GaussCurvature_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GaussCurvature_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GaussCurvature_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GaussCurvature_total, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GaussCurvature_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GaussCurvature_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GaussCurvature_total, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ********************************************************************** - * Fields - * ********************************************************************** */ + /* ********************************************************************** + * Fields + * ********************************************************************** */ -typedef struct { + typedef struct +{ objectfield *field; grade grade; } fieldref; @@ -2104,23 +2613,26 @@ typedef struct { * GradSq * ---------------------------------------------- */ -bool gradsq_computeperpendicular(unsigned int n, double *s1, double *s2, double *out) { +bool gradsq_computeperpendicular(unsigned int n, double *s1, double *s2, double *out) +{ double s1s2, s2s2, sout; /* Compute s1 - (s1.s2) s2 / (s2.2) */ s1s2 = functional_vecdot(n, s1, s2); s2s2 = functional_vecdot(n, s2, s2); - if (fabs(s2s2)psize * mesh->dim units of storage */ -bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) { +bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) +{ double *f[nv]; // Field value lists double *x[nv]; // Vertex coordinates - unsigned int nentries=0; + unsigned int nentries = 0; // Get field values and vertex coordinates - for (unsigned int i=0; idim], t[3][mesh->dim]; @@ -2154,10 +2670,13 @@ bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int * gradsq_computeperpendicular(mesh->dim, s[1], s[0], t[2]); /* Compute the gradient */ - for (unsigned int i=0; idim*nentries; i++) out[i]=0; - for (unsigned int j=0; jdim; j++) { - for (unsigned int i=0; idim, &out[i*mesh->dim], f[j][i], t[j], &out[i*mesh->dim]); + for (unsigned int i = 0; i < mesh->dim * nentries; i++) + out[i] = 0; + for (unsigned int j = 0; j < mesh->dim; j++) + { + for (unsigned int i = 0; i < nentries; i++) + { + functional_vecaddscale(mesh->dim, &out[i * mesh->dim], f[j][i], t[j], &out[i * mesh->dim]); } } @@ -2170,103 +2689,131 @@ bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int * @param[in] nv - number of vertices @param[in] vid - vertex ids @param[out] out - should be field->psize * mesh->dim units of storage */ -bool gradsq_evaluategradient3d(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) { - double *f[nv]; // Field value lists - double *x[nv]; // Vertex coordinates - double xarray[nv*mesh->dim]; // Vertex coordinates - double xtarray[nv*mesh->dim]; // Vertex coordinates - unsigned int nentries=0; +bool gradsq_evaluategradient3d(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) +{ + double *f[nv]; // Field value lists + double *x[nv]; // Vertex coordinates + double xarray[nv * mesh->dim]; // Vertex coordinates + double xtarray[nv * mesh->dim]; // Vertex coordinates + unsigned int nentries = 0; // Get field values and vertex coordinates - for (unsigned int i=0; idim, x[i], x[0], &xarray[(i-1)*mesh->dim]); + for (unsigned int i = 1; i < nv; i++) + { + functional_vecsub(mesh->dim, x[i], x[0], &xarray[(i - 1) * mesh->dim]); } - - for (unsigned int i=0; idim*nentries; i++) out[i]=0; - + + for (unsigned int i = 0; i < mesh->dim * nentries; i++) + out[i] = 0; + objectmatrix M = MORPHO_STATICMATRIX(xarray, mesh->dim, mesh->dim); objectmatrix Mt = MORPHO_STATICMATRIX(xtarray, mesh->dim, mesh->dim); matrix_transpose(&M, &Mt); - - double farray[nentries*mesh->dim]; // Field elements + + double farray[nentries * mesh->dim]; // Field elements objectmatrix frhs = MORPHO_STATICMATRIX(farray, mesh->dim, nentries); objectmatrix grad = MORPHO_STATICMATRIX(out, mesh->dim, nentries); - + // Loop over elements of the field - for (unsigned int i=0; idim; j++) farray[i*mesh->dim+j] = f[j+1][i]-f[0][i]; + for (unsigned int j = 0; j < mesh->dim; j++) + farray[i * mesh->dim + j] = f[j + 1][i] - f[0][i]; } - + // Solve to obtain the gradient of each element matrix_divs(&Mt, &frhs, &grad); - + return true; } /** Prepares the gradsq reference */ -bool gradsq_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, fieldref *ref) { - bool success=false, grdset=false; - value field=MORPHO_NIL, grd=MORPHO_NIL; - +bool gradsq_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, fieldref *ref) +{ + bool success = false, grdset = false; + value field = MORPHO_NIL, grd = MORPHO_NIL; + if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISFIELD(field)) { - ref->field=MORPHO_GETFIELD(field); - success=true; + MORPHO_ISFIELD(field)) + { + ref->field = MORPHO_GETFIELD(field); + success = true; } - + if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) { - ref->grade=MORPHO_GETINTEGERVALUE(grd); - if (ref->grade>0) grdset=true; + MORPHO_ISINTEGER(grd)) + { + ref->grade = MORPHO_GETINTEGERVALUE(grd); + if (ref->grade > 0) + grdset = true; } - if (!grdset) ref->grade=mesh_maxgrade(mesh); - + if (!grdset) + ref->grade = mesh_maxgrade(mesh); + return success; } /** Calculate the |grad q|^2 energy */ -bool gradsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { +bool gradsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ fieldref *eref = ref; - double size=0; // Length area or volume of the element - double grad[eref->field->psize*mesh->dim]; + double size = 0; // Length area or volume of the element + double grad[eref->field->psize * mesh->dim]; - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) + return false; - if (eref->grade==2) { - if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, grad)) return false; - } else if (eref->grade==3) { - if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, grad)) return false; - } else { + if (eref->grade == 2) + { + if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, grad)) + return false; + } + else if (eref->grade == 3) + { + if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, grad)) + return false; + } + else + { return false; } - - double gradnrm=functional_vecnorm(eref->field->psize*mesh->dim, grad); - *out = gradnrm*gradnrm*size; + + double gradnrm = functional_vecnorm(eref->field->psize * mesh->dim, grad); + *out = gradnrm * gradnrm * size; return true; } /** Initialize a GradSq object */ -value GradSq_init(vm *v, int nargs, value *args) { +value GradSq_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - if (nargs>0 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) { + if (nargs > 0 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) + { objectinstance_setproperty(self, functional_fieldproperty, MORPHO_GETARG(args, 0)); - } else { + } + else + { morpho_runtimeerror(v, VM_INVALIDARGS); return MORPHO_FALSE; } - + /* Second (optional) argument is the grade to act on */ - if (nargs>1) { - if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) { + if (nargs > 1) + { + if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) + { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_GETARG(args, 1)); } } @@ -2280,138 +2827,171 @@ FUNCTIONAL_METHOD(GradSq, total, (ref.grade), fieldref, gradsq_prepareref, funct FUNCTIONAL_METHOD(GradSq, gradient, (ref.grade), fieldref, gradsq_prepareref, functional_mapnumericalgradient, gradsq_integrand, NULL, GRADSQ_ARGS, SYMMETRY_ADD); -value GradSq_fieldgradient(vm *v, int nargs, value *args) { +value GradSq_fieldgradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; fieldref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { + if (functional_validateargs(v, nargs, args, &info)) + { + if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) + { info.g = ref.grade; info.field = ref.field; info.integrand = gradsq_integrand; info.ref = &ref; functional_mapnumericalfieldgradient(v, &info, &out); - } else morpho_runtimeerror(v, GRADSQ_ARGS); + } + else + morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(GradSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GradSq_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GradSq_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GradSq_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GradSq_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, GradSq_fieldgradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GradSq_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GradSq_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GradSq_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, GradSq_fieldgradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ---------------------------------------------- - * Nematic - * ---------------------------------------------- */ + /* ---------------------------------------------- + * Nematic + * ---------------------------------------------- */ -static value nematic_ksplayproperty; + static value nematic_ksplayproperty; static value nematic_ktwistproperty; static value nematic_kbendproperty; static value nematic_pitchproperty; -typedef struct { - double ksplay,ktwist,kbend,pitch; +typedef struct +{ + double ksplay, ktwist, kbend, pitch; bool haspitch; objectfield *field; grade grade; } nematicref; /** Prepares the nematic reference */ -bool nematic_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicref *ref) { - bool success=false, grdset=false; - value field=MORPHO_NIL, grd=MORPHO_NIL; - value val=MORPHO_NIL; - ref->ksplay=1.0; ref->ktwist=1.0; ref->kbend=1.0; ref->pitch=0.0; - ref->haspitch=false; +bool nematic_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicref *ref) +{ + bool success = false, grdset = false; + value field = MORPHO_NIL, grd = MORPHO_NIL; + value val = MORPHO_NIL; + ref->ksplay = 1.0; + ref->ktwist = 1.0; + ref->kbend = 1.0; + ref->pitch = 0.0; + ref->haspitch = false; if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISFIELD(field)) { - ref->field=MORPHO_GETFIELD(field); - success=true; + MORPHO_ISFIELD(field)) + { + ref->field = MORPHO_GETFIELD(field); + success = true; } - if (objectinstance_getproperty(self, nematic_ksplayproperty, &val) && MORPHO_ISNUMBER(val)) { + if (objectinstance_getproperty(self, nematic_ksplayproperty, &val) && MORPHO_ISNUMBER(val)) + { morpho_valuetofloat(val, &ref->ksplay); } - if (objectinstance_getproperty(self, nematic_ktwistproperty, &val) && MORPHO_ISNUMBER(val)) { + if (objectinstance_getproperty(self, nematic_ktwistproperty, &val) && MORPHO_ISNUMBER(val)) + { morpho_valuetofloat(val, &ref->ktwist); } - if (objectinstance_getproperty(self, nematic_kbendproperty, &val) && MORPHO_ISNUMBER(val)) { + if (objectinstance_getproperty(self, nematic_kbendproperty, &val) && MORPHO_ISNUMBER(val)) + { morpho_valuetofloat(val, &ref->kbend); } - if (objectinstance_getproperty(self, nematic_pitchproperty, &val) && MORPHO_ISNUMBER(val)) { + if (objectinstance_getproperty(self, nematic_pitchproperty, &val) && MORPHO_ISNUMBER(val)) + { morpho_valuetofloat(val, &ref->pitch); - ref->haspitch=true; + ref->haspitch = true; } - + if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) { - ref->grade=MORPHO_GETINTEGERVALUE(grd); - if (ref->grade>0) grdset=true; + MORPHO_ISINTEGER(grd)) + { + ref->grade = MORPHO_GETINTEGERVALUE(grd); + if (ref->grade > 0) + grdset = true; } - if (!grdset) ref->grade=mesh_maxgrade(mesh); - + if (!grdset) + ref->grade = mesh_maxgrade(mesh); + return success; } /* Integrates two linear functions with values at vertices f[0]...f[2] and g[0]...g[2] */ -double nematic_bcint(double *f, double *g) { - return (f[0]*(2*g[0]+g[1]+g[2]) + f[1]*(g[0]+2*g[1]+g[2]) + f[2]*(g[0]+g[1]+2*g[2]))/12; +double nematic_bcint(double *f, double *g) +{ + return (f[0] * (2 * g[0] + g[1] + g[2]) + f[1] * (g[0] + 2 * g[1] + g[2]) + f[2] * (g[0] + g[1] + 2 * g[2])) / 12; } /* Integrates a linear vector function with values at vertices f[0]...f[2] */ -double nematic_bcint1(double *f) { - return (f[0] + f[1] + f[2])/3; +double nematic_bcint1(double *f) +{ + return (f[0] + f[1] + f[2]) / 3; } /* Integrates a linear vector function with values at vertices f[0]...f[n] Works for dimensions 1-3 at least */ -double nematic_bcintf(unsigned int n, double *f) { +double nematic_bcintf(unsigned int n, double *f) +{ double sum = 0; - for (unsigned int i=0; ifield->psize*mesh->dim]; + double size = 0; // Length area or volume of the element + double gradnn[eref->field->psize * mesh->dim]; double divnn, curlnn[mesh->dim]; - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) + return false; // Get nematic director components double *nn[nv]; // Field value lists - unsigned int nentries=0; - for (unsigned int i=0; ifield, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) return false; + unsigned int nentries = 0; + for (unsigned int i = 0; i < nv; i++) + { + if (!field_getelementaslist(eref->field, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) + return false; } // Evaluate gradients of the director - if (eref->grade==2) { - if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, gradnn)) return - false; - } else if (eref->grade==3) { - if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, gradnn)) return - false; + if (eref->grade == 2) + { + if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, gradnn)) + return false; + } + else if (eref->grade == 3) + { + if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, gradnn)) + return false; } // Output of this is the matrix: // [ nx,x ny,x nz,x ] [ 0 3 6 ] <- indices @@ -2420,81 +3000,91 @@ bool nematic_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, objectmatrix gradnnmat = MORPHO_STATICMATRIX(gradnn, mesh->dim, mesh->dim); matrix_trace(&gradnnmat, &divnn); - curlnn[0]=gradnn[7]-gradnn[5]; // nz,y - ny,z - curlnn[1]=gradnn[2]-gradnn[6]; // nx,z - nz,x - curlnn[2]=gradnn[3]-gradnn[1]; // ny,x - nx,y + curlnn[0] = gradnn[7] - gradnn[5]; // nz,y - ny,z + curlnn[1] = gradnn[2] - gradnn[6]; // nx,z - nz,x + curlnn[2] = gradnn[3] - gradnn[1]; // ny,x - nx,y /* From components of the curl, construct the coefficients that go in front of integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element. */ - double ctwst[6] = { curlnn[0]*curlnn[0], curlnn[1]*curlnn[1], curlnn[2]*curlnn[2], - 2*curlnn[0]*curlnn[1], 2*curlnn[1]*curlnn[2], 2*curlnn[2]*curlnn[0]}; + double ctwst[6] = {curlnn[0] * curlnn[0], curlnn[1] * curlnn[1], curlnn[2] * curlnn[2], + 2 * curlnn[0] * curlnn[1], 2 * curlnn[1] * curlnn[2], 2 * curlnn[2] * curlnn[0]}; - double cbnd[6] = { ctwst[1] + ctwst[2], ctwst[0] + ctwst[2], ctwst[0] + ctwst[1], - -ctwst[3], -ctwst[4], -ctwst[5] }; + double cbnd[6] = {ctwst[1] + ctwst[2], ctwst[0] + ctwst[2], ctwst[0] + ctwst[1], + -ctwst[3], -ctwst[4], -ctwst[5]}; /* Calculate integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element */ double nnt[mesh->dim][nv]; // The transpose of nn - for (unsigned int i=0; idim; j++) nnt[j][i]=nn[i][j]; + for (unsigned int i = 0; i < nv; i++) + for (unsigned int j = 0; j < mesh->dim; j++) + nnt[j][i] = nn[i][j]; - double integrals[] = { nematic_bcintfg(nv, nnt[0], nnt[0]), - nematic_bcintfg(nv, nnt[1], nnt[1]), - nematic_bcintfg(nv, nnt[2], nnt[2]), - nematic_bcintfg(nv, nnt[0], nnt[1]), - nematic_bcintfg(nv, nnt[1], nnt[2]), - nematic_bcintfg(nv, nnt[2], nnt[0]) - }; + double integrals[] = {nematic_bcintfg(nv, nnt[0], nnt[0]), + nematic_bcintfg(nv, nnt[1], nnt[1]), + nematic_bcintfg(nv, nnt[2], nnt[2]), + nematic_bcintfg(nv, nnt[0], nnt[1]), + nematic_bcintfg(nv, nnt[1], nnt[2]), + nematic_bcintfg(nv, nnt[2], nnt[0])}; /* Now we can calculate the components of splay, twist and bend */ - double splay=0.0, twist=0.0, bend=0.0, chol=0.0; + double splay = 0.0, twist = 0.0, bend = 0.0, chol = 0.0; /* Evaluate the three contributions to the integral */ - splay = 0.5*eref->ksplay*size*divnn*divnn; - for (unsigned int i=0; i<6; i++) { - twist += ctwst[i]*integrals[i]; - bend += cbnd[i]*integrals[i]; + splay = 0.5 * eref->ksplay * size * divnn * divnn; + for (unsigned int i = 0; i < 6; i++) + { + twist += ctwst[i] * integrals[i]; + bend += cbnd[i] * integrals[i]; } - twist *= 0.5*eref->ktwist*size; - bend *= 0.5*eref->kbend*size; + twist *= 0.5 * eref->ktwist * size; + bend *= 0.5 * eref->kbend * size; - if (eref->haspitch) { + if (eref->haspitch) + { /* Cholesteric terms: 0.5 * k22 * [- 2 q (cx + cy + cz ) + q^2] */ - for (unsigned i=0; i<3; i++) { - chol += -2*curlnn[i]*nematic_bcintf(nv, nnt[i])*eref->pitch; + for (unsigned i = 0; i < 3; i++) + { + chol += -2 * curlnn[i] * nematic_bcintf(nv, nnt[i]) * eref->pitch; } - chol += (eref->pitch*eref->pitch); - chol *= 0.5*eref->ktwist*size; + chol += (eref->pitch * eref->pitch); + chol *= 0.5 * eref->ktwist * size; } - *out = splay+twist+bend+chol; + *out = splay + twist + bend + chol; return true; } /** Initialize a Nematic object */ -value Nematic_init(vm *v, int nargs, value *args) { +value Nematic_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - int nfixed=nargs; - value ksplay=MORPHO_FLOAT(1.0), - ktwist=MORPHO_FLOAT(1.0), - kbend=MORPHO_FLOAT(1.0); - value pitch=MORPHO_NIL; + int nfixed = nargs; + value ksplay = MORPHO_FLOAT(1.0), + ktwist = MORPHO_FLOAT(1.0), + kbend = MORPHO_FLOAT(1.0); + value pitch = MORPHO_NIL; if (builtin_options(v, nargs, args, &nfixed, 4, nematic_ksplayproperty, &ksplay, nematic_ktwistproperty, &ktwist, nematic_kbendproperty, &kbend, - nematic_pitchproperty, &pitch)) { + nematic_pitchproperty, &pitch)) + { objectinstance_setproperty(self, nematic_ksplayproperty, ksplay); objectinstance_setproperty(self, nematic_ktwistproperty, ktwist); objectinstance_setproperty(self, nematic_kbendproperty, kbend); objectinstance_setproperty(self, nematic_pitchproperty, pitch); - } else morpho_runtimeerror(v, NEMATIC_ARGS); + } + else + morpho_runtimeerror(v, NEMATIC_ARGS); - if (nfixed==1 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) { + if (nfixed == 1 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) + { objectinstance_setproperty(self, functional_fieldproperty, MORPHO_GETARG(args, 0)); - } else morpho_runtimeerror(v, NEMATIC_ARGS); + } + else + morpho_runtimeerror(v, NEMATIC_ARGS); return MORPHO_NIL; } @@ -2505,124 +3095,154 @@ FUNCTIONAL_METHOD(Nematic, total, (ref.grade), nematicref, nematic_prepareref, f FUNCTIONAL_METHOD(Nematic, gradient, (ref.grade), nematicref, nematic_prepareref, functional_mapnumericalgradient, nematic_integrand, NULL, NEMATIC_ARGS, SYMMETRY_NONE); -value Nematic_fieldgradient(vm *v, int nargs, value *args) { +value Nematic_fieldgradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; nematicref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (nematic_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { - info.g=ref.grade; - info.integrand=nematic_integrand; - info.ref=&ref; + if (functional_validateargs(v, nargs, args, &info)) + { + if (nematic_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) + { + info.g = ref.grade; + info.integrand = nematic_integrand; + info.ref = &ref; functional_mapnumericalfieldgradient(v, &info, &out); - } else morpho_runtimeerror(v, GRADSQ_ARGS); + } + else + morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(Nematic) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Nematic_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Nematic_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Nematic_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Nematic_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, Nematic_fieldgradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * NematicElectric - * ---------------------------------------------- */ - -typedef struct { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Nematic_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Nematic_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Nematic_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, Nematic_fieldgradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * NematicElectric + * ---------------------------------------------- */ + + typedef struct +{ objectfield *director; value field; grade grade; } nematicelectricref; /** Prepares the nematicelectric reference */ -bool nematicelectric_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicelectricref *ref) { - bool success=false, grdset=false; - ref->field=MORPHO_NIL; - value fieldlist=MORPHO_NIL, grd=MORPHO_NIL; +bool nematicelectric_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicelectricref *ref) +{ + bool success = false, grdset = false; + ref->field = MORPHO_NIL; + value fieldlist = MORPHO_NIL, grd = MORPHO_NIL; if (objectinstance_getproperty(self, functional_fieldproperty, &fieldlist) && - MORPHO_ISLIST(fieldlist)) { + MORPHO_ISLIST(fieldlist)) + { objectlist *lst = MORPHO_GETLIST(fieldlist); value director = MORPHO_NIL; list_getelement(lst, 0, &director); list_getelement(lst, 1, &ref->field); - if (MORPHO_ISFIELD(director)) ref->director=MORPHO_GETFIELD(director); + if (MORPHO_ISFIELD(director)) + ref->director = MORPHO_GETFIELD(director); - if (MORPHO_ISFIELD(ref->field) || MORPHO_ISMATRIX(ref->field)) success=true; + if (MORPHO_ISFIELD(ref->field) || MORPHO_ISMATRIX(ref->field)) + success = true; } if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) { - ref->grade=MORPHO_GETINTEGERVALUE(grd); - if (ref->grade>0) grdset=true; + MORPHO_ISINTEGER(grd)) + { + ref->grade = MORPHO_GETINTEGERVALUE(grd); + if (ref->grade > 0) + grdset = true; } - if (!grdset) ref->grade=mesh_maxgrade(mesh); - + if (!grdset) + ref->grade = mesh_maxgrade(mesh); + return success; } /** Calculate the integral (n.E)^2 energy, where E is calculated from the electric potential */ -bool nematicelectric_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { +bool nematicelectric_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ nematicelectricref *eref = ref; - double size=0; // Length area or volume of the element + double size = 0; // Length area or volume of the element - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) + return false; // Get nematic director components double *nn[nv]; // Field value lists - unsigned int nentries=0; - for (unsigned int i=0; idirector, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) return false; + unsigned int nentries = 0; + for (unsigned int i = 0; i < nv; i++) + { + if (!field_getelementaslist(eref->director, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) + return false; } // The electric field ends up being constant over the element double ee[mesh->dim]; - if (MORPHO_ISFIELD(eref->field)) { - if (eref->grade==2) { - if (!gradsq_evaluategradient(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) return false; - } else if (eref->grade==3) { - if (!gradsq_evaluategradient3d(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) return false; + if (MORPHO_ISFIELD(eref->field)) + { + if (eref->grade == 2) + { + if (!gradsq_evaluategradient(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) + return false; + } + else if (eref->grade == 3) + { + if (!gradsq_evaluategradient3d(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) + return false; } } /* Calculate integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element */ double nnt[mesh->dim][nv]; // The transpose of nn - for (unsigned int i=0; idim; j++) nnt[j][i]=nn[i][j]; + for (unsigned int i = 0; i < nv; i++) + for (unsigned int j = 0; j < mesh->dim; j++) + nnt[j][i] = nn[i][j]; /* Calculate integral (n.e)^2 using the above results */ - double total = ee[0]*ee[0]*nematic_bcintfg(nv, nnt[0], nnt[0])+ - ee[1]*ee[1]*nematic_bcintfg(nv, nnt[1], nnt[1])+ - ee[2]*ee[2]*nematic_bcintfg(nv, nnt[2], nnt[2])+ - 2*ee[0]*ee[1]*nematic_bcintfg(nv, nnt[0], nnt[1])+ - 2*ee[1]*ee[2]*nematic_bcintfg(nv, nnt[1], nnt[2])+ - 2*ee[2]*ee[0]*nematic_bcintfg(nv, nnt[2], nnt[0]); + double total = ee[0] * ee[0] * nematic_bcintfg(nv, nnt[0], nnt[0]) + + ee[1] * ee[1] * nematic_bcintfg(nv, nnt[1], nnt[1]) + + ee[2] * ee[2] * nematic_bcintfg(nv, nnt[2], nnt[2]) + + 2 * ee[0] * ee[1] * nematic_bcintfg(nv, nnt[0], nnt[1]) + + 2 * ee[1] * ee[2] * nematic_bcintfg(nv, nnt[1], nnt[2]) + + 2 * ee[2] * ee[0] * nematic_bcintfg(nv, nnt[2], nnt[0]); - *out = size*total; + *out = size * total; return true; } /** Initialize a NematicElectric object */ -value NematicElectric_init(vm *v, int nargs, value *args) { +value NematicElectric_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - if (nargs==2 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0)) && - MORPHO_ISFIELD(MORPHO_GETARG(args, 1))) { + if (nargs == 2 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0)) && + MORPHO_ISFIELD(MORPHO_GETARG(args, 1))) + { objectlist *new = object_newlist(2, &MORPHO_GETARG(args, 0)); - if (new) { + if (new) + { value lst = MORPHO_OBJECT(new); objectinstance_setproperty(self, functional_fieldproperty, lst); morpho_bindobjects(v, 1, &lst); } - } else morpho_runtimeerror(v, NEMATICELECTRIC_ARGS); + } + else + morpho_runtimeerror(v, NEMATICELECTRIC_ARGS); return MORPHO_NIL; } @@ -2633,42 +3253,50 @@ FUNCTIONAL_METHOD(NematicElectric, total, (ref.grade), nematicelectricref, nemat FUNCTIONAL_METHOD(NematicElectric, gradient, (ref.grade), nematicelectricref, nematicelectric_prepareref, functional_mapnumericalgradient, nematicelectric_integrand, NULL, FUNCTIONAL_ARGS, SYMMETRY_NONE); -value NematicElectric_fieldgradient(vm *v, int nargs, value *args) { +value NematicElectric_fieldgradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; nematicelectricref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { - if (nematicelectric_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { - info.g=ref.grade; - info.integrand=nematicelectric_integrand; - info.ref=&ref; + if (functional_validateargs(v, nargs, args, &info)) + { + if (nematicelectric_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) + { + info.g = ref.grade; + info.integrand = nematicelectric_integrand; + info.ref = &ref; functional_mapnumericalfieldgradient(v, &info, &out); - } else morpho_runtimeerror(v, GRADSQ_ARGS); + } + else + morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(NematicElectric) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, NematicElectric_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NematicElectric_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NematicElectric_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NematicElectric_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NematicElectric_fieldgradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ---------------------------------------------- - * NormSq - * ---------------------------------------------- */ - -/** Calculate the norm squared of a field quantity */ -bool normsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NematicElectric_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NematicElectric_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NematicElectric_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NematicElectric_fieldgradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ---------------------------------------------- + * NormSq + * ---------------------------------------------- */ + + /** Calculate the norm squared of a field quantity */ + bool normsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ fieldref *eref = ref; unsigned int nentries; double *entries; - if (field_getelementaslist(eref->field, MESH_GRADE_VERTEX, id, 0, &nentries, &entries)) { + if (field_getelementaslist(eref->field, MESH_GRADE_VERTEX, id, 0, &nentries, &entries)) + { *out = functional_vecdot(nentries, entries, entries); return true; } @@ -2682,49 +3310,57 @@ FUNCTIONAL_METHOD(NormSq, total, MESH_GRADE_VERTEX, fieldref, gradsq_prepareref, FUNCTIONAL_METHOD(NormSq, gradient, MESH_GRADE_AREA, fieldref, gradsq_prepareref, functional_mapnumericalgradient, normsq_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); -value NormSq_fieldgradient(vm *v, int nargs, value *args) { +value NormSq_fieldgradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; fieldref ref; - value out=MORPHO_NIL; - - if (functional_validateargs(v, nargs, args, &info)) { - if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_VERTEX, info.sel, &ref)) { - info.g=MESH_GRADE_VERTEX; - info.ref=&ref; - info.field=ref.field; - info.integrand=normsq_integrand; + value out = MORPHO_NIL; + + if (functional_validateargs(v, nargs, args, &info)) + { + if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_VERTEX, info.sel, &ref)) + { + info.g = MESH_GRADE_VERTEX; + info.ref = &ref; + info.field = ref.field; + info.integrand = normsq_integrand; functional_mapnumericalfieldgradient(v, &info, &out); - } else morpho_runtimeerror(v, GRADSQ_ARGS); + } + else + morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(NormSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GradSq_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NormSq_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NormSq_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NormSq_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NormSq_fieldgradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NormSq_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NormSq_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NormSq_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NormSq_fieldgradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS -/* ********************************************************************** - * Integrals - * ********************************************************************** */ + /* ********************************************************************** + * Integrals + * ********************************************************************** */ -/* ---------------------------------------------- - * Integrand functions - * ---------------------------------------------- */ + /* ---------------------------------------------- + * Integrand functions + * ---------------------------------------------- */ -value tangent; + value tangent; -static value functional_tangent(vm *v, int nargs, value *args) { +static value functional_tangent(vm *v, int nargs, value *args) +{ return tangent; } value norml; -static value functional_normal(vm *v, int nargs, value *args) { +static value functional_normal(vm *v, int nargs, value *args) +{ return norml; } @@ -2732,7 +3368,8 @@ static value functional_normal(vm *v, int nargs, value *args) { * LineIntegral * ---------------------------------------------- */ -typedef struct { +typedef struct +{ value integrand; int nfields; value *fields; @@ -2740,37 +3377,43 @@ typedef struct { } integralref; /** Prepares an integral reference */ -bool integral_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, integralref *ref) { - bool success=false; - value func=MORPHO_NIL; - value field=MORPHO_NIL; - ref->v=NULL; - ref->nfields=0; +bool integral_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, integralref *ref) +{ + bool success = false; + value func = MORPHO_NIL; + value field = MORPHO_NIL; + ref->v = NULL; + ref->nfields = 0; if (objectinstance_getproperty(self, scalarpotential_functionproperty, &func) && - MORPHO_ISCALLABLE(func)) { - ref->integrand=func; - success=true; + MORPHO_ISCALLABLE(func)) + { + ref->integrand = func; + success = true; } if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISLIST(field)) { + MORPHO_ISLIST(field)) + { objectlist *list = MORPHO_GETLIST(field); - ref->nfields=list->val.count; - ref->fields=list->val.data; + ref->nfields = list->val.count; + ref->fields = list->val.data; } return success; } -bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int nquantity, value *quantity, void *ref, double *fout) { +bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int nquantity, value *quantity, void *ref, double *fout) +{ integralref *iref = ref; objectmatrix posn = MORPHO_STATICMATRIX(x, dim, 1); - value args[nquantity+1], out; + value args[nquantity + 1], out; - args[0]=MORPHO_OBJECT(&posn); - for (unsigned int i=0; iv, iref->integrand, nquantity+1, args, &out)) { - morpho_valuetofloat(out,fout); + if (morpho_call(iref->v, iref->integrand, nquantity + 1, args, &out)) + { + morpho_valuetofloat(out, fout); return true; } @@ -2778,36 +3421,43 @@ bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int n } /** Integrate a function over a line */ -bool lineintegral_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { +bool lineintegral_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) +{ integralref *iref = ref; double *x[2], size; bool success; - if (!functional_elementsize(v, mesh, MESH_GRADE_LINE, id, nv, vid, &size)) return false; + if (!functional_elementsize(v, mesh, MESH_GRADE_LINE, id, nv, vid, &size)) + return false; - iref->v=v; - for (unsigned int i=0; iv = v; + for (unsigned int i = 0; i < nv; i++) + { mesh_getvertexcoordinatesaslist(mesh, vid[i], &x[i]); } /* Set up tangent vector... (temporary code here) */ - double tangentdata[mesh->dim], tnorm=0.0; + double tangentdata[mesh->dim], tnorm = 0.0; functional_vecsub(mesh->dim, x[1], x[0], tangentdata); - tnorm=functional_vecnorm(mesh->dim, tangentdata); - if (fabs(tnorm)>MORPHO_EPS) functional_vecscale(mesh->dim, 1.0/tnorm, tangentdata, tangentdata); + tnorm = functional_vecnorm(mesh->dim, tangentdata); + if (fabs(tnorm) > MORPHO_EPS) + functional_vecscale(mesh->dim, 1.0 / tnorm, tangentdata, tangentdata); objectmatrix mtangent = MORPHO_STATICMATRIX(tangentdata, mesh->dim, 1); tangent = MORPHO_OBJECT(&mtangent); - value q0[iref->nfields+1], q1[iref->nfields+1]; - value *q[2] = { q0, q1 }; - for (unsigned int k=0; knfields; k++) { - for (unsigned int i=0; infields + 1], q1[iref->nfields + 1]; + value *q[2] = {q0, q1}; + for (unsigned int k = 0; k < iref->nfields; k++) + { + for (unsigned int i = 0; i < nv; i++) + { field_getelement(MORPHO_GETFIELD(iref->fields[k]), MESH_GRADE_VERTEX, vid[i], 0, &q[i][k]); } } - success=integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_LINE, x, iref->nfields, q, iref, out); - if (success) *out *=size; + success = integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_LINE, x, iref->nfields, q, iref, out); + if (success) + *out *= size; return success; } @@ -2819,35 +3469,48 @@ FUNCTIONAL_METHOD(LineIntegral, total, MESH_GRADE_LINE, integralref, integral_pr FUNCTIONAL_METHOD(LineIntegral, gradient, MESH_GRADE_LINE, integralref, integral_prepareref, functional_mapnumericalgradient, lineintegral_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); /** Initialize a LineIntegral object */ -value LineIntegral_init(vm *v, int nargs, value *args) { +value LineIntegral_init(vm *v, int nargs, value *args) +{ objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); int nparams = -1, nfields = 0; - if (nargs>0) { + if (nargs > 0) + { value f = MORPHO_GETARG(args, 0); - if (morpho_countparameters(f, &nparams)) { + if (morpho_countparameters(f, &nparams)) + { objectinstance_setproperty(self, scalarpotential_functionproperty, MORPHO_GETARG(args, 0)); - } else { + } + else + { morpho_runtimeerror(v, LINEINTEGRAL_ARGS); return MORPHO_NIL; } } - if (nparams!=nargs) { + if (nparams != nargs) + { morpho_runtimeerror(v, LINEINTEGRAL_NFLDS); return MORPHO_NIL; } - if (nargs>1) { + if (nargs > 1) + { /* Remaining arguments should be fields */ - objectlist *list = object_newlist(nargs-1, & MORPHO_GETARG(args, 1)); - if (!list) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return MORPHO_NIL; } + objectlist *list = object_newlist(nargs - 1, &MORPHO_GETARG(args, 1)); + if (!list) + { + morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); + return MORPHO_NIL; + } - for (unsigned int i=1; iv=v; - for (unsigned int i=0; iv = v; + for (unsigned int i = 0; i < nv; i++) + { mesh_getvertexcoordinatesaslist(mesh, vid[i], &x[i]); } /* Set up normal vector... (temporary code here) */ - double s0[mesh->dim], s1[mesh->dim], normaldata[mesh->dim], nnorm=0.0; + double s0[mesh->dim], s1[mesh->dim], normaldata[mesh->dim], nnorm = 0.0; functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, normaldata); - nnorm=functional_vecnorm(mesh->dim, normaldata); - if (fabs(nnorm)>MORPHO_EPS) functional_vecscale(mesh->dim, 1.0/nnorm, normaldata, normaldata); + nnorm = functional_vecnorm(mesh->dim, normaldata); + if (fabs(nnorm) > MORPHO_EPS) + functional_vecscale(mesh->dim, 1.0 / nnorm, normaldata, normaldata); objectmatrix mnormal = MORPHO_STATICMATRIX(normaldata, mesh->dim, 1); norml = MORPHO_OBJECT(&mnormal); - - value q0[iref->nfields+1], q1[iref->nfields+1], q2[iref->nfields+1]; - value *q[3] = { q0, q1, q2 }; - for (unsigned int k=0; knfields; k++) { - for (unsigned int i=0; infields + 1], q1[iref->nfields + 1], q2[iref->nfields + 1]; + value *q[3] = {q0, q1, q2}; + for (unsigned int k = 0; k < iref->nfields; k++) + { + for (unsigned int i = 0; i < nv; i++) + { field_getelement(MORPHO_GETFIELD(iref->fields[k]), MESH_GRADE_VERTEX, vid[i], 0, &q[i][k]); } } - success=integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_AREA, x, iref->nfields, q, iref, out); - if (success) *out *=size; + success = integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_AREA, x, iref->nfields, q, iref, out); + if (success) + *out *= size; return success; } @@ -2935,54 +3611,63 @@ FUNCTIONAL_METHOD(AreaIntegral, total, MESH_GRADE_AREA, integralref, integral_pr FUNCTIONAL_METHOD(AreaIntegral, gradient, MESH_GRADE_AREA, integralref, integral_prepareref, functional_mapnumericalgradient, areaintegral_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); /** Field gradients for Area Integrals */ -value AreaIntegral_fieldgradient(vm *v, int nargs, value *args) { +value AreaIntegral_fieldgradient(vm *v, int nargs, value *args) +{ functional_mapinfo info; integralref ref; - value out=MORPHO_NIL; + value out = MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) { + if (functional_validateargs(v, nargs, args, &info)) + { // Should check whether the field is known about here... - if (integral_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { - info.g=MESH_GRADE_AREA; - info.integrand=areaintegral_integrand; - info.ref=&ref; + if (integral_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) + { + info.g = MESH_GRADE_AREA; + info.integrand = areaintegral_integrand; + info.ref = &ref; functional_mapnumericalfieldgradient(v, &info, &out); - } else morpho_runtimeerror(v, GRADSQ_ARGS); + } + else + morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) + morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(AreaIntegral) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineIntegral_init, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaIntegral_integrand, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaIntegral_total, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaIntegral_gradient, BUILTIN_FLAGSEMPTY), -MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, AreaIntegral_fieldgradient, BUILTIN_FLAGSEMPTY) -MORPHO_ENDCLASS - -/* ********************************************************************** - * Initialization - * ********************************************************************** */ - -void functional_initialize(void) { - functional_gradeproperty=builtin_internsymbolascstring(FUNCTIONAL_GRADE_PROPERTY); - functional_fieldproperty=builtin_internsymbolascstring(FUNCTIONAL_FIELD_PROPERTY); - scalarpotential_functionproperty=builtin_internsymbolascstring(SCALARPOTENTIAL_FUNCTION_PROPERTY); - scalarpotential_gradfunctionproperty=builtin_internsymbolascstring(SCALARPOTENTIAL_GRADFUNCTION_PROPERTY); - linearelasticity_referenceproperty=builtin_internsymbolascstring(LINEARELASTICITY_REFERENCE_PROPERTY); - linearelasticity_poissonproperty=builtin_internsymbolascstring(LINEARELASTICITY_POISSON_PROPERTY); - floryhuggins_aproperty=builtin_internsymbolascstring(FLORYHUGGINS_A_PROPERTY); - floryhuggins_bproperty=builtin_internsymbolascstring(FLORYHUGGINS_B_PROPERTY); - floryhuggins_cproperty=builtin_internsymbolascstring(FLORYHUGGINS_C_PROPERTY); - floryhuggins_phi0property=builtin_internsymbolascstring(FLORYHUGGINS_PHI0_PROPERTY); - equielement_weightproperty=builtin_internsymbolascstring(EQUIELEMENT_WEIGHT_PROPERTY); - nematic_ksplayproperty=builtin_internsymbolascstring(NEMATIC_KSPLAY_PROPERTY); - nematic_ktwistproperty=builtin_internsymbolascstring(NEMATIC_KTWIST_PROPERTY); - nematic_kbendproperty=builtin_internsymbolascstring(NEMATIC_KBEND_PROPERTY); - nematic_pitchproperty=builtin_internsymbolascstring(NEMATIC_PITCH_PROPERTY); - - curvature_integrandonlyproperty=builtin_internsymbolascstring(CURVATURE_INTEGRANDONLY_PROPERTY); + MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaIntegral_integrand, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaIntegral_total, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaIntegral_gradient, BUILTIN_FLAGSEMPTY), + MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, AreaIntegral_fieldgradient, BUILTIN_FLAGSEMPTY) + MORPHO_ENDCLASS + + /* ********************************************************************** + * Initialization + * ********************************************************************** */ + + void functional_initialize(void) +{ + functional_gradeproperty = builtin_internsymbolascstring(FUNCTIONAL_GRADE_PROPERTY); + functional_fieldproperty = builtin_internsymbolascstring(FUNCTIONAL_FIELD_PROPERTY); + scalarpotential_functionproperty = builtin_internsymbolascstring(SCALARPOTENTIAL_FUNCTION_PROPERTY); + scalarpotential_gradfunctionproperty = builtin_internsymbolascstring(SCALARPOTENTIAL_GRADFUNCTION_PROPERTY); + linearelasticity_referenceproperty = builtin_internsymbolascstring(LINEARELASTICITY_REFERENCE_PROPERTY); + linearelasticity_poissonproperty = builtin_internsymbolascstring(LINEARELASTICITY_POISSON_PROPERTY); + hydrogel_aproperty = builtin_internsymbolascstring(HYDROGEL_A_PROPERTY); + hydrogel_bproperty = builtin_internsymbolascstring(HYDROGEL_B_PROPERTY); + hydrogel_cproperty = builtin_internsymbolascstring(HYDROGEL_C_PROPERTY); + hydrogel_dproperty = builtin_internsymbolascstring(HYDROGEL_D_PROPERTY); + hydrogel_phirefproperty = builtin_internsymbolascstring(HYDROGEL_PHIREF_PROPERTY); + hydrogel_phi0property = builtin_internsymbolascstring(HYDROGEL_PHI0_PROPERTY); + equielement_weightproperty = builtin_internsymbolascstring(EQUIELEMENT_WEIGHT_PROPERTY); + nematic_ksplayproperty = builtin_internsymbolascstring(NEMATIC_KSPLAY_PROPERTY); + nematic_ktwistproperty = builtin_internsymbolascstring(NEMATIC_KTWIST_PROPERTY); + nematic_kbendproperty = builtin_internsymbolascstring(NEMATIC_KBEND_PROPERTY); + nematic_pitchproperty = builtin_internsymbolascstring(NEMATIC_PITCH_PROPERTY); + + curvature_integrandonlyproperty = builtin_internsymbolascstring(CURVATURE_INTEGRANDONLY_PROPERTY); objectstring objclassname = MORPHO_STATICSTRING(OBJECT_CLASSNAME); value objclass = builtin_findclass(MORPHO_OBJECT(&objclassname)); @@ -2994,7 +3679,7 @@ void functional_initialize(void) { builtin_addclass(VOLUME_CLASSNAME, MORPHO_GETCLASSDEFINITION(Volume), objclass); builtin_addclass(SCALARPOTENTIAL_CLASSNAME, MORPHO_GETCLASSDEFINITION(ScalarPotential), objclass); builtin_addclass(LINEARELASTICITY_CLASSNAME, MORPHO_GETCLASSDEFINITION(LinearElasticity), objclass); - builtin_addclass(FLORYHUGGINS_CLASSNAME, MORPHO_GETCLASSDEFINITION(FloryHuggins), objclass); + builtin_addclass(HYDROGEL_CLASSNAME, MORPHO_GETCLASSDEFINITION(Hydrogel), objclass); builtin_addclass(EQUIELEMENT_CLASSNAME, MORPHO_GETCLASSDEFINITION(EquiElement), objclass); builtin_addclass(LINECURVATURESQ_CLASSNAME, MORPHO_GETCLASSDEFINITION(LineCurvatureSq), objclass); builtin_addclass(LINETORSIONSQ_CLASSNAME, MORPHO_GETCLASSDEFINITION(LineTorsionSq), objclass); @@ -3015,8 +3700,8 @@ void functional_initialize(void) { morpho_defineerror(SCALARPOTENTIAL_FNCLLBL, ERROR_HALT, SCALARPOTENTIAL_FNCLLBL_MSG); morpho_defineerror(LINEARELASTICITY_REF, ERROR_HALT, LINEARELASTICITY_REF_MSG); morpho_defineerror(LINEARELASTICITY_PRP, ERROR_HALT, LINEARELASTICITY_PRP_MSG); - morpho_defineerror(FLORYHUGGINS_ARGS, ERROR_HALT, FLORYHUGGINS_ARGS_MSG); - morpho_defineerror(FLORYHUGGINS_PRP, ERROR_HALT, FLORYHUGGINS_PRP_MSG); + morpho_defineerror(HYDROGEL_ARGS, ERROR_HALT, HYDROGEL_ARGS_MSG); + morpho_defineerror(HYDROGEL_PRP, ERROR_HALT, HYDROGEL_PRP_MSG); morpho_defineerror(EQUIELEMENT_ARGS, ERROR_HALT, EQUIELEMENT_ARGS_MSG); morpho_defineerror(GRADSQ_ARGS, ERROR_HALT, GRADSQ_ARGS_MSG); morpho_defineerror(NEMATIC_ARGS, ERROR_HALT, NEMATIC_ARGS_MSG); diff --git a/morpho5/geometry/functional.h b/morpho5/geometry/functional.h index 01aa0092..afc98517 100644 --- a/morpho5/geometry/functional.h +++ b/morpho5/geometry/functional.h @@ -10,100 +10,102 @@ #include /* Functional properties */ -#define FUNCTIONAL_GRADE_PROPERTY "grade" -#define FUNCTIONAL_ONESIDED_PROPERTY "onesided" -#define FUNCTIONAL_FIELD_PROPERTY "field" -#define SCALARPOTENTIAL_FUNCTION_PROPERTY "function" +#define FUNCTIONAL_GRADE_PROPERTY "grade" +#define FUNCTIONAL_ONESIDED_PROPERTY "onesided" +#define FUNCTIONAL_FIELD_PROPERTY "field" +#define SCALARPOTENTIAL_FUNCTION_PROPERTY "function" #define SCALARPOTENTIAL_GRADFUNCTION_PROPERTY "gradfunction" -#define LINEARELASTICITY_REFERENCE_PROPERTY "reference" -#define LINEARELASTICITY_POISSON_PROPERTY "poissonratio" -#define FLORYHUGGINS_A_PROPERTY "a" -#define FLORYHUGGINS_B_PROPERTY "b" -#define FLORYHUGGINS_C_PROPERTY "c" -#define FLORYHUGGINS_PHI0_PROPERTY "phi0" -#define EQUIELEMENT_WEIGHT_PROPERTY "weight" - -#define NEMATIC_KSPLAY_PROPERTY "ksplay" -#define NEMATIC_KTWIST_PROPERTY "ktwist" -#define NEMATIC_KBEND_PROPERTY "kbend" -#define NEMATIC_PITCH_PROPERTY "pitch" -#define NEMATIC_DIRECTOR_PROPERTY "director" - -#define CURVATURE_INTEGRANDONLY_PROPERTY "integrandonly" +#define LINEARELASTICITY_REFERENCE_PROPERTY "reference" +#define LINEARELASTICITY_POISSON_PROPERTY "poissonratio" +#define HYDROGEL_A_PROPERTY "a" +#define HYDROGEL_B_PROPERTY "b" +#define HYDROGEL_C_PROPERTY "c" +#define HYDROGEL_D_PROPERTY "d" +#define HYDROGEL_PHIREF_PROPERTY "phiref" +#define HYDROGEL_PHI0_PROPERTY "phi0" +#define EQUIELEMENT_WEIGHT_PROPERTY "weight" + +#define NEMATIC_KSPLAY_PROPERTY "ksplay" +#define NEMATIC_KTWIST_PROPERTY "ktwist" +#define NEMATIC_KBEND_PROPERTY "kbend" +#define NEMATIC_PITCH_PROPERTY "pitch" +#define NEMATIC_DIRECTOR_PROPERTY "director" + +#define CURVATURE_INTEGRANDONLY_PROPERTY "integrandonly" /* Functional methods */ -#define FUNCTIONAL_INTEGRAND_METHOD "integrand" -#define FUNCTIONAL_TOTAL_METHOD "total" -#define FUNCTIONAL_GRADIENT_METHOD "gradient" -#define FUNCTIONAL_FIELDGRADIENT_METHOD "fieldgradient" +#define FUNCTIONAL_INTEGRAND_METHOD "integrand" +#define FUNCTIONAL_TOTAL_METHOD "total" +#define FUNCTIONAL_GRADIENT_METHOD "gradient" +#define FUNCTIONAL_FIELDGRADIENT_METHOD "fieldgradient" /* Special functions that can be used in integrands */ -#define TANGENT_FUNCTION "tangent" -#define NORMAL_FUNCTION "normal" +#define TANGENT_FUNCTION "tangent" +#define NORMAL_FUNCTION "normal" /* Functional names */ -#define LENGTH_CLASSNAME "Length" -#define AREA_CLASSNAME "Area" -#define AREAENCLOSED_CLASSNAME "AreaEnclosed" -#define VOLUME_CLASSNAME "Volume" -#define VOLUMEENCLOSED_CLASSNAME "VolumeEnclosed" -#define SCALARPOTENTIAL_CLASSNAME "ScalarPotential" -#define LINEARELASTICITY_CLASSNAME "LinearElasticity" -#define FLORYHUGGINS_CLASSNAME "FloryHuggins" -#define EQUIELEMENT_CLASSNAME "EquiElement" -#define LINECURVATURESQ_CLASSNAME "LineCurvatureSq" -#define LINETORSIONSQ_CLASSNAME "LineTorsionSq" -#define MEANCURVATURESQ_CLASSNAME "MeanCurvatureSq" -#define GAUSSCURVATURE_CLASSNAME "GaussCurvature" -#define GRADSQ_CLASSNAME "GradSq" -#define NORMSQ_CLASSNAME "NormSq" -#define LINEINTEGRAL_CLASSNAME "LineIntegral" -#define AREAINTEGRAL_CLASSNAME "AreaIntegral" -#define NEMATIC_CLASSNAME "Nematic" -#define NEMATICELECTRIC_CLASSNAME "NematicElectric" +#define LENGTH_CLASSNAME "Length" +#define AREA_CLASSNAME "Area" +#define AREAENCLOSED_CLASSNAME "AreaEnclosed" +#define VOLUME_CLASSNAME "Volume" +#define VOLUMEENCLOSED_CLASSNAME "VolumeEnclosed" +#define SCALARPOTENTIAL_CLASSNAME "ScalarPotential" +#define LINEARELASTICITY_CLASSNAME "LinearElasticity" +#define HYDROGEL_CLASSNAME "Hydrogel" +#define EQUIELEMENT_CLASSNAME "EquiElement" +#define LINECURVATURESQ_CLASSNAME "LineCurvatureSq" +#define LINETORSIONSQ_CLASSNAME "LineTorsionSq" +#define MEANCURVATURESQ_CLASSNAME "MeanCurvatureSq" +#define GAUSSCURVATURE_CLASSNAME "GaussCurvature" +#define GRADSQ_CLASSNAME "GradSq" +#define NORMSQ_CLASSNAME "NormSq" +#define LINEINTEGRAL_CLASSNAME "LineIntegral" +#define AREAINTEGRAL_CLASSNAME "AreaIntegral" +#define NEMATIC_CLASSNAME "Nematic" +#define NEMATICELECTRIC_CLASSNAME "NematicElectric" /* Errors */ -#define FUNC_INTEGRAND_MESH "FnctlIntMsh" -#define FUNC_INTEGRAND_MESH_MSG "Method 'integrand' requires a mesh as the argument." +#define FUNC_INTEGRAND_MESH "FnctlIntMsh" +#define FUNC_INTEGRAND_MESH_MSG "Method 'integrand' requires a mesh as the argument." -#define FUNC_ELNTFND "FnctlELNtFnd" -#define FUNC_ELNTFND_MSG "Mesh does not provide elements of grade %u." +#define FUNC_ELNTFND "FnctlELNtFnd" +#define FUNC_ELNTFND_MSG "Mesh does not provide elements of grade %u." -#define SCALARPOTENTIAL_FNCLLBL "SclrPtFnCllbl" -#define SCALARPOTENTIAL_FNCLLBL_MSG "ScalarPotential function is not callable." +#define SCALARPOTENTIAL_FNCLLBL "SclrPtFnCllbl" +#define SCALARPOTENTIAL_FNCLLBL_MSG "ScalarPotential function is not callable." -#define LINEINTEGRAL_ARGS "IntArgs" -#define LINEINTEGRAL_ARGS_MSG "Integral functionals require a callable argument, followed by zero or more Fields." +#define LINEINTEGRAL_ARGS "IntArgs" +#define LINEINTEGRAL_ARGS_MSG "Integral functionals require a callable argument, followed by zero or more Fields." -#define LINEINTEGRAL_NFLDS "IntNFlds" -#define LINEINTEGRAL_NFLDS_MSG "Incorrect number of Fields provided for integrand function." +#define LINEINTEGRAL_NFLDS "IntNFlds" +#define LINEINTEGRAL_NFLDS_MSG "Incorrect number of Fields provided for integrand function." -#define LINEARELASTICITY_REF "LnElstctyRef" -#define LINEARELASTICITY_REF_MSG "LinearElasticity requires a mesh as the argument." +#define LINEARELASTICITY_REF "LnElstctyRef" +#define LINEARELASTICITY_REF_MSG "LinearElasticity requires a mesh as the argument." -#define LINEARELASTICITY_PRP "LnElstctyPrp" -#define LINEARELASTICITY_PRP_MSG "LinearElasticity requires properties 'reference' to be a mesh, 'grade' to be an integer grade and 'poissonratio' to be a number." +#define LINEARELASTICITY_PRP "LnElstctyPrp" +#define LINEARELASTICITY_PRP_MSG "LinearElasticity requires properties 'reference' to be a mesh, 'grade' to be an integer grade and 'poissonratio' to be a number." -#define EQUIELEMENT_ARGS "EquiElArgs" -#define EQUIELEMENT_ARGS_MSG "EquiElement allows 'grade' and 'weight' as optional arguments." +#define EQUIELEMENT_ARGS "EquiElArgs" +#define EQUIELEMENT_ARGS_MSG "EquiElement allows 'grade' and 'weight' as optional arguments." -#define FLORYHUGGINS_ARGS "FlryHggnsArgs" -#define FLORYHUGGINS_ARGS_MSG "FloryHuggins requires a reference mesh and allows 'grade', 'a', 'b', 'c' and 'phi0' as optional arguments." +#define HYDROGEL_ARGS "HydrglArgs" +#define HYDROGEL_ARGS_MSG "Hydrogel requires a reference mesh and allows 'grade', 'a', 'b', 'c' and 'phi0' as optional arguments." -#define FLORYHUGGINS_PRP "FlryHggnsPrp" -#define FLORYHUGGINS_PRP_MSG "FloryHuggins requires properties 'reference' to be a mesh, 'grade' to be an integer grade, 'a', 'b' and 'c' to be numbers and 'phi0' as either a number or a field." +#define HYDROGEL_PRP "HydrglPrp" +#define HYDROGEL_PRP_MSG "Hydrogel requires properties 'reference' to be a mesh, 'grade' to be an integer grade, 'a', 'b' and 'c' to be numbers and 'phi0' as either a number or a field." -#define GRADSQ_ARGS "GradSqArgs" -#define GRADSQ_ARGS_MSG "GradSq requires a field as the argument." +#define GRADSQ_ARGS "GradSqArgs" +#define GRADSQ_ARGS_MSG "GradSq requires a field as the argument." -#define NEMATIC_ARGS "NmtcArgs" -#define NEMATIC_ARGS_MSG "Nematic requires a field as the argument." +#define NEMATIC_ARGS "NmtcArgs" +#define NEMATIC_ARGS_MSG "Nematic requires a field as the argument." -#define NEMATICELECTRIC_ARGS "NmtcElArgs" -#define NEMATICELECTRIC_ARGS_MSG "NematicElectric requires the director and electric field or potential as arguments (in that order)." +#define NEMATICELECTRIC_ARGS "NmtcElArgs" +#define NEMATICELECTRIC_ARGS_MSG "NematicElectric requires the director and electric field or potential as arguments (in that order)." -#define FUNCTIONAL_ARGS "FnctlArgs" -#define FUNCTIONAL_ARGS_MSG "Invalid args passed to method." +#define FUNCTIONAL_ARGS "FnctlArgs" +#define FUNCTIONAL_ARGS_MSG "Invalid args passed to method." void functional_initialize(void); From 2e5b2284e3f186e1bc116ccb8b0f8fa48c1c6c28 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Wed, 30 Mar 2022 17:25:12 -0400 Subject: [PATCH 02/13] Updated the test and docs for hydrogels --- morpho5/docs/functionals.md | 26 +++++++---- test/functionals/floryhuggins/fh.morpho | 19 -------- test/functionals/hydrogel/hydrogel.morpho | 45 +++++++++++++++++++ .../tetrahedron.mesh | 0 4 files changed, 63 insertions(+), 27 deletions(-) delete mode 100644 test/functionals/floryhuggins/fh.morpho create mode 100644 test/functionals/hydrogel/hydrogel.morpho rename test/functionals/{floryhuggins => hydrogel}/tetrahedron.mesh (100%) diff --git a/morpho5/docs/functionals.md b/morpho5/docs/functionals.md index c14cda45..a6c0fe68 100644 --- a/morpho5/docs/functionals.md +++ b/morpho5/docs/functionals.md @@ -192,18 +192,28 @@ You can also integrate functions that involve fields: More than one field can be used; they are passed as arguments to the integrand function in the order you supply them to `AreaIntegrand`. -## FloryHuggins -[tagfloryhuggins]: # (floryhuggins) +## Hydrogel +[taghydrogel]: # (hydrogel) -The `FloryHuggins` functional computes the Flory-Huggins mixing energy over an element: +The `Hydrogel` functional computes the Flory-Rehner energy over an element: - a*phi*log(phi) + b*(1-phi)+log(1-phi) + c*phi*(1-phi) + (a*phi*log(phi) + b*(1-phi)+log(1-phi) + c*phi*(1-phi))*V + + d*(log(phiref/phi)/3 - (phiref/phi)^(2/3) + 1)*V0 -where a, b and c are parameters you can supply. The value of phi is calculated from a reference mesh that you provide on initializing the Functional: +The first three terms come from the Flory-Huggins mixing energy, whereas +the fourth term proportional to d comes from the Flory-Rehner elastic +energy. - var lfh = FloryHuggins(mref) +The value of phi is calculated from a reference mesh +that you provide on initializing the Functional: + var lfh = Hydrogel(mref) + +Here, a, b, c, d and phiref are parameters you can supply, V is the +current volume and V0 is the reference volume of a given element. You +also need to supply the initial value of phi, labeled as phi0, which is +assumed to be the same for all the elements. Manually set the coefficients and grade to operate on: - lfh.a = 1; lfh.b = 1; lfh.c = 1; - lfh.grade = 2 + lfh.a = 1; lfh.b = 1; lfh.c = 1; lfh.d = 1; + lfh.grade = 2, lfh.phi0 = 0.5, lfh.phiref = 0.1 diff --git a/test/functionals/floryhuggins/fh.morpho b/test/functionals/floryhuggins/fh.morpho deleted file mode 100644 index 39d90482..00000000 --- a/test/functionals/floryhuggins/fh.morpho +++ /dev/null @@ -1,19 +0,0 @@ -// Flory-Huggins mixing energy -var m = Mesh("tetrahedron.mesh") -var m0 = Mesh("tetrahedron.mesh") -var lfh = FloryHuggins(m0, a=1, b=1, c=1, phi0=0.5) - -var expected = -0.0522253 -var tol = 1e-6 -print abs(lfh.integrand(m)[0]-expected) Date: Fri, 1 Apr 2022 12:01:28 -0400 Subject: [PATCH 03/13] temporarily adding back fh.morpho, hoping to resolve conflict --- test/functionals/floryhuggins/fh.morpho | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/functionals/floryhuggins/fh.morpho diff --git a/test/functionals/floryhuggins/fh.morpho b/test/functionals/floryhuggins/fh.morpho new file mode 100644 index 00000000..183dd0e2 --- /dev/null +++ b/test/functionals/floryhuggins/fh.morpho @@ -0,0 +1,19 @@ +// Flory-Huggins mixing energy +var m = Mesh("tetrahedron.mesh") +var m0 = Mesh("tetrahedron.mesh") +var lfh = FloryHuggins(m0, a=1, b=1, c=1, phi0=0.5) + +var expected = -0.0522253 +var tol = 1e-6 +print abs(lfh.integrand(m)[0]-expected) Date: Fri, 1 Apr 2022 12:10:41 -0400 Subject: [PATCH 04/13] removed the old test --- test/functionals/floryhuggins/fh.morpho | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 test/functionals/floryhuggins/fh.morpho diff --git a/test/functionals/floryhuggins/fh.morpho b/test/functionals/floryhuggins/fh.morpho deleted file mode 100644 index 183dd0e2..00000000 --- a/test/functionals/floryhuggins/fh.morpho +++ /dev/null @@ -1,19 +0,0 @@ -// Flory-Huggins mixing energy -var m = Mesh("tetrahedron.mesh") -var m0 = Mesh("tetrahedron.mesh") -var lfh = FloryHuggins(m0, a=1, b=1, c=1, phi0=0.5) - -var expected = -0.0522253 -var tol = 1e-6 -print abs(lfh.integrand(m)[0]-expected) Date: Mon, 4 Apr 2022 11:36:06 -0400 Subject: [PATCH 05/13] Attempting to revert the autoformatting --- morpho5/geometry/functional.c | 3041 +++++++++++++-------------------- 1 file changed, 1199 insertions(+), 1842 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 8a4a514e..2c8ee90f 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -21,59 +21,58 @@ #include #ifndef M_PI -#define M_PI 3.14159265358979323846 + #define M_PI 3.14159265358979323846 #endif static value functional_gradeproperty; static value functional_fieldproperty; -// static value functional_functionproperty; +//static value functional_functionproperty; /** Symmetry behaviors */ -typedef enum -{ +typedef enum { SYMMETRY_NONE, SYMMETRY_ADD } symmetrybhvr; /** Integrand function */ -typedef bool(functional_integrand)(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out); +typedef bool (functional_integrand) (vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out); /** Gradient function */ -typedef bool(functional_gradient)(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc); +typedef bool (functional_gradient) (vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc); struct s_functional_mapinfo; // Resolve circular typedef dependency /** Dependencies function */ -typedef bool(functional_dependencies)(struct s_functional_mapinfo *info, elementid id, varray_elementid *out); - -typedef struct s_functional_mapinfo -{ - objectmesh *mesh; // Mesh to use - objectselection *sel; // Selection, if any - objectfield *field; // Field, if any - grade g; // Grade to use - functional_integrand *integrand; // Integrand function - functional_gradient *grad; // Gradient +typedef bool (functional_dependencies) (struct s_functional_mapinfo *info, elementid id, varray_elementid *out); + +typedef struct s_functional_mapinfo { + objectmesh *mesh; // Mesh to use + objectselection *sel; // Selection, if any + objectfield *field; // Field, if any + grade g; // Grade to use + functional_integrand *integrand; // Integrand function + functional_gradient *grad; // Gradient functional_dependencies *dependencies; // Dependencies - symmetrybhvr sym; // Symmetry behavior - void *ref; // Reference to pass on + symmetrybhvr sym; // Symmetry behavior + void *ref; // Reference to pass on } functional_mapinfo; + + /* ********************************************************************** * Utility functions * ********************************************************************** */ -static void functional_clearmapinfo(functional_mapinfo *info) -{ - info->mesh = NULL; - info->field = NULL; - info->sel = NULL; - info->g = 0; - info->integrand = NULL; - info->grad = NULL; - info->dependencies = NULL; - info->ref = NULL; - info->sym = SYMMETRY_NONE; +static void functional_clearmapinfo(functional_mapinfo *info) { + info->mesh=NULL; + info->field=NULL; + info->sel=NULL; + info->g=0; + info->integrand=NULL; + info->grad=NULL; + info->dependencies=NULL; + info->ref=NULL; + info->sym=SYMMETRY_NONE; } /** Validates the arguments provided to a functional @@ -81,55 +80,41 @@ static void functional_clearmapinfo(functional_mapinfo *info) * @param[in] nargs - number of arguments * @param[in] args - the arguments * @param[out] info - mapinfo block */ -bool functional_validateargs(vm *v, int nargs, value *args, functional_mapinfo *info) -{ +bool functional_validateargs(vm *v, int nargs, value *args, functional_mapinfo *info) { functional_clearmapinfo(info); - for (unsigned int i = 0; i < nargs; i++) - { - if (MORPHO_ISMESH(MORPHO_GETARG(args, i))) - { - info->mesh = MORPHO_GETMESH(MORPHO_GETARG(args, i)); - } - else if (MORPHO_ISSELECTION(MORPHO_GETARG(args, i))) - { - info->sel = MORPHO_GETSELECTION(MORPHO_GETARG(args, i)); - } - else if (MORPHO_ISFIELD(MORPHO_GETARG(args, i))) - { - info->field = MORPHO_GETFIELD(MORPHO_GETARG(args, i)); - if (info->field) - info->mesh = (info->field->mesh); // Retrieve the mesh from the field + for (unsigned int i=0; imesh = MORPHO_GETMESH(MORPHO_GETARG(args,i)); + } else if (MORPHO_ISSELECTION(MORPHO_GETARG(args,i))) { + info->sel = MORPHO_GETSELECTION(MORPHO_GETARG(args,i)); + } else if (MORPHO_ISFIELD(MORPHO_GETARG(args,i))) { + info->field = MORPHO_GETFIELD(MORPHO_GETARG(args,i)); + if (info->field) info->mesh = (info->field->mesh); // Retrieve the mesh from the field } } - if (info->mesh) - return true; + + if (info->mesh) return true; morpho_runtimeerror(v, FUNC_INTEGRAND_MESH); return false; } + /* ********************************************************************** * Common routines * ********************************************************************** */ /** Internal function to count the number of elements */ -static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, objectsparse **s) -{ +static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, objectsparse **s) { /* How many elements? */ - if (g == MESH_GRADE_VERTEX) - { - *n = mesh->vert->ncols; - } - else - { - *s = mesh_getconnectivityelement(mesh, 0, g); - if (*s) - { - *n = (*s)->ccs.ncols; // Number of elements - } - else - { + if (g==MESH_GRADE_VERTEX) { + *n=mesh->vert->ncols; + } else { + *s=mesh_getconnectivityelement(mesh, 0, g); + if (*s) { + *n=(*s)->ccs.ncols; // Number of elements + } else { morpho_runtimeerror(v, FUNC_ELNTFND, g); return false; } @@ -137,11 +122,9 @@ static bool functional_countelements(vm *v, objectmesh *mesh, grade g, int *n, o return true; } -static int functional_symmetryimagelistfn(const void *a, const void *b) -{ - elementid i = *(elementid *)a; - elementid j = *(elementid *)b; - return (int)i - j; +static int functional_symmetryimagelistfn(const void *a, const void *b) { + elementid i=*(elementid *) a; elementid j=*(elementid *) b; + return (int) i-j; } /** Gets a list of all image elements (those that map onto a target element) @@ -149,48 +132,39 @@ static int functional_symmetryimagelistfn(const void *a, const void *b) * @param[in] g - grade to look up * @param[in] sort - whether to sort othe results * @param[out] ids - varray is filled with image element ids */ -void functional_symmetryimagelist(objectmesh *mesh, grade g, bool sort, varray_elementid *ids) -{ - objectsparse *conn = mesh_getconnectivityelement(mesh, g, g); +void functional_symmetryimagelist(objectmesh *mesh, grade g, bool sort, varray_elementid *ids) { + objectsparse *conn=mesh_getconnectivityelement(mesh, g, g); - ids->count = 0; // Initialize the varray + ids->count=0; // Initialize the varray - if (conn) - { - int i, j; - void *ctr = sparsedok_loopstart(&conn->dok); + if (conn) { + int i,j; + void *ctr=sparsedok_loopstart(&conn->dok); - while (sparsedok_loop(&conn->dok, &ctr, &i, &j)) - { + while (sparsedok_loop(&conn->dok, &ctr, &i, &j)) { varray_elementidwrite(ids, j); } - if (sort) - qsort(ids->data, ids->count, sizeof(elementid), functional_symmetryimagelistfn); + if (sort) qsort(ids->data, ids->count, sizeof(elementid), functional_symmetryimagelistfn); } } /** Sums forces on symmetry vertices * @param[in] mesh - mesh object * @param frc - force object; updated if symmetries are present. */ -bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) -{ - objectsparse *s = mesh_getconnectivityelement(mesh, 0, 0); // Checking for vertex symmetries +bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) { + objectsparse *s=mesh_getconnectivityelement(mesh, 0, 0); // Checking for vertex symmetries - if (s) - { - int i, j; + if (s) { + int i,j; void *ctr = sparsedok_loopstart(&s->dok); double *fi, *fj, fsum[mesh->dim]; - while (sparsedok_loop(&s->dok, &ctr, &i, &j)) - { + while (sparsedok_loop(&s->dok, &ctr, &i, &j)) { if (matrix_getcolumn(frc, i, &fi) && - matrix_getcolumn(frc, j, &fj)) - { + matrix_getcolumn(frc, j, &fj)) { - for (unsigned int k = 0; k < mesh->dim; k++) - fsum[k] = fi[k] + fj[k]; + for (unsigned int k=0; kdim; k++) fsum[k]=fi[k]+fj[k]; matrix_setcolumn(frc, i, fsum); matrix_setcolumn(frc, j, fsum); } @@ -200,19 +174,13 @@ bool functional_symmetrysumforces(objectmesh *mesh, objectmatrix *frc) return s; } -bool functional_inlist(varray_elementid *list, elementid id) -{ - for (unsigned int i = 0; i < list->count; i++) - if (list->data[i] == id) - return true; +bool functional_inlist(varray_elementid *list, elementid id) { + for (unsigned int i=0; icount; i++) if (list->data[i]==id) return true; return false; } -bool functional_containsvertex(int nv, int *vid, elementid id) -{ - for (unsigned int i = 0; i < nv; i++) - if (vid[i] == id) - return true; +bool functional_containsvertex(int nv, int *vid, elementid id) { + for (unsigned int i=0; imesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - objectsparse *s = NULL; - int n = 0; + objectsparse *s=NULL; + int n=0; - if (!functional_countelements(v, mesh, g, &n, &s)) - return false; + if (!functional_countelements(v, mesh, g, &n, &s)) return false; /* Find any image elements so we can skip over them */ varray_elementid imageids; varray_elementidinit(&imageids); functional_symmetryimagelist(mesh, g, true, &imageids); - if (n > 0) - { + if (n>0) { int vertexid; // Use this if looping over grade 0 - int *vid = (g == 0 ? &vertexid : NULL), - nv = (g == 0 ? 1 : 0); // The vertex indices - int sindx = 0; // Index into imageids array - double sum = 0.0, c = 0.0, y, t, result; - - if (sel) - { // Loop over selection - if (sel->selected[g].count > 0) - for (unsigned int k = 0; k < sel->selected[g].capacity; k++) - { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) - continue; - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - - // Skip this element if it's an image element: - if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } - - if (s) - sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else - vertexid = i; - - if (vid && nv > 0) - { - if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) - { - y = result - c; - t = sum + y; - c = (t - sum) - y; - sum = t; // Kahan summation - } - else - goto functional_sumintegrand_cleanup; - } + int *vid=(g==0 ? &vertexid : NULL), + nv=(g==0 ? 1 : 0); // The vertex indices + int sindx=0; // Index into imageids array + double sum=0.0, c=0.0, y, t, result; + + if (sel) { // Loop over selection + if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + + // Skip this element if it's an image element: + if ((imageids.count>0) && (sindxccs, i, &nv, &vid); + else vertexid=i; + + if (vid && nv>0) { + if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { + y=result-c; t=sum+y; c=(t-sum)-y; sum=t; // Kahan summation + } else goto functional_sumintegrand_cleanup; } - } - else - { // Loop over elements - for (elementid i = 0; i < n; i++) - { + } + } else { // Loop over elements + for (elementid i=0; i 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } + if ((imageids.count>0) && (sindxccs, i, &nv, &vid); - else - vertexid = i; - - if (vid && nv > 0) - { - if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) - { - y = result - c; - t = sum + y; - c = (t - sum) - y; - sum = t; // Kahan summation - } - else - goto functional_sumintegrand_cleanup; + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; + + if (vid && nv>0) { + if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { + y=result-c; t=sum+y; c=(t-sum)-y; sum=t; // Kahan summation + } else goto functional_sumintegrand_cleanup; } } } - *out = MORPHO_FLOAT(sum); + *out=MORPHO_FLOAT(sum); } - success = true; + success=true; functional_sumintegrand_cleanup: varray_elementidclear(&imageids); @@ -333,21 +265,19 @@ bool functional_sumintegrand(vm *v, functional_mapinfo *info, value *out) * @param[in] info - map info * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) -{ +bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) { objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - objectsparse *s = NULL; - objectmatrix *new = NULL; - bool ret = false; - int n = 0; + objectsparse *s=NULL; + objectmatrix *new=NULL; + bool ret=false; + int n=0; /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) - return false; + if (!functional_countelements(v, mesh, g, &n, &s)) return false; /* Find any image elements so we can skip over them */ varray_elementid imageids; @@ -355,92 +285,59 @@ bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) functional_symmetryimagelist(mesh, g, true, &imageids); /* Create the output matrix */ - if (n > 0) - { - new = object_newmatrix(1, n, true); - if (!new) - { - morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); - return false; - } + if (n>0) { + new=object_newmatrix(1, n, true); + if (!new) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } } - if (new) - { + if (new) { int vertexid; // Use this if looping over grade 0 - int *vid = (g == 0 ? &vertexid : NULL), - nv = (g == 0 ? 1 : 0); // The vertex indices - int sindx = 0; // Index into imageids array + int *vid=(g==0 ? &vertexid : NULL), + nv=(g==0 ? 1 : 0); // The vertex indices + int sindx=0; // Index into imageids array double result; - if (sel) - { // Loop over selection - if (sel->selected[g].count > 0) - for (unsigned int k = 0; k < sel->selected[g].capacity; k++) - { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) - continue; - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - - // Skip this element if it's an image element - if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } + if (sel) { // Loop over selection + if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - if (s) - sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else - vertexid = i; + // Skip this element if it's an image element + if ((imageids.count>0) && (sindx 0) - { - if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) - { - matrix_setelement(new, 0, i, result); - } - else - goto functional_mapintegrand_cleanup; - } + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; + + if (vid && nv>0) { + if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { + matrix_setelement(new, 0, i, result); + } else goto functional_mapintegrand_cleanup; } - } - else - { // Loop over elements - for (elementid i = 0; i < n; i++) - { + } + } else { // Loop over elements + for (elementid i=0; i 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } + if ((imageids.count>0) && (sindxccs, i, &nv, &vid); - else - vertexid = i; + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; - if (vid && nv > 0) - { - if ((*integrand)(v, mesh, i, nv, vid, ref, &result)) - { + if (vid && nv>0) { + if ((*integrand) (v, mesh, i, nv, vid, ref, &result)) { matrix_setelement(new, 0, i, result); - } - else - goto functional_mapintegrand_cleanup; + } else goto functional_mapintegrand_cleanup; } } } *out = MORPHO_OBJECT(new); - ret = true; + ret=true; } varray_elementidclear(&imageids); return ret; functional_mapintegrand_cleanup: - object_free((object *)new); + object_free((object *) new); varray_elementidclear(&imageids); return false; } @@ -450,176 +347,137 @@ bool functional_mapintegrand(vm *v, functional_mapinfo *info, value *out) * @param[in] info - map info structure * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapgradient(vm *v, functional_mapinfo *info, value *out) -{ +bool functional_mapgradient(vm *v, functional_mapinfo *info, value *out) { objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_gradient *grad = info->grad; void *ref = info->ref; symmetrybhvr sym = info->sym; - objectsparse *s = NULL; - objectmatrix *frc = NULL; - bool ret = false; - int n = 0; + objectsparse *s=NULL; + objectmatrix *frc=NULL; + bool ret=false; + int n=0; /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) - return false; + if (!functional_countelements(v, mesh, g, &n, &s)) return false; /* Create the output matrix */ - if (n > 0) - { - frc = object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); - if (!frc) - { - morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); - return false; - } + if (n>0) { + frc=object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); + if (!frc) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } } - if (frc) - { + if (frc) { int vertexid; // Use this if looping over grade 0 - int *vid = (g == 0 ? &vertexid : NULL), - nv = (g == 0 ? 1 : 0); // The vertex indices - - if (sel) - { // Loop over selection - if (sel->selected[g].count > 0) - for (unsigned int k = 0; k < sel->selected[g].capacity; k++) - { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) - continue; - - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - if (s) - sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else - vertexid = i; - - if (vid && nv > 0) - { - if (!(*grad)(v, mesh, i, nv, vid, ref, frc)) - goto functional_mapgradient_cleanup; - } + int *vid=(g==0 ? &vertexid : NULL), + nv=(g==0 ? 1 : 0); // The vertex indices + + + if (sel) { // Loop over selection + if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; + + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; + + if (vid && nv>0) { + if (!(*grad) (v, mesh, i, nv, vid, ref, frc)) goto functional_mapgradient_cleanup; } - } - else - { // Loop over elements - for (elementid i = 0; i < n; i++) - { - if (s) - sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else - vertexid = i; - - if (vid && nv > 0) - { - if (!(*grad)(v, mesh, i, nv, vid, ref, frc)) - goto functional_mapgradient_cleanup; + } + } else { // Loop over elements + for (elementid i=0; iccs, i, &nv, &vid); + else vertexid=i; + + if (vid && nv>0) { + if (!(*grad) (v, mesh, i, nv, vid, ref, frc)) goto functional_mapgradient_cleanup; } } } - if (sym == SYMMETRY_ADD) - functional_symmetrysumforces(mesh, frc); + if (sym==SYMMETRY_ADD) functional_symmetrysumforces(mesh, frc); *out = MORPHO_OBJECT(frc); - ret = true; + ret=true; } functional_mapgradient_cleanup: - if (!ret) - object_free((object *)frc); + if (!ret) object_free((object *) frc); return ret; } /* Calculates a numerical gradient */ -static bool functional_numericalgradient(vm *v, objectmesh *mesh, elementid i, int nv, int *vid, functional_integrand *integrand, void *ref, objectmatrix *frc) -{ - double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here +static bool functional_numericalgradient(vm *v, objectmesh *mesh, elementid i, int nv, int *vid, functional_integrand *integrand, void *ref, objectmatrix *frc) { + double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here // Loop over vertices in element - for (unsigned int j = 0; j < nv; j++) - { + for (unsigned int j=0; jdim; k++) - { + for (unsigned int k=0; kdim; k++) { matrix_getelement(frc, k, vid[j], &f0); matrix_getelement(mesh->vert, k, vid[j], &x0); - matrix_setelement(mesh->vert, k, vid[j], x0 + eps); - if (!(*integrand)(v, mesh, i, nv, vid, ref, &fp)) - return false; - matrix_setelement(mesh->vert, k, vid[j], x0 - eps); - if (!(*integrand)(v, mesh, i, nv, vid, ref, &fm)) - return false; + matrix_setelement(mesh->vert, k, vid[j], x0+eps); + if (!(*integrand) (v, mesh, i, nv, vid, ref, &fp)) return false; + matrix_setelement(mesh->vert, k, vid[j], x0-eps); + if (!(*integrand) (v, mesh, i, nv, vid, ref, &fm)) return false; matrix_setelement(mesh->vert, k, vid[j], x0); - matrix_setelement(frc, k, vid[j], f0 + (fp - fm) / (2 * eps)); + matrix_setelement(frc, k, vid[j], f0+(fp-fm)/(2*eps)); } } return true; } /* Calculates a numerical gradient for a remote vertex */ -static bool functional_numericalremotegradientold(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) -{ +static bool functional_numericalremotegradientold(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) { objectmesh *mesh = info->mesh; - double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here + double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here - int *rvid = (info->g == 0 ? &remoteid : NULL), - rnv = (info->g == 0 ? 1 : 0); // The vertex indices + int *rvid=(info->g==0 ? &remoteid : NULL), + rnv=(info->g==0 ? 1 : 0); // The vertex indices - if (conn) - sparseccs_getrowindices(&conn->ccs, remoteid, &rnv, &rvid); + if (conn) sparseccs_getrowindices(&conn->ccs, remoteid, &rnv, &rvid); // Loop over vertices in element - for (unsigned int j = 0; j < nv; j++) - { + for (unsigned int j=0; jdim; k++) - { + for (unsigned int k=0; kdim; k++) { matrix_getelement(frc, k, vid[j], &f0); matrix_getelement(mesh->vert, k, vid[j], &x0); - matrix_setelement(mesh->vert, k, vid[j], x0 + eps); - if (!(*info->integrand)(v, mesh, remoteid, rnv, rvid, info->ref, &fp)) - return false; - matrix_setelement(mesh->vert, k, vid[j], x0 - eps); - if (!(*info->integrand)(v, mesh, remoteid, rnv, rvid, info->ref, &fm)) - return false; + matrix_setelement(mesh->vert, k, vid[j], x0+eps); + if (!(*info->integrand) (v, mesh, remoteid, rnv, rvid, info->ref, &fp)) return false; + matrix_setelement(mesh->vert, k, vid[j], x0-eps); + if (!(*info->integrand) (v, mesh, remoteid, rnv, rvid, info->ref, &fm)) return false; matrix_setelement(mesh->vert, k, vid[j], x0); - matrix_setelement(frc, k, vid[j], f0 + (fp - fm) / (2 * eps)); + matrix_setelement(frc, k, vid[j], f0+(fp-fm)/(2*eps)); } } return true; } -static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) -{ +static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, objectsparse *conn, elementid remoteid, elementid i, int nv, int *vid, objectmatrix *frc) { objectmesh *mesh = info->mesh; - double f0, fp, fm, x0, eps = 1e-10; // Should use sqrt(machineeps)*(1+|x|) here + double f0,fp,fm,x0,eps=1e-10; // Should use sqrt(machineeps)*(1+|x|) here // Loop over coordinates - for (unsigned int k = 0; k < mesh->dim; k++) - { + for (unsigned int k=0; kdim; k++) { matrix_getelement(frc, k, remoteid, &f0); matrix_getelement(mesh->vert, k, remoteid, &x0); - matrix_setelement(mesh->vert, k, remoteid, x0 + eps); - if (!(*info->integrand)(v, mesh, i, nv, vid, info->ref, &fp)) - return false; - matrix_setelement(mesh->vert, k, remoteid, x0 - eps); - if (!(*info->integrand)(v, mesh, i, nv, vid, info->ref, &fm)) - return false; + matrix_setelement(mesh->vert, k, remoteid, x0+eps); + if (!(*info->integrand) (v, mesh, i, nv, vid, info->ref, &fp)) return false; + matrix_setelement(mesh->vert, k, remoteid, x0-eps); + if (!(*info->integrand) (v, mesh, i, nv, vid, info->ref, &fm)) return false; matrix_setelement(mesh->vert, k, remoteid, x0); - matrix_setelement(frc, k, remoteid, f0 + (fp - fm) / (2 * eps)); + matrix_setelement(frc, k, remoteid, f0+(fp-fm)/(2*eps)); } return true; @@ -630,22 +488,20 @@ static bool functional_numericalremotegradient(vm *v, functional_mapinfo *info, * @param[in] info - map info * @param[out] out - a matrix of integrand values * @returns true on success, false otherwise. Error reporting through VM. */ -bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out) -{ +bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out) { objectmesh *mesh = info->mesh; objectselection *sel = info->sel; grade g = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; symmetrybhvr sym = info->sym; - objectsparse *s = NULL; - objectmatrix *frc = NULL; - bool ret = false; - int n = 0; + objectsparse *s=NULL; + objectmatrix *frc=NULL; + bool ret=false; + int n=0; varray_elementid dependencies; - if (info->dependencies) - varray_elementidinit(&dependencies); + if (info->dependencies) varray_elementidinit(&dependencies); /* Find any image elements so we can skip over them */ varray_elementid imageids; @@ -653,206 +509,147 @@ bool functional_mapnumericalgradient(vm *v, functional_mapinfo *info, value *out functional_symmetryimagelist(mesh, g, true, &imageids); /* How many elements? */ - if (!functional_countelements(v, mesh, g, &n, &s)) - return false; + if (!functional_countelements(v, mesh, g, &n, &s)) return false; /* Create the output matrix */ - if (n > 0) - { - frc = object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); - if (!frc) - { - morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); - return false; - } + if (n>0) { + frc=object_newmatrix(mesh->vert->nrows, mesh->vert->ncols, true); + if (!frc) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return false; } } - if (frc) - { + if (frc) { int vertexid; // Use this if looping over grade 0 - int *vid = (g == 0 ? &vertexid : NULL), - nv = (g == 0 ? 1 : 0); // The vertex indices - int sindx = 0; // Index into imageids array - - if (sel) - { // Loop over selection - if (sel->selected[g].count > 0) - for (unsigned int k = 0; k < sel->selected[g].capacity; k++) - { - if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) - continue; - - elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); - if (s) - sparseccs_getrowindices(&s->ccs, i, &nv, &vid); - else - vertexid = i; - - // Skip this element if it's an image element - if ((imageids.count > 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } + int *vid=(g==0 ? &vertexid : NULL), + nv=(g==0 ? 1 : 0); // The vertex indices + int sindx=0; // Index into imageids array + + if (sel) { // Loop over selection + if (sel->selected[g].count>0) for (unsigned int k=0; kselected[g].capacity; k++) { + if (!MORPHO_ISINTEGER(sel->selected[g].contents[k].key)) continue; + + elementid i = MORPHO_GETINTEGERVALUE(sel->selected[g].contents[k].key); + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; + + // Skip this element if it's an image element + if ((imageids.count>0) && (sindx 0) - { - if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) - goto functional_numericalgradient_cleanup; - - if (info->dependencies && // Loop over dependencies if there are any - (info->dependencies)(info, i, &dependencies)) - { - for (int j = 0; j < dependencies.count; j++) - { - if (!functional_numericalremotegradient(v, info, s, dependencies.data[j], i, nv, vid, frc)) - goto functional_numericalgradient_cleanup; - } - dependencies.count = 0; + if (vid && nv>0) { + if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) goto functional_numericalgradient_cleanup; + + if (info->dependencies && // Loop over dependencies if there are any + (info->dependencies) (info, i, &dependencies)) { + for (int j=0; j 0) && (sindx < imageids.count) && imageids.data[sindx] == i) - { - sindx++; - continue; - } + if ((imageids.count>0) && (sindxccs, i, &nv, &vid); - else - vertexid = i; + if (s) sparseccs_getrowindices(&s->ccs, i, &nv, &vid); + else vertexid=i; - if (vid && nv > 0) - { + if (vid && nv>0) { - if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) - goto functional_numericalgradient_cleanup; + if (!functional_numericalgradient(v, mesh, i, nv, vid, integrand, ref, frc)) goto functional_numericalgradient_cleanup; if (info->dependencies && // Loop over dependencies if there are any - (info->dependencies)(info, i, &dependencies)) - { - for (int j = 0; j < dependencies.count; j++) - { - if (functional_containsvertex(nv, vid, dependencies.data[j])) - continue; - if (!functional_numericalremotegradient(v, info, s, dependencies.data[j], i, nv, vid, frc)) - goto functional_numericalgradient_cleanup; + (info->dependencies) (info, i, &dependencies)) { + for (int j=0; jdependencies) - varray_elementidclear(&dependencies); - if (!ret) - object_free((object *)frc); + if (info->dependencies) varray_elementidclear(&dependencies); + if (!ret) object_free((object *) frc); return ret; } -bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value *out) -{ +bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value *out) { objectmesh *mesh = info->mesh; objectselection *sel = info->sel; objectfield *field = info->field; grade grd = info->g; functional_integrand *integrand = info->integrand; void *ref = info->ref; - // symmetrybhvr sym = info->sym; + //symmetrybhvr sym = info->sym; - double eps = 1e-10; - bool ret = false; - objectsparse *conn = mesh_getconnectivityelement(mesh, 0, grd); // Connectivity for the element + double eps=1e-10; + bool ret=false; + objectsparse *conn=mesh_getconnectivityelement(mesh, 0, grd); // Connectivity for the element /* Create the output field */ - objectfield *grad = object_newfield(mesh, field->prototype, field->dof); - if (!grad) - return false; + objectfield *grad=object_newfield(mesh, field->prototype, field->dof); + if (!grad) return false; field_zero(grad); /* Loop over elements in the field */ - for (grade g = 0; g < field->ngrades; g++) - { - if (field->dof[g] == 0) - continue; - int nentries = 1, *entries, nv, *vid; - double fr, fl; - objectsparse *rconn = mesh_addconnectivityelement(mesh, grd, g); // Find dependencies for the grade + for (grade g=0; gngrades; g++) { + if (field->dof[g]==0) continue; + int nentries=1, *entries, nv, *vid; + double fr,fl; + objectsparse *rconn=mesh_addconnectivityelement(mesh, grd, g); // Find dependencies for the grade - for (elementid id = 0; id < mesh_nelementsforgrade(mesh, g); id++) - { + for (elementid id=0; idccs, entries[i], &nv, &vid); - } - else - { - if (sel) - if (!selection_isselected(sel, grd, id)) - continue; - nv = 1; - vid = &id; + } else { + if (sel) if (!selection_isselected(sel, grd, id)) continue; + nv=1; vid=&id; } /* Loop over dofs in field entry */ - for (int j = 0; j < field->psize * field->dof[g]; j++) - { - int k = field->offset[g] + id * field->psize * field->dof[g] + j; - double fld = field->data.elements[k]; - field->data.elements[k] += eps; + for (int j=0; jpsize*field->dof[g]; j++) { + int k=field->offset[g]+id*field->psize*field->dof[g]+j; + double fld=field->data.elements[k]; + field->data.elements[k]+=eps; - if (!(*integrand)(v, mesh, id, nv, vid, ref, &fr)) - goto functional_mapnumericalfieldgradient_cleanup; + if (!(*integrand) (v, mesh, id, nv, vid, ref, &fr)) goto functional_mapnumericalfieldgradient_cleanup; - field->data.elements[k] = fld - eps; + field->data.elements[k]=fld-eps; - if (!(*integrand)(v, mesh, id, nv, vid, ref, &fl)) - goto functional_mapnumericalfieldgradient_cleanup; + if (!(*integrand) (v, mesh, id, nv, vid, ref, &fl)) goto functional_mapnumericalfieldgradient_cleanup; - field->data.elements[k] = fld; + field->data.elements[k]=fld; - grad->data.elements[k] += (fr - fl) / (2 * eps); + grad->data.elements[k]+=(fr-fl)/(2*eps); } } } } *out = MORPHO_OBJECT(grad); - ret = true; + ret=true; } functional_mapnumericalfieldgradient_cleanup: - if (!ret) - object_free((object *)grad); + if (!ret) object_free((object *) grad); return ret; } @@ -862,51 +659,40 @@ bool functional_mapnumericalfieldgradient(vm *v, functional_mapinfo *info, value * ********************************************************************** */ /** Calculate the difference of two vectors */ -void functional_vecadd(unsigned int n, double *a, double *b, double *out) -{ - for (unsigned int i = 0; i < n; i++) - out[i] = a[i] + b[i]; +void functional_vecadd(unsigned int n, double *a, double *b, double *out) { + for (unsigned int i=0; idim]; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); - *out = functional_vecnorm(mesh->dim, s0); + *out=functional_vecnorm(mesh->dim, s0); return true; } /** Calculate gradient */ -bool length_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool length_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x[nv], s0[mesh->dim], norm; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); - norm = functional_vecnorm(mesh->dim, s0); - if (norm < MORPHO_EPS) - return false; + norm=functional_vecnorm(mesh->dim, s0); + if (normdim]; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - *out = 0.5 * functional_vecnorm(mesh->dim, cx); + *out=0.5*functional_vecnorm(mesh->dim, cx); return true; } /** Calculate gradient */ -bool areaenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool areaenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x[nv], cx[mesh->dim], s[mesh->dim]; double norm; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - norm = functional_vecnorm(mesh->dim, cx); - if (norm < MORPHO_EPS) - return false; + norm=functional_vecnorm(mesh->dim, cx); + if (normdim], s1[mesh->dim], cx[mesh->dim]; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, cx); - *out = 0.5 * functional_vecnorm(mesh->dim, cx); + *out=0.5*functional_vecnorm(mesh->dim, cx); return true; } /** Calculate gradient */ -bool area_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool area_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x[nv], s0[3], s1[3], s01[3], s010[3], s011[3]; double norm; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, s01); - norm = functional_vecnorm(mesh->dim, s01); - if (norm < MORPHO_EPS) - return false; + norm=functional_vecnorm(mesh->dim, s01); + if (normdim, s010, s011, s0); - matrix_addtocolumn(frc, vid[1], -0.5 / norm, s0); + matrix_addtocolumn(frc, vid[1], -0.5/norm, s0); return true; } @@ -1176,46 +920,42 @@ FUNCTIONAL_TOTAL(Area, MESH_GRADE_AREA, area_integrand) MORPHO_BEGINCLASS(Area) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Area_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Area_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Area_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Area_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Area_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Area_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Area_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Enclosed volume - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Enclosed volume + * ---------------------------------------------- */ - /** Calculate enclosed volume */ - bool volumeenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +/** Calculate enclosed volume */ +bool volumeenclosed_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { double *x[nv], cx[mesh->dim]; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - *out = fabs(functional_vecdot(mesh->dim, cx, x[2])) / 6.0; + *out=fabs(functional_vecdot(mesh->dim, cx, x[2]))/6.0; return true; } /** Calculate gradient */ -bool volumeenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool volumeenclosed_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x[nv], cx[mesh->dim], dot; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_veccross(x[0], x[1], cx); - dot = functional_vecdot(mesh->dim, cx, x[2]); - dot /= fabs(dot); + dot=functional_vecdot(mesh->dim, cx, x[2]); + dot/=fabs(dot); - matrix_addtocolumn(frc, vid[2], dot / 6.0, cx); + matrix_addtocolumn(frc, vid[2], dot/6.0, cx); functional_veccross(x[1], x[2], cx); - matrix_addtocolumn(frc, vid[0], dot / 6.0, cx); + matrix_addtocolumn(frc, vid[0], dot/6.0, cx); functional_veccross(x[2], x[0], cx); - matrix_addtocolumn(frc, vid[1], dot / 6.0, cx); + matrix_addtocolumn(frc, vid[1], dot/6.0, cx); return true; } @@ -1227,21 +967,19 @@ FUNCTIONAL_TOTAL(VolumeEnclosed, MESH_GRADE_AREA, volumeenclosed_integrand) MORPHO_BEGINCLASS(VolumeEnclosed) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, VolumeEnclosed_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, VolumeEnclosed_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, VolumeEnclosed_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, VolumeEnclosed_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, VolumeEnclosed_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, VolumeEnclosed_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, VolumeEnclosed_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Volume - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Volume + * ---------------------------------------------- */ - /** Calculate enclosed volume */ - bool volume_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +/** Calculate enclosed volume */ +bool volume_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { double *x[nv], s10[mesh->dim], s20[mesh->dim], s30[mesh->dim], cx[mesh->dim]; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s10); functional_vecsub(mesh->dim, x[2], x[0], s20); @@ -1249,17 +987,15 @@ MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, VolumeEnclosed_init, BUILTIN_FLAGSEMPTY functional_veccross(s20, s30, cx); - *out = fabs(functional_vecdot(mesh->dim, s10, cx)) / 6.0; + *out=fabs(functional_vecdot(mesh->dim, s10, cx))/6.0; return true; } /** Calculate gradient */ -bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x[nv], s10[mesh->dim], s20[mesh->dim], s30[mesh->dim]; double s31[mesh->dim], s21[mesh->dim], cx[mesh->dim], uu; - for (int j = 0; j < nv; j++) - matrix_getcolumn(mesh->vert, vid[j], &x[j]); + for (int j=0; jvert, vid[j], &x[j]); functional_vecsub(mesh->dim, x[1], x[0], s10); functional_vecsub(mesh->dim, x[2], x[0], s20); @@ -1268,19 +1004,19 @@ bool volume_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, vo functional_vecsub(mesh->dim, x[2], x[1], s21); functional_veccross(s20, s30, cx); - uu = functional_vecdot(mesh->dim, s10, cx); - uu = (uu > 0 ? 1.0 : -1.0); + uu=functional_vecdot(mesh->dim, s10, cx); + uu=(uu>0 ? 1.0 : -1.0); - matrix_addtocolumn(frc, vid[1], uu / 6.0, cx); + matrix_addtocolumn(frc, vid[1], uu/6.0, cx); functional_veccross(s31, s21, cx); - matrix_addtocolumn(frc, vid[0], uu / 6.0, cx); + matrix_addtocolumn(frc, vid[0], uu/6.0, cx); functional_veccross(s30, s10, cx); - matrix_addtocolumn(frc, vid[2], uu / 6.0, cx); + matrix_addtocolumn(frc, vid[2], uu/6.0, cx); functional_veccross(s10, s20, cx); - matrix_addtocolumn(frc, vid[3], uu / 6.0, cx); + matrix_addtocolumn(frc, vid[3], uu/6.0, cx); return true; } @@ -1292,32 +1028,29 @@ FUNCTIONAL_TOTAL(Volume, MESH_GRADE_VOLUME, volume_integrand) MORPHO_BEGINCLASS(Volume) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Volume_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Volume_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Volume_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Volume_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Volume_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Volume_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Volume_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Scalar potential - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Scalar potential + * ---------------------------------------------- */ - static value scalarpotential_functionproperty; +static value scalarpotential_functionproperty; static value scalarpotential_gradfunctionproperty; /** Evaluate the scalar potential */ -bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { double *x; - value fn = *(value *)ref; + value fn = *(value *) ref; value args[mesh->dim]; value ret; matrix_getcolumn(mesh->vert, id, &x); - for (int i = 0; i < mesh->dim; i++) - args[i] = MORPHO_FLOAT(x[i]); + for (int i=0; idim; i++) args[i]=MORPHO_FLOAT(x[i]); - if (morpho_call(v, fn, mesh->dim, args, &ret)) - { + if (morpho_call(v, fn, mesh->dim, args, &ret)) { return morpho_valuetofloat(ret, out); } @@ -1325,25 +1058,20 @@ bool scalarpotential_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in } /** Evaluate the gradient of the scalar potential */ -bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) -{ +bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, objectmatrix *frc) { double *x; - value fn = *(value *)ref; + value fn = *(value *) ref; value args[mesh->dim]; value ret; matrix_getcolumn(mesh->vert, id, &x); - for (int i = 0; i < mesh->dim; i++) - args[i] = MORPHO_FLOAT(x[i]); + for (int i=0; idim; i++) args[i]=MORPHO_FLOAT(x[i]); - if (morpho_call(v, fn, mesh->dim, args, &ret)) - { - if (MORPHO_ISMATRIX(ret)) - { - objectmatrix *vf = MORPHO_GETMATRIX(ret); + if (morpho_call(v, fn, mesh->dim, args, &ret)) { + if (MORPHO_ISMATRIX(ret)) { + objectmatrix *vf=MORPHO_GETMATRIX(ret); - if (vf->nrows * vf->ncols == frc->nrows) - { + if (vf->nrows*vf->ncols==frc->nrows) { return matrix_addtocolumn(frc, id, 1.0, vf->elements); } } @@ -1352,158 +1080,116 @@ bool scalarpotential_gradient(vm *v, objectmesh *mesh, elementid id, int nv, int return false; } + /** Initialize a scalar potential */ -value ScalarPotential_init(vm *v, int nargs, value *args) -{ +value ScalarPotential_init(vm *v, int nargs, value *args) { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_INTEGER(MESH_GRADE_VERTEX)); /* First argument is the potential function */ - if (nargs > 0) - { - if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 0))) - { + if (nargs>0) { + if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, MORPHO_GETARG(args, 0)); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); } /* Second argument is the gradient of the potential function */ - if (nargs > 1) - { - if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 1))) - { + if (nargs>1) { + if (MORPHO_ISCALLABLE(MORPHO_GETARG(args, 1))) { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, MORPHO_GETARG(args, 1)); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); } return MORPHO_NIL; } /** Integrand function */ -value ScalarPotential_integrand(vm *v, int nargs, value *args) -{ +value ScalarPotential_integrand(vm *v, int nargs, value *args) { functional_mapinfo info; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { + if (functional_validateargs(v, nargs, args, &info)) { value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) - { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) - { + if (MORPHO_ISCALLABLE(fn)) { functional_mapintegrand(v, &info, &out); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } - else - morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } /** Evaluate a gradient */ -value ScalarPotential_gradient(vm *v, int nargs, value *args) -{ +value ScalarPotential_gradient(vm *v, int nargs, value *args) { functional_mapinfo info; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { + if (functional_validateargs(v, nargs, args, &info)) { value fn; // Check if a gradient function is available - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, &fn)) - { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_gradfunctionproperty, &fn)) { info.g = MESH_GRADE_VERTEX; info.grad = scalarpotential_gradient; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) - { + if (MORPHO_ISCALLABLE(fn)) { functional_mapgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } - else if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) - { + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { // Otherwise try to use the regular scalar function - + value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) - { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) - { + if (MORPHO_ISCALLABLE(fn)) { functional_mapnumericalgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } - else - morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); - } - else - morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + + } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } /** Total function */ -value ScalarPotential_total(vm *v, int nargs, value *args) -{ +value ScalarPotential_total(vm *v, int nargs, value *args) { functional_mapinfo info; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { + if (functional_validateargs(v, nargs, args, &info)) { value fn; - if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) - { + if (objectinstance_getproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), scalarpotential_functionproperty, &fn)) { info.g = MESH_GRADE_VERTEX; info.integrand = scalarpotential_integrand; info.ref = &fn; - if (MORPHO_ISCALLABLE(fn)) - { + if (MORPHO_ISCALLABLE(fn)) { functional_sumintegrand(v, &info, &out); - } - else - morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); - } - else - morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); + } else morpho_runtimeerror(v, SCALARPOTENTIAL_FNCLLBL); + } else morpho_runtimeerror(v, VM_OBJECTLACKSPROPERTY, SCALARPOTENTIAL_FUNCTION_PROPERTY); } return out; } MORPHO_BEGINCLASS(ScalarPotential) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, ScalarPotential_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, ScalarPotential_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, ScalarPotential_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, ScalarPotential_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, ScalarPotential_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, ScalarPotential_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, ScalarPotential_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Linear Elasticity - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Linear Elasticity + * ---------------------------------------------- */ - static value linearelasticity_referenceproperty; +static value linearelasticity_referenceproperty; static value linearelasticity_poissonproperty; -typedef struct -{ +typedef struct { objectmesh *refmesh; grade grade; double lambda; // Lamé coefficients @@ -1511,114 +1197,94 @@ typedef struct } linearelasticityref; /** Calculates the Gram matrix */ -void linearelasticity_calculategram(objectmatrix *vert, int dim, int nv, int *vid, objectmatrix *gram) -{ - int gdim = nv - 1; // Dimension of Gram matrix - double *x[nv], // Positions of vertices - s[gdim][nv]; // Side vectors - - for (int j = 0; j < nv; j++) - matrix_getcolumn(vert, vid[j], &x[j]); // Get vertices - for (int j = 1; j < nv; j++) - functional_vecsub(dim, x[j], x[0], s[j - 1]); // u_i = X_i - X_0 +void linearelasticity_calculategram(objectmatrix *vert, int dim, int nv, int *vid, objectmatrix *gram) { + int gdim=nv-1; // Dimension of Gram matrix + double *x[nv], // Positions of vertices + s[gdim][nv]; // Side vectors + + for (int j=0; j - for (int i = 0; i < nv - 1; i++) - for (int j = 0; j < nv - 1; j++) - gram->elements[i + j * gdim] = functional_vecdot(dim, s[i], s[j]); + for (int i=0; ielements[i+j*gdim]=functional_vecdot(dim, s[i], s[j]); } /** Calculate the linear elastic energy */ -bool linearelasticity_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ - double weight = 0.0; - linearelasticityref *info = (linearelasticityref *)ref; - int gdim = nv - 1; // Dimension of Gram matrix +bool linearelasticity_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + double weight=0.0; + linearelasticityref *info = (linearelasticityref *) ref; + int gdim=nv-1; // Dimension of Gram matrix /* Construct static matrices */ - double gramrefel[gdim * gdim], gramdefel[gdim * gdim], qel[gdim * gdim], rel[gdim * gdim], cgel[gdim * gdim]; + double gramrefel[gdim*gdim], gramdefel[gdim*gdim], qel[gdim*gdim], rel[gdim*gdim], cgel[gdim*gdim]; objectmatrix gramref = MORPHO_STATICMATRIX(gramrefel, gdim, gdim); // Gram matrices objectmatrix gramdef = MORPHO_STATICMATRIX(gramdefel, gdim, gdim); // - objectmatrix q = MORPHO_STATICMATRIX(qel, gdim, gdim); // Inverse of Gram in source domain - objectmatrix r = MORPHO_STATICMATRIX(rel, gdim, gdim); // Intermediate calculations - objectmatrix cg = MORPHO_STATICMATRIX(cgel, gdim, gdim); // Cauchy-Green strain tensor + objectmatrix q = MORPHO_STATICMATRIX(qel, gdim, gdim); // Inverse of Gram in source domain + objectmatrix r = MORPHO_STATICMATRIX(rel, gdim, gdim); // Intermediate calculations + objectmatrix cg = MORPHO_STATICMATRIX(cgel, gdim, gdim); // Cauchy-Green strain tensor linearelasticity_calculategram(info->refmesh->vert, mesh->dim, nv, vid, &gramref); linearelasticity_calculategram(mesh->vert, mesh->dim, nv, vid, &gramdef); - if (matrix_inverse(&gramref, &q) != MATRIX_OK) - return false; - if (matrix_mul(&gramdef, &q, &r) != MATRIX_OK) - return false; + if (matrix_inverse(&gramref, &q)!=MATRIX_OK) return false; + if (matrix_mul(&gramdef, &q, &r)!=MATRIX_OK) return false; matrix_identity(&cg); matrix_scale(&cg, -0.5); matrix_accumulate(&cg, 0.5, &r); - double trcg = 0.0, trcgcg = 0.0; + double trcg=0.0, trcgcg=0.0; matrix_trace(&cg, &trcg); matrix_mul(&cg, &cg, &r); matrix_trace(&r, &trcgcg); - if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &weight)) - return false; + if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &weight)) return false; - *out = weight * (info->mu * trcgcg + 0.5 * info->lambda * trcg * trcg); + *out=weight*(info->mu*trcgcg + 0.5*info->lambda*trcg*trcg); return true; } /** Prepares the reference structure from the LinearElasticity object's properties */ -bool linearelasticity_prepareref(objectinstance *self, linearelasticityref *ref) -{ - bool success = false; - value refmesh = MORPHO_NIL; - value grade = MORPHO_NIL; - value poisson = MORPHO_NIL; +bool linearelasticity_prepareref(objectinstance *self, linearelasticityref *ref) { + bool success=false; + value refmesh=MORPHO_NIL; + value grade=MORPHO_NIL; + value poisson=MORPHO_NIL; if (objectinstance_getproperty(self, linearelasticity_referenceproperty, &refmesh) && objectinstance_getproperty(self, functional_gradeproperty, &grade) && MORPHO_ISINTEGER(grade) && objectinstance_getproperty(self, linearelasticity_poissonproperty, &poisson) && - MORPHO_ISNUMBER(poisson)) - { - ref->refmesh = MORPHO_GETMESH(refmesh); - ref->grade = MORPHO_GETINTEGERVALUE(grade); + MORPHO_ISNUMBER(poisson)) { + ref->refmesh=MORPHO_GETMESH(refmesh); + ref->grade=MORPHO_GETINTEGERVALUE(grade); double nu = MORPHO_GETFLOATVALUE(poisson); - ref->mu = 0.5 / (1 + nu); - ref->lambda = nu / (1 + nu) / (1 - 2 * nu); - success = true; + ref->mu=0.5/(1+nu); + ref->lambda=nu/(1+nu)/(1-2*nu); + success=true; } return success; } -value LinearElasticity_init(vm *v, int nargs, value *args) -{ +value LinearElasticity_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); /* First argument is the reference mesh */ - if (nargs > 0) - { - if (MORPHO_ISMESH(MORPHO_GETARG(args, 0))) - { + if (nargs>0) { + if (MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(self, linearelasticity_referenceproperty, MORPHO_GETARG(args, 0)); objectmesh *mesh = MORPHO_GETMESH(MORPHO_GETARG(args, 0)); objectinstance_setproperty(self, functional_gradeproperty, MORPHO_INTEGER(mesh_maxgrade(mesh))); objectinstance_setproperty(self, linearelasticity_poissonproperty, MORPHO_FLOAT(0.3)); - } - else - morpho_runtimeerror(v, LINEARELASTICITY_REF); - } - else - morpho_runtimeerror(v, LINEARELASTICITY_REF); + } else morpho_runtimeerror(v, LINEARELASTICITY_REF); + } else morpho_runtimeerror(v, LINEARELASTICITY_REF); /* Second (optional) argument is the grade to act on */ - if (nargs > 1) - { - if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) - { + if (nargs>1) { + if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_GETARG(args, 1)); } } @@ -1627,88 +1293,71 @@ value LinearElasticity_init(vm *v, int nargs, value *args) } /** Integrand function */ -value LinearElasticity_integrand(vm *v, int nargs, value *args) -{ +value LinearElasticity_integrand(vm *v, int nargs, value *args) { functional_mapinfo info; linearelasticityref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) - { + if (functional_validateargs(v, nargs, args, &info)) { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; functional_mapintegrand(v, &info, &out); - } - else - morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } /** Total function */ -value LinearElasticity_total(vm *v, int nargs, value *args) -{ +value LinearElasticity_total(vm *v, int nargs, value *args) { functional_mapinfo info; linearelasticityref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) - { + if (functional_validateargs(v, nargs, args, &info)) { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; functional_sumintegrand(v, &info, &out); - } - else - morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); } return out; } /** Integrand function */ -value LinearElasticity_gradient(vm *v, int nargs, value *args) -{ +value LinearElasticity_gradient(vm *v, int nargs, value *args) { functional_mapinfo info; linearelasticityref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) - { + if (functional_validateargs(v, nargs, args, &info)) { + if (linearelasticity_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), &ref)) { info.g = ref.grade; info.integrand = linearelasticity_integrand; info.ref = &ref; info.sym = SYMMETRY_ADD; functional_mapnumericalgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, LINEARELASTICITY_PRP); + } else morpho_runtimeerror(v, LINEARELASTICITY_PRP); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(LinearElasticity) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LinearElasticity_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LinearElasticity_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LinearElasticity_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LinearElasticity_gradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LinearElasticity_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LinearElasticity_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LinearElasticity_gradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Hydrogel - * ---------------------------------------------- */ +/* ---------------------------------------------- +* Hydrogel +* ---------------------------------------------- */ - static value hydrogel_aproperty; +static value hydrogel_aproperty; static value hydrogel_bproperty; static value hydrogel_cproperty; static value hydrogel_dproperty; @@ -1728,8 +1377,8 @@ typedef struct bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, hydrogelref *ref) { bool success = false; - value refmesh = MORPHO_NIL, grade = MORPHO_NIL, phi0 = MORPHO_NIL; - value a = MORPHO_NIL, b = MORPHO_NIL, c = MORPHO_NIL, d = MORPHO_NIL, phiref = MORPHO_NIL; + value refmesh=MORPHO_NIL, grade=MORPHO_NIL, phi0=MORPHO_NIL; + value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL, d=MORPHO_NIL, phiref=MORPHO_NIL; /* Add other parameters relevant to the elasticity term */ if (objectinstance_getproperty(self, linearelasticity_referenceproperty, &refmesh) && objectinstance_getproperty(self, functional_gradeproperty, &grade) && @@ -1771,7 +1420,7 @@ bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, { hydrogelref *info = (hydrogelref *)ref; value vphi0 = info->phi0; - double V = 0.0, V0 = 0.0, phi0 = 0.0; + double V=0.0, V0=0.0, phi0=0.0; if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) return false; @@ -1866,58 +1515,51 @@ FUNCTIONAL_METHOD(Hydrogel, gradient, (ref.grade), hydrogelref, hydrogel_prepare MORPHO_BEGINCLASS(Hydrogel) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Hydrogel_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Hydrogel_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Hydrogel_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Hydrogel_gradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Hydrogel_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Hydrogel_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Hydrogel_gradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Equielement - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Equielement + * ---------------------------------------------- */ - static value equielement_weightproperty; +static value equielement_weightproperty; -typedef struct -{ +typedef struct { grade grade; - objectsparse *vtoel; // Connect vertices to elements - objectsparse *eltov; // Connect elements to vertices + objectsparse *vtoel; // Connect vertices to elements + objectsparse *eltov; // Connect elements to vertices objectmatrix *weight; // Weight field double mean; } equielementref; /** Prepares the reference structure from the Equielement object's properties */ -bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, equielementref *ref) -{ - bool success = false; - value grade = MORPHO_NIL; - value weight = MORPHO_NIL; +bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, equielementref *ref) { + bool success=false; + value grade=MORPHO_NIL; + value weight=MORPHO_NIL; if (objectinstance_getproperty(self, functional_gradeproperty, &grade) && - MORPHO_ISINTEGER(grade)) - { - ref->grade = MORPHO_GETINTEGERVALUE(grade); - ref->weight = NULL; + MORPHO_ISINTEGER(grade) ) { + ref->grade=MORPHO_GETINTEGERVALUE(grade); + ref->weight=NULL; - int maxgrade = mesh_maxgrade(mesh); - if (ref->grade < 0 || ref->grade > maxgrade) - ref->grade = maxgrade; + int maxgrade=mesh_maxgrade(mesh); + if (ref->grade<0 || ref->grade>maxgrade) ref->grade = maxgrade; - ref->vtoel = mesh_addconnectivityelement(mesh, ref->grade, 0); - ref->eltov = mesh_addconnectivityelement(mesh, 0, ref->grade); + ref->vtoel=mesh_addconnectivityelement(mesh, ref->grade, 0); + ref->eltov=mesh_addconnectivityelement(mesh, 0, ref->grade); - if (ref->vtoel && ref->eltov) - success = true; + if (ref->vtoel && ref->eltov) success=true; } if (objectinstance_getproperty(self, equielement_weightproperty, &weight) && - MORPHO_ISMATRIX(weight)) - { - ref->weight = MORPHO_GETMATRIX(weight); - if (ref->weight) - { - ref->mean = matrix_sum(ref->weight); - ref->mean /= ref->weight->ncols; + MORPHO_ISMATRIX(weight) ) { + ref->weight=MORPHO_GETMATRIX(weight); + if (ref->weight) { + ref->mean=matrix_sum(ref->weight); + ref->mean/=ref->weight->ncols; } } @@ -1925,59 +1567,44 @@ bool equielement_prepareref(objectinstance *self, objectmesh *mesh, grade g, obj } /** Calculate the linear elastic energy */ -bool equielement_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *r, double *out) -{ - equielementref *ref = (equielementref *)r; +bool equielement_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *r, double *out) { + equielementref *ref = (equielementref *) r; int nconn, *conn; - if (sparseccs_getrowindices(&ref->vtoel->ccs, id, &nconn, &conn)) - { - if (nconn == 1) - { - *out = 0; - return true; - } + if (sparseccs_getrowindices(&ref->vtoel->ccs, id, &nconn, &conn)) { + if (nconn==1) { *out = 0; return true; } - double size[nconn], mean = 0.0, total = 0.0; + double size[nconn], mean=0.0, total=0.0; - for (int i = 0; i < nconn; i++) - { + for (int i=0; ieltov->ccs, conn[i], &nv, &vid); functional_elementsize(v, mesh, ref->grade, conn[i], nv, vid, &size[i]); - mean += size[i]; + mean+=size[i]; } - mean /= ((double)nconn); + mean /= ((double) nconn); - if (fabs(mean) < MORPHO_EPS) - return false; + if (fabs(mean)weight || fabs(ref->mean) < MORPHO_EPS) - { - for (unsigned int i = 0; i < nconn; i++) - total += (1.0 - size[i] / mean) * (1.0 - size[i] / mean); - } - else - { - double weight[nconn], wmean = 0.0; + if (!ref->weight || fabs(ref->mean)weight, 0, conn[i], &weight[i]); - wmean += weight[i]; + wmean+=weight[i]; } - wmean /= ((double)nconn); - if (fabs(wmean) < MORPHO_EPS) - wmean = 1.0; + wmean /= ((double) nconn); + if (fabs(wmean)selection = sel; + ref->selection=sel; ref->lineel = mesh_getconnectivityelement(mesh, MESH_GRADE_VERTEX, MESH_GRADE_LINE); - if (ref->lineel) - success = sparse_checkformat(ref->lineel, SPARSE_CCS, true, false); + if (ref->lineel) success=sparse_checkformat(ref->lineel, SPARSE_CCS, true, false); - if (success) - { + if (success) { objectsparse *s = mesh_getconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); - if (!s) - s = mesh_addconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); - success = s; + if (!s) s=mesh_addconnectivityelement(mesh, MESH_GRADE_LINE, MESH_GRADE_VERTEX); + success=s; } - if (success) - { - value integrandonly = MORPHO_FALSE; + if (success) { + value integrandonly=MORPHO_FALSE; objectinstance_getproperty(self, curvature_integrandonlyproperty, &integrandonly); - ref->integrandonly = MORPHO_ISTRUE(integrandonly); + ref->integrandonly=MORPHO_ISTRUE(integrandonly); } return success; } /** Finds the points that a point depends on */ -bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) -{ +bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { objectmesh *mesh = info->mesh; curvatureref *cref = info->ref; - bool success = false; + bool success=false; varray_elementid nbrs; varray_elementidinit(&nbrs); - if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs) > 0) - { - for (unsigned int i = 0; i < nbrs.count; i++) - { + if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs)>0) { + for (unsigned int i=0; ilineel->ccs, nbrs.data[i], &nentries, &entries)) - goto linecurvsq_dependencies_cleanup; - for (unsigned int j = 0; j < nentries; j++) - { - if (entries[j] == id) - continue; + if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) goto linecurvsq_dependencies_cleanup; + for (unsigned int j=0; jcount; k++) printf("%u ", out->data[k]); printf("\n");*/ @@ -2099,64 +1710,51 @@ bool linecurvsq_dependencies(functional_mapinfo *info, elementid id, varray_elem } /** Calculate the integral of the curvature squared */ -bool linecurvsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ - curvatureref *cref = (curvatureref *)ref; +bool linecurvsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + curvatureref *cref = (curvatureref *) ref; double result = 0.0; varray_elementid nbrs; varray_elementid synid; varray_elementidinit(&nbrs); varray_elementidinit(&synid); - double s0[mesh->dim], s1[mesh->dim], *s[2] = {s0, s1}, sgn = -1.0; + double s0[mesh->dim], s1[mesh->dim], *s[2] = { s0, s1}, sgn=-1.0; - if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs) > 0 && - mesh_getsynonyms(mesh, MESH_GRADE_VERTEX, id, &synid)) - { - if (nbrs.count != 2) - goto linecurvsq_integrand_cleanup; + if (mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_LINE, &nbrs)>0 && + mesh_getsynonyms(mesh, MESH_GRADE_VERTEX, id, &synid)) { + if (nbrs.count!=2) goto linecurvsq_integrand_cleanup; - for (unsigned int i = 0; i < 2; i++) - { + for (unsigned int i=0; i<2; i++) { int nentries, *entries; // Get the vertices for this edge - if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) - break; + if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) break; double *x0, *x1; if (mesh_getvertexcoordinatesaslist(mesh, entries[0], &x0) && - mesh_getvertexcoordinatesaslist(mesh, entries[1], &x1)) - { + mesh_getvertexcoordinatesaslist(mesh, entries[1], &x1)) { functional_vecsub(mesh->dim, x0, x1, s[i]); } - if (!(entries[0] == id || functional_inlist(&synid, entries[0]))) - sgn *= -1; + if (!(entries[0]==id || functional_inlist(&synid, entries[0]))) sgn*=-1; } - double s0s0 = functional_vecdot(mesh->dim, s0, s0), - s0s1 = functional_vecdot(mesh->dim, s0, s1), - s1s1 = functional_vecdot(mesh->dim, s1, s1); + double s0s0=functional_vecdot(mesh->dim, s0, s0), + s0s1=functional_vecdot(mesh->dim, s0, s1), + s1s1=functional_vecdot(mesh->dim, s1, s1); - s0s0 = sqrt(s0s0); - s1s1 = sqrt(s1s1); + s0s0=sqrt(s0s0); s1s1=sqrt(s1s1); - if (s0s0 < MORPHO_EPS || s1s1 < MORPHO_EPS) - return false; + if (s0s0integrandonly) - result /= len; // Get the bare curvature. + result = u*u/len; + if (cref->integrandonly) result /= len; // Get the bare curvature. } linecurvsq_integrand_cleanup: - + *out = result; varray_elementidclear(&nbrs); varray_elementidclear(&synid); @@ -2171,41 +1769,36 @@ FUNCTIONAL_METHOD(LineCurvatureSq, gradient, MESH_GRADE_VERTEX, curvatureref, cu MORPHO_BEGINCLASS(LineCurvatureSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineCurvatureSq_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineCurvatureSq_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineCurvatureSq_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * LineTorsionSq - * ---------------------------------------------- */ +/* ---------------------------------------------- + * LineTorsionSq + * ---------------------------------------------- */ - /** Return a list of vertices that an element depends on */ - bool linetorsionsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) -{ +/** Return a list of vertices that an element depends on */ +bool linetorsionsq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { objectmesh *mesh = info->mesh; curvatureref *cref = info->ref; - bool success = false; + bool success=false; varray_elementid nbrs; varray_elementid synid; varray_elementidinit(&nbrs); varray_elementidinit(&synid); - if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs) > 0) - { - for (unsigned int i = 0; i < nbrs.count; i++) - { + if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs)>0) { + for (unsigned int i=0; ilineel->ccs, nbrs.data[i], &nentries, &entries)) - goto linetorsionsq_dependencies_cleanup; - for (unsigned int j = 0; j < nentries; j++) - { + if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) goto linetorsionsq_dependencies_cleanup; + for (unsigned int j=0; j 0) - { - if (nbrs.count < 2) - { - *out = 0; - success = true; + if (mesh_findneighbors(mesh, MESH_GRADE_LINE, id, MESH_GRADE_LINE, &nbrs)>0) { + if (nbrs.count<2) { + *out = 0; success=true; goto linecurvsq_torsion_cleanup; } - for (unsigned int i = 0; i < nbrs.count; i++) - { + for (unsigned int i=0; ilineel->ccs, nbrs.data[i], &nentries, &entries)) - goto linecurvsq_torsion_cleanup; - for (unsigned int j = 0; j < nentries; j++) - { // Copy the vertexids - vlist[4 * i + j] = entries[j]; + if (!sparseccs_getrowindices(&cref->lineel->ccs, nbrs.data[i], &nentries, &entries)) goto linecurvsq_torsion_cleanup; + for (unsigned int j=0; jvert, vlist[i], &x[i]); + for (int i=0; i<6; i++) matrix_getcolumn(mesh->vert, vlist[i], &x[i]); double A[3], B[3], C[3], crossAB[3], crossBC[3]; functional_vecsub(3, x[1], x[0], A); @@ -2313,19 +1882,17 @@ bool linetorsionsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int functional_veccross(A, B, crossAB); functional_veccross(B, C, crossBC); - double normB = functional_vecnorm(3, B), - normAB = functional_vecnorm(3, crossAB), - normBC = functional_vecnorm(3, crossBC); + double normB=functional_vecnorm(3, B), + normAB=functional_vecnorm(3, crossAB), + normBC=functional_vecnorm(3, crossBC); - double S = functional_vecdot(3, A, crossBC) * normB; - if (normAB > MORPHO_EPS) - S /= normAB; - if (normBC > MORPHO_EPS) - S /= normBC; + double S = functional_vecdot(3, A, crossBC)*normB; + if (normAB>MORPHO_EPS) S/=normAB; + if (normBC>MORPHO_EPS) S/=normBC; - S = asin(S); - *out = S * S / normB; - success = true; + S=asin(S); + *out=S*S/normB; + success=true; linecurvsq_torsion_cleanup: varray_elementidclear(&nbrs); @@ -2341,56 +1908,49 @@ FUNCTIONAL_METHOD(LineTorsionSq, gradient, MESH_GRADE_LINE, curvatureref, curvat MORPHO_BEGINCLASS(LineTorsionSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineTorsionSq_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineTorsionSq_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineTorsionSq_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineTorsionSq_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, LineTorsionSq_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, LineTorsionSq_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, LineTorsionSq_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * MeanCurvatureSq - * ---------------------------------------------- */ +/* ---------------------------------------------- + * MeanCurvatureSq + * ---------------------------------------------- */ - typedef struct -{ - objectsparse *areael; // Areas +typedef struct { + objectsparse *areael; // Areas objectselection *selection; // Selection - bool integrandonly; // Output integrated curvature or 'bare' curvature. + bool integrandonly; // Output integrated curvature or 'bare' curvature. } areacurvatureref; -bool areacurvature_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, areacurvatureref *ref) -{ +bool areacurvature_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, areacurvatureref *ref) { bool success = true; - ref->selection = sel; + ref->selection=sel; ref->areael = mesh_getconnectivityelement(mesh, MESH_GRADE_VERTEX, MESH_GRADE_AREA); - if (ref->areael) - success = sparse_checkformat(ref->areael, SPARSE_CCS, true, false); + if (ref->areael) success=sparse_checkformat(ref->areael, SPARSE_CCS, true, false); - if (success) - { + if (success) { objectsparse *s = mesh_getconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); - if (!s) - s = mesh_addconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); - success = s; + if (!s) s=mesh_addconnectivityelement(mesh, MESH_GRADE_AREA, MESH_GRADE_VERTEX); + success=s; } - if (success) - { - value integrandonly = MORPHO_FALSE; + if (success) { + value integrandonly=MORPHO_FALSE; objectinstance_getproperty(self, curvature_integrandonlyproperty, &integrandonly); - ref->integrandonly = MORPHO_ISTRUE(integrandonly); + ref->integrandonly=MORPHO_ISTRUE(integrandonly); } return success; } /** Return a list of vertices that an element depends on */ -bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) -{ +bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray_elementid *out) { objectmesh *mesh = info->mesh; areacurvatureref *cref = info->ref; - bool success = false; + bool success=false; varray_elementid nbrs; varray_elementid synid; @@ -2403,20 +1963,16 @@ bool meancurvaturesq_dependencies(functional_mapinfo *info, elementid id, varray /* Loop over synonyms of the element id */ mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i = 0; i < nbrs.count; i++) - { /* Loop over adjacent triangles */ + for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) - goto meancurvsq_dependencies_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) goto meancurvsq_dependencies_cleanup; - for (unsigned int j = 0; j < nvert; j++) - { - if (vids[j] == id) - continue; + for (unsigned int j=0; jcount; k++) - if (synid->data[k] == vids[i]) - { - posn = i; - break; - } +bool curvature_ordervertices(varray_elementid *synid, int nv, int *vids) { + int posn=-1; + for (unsigned int i=0; icount; k++) if (synid->data[k]==vids[i]) { posn = i; break; } } - if (posn > 0) - { // If the desired vertex isn't in first position, move it there. - int tmp = vids[posn]; - vids[posn] = vids[0]; - vids[0] = tmp; + if (posn>0) { // If the desired vertex isn't in first position, move it there. + int tmp=vids[posn]; + vids[posn]=vids[0]; vids[0]=tmp; } - return (posn >= 0); + return (posn>=0); } /** Calculate the integral of the mean curvature squared */ -bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ - areacurvatureref *cref = (areacurvatureref *)ref; +bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + areacurvatureref *cref = (areacurvatureref *) ref; double areasum = 0; - bool success = false; + bool success=false; varray_elementid nbrs; varray_elementid synid; @@ -2465,25 +2011,20 @@ bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in varray_elementidwriteunique(&synid, id); double frc[mesh->dim]; // This will hold the total force due to the triangles present - for (unsigned int i = 0; i < mesh->dim; i++) - frc[i] = 0.0; + for (unsigned int i=0; idim; i++) frc[i]=0.0; mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i = 0; i < nbrs.count; i++) - { /* Loop over adjacent triangles */ + for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) - goto meancurvsq_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) goto meancurvsq_cleanup; /* Order the vertices */ - if (!curvature_ordervertices(&synid, nvert, vids)) - goto meancurvsq_cleanup; + if (!curvature_ordervertices(&synid, nvert, vids)) goto meancurvsq_cleanup; double *x[3], s0[3], s1[3], s01[3], s101[3]; double norm; - for (int j = 0; j < 3; j++) - matrix_getcolumn(mesh->vert, vids[j], &x[j]); + for (int j=0; j<3; j++) matrix_getcolumn(mesh->vert, vids[j], &x[j]); /* s0 = x1-x0; s1 = x2-x1 */ functional_vecsub(mesh->dim, x[1], x[0], s0); @@ -2491,20 +2032,18 @@ bool meancurvaturesq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, in /* F(v0) = (s1 x s0 x s1)/|s0 x x1|/2 */ functional_veccross(s0, s1, s01); - norm = functional_vecnorm(mesh->dim, s01); - if (norm < MORPHO_EPS) - goto meancurvsq_cleanup; + norm=functional_vecnorm(mesh->dim, s01); + if (normdim, frc, 0.5 / norm, s101, frc); + functional_vecaddscale(mesh->dim, frc, 0.5/norm, s101, frc); } - *out = functional_vecdot(mesh->dim, frc, frc) / (areasum / 3.0) / 4.0; - if (cref->integrandonly) - *out /= (areasum / 3.0); - success = true; + *out = functional_vecdot(mesh->dim, frc, frc)/(areasum/3.0)/4.0; + if (cref->integrandonly) *out /= (areasum/3.0); + success=true; meancurvsq_cleanup: varray_elementidclear(&nbrs); @@ -2520,21 +2059,20 @@ FUNCTIONAL_METHOD(MeanCurvatureSq, gradient, MESH_GRADE_VERTEX, areacurvatureref MORPHO_BEGINCLASS(MeanCurvatureSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, MeanCurvatureSq_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, MeanCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, MeanCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, MeanCurvatureSq_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, MeanCurvatureSq_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, MeanCurvatureSq_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, MeanCurvatureSq_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * GaussCurvature - * ---------------------------------------------- */ +/* ---------------------------------------------- + * GaussCurvature + * ---------------------------------------------- */ - /** Calculate the integral of the gaussian curvature */ - bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ - areacurvatureref *cref = (areacurvatureref *)ref; +/** Calculate the integral of the gaussian curvature */ +bool gausscurvature_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { + areacurvatureref *cref = (areacurvatureref *) ref; double anglesum = 0, areasum = 0; - bool success = false; + bool success=false; varray_elementid nbrs; varray_elementid synid; @@ -2545,24 +2083,19 @@ MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, MeanCurvatureSq_init, BUILTIN_FLAGSEMPT varray_elementidwriteunique(&synid, id); double frc[mesh->dim]; // This will hold the total force due to the triangles present - for (unsigned int i = 0; i < mesh->dim; i++) - frc[i] = 0.0; + for (unsigned int i=0; idim; i++) frc[i]=0.0; mesh_findneighbors(mesh, MESH_GRADE_VERTEX, id, MESH_GRADE_AREA, &nbrs); - for (unsigned int i = 0; i < nbrs.count; i++) - { /* Loop over adjacent triangles */ + for (unsigned int i=0; iareael->ccs, nbrs.data[i], &nvert, &vids)) - goto gausscurv_cleanup; + if (!sparseccs_getrowindices(&cref->areael->ccs, nbrs.data[i], &nvert, &vids)) goto gausscurv_cleanup; /* Order the vertices */ - if (!curvature_ordervertices(&synid, nvert, vids)) - goto gausscurv_cleanup; + if (!curvature_ordervertices(&synid, nvert, vids)) goto gausscurv_cleanup; double *x[3], s0[3], s1[3], s01[3]; - for (int j = 0; j < 3; j++) - matrix_getcolumn(mesh->vert, vids[j], &x[j]); + for (int j=0; j<3; j++) matrix_getcolumn(mesh->vert, vids[j], &x[j]); /* s0 = x1-x0; s1 = x2-x0 */ functional_vecsub(mesh->dim, x[1], x[0], s0); @@ -2570,15 +2103,14 @@ MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, MeanCurvatureSq_init, BUILTIN_FLAGSEMPT functional_veccross(s0, s1, s01); double area = functional_vecnorm(mesh->dim, s01); - anglesum += atan2(area, functional_vecdot(mesh->dim, s0, s1)); + anglesum+=atan2(area, functional_vecdot(mesh->dim, s0, s1)); - areasum += area / 2; + areasum+=area/2; } - *out = 2 * M_PI - anglesum; - if (cref->integrandonly) - *out /= (areasum / 3.0); - success = true; + *out = 2*M_PI-anglesum; + if (cref->integrandonly) *out /= (areasum/3.0); + success=true; gausscurv_cleanup: varray_elementidclear(&nbrs); @@ -2594,17 +2126,16 @@ FUNCTIONAL_METHOD(GaussCurvature, gradient, MESH_GRADE_VERTEX, areacurvatureref, MORPHO_BEGINCLASS(GaussCurvature) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GaussCurvature_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GaussCurvature_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GaussCurvature_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GaussCurvature_total, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GaussCurvature_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GaussCurvature_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GaussCurvature_total, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ********************************************************************** - * Fields - * ********************************************************************** */ +/* ********************************************************************** + * Fields + * ********************************************************************** */ - typedef struct -{ +typedef struct { objectfield *field; grade grade; } fieldref; @@ -2613,26 +2144,23 @@ MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GaussCurvature_init, BUILTIN_FLAGSEMPTY * GradSq * ---------------------------------------------- */ -bool gradsq_computeperpendicular(unsigned int n, double *s1, double *s2, double *out) -{ +bool gradsq_computeperpendicular(unsigned int n, double *s1, double *s2, double *out) { double s1s2, s2s2, sout; /* Compute s1 - (s1.s2) s2 / (s2.2) */ s1s2 = functional_vecdot(n, s1, s2); s2s2 = functional_vecdot(n, s2, s2); - if (fabs(s2s2) < MORPHO_EPS) - return false; // Check for side of zero weight + if (fabs(s2s2)psize * mesh->dim units of storage */ -bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) -{ +bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) { double *f[nv]; // Field value lists double *x[nv]; // Vertex coordinates - unsigned int nentries = 0; + unsigned int nentries=0; // Get field values and vertex coordinates - for (unsigned int i = 0; i < nv; i++) - { - if (!mesh_getvertexcoordinatesaslist(mesh, vid[i], &x[i])) - return false; - if (!field_getelementaslist(field, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &f[i])) - return false; + for (unsigned int i=0; idim], t[3][mesh->dim]; @@ -2670,13 +2194,10 @@ bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int * gradsq_computeperpendicular(mesh->dim, s[1], s[0], t[2]); /* Compute the gradient */ - for (unsigned int i = 0; i < mesh->dim * nentries; i++) - out[i] = 0; - for (unsigned int j = 0; j < mesh->dim; j++) - { - for (unsigned int i = 0; i < nentries; i++) - { - functional_vecaddscale(mesh->dim, &out[i * mesh->dim], f[j][i], t[j], &out[i * mesh->dim]); + for (unsigned int i=0; idim*nentries; i++) out[i]=0; + for (unsigned int j=0; jdim; j++) { + for (unsigned int i=0; idim, &out[i*mesh->dim], f[j][i], t[j], &out[i*mesh->dim]); } } @@ -2689,131 +2210,103 @@ bool gradsq_evaluategradient(objectmesh *mesh, objectfield *field, int nv, int * @param[in] nv - number of vertices @param[in] vid - vertex ids @param[out] out - should be field->psize * mesh->dim units of storage */ -bool gradsq_evaluategradient3d(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) -{ - double *f[nv]; // Field value lists - double *x[nv]; // Vertex coordinates - double xarray[nv * mesh->dim]; // Vertex coordinates - double xtarray[nv * mesh->dim]; // Vertex coordinates - unsigned int nentries = 0; +bool gradsq_evaluategradient3d(objectmesh *mesh, objectfield *field, int nv, int *vid, double *out) { + double *f[nv]; // Field value lists + double *x[nv]; // Vertex coordinates + double xarray[nv*mesh->dim]; // Vertex coordinates + double xtarray[nv*mesh->dim]; // Vertex coordinates + unsigned int nentries=0; // Get field values and vertex coordinates - for (unsigned int i = 0; i < nv; i++) - { - if (!mesh_getvertexcoordinatesaslist(mesh, vid[i], &x[i])) - return false; - if (!field_getelementaslist(field, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &f[i])) - return false; + for (unsigned int i=0; idim, x[i], x[0], &xarray[(i - 1) * mesh->dim]); + for (unsigned int i=1; idim, x[i], x[0], &xarray[(i-1)*mesh->dim]); } - - for (unsigned int i = 0; i < mesh->dim * nentries; i++) - out[i] = 0; - + + for (unsigned int i=0; idim*nentries; i++) out[i]=0; + objectmatrix M = MORPHO_STATICMATRIX(xarray, mesh->dim, mesh->dim); objectmatrix Mt = MORPHO_STATICMATRIX(xtarray, mesh->dim, mesh->dim); matrix_transpose(&M, &Mt); - - double farray[nentries * mesh->dim]; // Field elements + + double farray[nentries*mesh->dim]; // Field elements objectmatrix frhs = MORPHO_STATICMATRIX(farray, mesh->dim, nentries); objectmatrix grad = MORPHO_STATICMATRIX(out, mesh->dim, nentries); - + // Loop over elements of the field - for (unsigned int i = 0; i < nentries; i++) - { + for (unsigned int i=0; idim; j++) - farray[i * mesh->dim + j] = f[j + 1][i] - f[0][i]; + for (unsigned int j=0; jdim; j++) farray[i*mesh->dim+j] = f[j+1][i]-f[0][i]; } - + // Solve to obtain the gradient of each element matrix_divs(&Mt, &frhs, &grad); - + return true; } /** Prepares the gradsq reference */ -bool gradsq_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, fieldref *ref) -{ - bool success = false, grdset = false; - value field = MORPHO_NIL, grd = MORPHO_NIL; - +bool gradsq_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, fieldref *ref) { + bool success=false, grdset=false; + value field=MORPHO_NIL, grd=MORPHO_NIL; + if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISFIELD(field)) - { - ref->field = MORPHO_GETFIELD(field); - success = true; + MORPHO_ISFIELD(field)) { + ref->field=MORPHO_GETFIELD(field); + success=true; } - + if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) - { - ref->grade = MORPHO_GETINTEGERVALUE(grd); - if (ref->grade > 0) - grdset = true; + MORPHO_ISINTEGER(grd)) { + ref->grade=MORPHO_GETINTEGERVALUE(grd); + if (ref->grade>0) grdset=true; } - if (!grdset) - ref->grade = mesh_maxgrade(mesh); - + if (!grdset) ref->grade=mesh_maxgrade(mesh); + return success; } /** Calculate the |grad q|^2 energy */ -bool gradsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +bool gradsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { fieldref *eref = ref; - double size = 0; // Length area or volume of the element - double grad[eref->field->psize * mesh->dim]; + double size=0; // Length area or volume of the element + double grad[eref->field->psize*mesh->dim]; - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) - return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; - if (eref->grade == 2) - { - if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, grad)) - return false; - } - else if (eref->grade == 3) - { - if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, grad)) - return false; - } - else - { + if (eref->grade==2) { + if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, grad)) return false; + } else if (eref->grade==3) { + if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, grad)) return false; + } else { return false; } - - double gradnrm = functional_vecnorm(eref->field->psize * mesh->dim, grad); - *out = gradnrm * gradnrm * size; + + double gradnrm=functional_vecnorm(eref->field->psize*mesh->dim, grad); + *out = gradnrm*gradnrm*size; return true; } /** Initialize a GradSq object */ -value GradSq_init(vm *v, int nargs, value *args) -{ +value GradSq_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - if (nargs > 0 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) - { + if (nargs>0 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(self, functional_fieldproperty, MORPHO_GETARG(args, 0)); - } - else - { + } else { morpho_runtimeerror(v, VM_INVALIDARGS); return MORPHO_FALSE; } - + /* Second (optional) argument is the grade to act on */ - if (nargs > 1) - { - if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) - { + if (nargs>1) { + if (MORPHO_ISINTEGER(MORPHO_GETARG(args, 1))) { objectinstance_setproperty(MORPHO_GETINSTANCE(MORPHO_SELF(args)), functional_gradeproperty, MORPHO_GETARG(args, 1)); } } @@ -2827,171 +2320,138 @@ FUNCTIONAL_METHOD(GradSq, total, (ref.grade), fieldref, gradsq_prepareref, funct FUNCTIONAL_METHOD(GradSq, gradient, (ref.grade), fieldref, gradsq_prepareref, functional_mapnumericalgradient, gradsq_integrand, NULL, GRADSQ_ARGS, SYMMETRY_ADD); -value GradSq_fieldgradient(vm *v, int nargs, value *args) -{ +value GradSq_fieldgradient(vm *v, int nargs, value *args) { functional_mapinfo info; fieldref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) - { + if (functional_validateargs(v, nargs, args, &info)) { + if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { info.g = ref.grade; info.field = ref.field; info.integrand = gradsq_integrand; info.ref = &ref; functional_mapnumericalfieldgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, GRADSQ_ARGS); + } else morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(GradSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GradSq_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GradSq_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GradSq_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GradSq_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, GradSq_fieldgradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, GradSq_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, GradSq_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, GradSq_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, GradSq_fieldgradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * Nematic - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Nematic + * ---------------------------------------------- */ - static value nematic_ksplayproperty; +static value nematic_ksplayproperty; static value nematic_ktwistproperty; static value nematic_kbendproperty; static value nematic_pitchproperty; -typedef struct -{ - double ksplay, ktwist, kbend, pitch; +typedef struct { + double ksplay,ktwist,kbend,pitch; bool haspitch; objectfield *field; grade grade; } nematicref; /** Prepares the nematic reference */ -bool nematic_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicref *ref) -{ - bool success = false, grdset = false; - value field = MORPHO_NIL, grd = MORPHO_NIL; - value val = MORPHO_NIL; - ref->ksplay = 1.0; - ref->ktwist = 1.0; - ref->kbend = 1.0; - ref->pitch = 0.0; - ref->haspitch = false; +bool nematic_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicref *ref) { + bool success=false, grdset=false; + value field=MORPHO_NIL, grd=MORPHO_NIL; + value val=MORPHO_NIL; + ref->ksplay=1.0; ref->ktwist=1.0; ref->kbend=1.0; ref->pitch=0.0; + ref->haspitch=false; if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISFIELD(field)) - { - ref->field = MORPHO_GETFIELD(field); - success = true; + MORPHO_ISFIELD(field)) { + ref->field=MORPHO_GETFIELD(field); + success=true; } - if (objectinstance_getproperty(self, nematic_ksplayproperty, &val) && MORPHO_ISNUMBER(val)) - { + if (objectinstance_getproperty(self, nematic_ksplayproperty, &val) && MORPHO_ISNUMBER(val)) { morpho_valuetofloat(val, &ref->ksplay); } - if (objectinstance_getproperty(self, nematic_ktwistproperty, &val) && MORPHO_ISNUMBER(val)) - { + if (objectinstance_getproperty(self, nematic_ktwistproperty, &val) && MORPHO_ISNUMBER(val)) { morpho_valuetofloat(val, &ref->ktwist); } - if (objectinstance_getproperty(self, nematic_kbendproperty, &val) && MORPHO_ISNUMBER(val)) - { + if (objectinstance_getproperty(self, nematic_kbendproperty, &val) && MORPHO_ISNUMBER(val)) { morpho_valuetofloat(val, &ref->kbend); } - if (objectinstance_getproperty(self, nematic_pitchproperty, &val) && MORPHO_ISNUMBER(val)) - { + if (objectinstance_getproperty(self, nematic_pitchproperty, &val) && MORPHO_ISNUMBER(val)) { morpho_valuetofloat(val, &ref->pitch); - ref->haspitch = true; + ref->haspitch=true; } - + if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) - { - ref->grade = MORPHO_GETINTEGERVALUE(grd); - if (ref->grade > 0) - grdset = true; + MORPHO_ISINTEGER(grd)) { + ref->grade=MORPHO_GETINTEGERVALUE(grd); + if (ref->grade>0) grdset=true; } - if (!grdset) - ref->grade = mesh_maxgrade(mesh); - + if (!grdset) ref->grade=mesh_maxgrade(mesh); + return success; } /* Integrates two linear functions with values at vertices f[0]...f[2] and g[0]...g[2] */ -double nematic_bcint(double *f, double *g) -{ - return (f[0] * (2 * g[0] + g[1] + g[2]) + f[1] * (g[0] + 2 * g[1] + g[2]) + f[2] * (g[0] + g[1] + 2 * g[2])) / 12; +double nematic_bcint(double *f, double *g) { + return (f[0]*(2*g[0]+g[1]+g[2]) + f[1]*(g[0]+2*g[1]+g[2]) + f[2]*(g[0]+g[1]+2*g[2]))/12; } /* Integrates a linear vector function with values at vertices f[0]...f[2] */ -double nematic_bcint1(double *f) -{ - return (f[0] + f[1] + f[2]) / 3; +double nematic_bcint1(double *f) { + return (f[0] + f[1] + f[2])/3; } /* Integrates a linear vector function with values at vertices f[0]...f[n] Works for dimensions 1-3 at least */ -double nematic_bcintf(unsigned int n, double *f) -{ +double nematic_bcintf(unsigned int n, double *f) { double sum = 0; - for (unsigned int i = 0; i < n; i++) - sum += f[i]; - return sum / n; + for (unsigned int i=0; ifield->psize * mesh->dim]; + double size=0; // Length area or volume of the element + double gradnn[eref->field->psize*mesh->dim]; double divnn, curlnn[mesh->dim]; - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) - return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; // Get nematic director components double *nn[nv]; // Field value lists - unsigned int nentries = 0; - for (unsigned int i = 0; i < nv; i++) - { - if (!field_getelementaslist(eref->field, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) - return false; + unsigned int nentries=0; + for (unsigned int i=0; ifield, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) return false; } // Evaluate gradients of the director - if (eref->grade == 2) - { - if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, gradnn)) - return false; - } - else if (eref->grade == 3) - { - if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, gradnn)) - return false; + if (eref->grade==2) { + if (!gradsq_evaluategradient(mesh, eref->field, nv, vid, gradnn)) return + false; + } else if (eref->grade==3) { + if (!gradsq_evaluategradient3d(mesh, eref->field, nv, vid, gradnn)) return + false; } // Output of this is the matrix: // [ nx,x ny,x nz,x ] [ 0 3 6 ] <- indices @@ -3000,91 +2460,81 @@ bool nematic_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, objectmatrix gradnnmat = MORPHO_STATICMATRIX(gradnn, mesh->dim, mesh->dim); matrix_trace(&gradnnmat, &divnn); - curlnn[0] = gradnn[7] - gradnn[5]; // nz,y - ny,z - curlnn[1] = gradnn[2] - gradnn[6]; // nx,z - nz,x - curlnn[2] = gradnn[3] - gradnn[1]; // ny,x - nx,y + curlnn[0]=gradnn[7]-gradnn[5]; // nz,y - ny,z + curlnn[1]=gradnn[2]-gradnn[6]; // nx,z - nz,x + curlnn[2]=gradnn[3]-gradnn[1]; // ny,x - nx,y /* From components of the curl, construct the coefficients that go in front of integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element. */ - double ctwst[6] = {curlnn[0] * curlnn[0], curlnn[1] * curlnn[1], curlnn[2] * curlnn[2], - 2 * curlnn[0] * curlnn[1], 2 * curlnn[1] * curlnn[2], 2 * curlnn[2] * curlnn[0]}; + double ctwst[6] = { curlnn[0]*curlnn[0], curlnn[1]*curlnn[1], curlnn[2]*curlnn[2], + 2*curlnn[0]*curlnn[1], 2*curlnn[1]*curlnn[2], 2*curlnn[2]*curlnn[0]}; - double cbnd[6] = {ctwst[1] + ctwst[2], ctwst[0] + ctwst[2], ctwst[0] + ctwst[1], - -ctwst[3], -ctwst[4], -ctwst[5]}; + double cbnd[6] = { ctwst[1] + ctwst[2], ctwst[0] + ctwst[2], ctwst[0] + ctwst[1], + -ctwst[3], -ctwst[4], -ctwst[5] }; /* Calculate integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element */ double nnt[mesh->dim][nv]; // The transpose of nn - for (unsigned int i = 0; i < nv; i++) - for (unsigned int j = 0; j < mesh->dim; j++) - nnt[j][i] = nn[i][j]; + for (unsigned int i=0; idim; j++) nnt[j][i]=nn[i][j]; - double integrals[] = {nematic_bcintfg(nv, nnt[0], nnt[0]), - nematic_bcintfg(nv, nnt[1], nnt[1]), - nematic_bcintfg(nv, nnt[2], nnt[2]), - nematic_bcintfg(nv, nnt[0], nnt[1]), - nematic_bcintfg(nv, nnt[1], nnt[2]), - nematic_bcintfg(nv, nnt[2], nnt[0])}; + double integrals[] = { nematic_bcintfg(nv, nnt[0], nnt[0]), + nematic_bcintfg(nv, nnt[1], nnt[1]), + nematic_bcintfg(nv, nnt[2], nnt[2]), + nematic_bcintfg(nv, nnt[0], nnt[1]), + nematic_bcintfg(nv, nnt[1], nnt[2]), + nematic_bcintfg(nv, nnt[2], nnt[0]) + }; /* Now we can calculate the components of splay, twist and bend */ - double splay = 0.0, twist = 0.0, bend = 0.0, chol = 0.0; + double splay=0.0, twist=0.0, bend=0.0, chol=0.0; /* Evaluate the three contributions to the integral */ - splay = 0.5 * eref->ksplay * size * divnn * divnn; - for (unsigned int i = 0; i < 6; i++) - { - twist += ctwst[i] * integrals[i]; - bend += cbnd[i] * integrals[i]; + splay = 0.5*eref->ksplay*size*divnn*divnn; + for (unsigned int i=0; i<6; i++) { + twist += ctwst[i]*integrals[i]; + bend += cbnd[i]*integrals[i]; } - twist *= 0.5 * eref->ktwist * size; - bend *= 0.5 * eref->kbend * size; + twist *= 0.5*eref->ktwist*size; + bend *= 0.5*eref->kbend*size; - if (eref->haspitch) - { + if (eref->haspitch) { /* Cholesteric terms: 0.5 * k22 * [- 2 q (cx + cy + cz ) + q^2] */ - for (unsigned i = 0; i < 3; i++) - { - chol += -2 * curlnn[i] * nematic_bcintf(nv, nnt[i]) * eref->pitch; + for (unsigned i=0; i<3; i++) { + chol += -2*curlnn[i]*nematic_bcintf(nv, nnt[i])*eref->pitch; } - chol += (eref->pitch * eref->pitch); - chol *= 0.5 * eref->ktwist * size; + chol += (eref->pitch*eref->pitch); + chol *= 0.5*eref->ktwist*size; } - *out = splay + twist + bend + chol; + *out = splay+twist+bend+chol; return true; } /** Initialize a Nematic object */ -value Nematic_init(vm *v, int nargs, value *args) -{ +value Nematic_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - int nfixed = nargs; - value ksplay = MORPHO_FLOAT(1.0), - ktwist = MORPHO_FLOAT(1.0), - kbend = MORPHO_FLOAT(1.0); - value pitch = MORPHO_NIL; + int nfixed=nargs; + value ksplay=MORPHO_FLOAT(1.0), + ktwist=MORPHO_FLOAT(1.0), + kbend=MORPHO_FLOAT(1.0); + value pitch=MORPHO_NIL; if (builtin_options(v, nargs, args, &nfixed, 4, nematic_ksplayproperty, &ksplay, nematic_ktwistproperty, &ktwist, nematic_kbendproperty, &kbend, - nematic_pitchproperty, &pitch)) - { + nematic_pitchproperty, &pitch)) { objectinstance_setproperty(self, nematic_ksplayproperty, ksplay); objectinstance_setproperty(self, nematic_ktwistproperty, ktwist); objectinstance_setproperty(self, nematic_kbendproperty, kbend); objectinstance_setproperty(self, nematic_pitchproperty, pitch); - } - else - morpho_runtimeerror(v, NEMATIC_ARGS); + } else morpho_runtimeerror(v, NEMATIC_ARGS); - if (nfixed == 1 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) - { + if (nfixed==1 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(self, functional_fieldproperty, MORPHO_GETARG(args, 0)); - } - else - morpho_runtimeerror(v, NEMATIC_ARGS); + } else morpho_runtimeerror(v, NEMATIC_ARGS); return MORPHO_NIL; } @@ -3095,154 +2545,124 @@ FUNCTIONAL_METHOD(Nematic, total, (ref.grade), nematicref, nematic_prepareref, f FUNCTIONAL_METHOD(Nematic, gradient, (ref.grade), nematicref, nematic_prepareref, functional_mapnumericalgradient, nematic_integrand, NULL, NEMATIC_ARGS, SYMMETRY_NONE); -value Nematic_fieldgradient(vm *v, int nargs, value *args) -{ +value Nematic_fieldgradient(vm *v, int nargs, value *args) { functional_mapinfo info; nematicref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (nematic_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) - { - info.g = ref.grade; - info.integrand = nematic_integrand; - info.ref = &ref; + if (functional_validateargs(v, nargs, args, &info)) { + if (nematic_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { + info.g=ref.grade; + info.integrand=nematic_integrand; + info.ref=&ref; functional_mapnumericalfieldgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, GRADSQ_ARGS); + } else morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(Nematic) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, Nematic_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Nematic_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Nematic_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Nematic_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, Nematic_fieldgradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, Nematic_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, Nematic_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, Nematic_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, Nematic_fieldgradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ---------------------------------------------- - * NematicElectric - * ---------------------------------------------- */ +/* ---------------------------------------------- + * NematicElectric + * ---------------------------------------------- */ - typedef struct -{ +typedef struct { objectfield *director; value field; grade grade; } nematicelectricref; /** Prepares the nematicelectric reference */ -bool nematicelectric_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicelectricref *ref) -{ - bool success = false, grdset = false; - ref->field = MORPHO_NIL; - value fieldlist = MORPHO_NIL, grd = MORPHO_NIL; +bool nematicelectric_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, nematicelectricref *ref) { + bool success=false, grdset=false; + ref->field=MORPHO_NIL; + value fieldlist=MORPHO_NIL, grd=MORPHO_NIL; if (objectinstance_getproperty(self, functional_fieldproperty, &fieldlist) && - MORPHO_ISLIST(fieldlist)) - { + MORPHO_ISLIST(fieldlist)) { objectlist *lst = MORPHO_GETLIST(fieldlist); value director = MORPHO_NIL; list_getelement(lst, 0, &director); list_getelement(lst, 1, &ref->field); - if (MORPHO_ISFIELD(director)) - ref->director = MORPHO_GETFIELD(director); + if (MORPHO_ISFIELD(director)) ref->director=MORPHO_GETFIELD(director); - if (MORPHO_ISFIELD(ref->field) || MORPHO_ISMATRIX(ref->field)) - success = true; + if (MORPHO_ISFIELD(ref->field) || MORPHO_ISMATRIX(ref->field)) success=true; } if (objectinstance_getproperty(self, functional_gradeproperty, &grd) && - MORPHO_ISINTEGER(grd)) - { - ref->grade = MORPHO_GETINTEGERVALUE(grd); - if (ref->grade > 0) - grdset = true; + MORPHO_ISINTEGER(grd)) { + ref->grade=MORPHO_GETINTEGERVALUE(grd); + if (ref->grade>0) grdset=true; } - if (!grdset) - ref->grade = mesh_maxgrade(mesh); - + if (!grdset) ref->grade=mesh_maxgrade(mesh); + return success; } /** Calculate the integral (n.E)^2 energy, where E is calculated from the electric potential */ -bool nematicelectric_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +bool nematicelectric_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { nematicelectricref *eref = ref; - double size = 0; // Length area or volume of the element + double size=0; // Length area or volume of the element - if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) - return false; + if (!functional_elementsize(v, mesh, eref->grade, id, nv, vid, &size)) return false; // Get nematic director components double *nn[nv]; // Field value lists - unsigned int nentries = 0; - for (unsigned int i = 0; i < nv; i++) - { - if (!field_getelementaslist(eref->director, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) - return false; + unsigned int nentries=0; + for (unsigned int i=0; idirector, MESH_GRADE_VERTEX, vid[i], 0, &nentries, &nn[i])) return false; } // The electric field ends up being constant over the element double ee[mesh->dim]; - if (MORPHO_ISFIELD(eref->field)) - { - if (eref->grade == 2) - { - if (!gradsq_evaluategradient(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) - return false; - } - else if (eref->grade == 3) - { - if (!gradsq_evaluategradient3d(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) - return false; + if (MORPHO_ISFIELD(eref->field)) { + if (eref->grade==2) { + if (!gradsq_evaluategradient(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) return false; + } else if (eref->grade==3) { + if (!gradsq_evaluategradient3d(mesh, MORPHO_GETFIELD(eref->field), nv, vid, ee)) return false; } } /* Calculate integrals of nx^2, ny^2, nz^2, nx*ny, ny*nz, and nz*nx over the element */ double nnt[mesh->dim][nv]; // The transpose of nn - for (unsigned int i = 0; i < nv; i++) - for (unsigned int j = 0; j < mesh->dim; j++) - nnt[j][i] = nn[i][j]; + for (unsigned int i=0; idim; j++) nnt[j][i]=nn[i][j]; /* Calculate integral (n.e)^2 using the above results */ - double total = ee[0] * ee[0] * nematic_bcintfg(nv, nnt[0], nnt[0]) + - ee[1] * ee[1] * nematic_bcintfg(nv, nnt[1], nnt[1]) + - ee[2] * ee[2] * nematic_bcintfg(nv, nnt[2], nnt[2]) + - 2 * ee[0] * ee[1] * nematic_bcintfg(nv, nnt[0], nnt[1]) + - 2 * ee[1] * ee[2] * nematic_bcintfg(nv, nnt[1], nnt[2]) + - 2 * ee[2] * ee[0] * nematic_bcintfg(nv, nnt[2], nnt[0]); + double total = ee[0]*ee[0]*nematic_bcintfg(nv, nnt[0], nnt[0])+ + ee[1]*ee[1]*nematic_bcintfg(nv, nnt[1], nnt[1])+ + ee[2]*ee[2]*nematic_bcintfg(nv, nnt[2], nnt[2])+ + 2*ee[0]*ee[1]*nematic_bcintfg(nv, nnt[0], nnt[1])+ + 2*ee[1]*ee[2]*nematic_bcintfg(nv, nnt[1], nnt[2])+ + 2*ee[2]*ee[0]*nematic_bcintfg(nv, nnt[2], nnt[0]); - *out = size * total; + *out = size*total; return true; } /** Initialize a NematicElectric object */ -value NematicElectric_init(vm *v, int nargs, value *args) -{ +value NematicElectric_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); - if (nargs == 2 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0)) && - MORPHO_ISFIELD(MORPHO_GETARG(args, 1))) - { + if (nargs==2 && MORPHO_ISFIELD(MORPHO_GETARG(args, 0)) && + MORPHO_ISFIELD(MORPHO_GETARG(args, 1))) { objectlist *new = object_newlist(2, &MORPHO_GETARG(args, 0)); - if (new) - { + if (new) { value lst = MORPHO_OBJECT(new); objectinstance_setproperty(self, functional_fieldproperty, lst); morpho_bindobjects(v, 1, &lst); } - } - else - morpho_runtimeerror(v, NEMATICELECTRIC_ARGS); + } else morpho_runtimeerror(v, NEMATICELECTRIC_ARGS); return MORPHO_NIL; } @@ -3253,50 +2673,42 @@ FUNCTIONAL_METHOD(NematicElectric, total, (ref.grade), nematicelectricref, nemat FUNCTIONAL_METHOD(NematicElectric, gradient, (ref.grade), nematicelectricref, nematicelectric_prepareref, functional_mapnumericalgradient, nematicelectric_integrand, NULL, FUNCTIONAL_ARGS, SYMMETRY_NONE); -value NematicElectric_fieldgradient(vm *v, int nargs, value *args) -{ +value NematicElectric_fieldgradient(vm *v, int nargs, value *args) { functional_mapinfo info; nematicelectricref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { - if (nematicelectric_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) - { - info.g = ref.grade; - info.integrand = nematicelectric_integrand; - info.ref = &ref; + if (functional_validateargs(v, nargs, args, &info)) { + if (nematicelectric_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { + info.g=ref.grade; + info.integrand=nematicelectric_integrand; + info.ref=&ref; functional_mapnumericalfieldgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, GRADSQ_ARGS); + } else morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(NematicElectric) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, NematicElectric_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NematicElectric_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NematicElectric_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NematicElectric_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NematicElectric_fieldgradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS - - /* ---------------------------------------------- - * NormSq - * ---------------------------------------------- */ - - /** Calculate the norm squared of a field quantity */ - bool normsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NematicElectric_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NematicElectric_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NematicElectric_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NematicElectric_fieldgradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS + +/* ---------------------------------------------- + * NormSq + * ---------------------------------------------- */ + +/** Calculate the norm squared of a field quantity */ +bool normsq_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { fieldref *eref = ref; unsigned int nentries; double *entries; - if (field_getelementaslist(eref->field, MESH_GRADE_VERTEX, id, 0, &nentries, &entries)) - { + if (field_getelementaslist(eref->field, MESH_GRADE_VERTEX, id, 0, &nentries, &entries)) { *out = functional_vecdot(nentries, entries, entries); return true; } @@ -3310,57 +2722,49 @@ FUNCTIONAL_METHOD(NormSq, total, MESH_GRADE_VERTEX, fieldref, gradsq_prepareref, FUNCTIONAL_METHOD(NormSq, gradient, MESH_GRADE_AREA, fieldref, gradsq_prepareref, functional_mapnumericalgradient, normsq_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); -value NormSq_fieldgradient(vm *v, int nargs, value *args) -{ +value NormSq_fieldgradient(vm *v, int nargs, value *args) { functional_mapinfo info; fieldref ref; - value out = MORPHO_NIL; - - if (functional_validateargs(v, nargs, args, &info)) - { - if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_VERTEX, info.sel, &ref)) - { - info.g = MESH_GRADE_VERTEX; - info.ref = &ref; - info.field = ref.field; - info.integrand = normsq_integrand; + value out=MORPHO_NIL; + + if (functional_validateargs(v, nargs, args, &info)) { + if (gradsq_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_VERTEX, info.sel, &ref)) { + info.g=MESH_GRADE_VERTEX; + info.ref=&ref; + info.field=ref.field; + info.integrand=normsq_integrand; functional_mapnumericalfieldgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, GRADSQ_ARGS); + } else morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(NormSq) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, GradSq_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NormSq_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NormSq_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NormSq_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NormSq_fieldgradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, NormSq_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, NormSq_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, NormSq_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, NormSq_fieldgradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ********************************************************************** - * Integrals - * ********************************************************************** */ +/* ********************************************************************** + * Integrals + * ********************************************************************** */ - /* ---------------------------------------------- - * Integrand functions - * ---------------------------------------------- */ +/* ---------------------------------------------- + * Integrand functions + * ---------------------------------------------- */ - value tangent; +value tangent; -static value functional_tangent(vm *v, int nargs, value *args) -{ +static value functional_tangent(vm *v, int nargs, value *args) { return tangent; } value norml; -static value functional_normal(vm *v, int nargs, value *args) -{ +static value functional_normal(vm *v, int nargs, value *args) { return norml; } @@ -3368,8 +2772,7 @@ static value functional_normal(vm *v, int nargs, value *args) * LineIntegral * ---------------------------------------------- */ -typedef struct -{ +typedef struct { value integrand; int nfields; value *fields; @@ -3377,43 +2780,37 @@ typedef struct } integralref; /** Prepares an integral reference */ -bool integral_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, integralref *ref) -{ - bool success = false; - value func = MORPHO_NIL; - value field = MORPHO_NIL; - ref->v = NULL; - ref->nfields = 0; +bool integral_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, integralref *ref) { + bool success=false; + value func=MORPHO_NIL; + value field=MORPHO_NIL; + ref->v=NULL; + ref->nfields=0; if (objectinstance_getproperty(self, scalarpotential_functionproperty, &func) && - MORPHO_ISCALLABLE(func)) - { - ref->integrand = func; - success = true; + MORPHO_ISCALLABLE(func)) { + ref->integrand=func; + success=true; } if (objectinstance_getproperty(self, functional_fieldproperty, &field) && - MORPHO_ISLIST(field)) - { + MORPHO_ISLIST(field)) { objectlist *list = MORPHO_GETLIST(field); - ref->nfields = list->val.count; - ref->fields = list->val.data; + ref->nfields=list->val.count; + ref->fields=list->val.data; } return success; } -bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int nquantity, value *quantity, void *ref, double *fout) -{ +bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int nquantity, value *quantity, void *ref, double *fout) { integralref *iref = ref; objectmatrix posn = MORPHO_STATICMATRIX(x, dim, 1); - value args[nquantity + 1], out; + value args[nquantity+1], out; - args[0] = MORPHO_OBJECT(&posn); - for (unsigned int i = 0; i < nquantity; i++) - args[i + 1] = quantity[i]; + args[0]=MORPHO_OBJECT(&posn); + for (unsigned int i=0; iv, iref->integrand, nquantity + 1, args, &out)) - { - morpho_valuetofloat(out, fout); + if (morpho_call(iref->v, iref->integrand, nquantity+1, args, &out)) { + morpho_valuetofloat(out,fout); return true; } @@ -3421,43 +2818,36 @@ bool integral_integrandfn(unsigned int dim, double *t, double *x, unsigned int n } /** Integrate a function over a line */ -bool lineintegral_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +bool lineintegral_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { integralref *iref = ref; double *x[2], size; bool success; - if (!functional_elementsize(v, mesh, MESH_GRADE_LINE, id, nv, vid, &size)) - return false; + if (!functional_elementsize(v, mesh, MESH_GRADE_LINE, id, nv, vid, &size)) return false; - iref->v = v; - for (unsigned int i = 0; i < nv; i++) - { + iref->v=v; + for (unsigned int i=0; idim], tnorm = 0.0; + double tangentdata[mesh->dim], tnorm=0.0; functional_vecsub(mesh->dim, x[1], x[0], tangentdata); - tnorm = functional_vecnorm(mesh->dim, tangentdata); - if (fabs(tnorm) > MORPHO_EPS) - functional_vecscale(mesh->dim, 1.0 / tnorm, tangentdata, tangentdata); + tnorm=functional_vecnorm(mesh->dim, tangentdata); + if (fabs(tnorm)>MORPHO_EPS) functional_vecscale(mesh->dim, 1.0/tnorm, tangentdata, tangentdata); objectmatrix mtangent = MORPHO_STATICMATRIX(tangentdata, mesh->dim, 1); tangent = MORPHO_OBJECT(&mtangent); - value q0[iref->nfields + 1], q1[iref->nfields + 1]; - value *q[2] = {q0, q1}; - for (unsigned int k = 0; k < iref->nfields; k++) - { - for (unsigned int i = 0; i < nv; i++) - { + value q0[iref->nfields+1], q1[iref->nfields+1]; + value *q[2] = { q0, q1 }; + for (unsigned int k=0; knfields; k++) { + for (unsigned int i=0; ifields[k]), MESH_GRADE_VERTEX, vid[i], 0, &q[i][k]); } } - success = integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_LINE, x, iref->nfields, q, iref, out); - if (success) - *out *= size; + success=integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_LINE, x, iref->nfields, q, iref, out); + if (success) *out *=size; return success; } @@ -3469,48 +2859,35 @@ FUNCTIONAL_METHOD(LineIntegral, total, MESH_GRADE_LINE, integralref, integral_pr FUNCTIONAL_METHOD(LineIntegral, gradient, MESH_GRADE_LINE, integralref, integral_prepareref, functional_mapnumericalgradient, lineintegral_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); /** Initialize a LineIntegral object */ -value LineIntegral_init(vm *v, int nargs, value *args) -{ +value LineIntegral_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); int nparams = -1, nfields = 0; - if (nargs > 0) - { + if (nargs>0) { value f = MORPHO_GETARG(args, 0); - if (morpho_countparameters(f, &nparams)) - { + if (morpho_countparameters(f, &nparams)) { objectinstance_setproperty(self, scalarpotential_functionproperty, MORPHO_GETARG(args, 0)); - } - else - { + } else { morpho_runtimeerror(v, LINEINTEGRAL_ARGS); return MORPHO_NIL; } } - if (nparams != nargs) - { + if (nparams!=nargs) { morpho_runtimeerror(v, LINEINTEGRAL_NFLDS); return MORPHO_NIL; } - if (nargs > 1) - { + if (nargs>1) { /* Remaining arguments should be fields */ - objectlist *list = object_newlist(nargs - 1, &MORPHO_GETARG(args, 1)); - if (!list) - { - morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); - return MORPHO_NIL; - } + objectlist *list = object_newlist(nargs-1, & MORPHO_GETARG(args, 1)); + if (!list) { morpho_runtimeerror(v, ERROR_ALLOCATIONFAILED); return MORPHO_NIL; } - for (unsigned int i = 1; i < nargs; i++) - { - if (!MORPHO_ISFIELD(MORPHO_GETARG(args, i))) - { + for (unsigned int i=1; iv = v; - for (unsigned int i = 0; i < nv; i++) - { + iref->v=v; + for (unsigned int i=0; idim], s1[mesh->dim], normaldata[mesh->dim], nnorm = 0.0; + double s0[mesh->dim], s1[mesh->dim], normaldata[mesh->dim], nnorm=0.0; functional_vecsub(mesh->dim, x[1], x[0], s0); functional_vecsub(mesh->dim, x[2], x[1], s1); functional_veccross(s0, s1, normaldata); - nnorm = functional_vecnorm(mesh->dim, normaldata); - if (fabs(nnorm) > MORPHO_EPS) - functional_vecscale(mesh->dim, 1.0 / nnorm, normaldata, normaldata); + nnorm=functional_vecnorm(mesh->dim, normaldata); + if (fabs(nnorm)>MORPHO_EPS) functional_vecscale(mesh->dim, 1.0/nnorm, normaldata, normaldata); objectmatrix mnormal = MORPHO_STATICMATRIX(normaldata, mesh->dim, 1); norml = MORPHO_OBJECT(&mnormal); - - value q0[iref->nfields + 1], q1[iref->nfields + 1], q2[iref->nfields + 1]; - value *q[3] = {q0, q1, q2}; - for (unsigned int k = 0; k < iref->nfields; k++) - { - for (unsigned int i = 0; i < nv; i++) - { + + value q0[iref->nfields+1], q1[iref->nfields+1], q2[iref->nfields+1]; + value *q[3] = { q0, q1, q2 }; + for (unsigned int k=0; knfields; k++) { + for (unsigned int i=0; ifields[k]), MESH_GRADE_VERTEX, vid[i], 0, &q[i][k]); } } - success = integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_AREA, x, iref->nfields, q, iref, out); - if (success) - *out *= size; + success=integrate_integrate(integral_integrandfn, mesh->dim, MESH_GRADE_AREA, x, iref->nfields, q, iref, out); + if (success) *out *=size; return success; } @@ -3611,63 +2975,56 @@ FUNCTIONAL_METHOD(AreaIntegral, total, MESH_GRADE_AREA, integralref, integral_pr FUNCTIONAL_METHOD(AreaIntegral, gradient, MESH_GRADE_AREA, integralref, integral_prepareref, functional_mapnumericalgradient, areaintegral_integrand, NULL, GRADSQ_ARGS, SYMMETRY_NONE); /** Field gradients for Area Integrals */ -value AreaIntegral_fieldgradient(vm *v, int nargs, value *args) -{ +value AreaIntegral_fieldgradient(vm *v, int nargs, value *args) { functional_mapinfo info; integralref ref; - value out = MORPHO_NIL; + value out=MORPHO_NIL; - if (functional_validateargs(v, nargs, args, &info)) - { + if (functional_validateargs(v, nargs, args, &info)) { // Should check whether the field is known about here... - if (integral_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) - { - info.g = MESH_GRADE_AREA; - info.integrand = areaintegral_integrand; - info.ref = &ref; + if (integral_prepareref(MORPHO_GETINSTANCE(MORPHO_SELF(args)), info.mesh, MESH_GRADE_AREA, info.sel, &ref)) { + info.g=MESH_GRADE_AREA; + info.integrand=areaintegral_integrand; + info.ref=&ref; functional_mapnumericalfieldgradient(v, &info, &out); - } - else - morpho_runtimeerror(v, GRADSQ_ARGS); + } else morpho_runtimeerror(v, GRADSQ_ARGS); } - if (!MORPHO_ISNIL(out)) - morpho_bindobjects(v, 1, &out); + if (!MORPHO_ISNIL(out)) morpho_bindobjects(v, 1, &out); return out; } MORPHO_BEGINCLASS(AreaIntegral) MORPHO_METHOD(MORPHO_INITIALIZER_METHOD, LineIntegral_init, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaIntegral_integrand, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaIntegral_total, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaIntegral_gradient, BUILTIN_FLAGSEMPTY), - MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, AreaIntegral_fieldgradient, BUILTIN_FLAGSEMPTY) - MORPHO_ENDCLASS +MORPHO_METHOD(FUNCTIONAL_INTEGRAND_METHOD, AreaIntegral_integrand, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_TOTAL_METHOD, AreaIntegral_total, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_GRADIENT_METHOD, AreaIntegral_gradient, BUILTIN_FLAGSEMPTY), +MORPHO_METHOD(FUNCTIONAL_FIELDGRADIENT_METHOD, AreaIntegral_fieldgradient, BUILTIN_FLAGSEMPTY) +MORPHO_ENDCLASS - /* ********************************************************************** - * Initialization - * ********************************************************************** */ +/* ********************************************************************** + * Initialization + * ********************************************************************** */ - void functional_initialize(void) -{ - functional_gradeproperty = builtin_internsymbolascstring(FUNCTIONAL_GRADE_PROPERTY); - functional_fieldproperty = builtin_internsymbolascstring(FUNCTIONAL_FIELD_PROPERTY); - scalarpotential_functionproperty = builtin_internsymbolascstring(SCALARPOTENTIAL_FUNCTION_PROPERTY); - scalarpotential_gradfunctionproperty = builtin_internsymbolascstring(SCALARPOTENTIAL_GRADFUNCTION_PROPERTY); - linearelasticity_referenceproperty = builtin_internsymbolascstring(LINEARELASTICITY_REFERENCE_PROPERTY); - linearelasticity_poissonproperty = builtin_internsymbolascstring(LINEARELASTICITY_POISSON_PROPERTY); - hydrogel_aproperty = builtin_internsymbolascstring(HYDROGEL_A_PROPERTY); - hydrogel_bproperty = builtin_internsymbolascstring(HYDROGEL_B_PROPERTY); - hydrogel_cproperty = builtin_internsymbolascstring(HYDROGEL_C_PROPERTY); - hydrogel_dproperty = builtin_internsymbolascstring(HYDROGEL_D_PROPERTY); - hydrogel_phirefproperty = builtin_internsymbolascstring(HYDROGEL_PHIREF_PROPERTY); - hydrogel_phi0property = builtin_internsymbolascstring(HYDROGEL_PHI0_PROPERTY); - equielement_weightproperty = builtin_internsymbolascstring(EQUIELEMENT_WEIGHT_PROPERTY); - nematic_ksplayproperty = builtin_internsymbolascstring(NEMATIC_KSPLAY_PROPERTY); - nematic_ktwistproperty = builtin_internsymbolascstring(NEMATIC_KTWIST_PROPERTY); - nematic_kbendproperty = builtin_internsymbolascstring(NEMATIC_KBEND_PROPERTY); - nematic_pitchproperty = builtin_internsymbolascstring(NEMATIC_PITCH_PROPERTY); - - curvature_integrandonlyproperty = builtin_internsymbolascstring(CURVATURE_INTEGRANDONLY_PROPERTY); +void functional_initialize(void) { + functional_gradeproperty=builtin_internsymbolascstring(FUNCTIONAL_GRADE_PROPERTY); + functional_fieldproperty=builtin_internsymbolascstring(FUNCTIONAL_FIELD_PROPERTY); + scalarpotential_functionproperty=builtin_internsymbolascstring(SCALARPOTENTIAL_FUNCTION_PROPERTY); + scalarpotential_gradfunctionproperty=builtin_internsymbolascstring(SCALARPOTENTIAL_GRADFUNCTION_PROPERTY); + linearelasticity_referenceproperty=builtin_internsymbolascstring(LINEARELASTICITY_REFERENCE_PROPERTY); + linearelasticity_poissonproperty=builtin_internsymbolascstring(LINEARELASTICITY_POISSON_PROPERTY); + hydrogel_aproperty=builtin_internsymbolascstring(HYDROGEL_A_PROPERTY); + hydrogel_bproperty=builtin_internsymbolascstring(HYDROGEL_B_PROPERTY); + hydrogel_cproperty=builtin_internsymbolascstring(HYDROGEL_C_PROPERTY); + hydrogel_dproperty=builtin_internsymbolascstring(HYDROGEL_D_PROPERTY); + hydrogel_phirefproperty=builtin_internsymbolascstring(HYDROGEL_PHIREF_PROPERTY); + hydrogel_phi0property=builtin_internsymbolascstring(HYDROGEL_PHI0_PROPERTY); + equielement_weightproperty=builtin_internsymbolascstring(EQUIELEMENT_WEIGHT_PROPERTY); + nematic_ksplayproperty=builtin_internsymbolascstring(NEMATIC_KSPLAY_PROPERTY); + nematic_ktwistproperty=builtin_internsymbolascstring(NEMATIC_KTWIST_PROPERTY); + nematic_kbendproperty=builtin_internsymbolascstring(NEMATIC_KBEND_PROPERTY); + nematic_pitchproperty=builtin_internsymbolascstring(NEMATIC_PITCH_PROPERTY); + + curvature_integrandonlyproperty=builtin_internsymbolascstring(CURVATURE_INTEGRANDONLY_PROPERTY); objectstring objclassname = MORPHO_STATICSTRING(OBJECT_CLASSNAME); value objclass = builtin_findclass(MORPHO_OBJECT(&objclassname)); From 0942dab4da6ef90afd205f068896b4243380f7a3 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 11:36:44 -0400 Subject: [PATCH 06/13] revert the autoformatting, update error messages --- morpho5/geometry/functional.h | 148 +++++++++++++++++----------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/morpho5/geometry/functional.h b/morpho5/geometry/functional.h index afc98517..2ceda9a7 100644 --- a/morpho5/geometry/functional.h +++ b/morpho5/geometry/functional.h @@ -10,102 +10,102 @@ #include /* Functional properties */ -#define FUNCTIONAL_GRADE_PROPERTY "grade" -#define FUNCTIONAL_ONESIDED_PROPERTY "onesided" -#define FUNCTIONAL_FIELD_PROPERTY "field" -#define SCALARPOTENTIAL_FUNCTION_PROPERTY "function" +#define FUNCTIONAL_GRADE_PROPERTY "grade" +#define FUNCTIONAL_ONESIDED_PROPERTY "onesided" +#define FUNCTIONAL_FIELD_PROPERTY "field" +#define SCALARPOTENTIAL_FUNCTION_PROPERTY "function" #define SCALARPOTENTIAL_GRADFUNCTION_PROPERTY "gradfunction" -#define LINEARELASTICITY_REFERENCE_PROPERTY "reference" -#define LINEARELASTICITY_POISSON_PROPERTY "poissonratio" -#define HYDROGEL_A_PROPERTY "a" -#define HYDROGEL_B_PROPERTY "b" -#define HYDROGEL_C_PROPERTY "c" -#define HYDROGEL_D_PROPERTY "d" -#define HYDROGEL_PHIREF_PROPERTY "phiref" -#define HYDROGEL_PHI0_PROPERTY "phi0" -#define EQUIELEMENT_WEIGHT_PROPERTY "weight" - -#define NEMATIC_KSPLAY_PROPERTY "ksplay" -#define NEMATIC_KTWIST_PROPERTY "ktwist" -#define NEMATIC_KBEND_PROPERTY "kbend" -#define NEMATIC_PITCH_PROPERTY "pitch" -#define NEMATIC_DIRECTOR_PROPERTY "director" - -#define CURVATURE_INTEGRANDONLY_PROPERTY "integrandonly" +#define LINEARELASTICITY_REFERENCE_PROPERTY "reference" +#define LINEARELASTICITY_POISSON_PROPERTY "poissonratio" +#define HYDROGEL_A_PROPERTY "a" +#define HYDROGEL_B_PROPERTY "b" +#define HYDROGEL_C_PROPERTY "c" +#define HYDROGEL_D_PROPERTY "d" +#define HYDROGEL_PHIREF_PROPERTY "phiref" +#define HYDROGEL_PHI0_PROPERTY "phi0" +#define EQUIELEMENT_WEIGHT_PROPERTY "weight" + +#define NEMATIC_KSPLAY_PROPERTY "ksplay" +#define NEMATIC_KTWIST_PROPERTY "ktwist" +#define NEMATIC_KBEND_PROPERTY "kbend" +#define NEMATIC_PITCH_PROPERTY "pitch" +#define NEMATIC_DIRECTOR_PROPERTY "director" + +#define CURVATURE_INTEGRANDONLY_PROPERTY "integrandonly" /* Functional methods */ -#define FUNCTIONAL_INTEGRAND_METHOD "integrand" -#define FUNCTIONAL_TOTAL_METHOD "total" -#define FUNCTIONAL_GRADIENT_METHOD "gradient" -#define FUNCTIONAL_FIELDGRADIENT_METHOD "fieldgradient" +#define FUNCTIONAL_INTEGRAND_METHOD "integrand" +#define FUNCTIONAL_TOTAL_METHOD "total" +#define FUNCTIONAL_GRADIENT_METHOD "gradient" +#define FUNCTIONAL_FIELDGRADIENT_METHOD "fieldgradient" /* Special functions that can be used in integrands */ -#define TANGENT_FUNCTION "tangent" -#define NORMAL_FUNCTION "normal" +#define TANGENT_FUNCTION "tangent" +#define NORMAL_FUNCTION "normal" /* Functional names */ -#define LENGTH_CLASSNAME "Length" -#define AREA_CLASSNAME "Area" -#define AREAENCLOSED_CLASSNAME "AreaEnclosed" -#define VOLUME_CLASSNAME "Volume" -#define VOLUMEENCLOSED_CLASSNAME "VolumeEnclosed" -#define SCALARPOTENTIAL_CLASSNAME "ScalarPotential" -#define LINEARELASTICITY_CLASSNAME "LinearElasticity" -#define HYDROGEL_CLASSNAME "Hydrogel" -#define EQUIELEMENT_CLASSNAME "EquiElement" -#define LINECURVATURESQ_CLASSNAME "LineCurvatureSq" -#define LINETORSIONSQ_CLASSNAME "LineTorsionSq" -#define MEANCURVATURESQ_CLASSNAME "MeanCurvatureSq" -#define GAUSSCURVATURE_CLASSNAME "GaussCurvature" -#define GRADSQ_CLASSNAME "GradSq" -#define NORMSQ_CLASSNAME "NormSq" -#define LINEINTEGRAL_CLASSNAME "LineIntegral" -#define AREAINTEGRAL_CLASSNAME "AreaIntegral" -#define NEMATIC_CLASSNAME "Nematic" -#define NEMATICELECTRIC_CLASSNAME "NematicElectric" +#define LENGTH_CLASSNAME "Length" +#define AREA_CLASSNAME "Area" +#define AREAENCLOSED_CLASSNAME "AreaEnclosed" +#define VOLUME_CLASSNAME "Volume" +#define VOLUMEENCLOSED_CLASSNAME "VolumeEnclosed" +#define SCALARPOTENTIAL_CLASSNAME "ScalarPotential" +#define LINEARELASTICITY_CLASSNAME "LinearElasticity" +#define HYDROGEL_CLASSNAME "Hydrogel" +#define EQUIELEMENT_CLASSNAME "EquiElement" +#define LINECURVATURESQ_CLASSNAME "LineCurvatureSq" +#define LINETORSIONSQ_CLASSNAME "LineTorsionSq" +#define MEANCURVATURESQ_CLASSNAME "MeanCurvatureSq" +#define GAUSSCURVATURE_CLASSNAME "GaussCurvature" +#define GRADSQ_CLASSNAME "GradSq" +#define NORMSQ_CLASSNAME "NormSq" +#define LINEINTEGRAL_CLASSNAME "LineIntegral" +#define AREAINTEGRAL_CLASSNAME "AreaIntegral" +#define NEMATIC_CLASSNAME "Nematic" +#define NEMATICELECTRIC_CLASSNAME "NematicElectric" /* Errors */ -#define FUNC_INTEGRAND_MESH "FnctlIntMsh" -#define FUNC_INTEGRAND_MESH_MSG "Method 'integrand' requires a mesh as the argument." +#define FUNC_INTEGRAND_MESH "FnctlIntMsh" +#define FUNC_INTEGRAND_MESH_MSG "Method 'integrand' requires a mesh as the argument." -#define FUNC_ELNTFND "FnctlELNtFnd" -#define FUNC_ELNTFND_MSG "Mesh does not provide elements of grade %u." +#define FUNC_ELNTFND "FnctlELNtFnd" +#define FUNC_ELNTFND_MSG "Mesh does not provide elements of grade %u." -#define SCALARPOTENTIAL_FNCLLBL "SclrPtFnCllbl" -#define SCALARPOTENTIAL_FNCLLBL_MSG "ScalarPotential function is not callable." +#define SCALARPOTENTIAL_FNCLLBL "SclrPtFnCllbl" +#define SCALARPOTENTIAL_FNCLLBL_MSG "ScalarPotential function is not callable." -#define LINEINTEGRAL_ARGS "IntArgs" -#define LINEINTEGRAL_ARGS_MSG "Integral functionals require a callable argument, followed by zero or more Fields." +#define LINEINTEGRAL_ARGS "IntArgs" +#define LINEINTEGRAL_ARGS_MSG "Integral functionals require a callable argument, followed by zero or more Fields." -#define LINEINTEGRAL_NFLDS "IntNFlds" -#define LINEINTEGRAL_NFLDS_MSG "Incorrect number of Fields provided for integrand function." +#define LINEINTEGRAL_NFLDS "IntNFlds" +#define LINEINTEGRAL_NFLDS_MSG "Incorrect number of Fields provided for integrand function." -#define LINEARELASTICITY_REF "LnElstctyRef" -#define LINEARELASTICITY_REF_MSG "LinearElasticity requires a mesh as the argument." +#define LINEARELASTICITY_REF "LnElstctyRef" +#define LINEARELASTICITY_REF_MSG "LinearElasticity requires a mesh as the argument." -#define LINEARELASTICITY_PRP "LnElstctyPrp" -#define LINEARELASTICITY_PRP_MSG "LinearElasticity requires properties 'reference' to be a mesh, 'grade' to be an integer grade and 'poissonratio' to be a number." +#define LINEARELASTICITY_PRP "LnElstctyPrp" +#define LINEARELASTICITY_PRP_MSG "LinearElasticity requires properties 'reference' to be a mesh, 'grade' to be an integer grade and 'poissonratio' to be a number." -#define EQUIELEMENT_ARGS "EquiElArgs" -#define EQUIELEMENT_ARGS_MSG "EquiElement allows 'grade' and 'weight' as optional arguments." +#define EQUIELEMENT_ARGS "EquiElArgs" +#define EQUIELEMENT_ARGS_MSG "EquiElement allows 'grade' and 'weight' as optional arguments." -#define HYDROGEL_ARGS "HydrglArgs" -#define HYDROGEL_ARGS_MSG "Hydrogel requires a reference mesh and allows 'grade', 'a', 'b', 'c' and 'phi0' as optional arguments." +#define HYDROGEL_ARGS "HydrglArgs" +#define HYDROGEL_ARGS_MSG "Hydrogel requires a reference mesh and allows 'grade', 'a', 'b', 'c', 'd', 'phi0' and 'phiref' as optional arguments." -#define HYDROGEL_PRP "HydrglPrp" -#define HYDROGEL_PRP_MSG "Hydrogel requires properties 'reference' to be a mesh, 'grade' to be an integer grade, 'a', 'b' and 'c' to be numbers and 'phi0' as either a number or a field." +#define HYDROGEL_PRP "HydrglPrp" +#define HYDROGEL_PRP_MSG "Hydrogel requires properties 'reference' to be a mesh, 'grade' to be an integer grade, 'a', 'b', 'c' 'd' and 'phiref' to be numbers and 'phi0' as either a number or a field." -#define GRADSQ_ARGS "GradSqArgs" -#define GRADSQ_ARGS_MSG "GradSq requires a field as the argument." +#define GRADSQ_ARGS "GradSqArgs" +#define GRADSQ_ARGS_MSG "GradSq requires a field as the argument." -#define NEMATIC_ARGS "NmtcArgs" -#define NEMATIC_ARGS_MSG "Nematic requires a field as the argument." +#define NEMATIC_ARGS "NmtcArgs" +#define NEMATIC_ARGS_MSG "Nematic requires a field as the argument." -#define NEMATICELECTRIC_ARGS "NmtcElArgs" -#define NEMATICELECTRIC_ARGS_MSG "NematicElectric requires the director and electric field or potential as arguments (in that order)." +#define NEMATICELECTRIC_ARGS "NmtcElArgs" +#define NEMATICELECTRIC_ARGS_MSG "NematicElectric requires the director and electric field or potential as arguments (in that order)." -#define FUNCTIONAL_ARGS "FnctlArgs" -#define FUNCTIONAL_ARGS_MSG "Invalid args passed to method." +#define FUNCTIONAL_ARGS "FnctlArgs" +#define FUNCTIONAL_ARGS_MSG "Invalid args passed to method." void functional_initialize(void); From 9c5d362396e51e0478377e7104b742323986361c Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 11:37:10 -0400 Subject: [PATCH 07/13] Updated the hydrogel docs a bit --- morpho5/docs/functionals.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/morpho5/docs/functionals.md b/morpho5/docs/functionals.md index a6c0fe68..9e71b540 100644 --- a/morpho5/docs/functionals.md +++ b/morpho5/docs/functionals.md @@ -209,10 +209,10 @@ that you provide on initializing the Functional: var lfh = Hydrogel(mref) -Here, a, b, c, d and phiref are parameters you can supply, V is the -current volume and V0 is the reference volume of a given element. You -also need to supply the initial value of phi, labeled as phi0, which is -assumed to be the same for all the elements. +Here, a, b, c, d and phiref are parameters you can supply (they are `nil` +by default), V is the current volume and V0 is the reference volume of a +given element. You also need to supply the initial value of phi, labeled +as phi0, which is assumed to be the same for all the elements. Manually set the coefficients and grade to operate on: lfh.a = 1; lfh.b = 1; lfh.c = 1; lfh.d = 1; From 70cde5aa135e56ea721e162ddc30b12c78de2e64 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 11:54:28 -0400 Subject: [PATCH 08/13] Fixed style issues --- morpho5/geometry/functional.c | 84 +++++++++++++---------------------- 1 file changed, 30 insertions(+), 54 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 2c8ee90f..1559fa9d 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -1364,22 +1364,19 @@ static value hydrogel_dproperty; static value hydrogel_phirefproperty; static value hydrogel_phi0property; -typedef struct -{ +typedef struct { objectmesh *refmesh; grade grade; double a, b, c, d, phiref; // Hydrogel coefficients - /* Add other parameters relevant to the elasticity term */ value phi0; // Can be a number or a field } hydrogelref; /** Prepares the reference structure from the object's properties */ -bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, hydrogelref *ref) -{ +bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, hydrogelref *ref) { bool success = false; value refmesh=MORPHO_NIL, grade=MORPHO_NIL, phi0=MORPHO_NIL; value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL, d=MORPHO_NIL, phiref=MORPHO_NIL; - /* Add other parameters relevant to the elasticity term */ + if (objectinstance_getproperty(self, linearelasticity_referenceproperty, &refmesh) && objectinstance_getproperty(self, functional_gradeproperty, &grade) && MORPHO_ISINTEGER(grade) && @@ -1409,72 +1406,57 @@ bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, object morpho_valuetofloat(phiref, &ref->phiref)) { ref->phi0 = phi0; - success = true; + success=true; } } return success; } /** Calculate the Hydrogel energy */ -bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) -{ +bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { hydrogelref *info = (hydrogelref *)ref; value vphi0 = info->phi0; double V=0.0, V0=0.0, phi0=0.0; - if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) - return false; - if (!functional_elementsize(v, mesh, info->grade, id, nv, vid, &V)) - return false; + if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) return false; + if (!functional_elementsize(v, mesh, info->grade, id, nv, vid, &V)) return false; - if (V0 < 1e-8) - printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); + if (V0 < 1e-8) printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); - if (fabs(V) < MORPHO_EPS) - return false; + if (fabs(V) < MORPHO_EPS) return false; // Determine phi0 either as a number or by looking up something in a field - if (MORPHO_ISFIELD(info->phi0)) - { + if (MORPHO_ISFIELD(info->phi0)) { objectfield *p = MORPHO_GETFIELD(info->phi0); field_getelement(p, info->grade, id, 0, &vphi0); } - if (MORPHO_ISNUMBER(vphi0)) - { - if (!morpho_valuetofloat(vphi0, &phi0)) - return false; + if (MORPHO_ISNUMBER(vphi0)) { + if (!morpho_valuetofloat(vphi0, &phi0)) return false; } - double phi = phi0 / (V / V0); + double phi = phi0/(V/V0); double pr = info->phiref; - if (phi < 0) - printf("Warning: phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1 - phi); - if (1 - phi < 0) - printf("Warning: 1-phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1 - phi); - - if (phi > 1 - MORPHO_EPS) - phi = 1 - MORPHO_EPS; - if (phi < MORPHO_EPS) - phi = MORPHO_EPS; + if (phi<0) printf("Warning: phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1-phi); + if (1-phi<0) printf("Warning: 1-phi<0 at element %u V=%g, V0=%g, phi=%g, 1-phi=%g\n", id, V, V0, phi, 1-phi); + + if (phi>1-MORPHO_EPS) phi = 1-MORPHO_EPS; + if (phia * phi * log(phi) + - info->b * (1 - phi) * log(1 - phi) + - info->c * phi * (1 - phi)) * - V + - info->d * (log(pr / phi) / 3.0 - pow((pr / phi), (2.0 / 3)) + 1.0) * V0; + *out = (info->a * phi*log(phi) + + info->b * (1-phi)*log(1-phi) + + info->c * phi*(1-phi))*V + + info->d * (log(pr/phi)/3.0 - pow((pr/phi), (2.0/3)) + 1.0)*V0; - if (phi < 0 || 1 - phi < 0) - return false; + if (phi<0 || 1-phi<0) return false; return true; } -value Hydrogel_init(vm *v, int nargs, value *args) -{ +value Hydrogel_init(vm *v, int nargs, value *args) { objectinstance *self = MORPHO_GETINSTANCE(MORPHO_SELF(args)); int nfixed; - value grade = MORPHO_INTEGER(-1); - value a = MORPHO_NIL, b = MORPHO_NIL, c = MORPHO_NIL, d = MORPHO_NIL, phiref = MORPHO_NIL, phi0 = MORPHO_NIL; + value grade=MORPHO_INTEGER(-1); + value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL, d=MORPHO_NIL, phiref=MORPHO_NIL, phi0=MORPHO_NIL; if (builtin_options(v, nargs, args, &nfixed, 6, hydrogel_aproperty, &a, @@ -1483,8 +1465,7 @@ value Hydrogel_init(vm *v, int nargs, value *args) hydrogel_dproperty, &d, hydrogel_phirefproperty, &phiref, hydrogel_phi0property, &phi0, - functional_gradeproperty, &grade)) - { + functional_gradeproperty, &grade)) { objectinstance_setproperty(self, hydrogel_aproperty, a); objectinstance_setproperty(self, hydrogel_bproperty, b); @@ -1494,15 +1475,10 @@ value Hydrogel_init(vm *v, int nargs, value *args) objectinstance_setproperty(self, hydrogel_phi0property, phi0); objectinstance_setproperty(self, functional_gradeproperty, grade); - if (nfixed == 1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) - { + if (nfixed == 1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(self, linearelasticity_referenceproperty, MORPHO_GETARG(args, 0)); - } - else - morpho_runtimeerror(v, HYDROGEL_ARGS); - } - else - morpho_runtimeerror(v, HYDROGEL_ARGS); + } else morpho_runtimeerror(v, HYDROGEL_ARGS); + } else morpho_runtimeerror(v, HYDROGEL_ARGS); return MORPHO_NIL; } From bc0897d73ccc1503b0a9b921ccbc0517368106d3 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 11:59:18 -0400 Subject: [PATCH 09/13] More style fixes --- morpho5/geometry/functional.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 1559fa9d..6482e776 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -1391,20 +1391,17 @@ bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, object objectinstance_getproperty(self, hydrogel_phirefproperty, &phiref) && MORPHO_ISNUMBER(phiref) && objectinstance_getproperty(self, hydrogel_phi0property, &phi0) && - (MORPHO_ISNUMBER(phi0) || MORPHO_ISFIELD(phi0))) - { + (MORPHO_ISNUMBER(phi0) || MORPHO_ISFIELD(phi0))) { ref->refmesh = MORPHO_GETMESH(refmesh); ref->grade = MORPHO_GETINTEGERVALUE(grade); - if (ref->grade < 0) - ref->grade = mesh_maxgrade(mesh); + if (ref->grade < 0) ref->grade = mesh_maxgrade(mesh); if (morpho_valuetofloat(a, &ref->a) && morpho_valuetofloat(b, &ref->b) && morpho_valuetofloat(c, &ref->c) && morpho_valuetofloat(d, &ref->d) && - morpho_valuetofloat(phiref, &ref->phiref)) - { + morpho_valuetofloat(phiref, &ref->phiref)) { ref->phi0 = phi0; success=true; } From e523e0a2445d3751cdf848b568a1d7de0b01d26d Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 12:10:59 -0400 Subject: [PATCH 10/13] Removed spurious comment, more style fixes --- morpho5/geometry/functional.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 6482e776..112d35f4 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -1373,7 +1373,7 @@ typedef struct { /** Prepares the reference structure from the object's properties */ bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, objectselection *sel, hydrogelref *ref) { - bool success = false; + bool success=false; value refmesh=MORPHO_NIL, grade=MORPHO_NIL, phi0=MORPHO_NIL; value a=MORPHO_NIL, b=MORPHO_NIL, c=MORPHO_NIL, d=MORPHO_NIL, phiref=MORPHO_NIL; @@ -1392,10 +1392,10 @@ bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, object MORPHO_ISNUMBER(phiref) && objectinstance_getproperty(self, hydrogel_phi0property, &phi0) && (MORPHO_ISNUMBER(phi0) || MORPHO_ISFIELD(phi0))) { - ref->refmesh = MORPHO_GETMESH(refmesh); - ref->grade = MORPHO_GETINTEGERVALUE(grade); + ref->refmesh=MORPHO_GETMESH(refmesh); + ref->grade=MORPHO_GETINTEGERVALUE(grade); - if (ref->grade < 0) ref->grade = mesh_maxgrade(mesh); + if (ref->grade<0) ref->grade=mesh_maxgrade(mesh); if (morpho_valuetofloat(a, &ref->a) && morpho_valuetofloat(b, &ref->b) && @@ -1418,7 +1418,7 @@ bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, if (!functional_elementsize(v, info->refmesh, info->grade, id, nv, vid, &V0)) return false; if (!functional_elementsize(v, mesh, info->grade, id, nv, vid, &V)) return false; - if (V0 < 1e-8) printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); + if (V0<1e-8) printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); if (fabs(V) < MORPHO_EPS) return false; @@ -1438,7 +1438,7 @@ bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, if (phi>1-MORPHO_EPS) phi = 1-MORPHO_EPS; if (phia * phi*log(phi) + info->b * (1-phi)*log(1-phi) + info->c * phi*(1-phi))*V + @@ -1472,7 +1472,7 @@ value Hydrogel_init(vm *v, int nargs, value *args) { objectinstance_setproperty(self, hydrogel_phi0property, phi0); objectinstance_setproperty(self, functional_gradeproperty, grade); - if (nfixed == 1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { + if (nfixed==1 && MORPHO_ISMESH(MORPHO_GETARG(args, 0))) { objectinstance_setproperty(self, linearelasticity_referenceproperty, MORPHO_GETARG(args, 0)); } else morpho_runtimeerror(v, HYDROGEL_ARGS); } else morpho_runtimeerror(v, HYDROGEL_ARGS); From c4cf41779ca3adac9d5da5f5b6e9ed77de913294 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Mon, 4 Apr 2022 12:15:57 -0400 Subject: [PATCH 11/13] Added newline at the end of the test --- test/functionals/hydrogel/hydrogel.morpho | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functionals/hydrogel/hydrogel.morpho b/test/functionals/hydrogel/hydrogel.morpho index d00a8a4f..fce8d2e5 100644 --- a/test/functionals/hydrogel/hydrogel.morpho +++ b/test/functionals/hydrogel/hydrogel.morpho @@ -42,4 +42,4 @@ expected = Matrix([ [ 0, 0.00561671, 0.00561671, -0.0112336 ], [ -0.011915, 0.00397177, 0.00397167, 0.00397174 ]]) print (lh.gradient(m)-expected).norm() Date: Mon, 4 Apr 2022 12:16:16 -0400 Subject: [PATCH 12/13] Some final formatting changes --- morpho5/geometry/functional.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 112d35f4..27aade0d 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -1411,7 +1411,7 @@ bool hydrogel_prepareref(objectinstance *self, objectmesh *mesh, grade g, object /** Calculate the Hydrogel energy */ bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, void *ref, double *out) { - hydrogelref *info = (hydrogelref *)ref; + hydrogelref *info = (hydrogelref *) ref; value vphi0 = info->phi0; double V=0.0, V0=0.0, phi0=0.0; @@ -1420,7 +1420,7 @@ bool hydrogel_integrand(vm *v, objectmesh *mesh, elementid id, int nv, int *vid, if (V0<1e-8) printf("Warning: Reference element %u has tiny volume V=%g, V0=%g\n", id, V, V0); - if (fabs(V) < MORPHO_EPS) return false; + if (fabs(V)phi0)) { From dd0af9a96dce8be4df27c8c150ea8fda0aa6e2b5 Mon Sep 17 00:00:00 2001 From: Chaitanya Joshi Date: Wed, 6 Apr 2022 10:58:12 -0400 Subject: [PATCH 13/13] Reworded HydrglPrp error message Removed the message that phi0 can be a field as well. This is a feature that will be added in the future. Additional small rewording and comments --- morpho5/geometry/functional.c | 2 +- morpho5/geometry/functional.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/morpho5/geometry/functional.c b/morpho5/geometry/functional.c index 27aade0d..07ebf659 100644 --- a/morpho5/geometry/functional.c +++ b/morpho5/geometry/functional.c @@ -1368,7 +1368,7 @@ typedef struct { objectmesh *refmesh; grade grade; double a, b, c, d, phiref; // Hydrogel coefficients - value phi0; // Can be a number or a field + value phi0; // Can be a number or a field. (Ensuring flexibility for supplying a phi0 field in the future) } hydrogelref; /** Prepares the reference structure from the object's properties */ diff --git a/morpho5/geometry/functional.h b/morpho5/geometry/functional.h index 2ceda9a7..262ce725 100644 --- a/morpho5/geometry/functional.h +++ b/morpho5/geometry/functional.h @@ -93,7 +93,7 @@ #define HYDROGEL_ARGS_MSG "Hydrogel requires a reference mesh and allows 'grade', 'a', 'b', 'c', 'd', 'phi0' and 'phiref' as optional arguments." #define HYDROGEL_PRP "HydrglPrp" -#define HYDROGEL_PRP_MSG "Hydrogel requires properties 'reference' to be a mesh, 'grade' to be an integer grade, 'a', 'b', 'c' 'd' and 'phiref' to be numbers and 'phi0' as either a number or a field." +#define HYDROGEL_PRP_MSG "Hydrogel requires the first argument to be a mesh, 'grade' to be an integer grade, 'a', 'b', 'c' 'd', 'phi0' and 'phiref' to be numbers." #define GRADSQ_ARGS "GradSqArgs" #define GRADSQ_ARGS_MSG "GradSq requires a field as the argument."