/* filter out epsilon margin separated points */ static int separate (int n, double **q, double epsilon) { if (epsilon <= 0.0) return n; double epshalf = .5 * epsilon, epsq = epsilon * epsilon, d [3], r; BOX *b, *g, **pb; SET *item; int i, m; ERRMEM (b = malloc (n * sizeof (BOX))); ERRMEM (pb = malloc (n * sizeof (BOX*))); for (i = 0, g = b; i < n; i ++, g ++) { double *e = g->extents, *p = q [i]; e [0] = p [0] - epshalf; e [1] = p [1] - epshalf; e [2] = p [2] - epshalf; e [3] = p [0] + epshalf; e [4] = p [1] + epshalf; e [5] = p [2] + epshalf; g->sgp = (void*) p; g->body = NULL; g->mark = NULL; pb [i] = g; } hybrid (pb, n, NULL, overlap); for (i = m = 0, g = b; i < n; i ++, g ++) { if (!g->mark) { double *a = (double*) g->sgp; q [m ++] = a; for (item = SET_First ((SET*)g->body); item; item = SET_Next (item)) { BOX *adj = item->data; double *b = (double*) adj->sgp; SUB (a, b, d); r = DOT (d, d); if (r < epsq) adj->mark = (void*) 1; /* epsilon separation */ } } SET_Free (NULL, (SET**) &g->body); } free (pb); free (b); return m; }
/* attach constraints to bodies after reading */ static void dom_attach_constraints (DOM *dom) { BODY *bod; CON *con; for (bod = dom->bod; bod; bod = bod->next) SET_Free (&dom->setmem, &bod->con); for (con = dom->con; con; con = con->next) { if (con->master) { ASSERT_DEBUG (MAP_Find_Node (dom->idb, (void*) (long) con->master->id, NULL), "Invalid master id"); SET_Insert (&dom->setmem, &con->master->con, con, NULL); } if (con->slave) { ASSERT_DEBUG (MAP_Find_Node (dom->idb, (void*) (long) con->slave->id, NULL), "Invalid slave id"); SET_Insert (&dom->setmem, &con->slave->con, con, NULL); } } }
/* export data for fracture analysis in MoFEM (return number of exported analysis instances) */ int Fracture_Export_MoFEM (BODY *bod, double volume, double quality, FILE *output) { double extents [6], *q, *u, (*p) [3]; SOLFEC *sol = bod->dom->solfec; int n, elno, fano; FS *list, *it, *jt; ELEMENT *ele; FACE *fac; MESH *msh; KDT *kd; if (!(bod->flags & BODY_CHECK_FRACTURE) || sol->mode == SOLFEC_WRITE) return 0; list = fracture_state_read (bod); if (list) { MESH *copy = MESH_Copy (bod->shape->data); MESH_Update (copy, NULL, NULL, NULL); /* reference configuration */ msh = tetrahedralize1 (copy, volume, quality, -INT_MAX, -INT_MAX, NULL); /* generate tet mesh in reference configuration */ MESH_Destroy (copy); /* allocate displacements on the tet mesh */ ERRMEM (q = malloc (6 * msh->nodes_count * sizeof (double))); u = q + 3 * msh->nodes_count; /* map faces to a kd-tree for quick point queries */ kd = KDT_Create (msh->nodes_count, (double*)msh->ref_nodes, 0.0); for (ele = msh->surfeles; ele; ele = ele->next) { ELEMENT_Ref_Extents (msh, ele, extents); for (fac = ele->faces; fac; fac = fac->next) KDT_Drop (kd, extents, fac); } //______________________________________________________ // output file start for (fano = 0, fac = msh->faces; fac; fano ++, fac = fac->n) fac->index = fano; /* count and index faces */ ERRMEM (p = malloc (fano * sizeof (double [3]))); /* allocate face pressures */ elno = msh->surfeles_count + msh->bulkeles_count; fprintf (output, "mOFF %d %d %d\n", msh->nodes_count, fano, elno); // file header /* map displacements from the hex to the tet mesh */ FEM_Map_State (bod->shape->data, bod->conf, bod->velo, msh, q, u); /* only bod->disp to q mapping is used */ for (n = 0; n < msh->nodes_count; n ++) { fprintf (output, "%f %f %f %f %f %f\n", msh->ref_nodes [n][0], msh->ref_nodes [n][1], msh->ref_nodes [n][2], q[3*n], q[3*n+1], q[3*n+2]); } //______________________________________________________ /* rewind the list to the end to find the last element, which corresponds to the earliest in time fracture instance */ for (it = list; it->next; it = it->next) continue; /* for (it = list; it; it = it->next) */ /* FIXME -- FIXME -- FIXME -- FIXME */ { for (n = 0; n < fano; n ++) { SET (p [n], 0.0); /* zero face pressures */ } for (jt = it; jt; jt = jt->inext) /* for each point force in this instance */ { double (*ref) [3] = msh->ref_nodes; double a [3], b [3], c [3], area; SET *set = NULL, *item; double *qa, *qb, *qc; extents [0] = jt->point[0] - jt->radius - GEOMETRIC_EPSILON; /* set up search extents */ extents [1] = jt->point[1] - jt->radius - GEOMETRIC_EPSILON; extents [2] = jt->point[2] - jt->radius - GEOMETRIC_EPSILON; extents [3] = jt->point[0] + jt->radius + GEOMETRIC_EPSILON; extents [4] = jt->point[1] + jt->radius + GEOMETRIC_EPSILON; extents [5] = jt->point[2] + jt->radius + GEOMETRIC_EPSILON; KDT_Pick_Extents (kd, extents, &set); /* pick kd-tree leaves within the extents */ for (item = SET_First (set); item; item = SET_Next (item)) { KDT *leaf = item->data; for (n = 0; n < leaf->n; n ++) { fac = leaf->data [n]; /* face dropped into this leaf */ qa = &q[3*fac->nodes[0]]; qb = &q[3*fac->nodes[1]]; qc = &q[3*fac->nodes[2]]; ADD (ref[fac->nodes[0]], qa, a); /* current face nodes */ ADD (ref[fac->nodes[1]], qb, b); ADD (ref[fac->nodes[2]], qc, c); TRIANGLE_AREA (a, b, c, area); /* current face area */ if (area > 0.0) /* XXX */ { p [fac->index][0] += jt->force [0] / area; /* add up pressure */ p [fac->index][1] += jt->force [1] / area; /* FIXME: seems to be adding up to much pressure -> divided by area */ p [fac->index][2] += jt->force [2] / area; } } } SET_Free (NULL, &set); } for (fac = msh->faces, n=0; fac; fac = fac->n, n ++) { fprintf (output, "3 %d %d %d %g %g %g\n", fac->nodes[0], fac->nodes[1], fac->nodes[2], p[n][0], p[n][1], p[n][2]); } } //______________________________________________________ for (ele = msh->surfeles; ele; ele = ele->next) { fprintf (output, "4 %d %d %d %d\n", ele->nodes[0], ele->nodes[1], ele->nodes[2], ele->nodes[3]); } for (ele = msh->bulkeles; ele; ele = ele->next) { fprintf (output, "4 %d %d %d %d\n", ele->nodes[0], ele->nodes[1], ele->nodes[2], ele->nodes[3]); } // output file complete //______________________________________________________ fracture_state_free (list); free (q); free (p); MESH_Destroy (msh); } return 0; }
/* export data for fracture analysis in Yaffems (return number of exported analysis instances) */ int Fracture_Export_Yaffems (BODY *bod, double volume, double quality, FILE *output) { double extents [6], *q, *u, (*p) [3]; SOLFEC *sol = bod->dom->solfec; int n, m, elno, fano; FS *list, *it, *jt; ELEMENT *ele; FACE *fac; MESH *msh; KDT *kd; if (!(bod->flags & BODY_CHECK_FRACTURE) || sol->mode == SOLFEC_WRITE) return 0; list = fracture_state_read (bod); if (list) { MESH *copy = MESH_Copy (bod->shape->data); MESH_Update (copy, NULL, NULL, NULL); /* reference configuration */ msh = tetrahedralize1 (copy, volume, quality, -INT_MAX, -INT_MAX, NULL); /* generate tet mesh in reference configuration */ MESH_Destroy (copy); /* allocate displacements on the tet mesh */ ERRMEM (q = malloc (6 * msh->nodes_count * sizeof (double))); u = q + 3 * msh->nodes_count; /* map faces to a kd-tree for quick point queries */ kd = KDT_Create (msh->nodes_count, (double*)msh->ref_nodes, 0.0); for (ele = msh->surfeles; ele; ele = ele->next) { ELEMENT_Ref_Extents (msh, ele, extents); for (fac = ele->faces; fac; fac = fac->next) KDT_Drop (kd, extents, fac); } fprintf (output, "%s\n", "# vtk DataFile Version 2.0"); fprintf (output, "%s\n", "Test Title"); fprintf (output, "ASCII\n"); fprintf (output, "\n"); fprintf (output, "DATASET UNSTRUCTURED_GRID\n"); fprintf (output, "POINTS %d float\n", msh->nodes_count); for (n = 0; n < msh->nodes_count; n ++) { fprintf (output, "%f %f %f\n", msh->ref_nodes [n][0], msh->ref_nodes [n][1], msh->ref_nodes [n][2]); } for (fano = 0, fac = msh->faces; fac; fano ++, fac = fac->n) fac->index = fano; /* count and index faces */ ERRMEM (p = malloc (fano * sizeof (double [3]))); /* allocate face pressures */ elno = msh->surfeles_count + msh->bulkeles_count; fprintf (output, "\n"); fprintf (output, "CELLS %d %d\n", elno + fano, elno*5 + fano*4); for (ele = msh->surfeles; ele; ele = ele->next) { fprintf (output, "4 %d %d %d %d\n", ele->nodes[0], ele->nodes[1], ele->nodes[2], ele->nodes[3]); } for (ele = msh->bulkeles; ele; ele = ele->next) { fprintf (output, "4 %d %d %d %d\n", ele->nodes[0], ele->nodes[1], ele->nodes[2], ele->nodes[3]); } for (fac = msh->faces; fac; fac = fac->n) { fprintf (output, "3 %d %d %d\n", fac->nodes[0], fac->nodes[1], fac->nodes[2]); } fprintf (output, "\n"); fprintf (output, "CELL_TYPES %d\n", elno + fano); for (n = 0; n < elno; n++) { fprintf (output, "10\n"); } for (n = 0; n < fano; n++) { fprintf (output, "5\n"); } fprintf (output, "\n"); fprintf (output, "POINT_DATA %d\n", msh->nodes_count); for (it = list, m = 0; it; it = it->next, m ++) { /* map displacements from the hex to the tet mesh */ FEM_Map_State (bod->shape->data, it->disp, bod->velo, msh, q, u); /* only it->disp to q mapping is used */ fprintf (output, "\n"); fprintf (output, "VECTORS disp%d float\n", m+1); for (n = 0; n < msh->nodes_count; n ++) { fprintf (output, "%f %f %f\n", q[3*n], q[3*n+1], q[3*n+2]); } } fprintf (output, "\n"); fprintf (output, "CELL_DATA %d\n", elno + fano); for (it = list, m = 0; it; it = it->next, m ++) { fprintf (output, "\n"); fprintf (output, "VECTORS pres%d float\n", m); for (n = 0; n < elno; n ++) /* skip elements */ { fprintf (output, "0 0 0\n"); } for (n = 0; n < fano; n ++) { SET (p [n], 0.0); /* zero face pressures */ } for (jt = it; jt; jt = jt->inext) /* for each point force in this instance */ { double (*ref) [3] = msh->ref_nodes; double a [3], b [3], c [3], area; SET *set = NULL, *item; double *qa, *qb, *qc; extents [0] = jt->point[0] - jt->radius - GEOMETRIC_EPSILON; /* set up search extents */ extents [1] = jt->point[1] - jt->radius - GEOMETRIC_EPSILON; extents [2] = jt->point[2] - jt->radius - GEOMETRIC_EPSILON; extents [3] = jt->point[0] + jt->radius + GEOMETRIC_EPSILON; extents [4] = jt->point[1] + jt->radius + GEOMETRIC_EPSILON; extents [5] = jt->point[2] + jt->radius + GEOMETRIC_EPSILON; KDT_Pick_Extents (kd, extents, &set); /* pick kd-tree leaves within the extents */ for (item = SET_First (set); item; item = SET_Next (item)) { KDT *leaf = item->data; for (n = 0; n < leaf->n; n ++) { fac = leaf->data [n]; /* face dropped into this leaf */ qa = &q[3*fac->nodes[0]]; qb = &q[3*fac->nodes[1]]; qc = &q[3*fac->nodes[2]]; ADD (ref[fac->nodes[0]], qa, a); /* current face nodes */ ADD (ref[fac->nodes[1]], qb, b); ADD (ref[fac->nodes[2]], qc, c); TRIANGLE_AREA (a, b, c, area); /* current face area */ if (area > 0.0) /* XXX */ { p [fac->index][0] += jt->force [0] / area; /* add up pressure */ p [fac->index][1] += jt->force [1] / area; p [fac->index][2] += jt->force [2] / area; } } } SET_Free (NULL, &set); } for (n = 0; n < fano; n ++) { fprintf (output, "%g %g %g\n", p[n][0], p[n][1], p[n][2]); } } fracture_state_free (list); free (q); free (p); return m; } return 0; }
/* read domain state */ void dom_read_state (DOM *dom, PBF *bf) { BODY *bod, *next; int ncon; /* clear contacts */ MAP_Free (&dom->mapmem, &dom->idc); MEM_Release (&dom->conmem); dom->con = NULL; dom->ncon = 0; /* read all bodies if needed */ if (!dom->allbodiesread) read_new_bodies (dom, bf); /* mark all bodies as absent */ for (bod = dom->bod; bod; bod = bod->next) bod->flags |= BODY_ABSENT; SET *usedlabel = NULL; for (; bf; bf = bf->next) { if (PBF_Label (bf, "DOM")) { /* read iover */ int iover = 2; if (PBF_Label (bf, "IOVER")) { PBF_Int (bf, &iover, 1); } /* read time step */ ASSERT (PBF_Label (bf, "STEP"), ERR_FILE_FORMAT); PBF_Double (bf, &dom->step, 1); /* read constraints merit */ ASSERT (PBF_Label (bf, "MERIT"), ERR_FILE_FORMAT); PBF_Double (bf, &dom->merit, 1); /* read body states */ ASSERT (PBF_Label (bf, "BODS"), ERR_FILE_FORMAT); int nbod; PBF_Int (bf, &nbod, 1); for (int n = 0; n < nbod; n ++) { unsigned int id; PBF_Uint (bf, &id, 1); bod = MAP_Find (dom->idb, (void*) (long) id, NULL); if (bod == NULL) /* pick from all bodies set */ { ASSERT_DEBUG_EXT (bod = MAP_Find (dom->allbodies, (void*) (long) id, NULL), "Body id invalid"); if (bod->label) { MAP *node = MAP_Find_Node (dom->lab, bod->label, (MAP_Compare)strcmp); if (node) { node->data = bod; /* body fregments can inherit labels */ SET_Insert (NULL, &usedlabel, bod->label, (SET_Compare)strcmp); } else MAP_Insert (&dom->mapmem, &dom->lab, bod->label, bod, (MAP_Compare) strcmp); } MAP_Insert (&dom->mapmem, &dom->idb, (void*) (long) bod->id, bod, NULL); bod->next = dom->bod; if (dom->bod) dom->bod->prev = bod; dom->bod = bod; bod->dom = dom; dom->nbod ++; } BODY_Read_State (bod, bf, iover); bod->flags &= ~BODY_ABSENT; } /* read constraints */ ASSERT (PBF_Label (bf, "CONS"), ERR_FILE_FORMAT); PBF_Int (bf, &ncon, 1); for (int n = 0; n < ncon; n ++) { CON *con; con = read_constraint (dom, iover, bf); MAP_Insert (&dom->mapmem, &dom->idc, (void*) (long) con->id, con, NULL); con->next = dom->con; if (dom->con) dom->con->prev = con; dom->con = con; } dom->ncon += ncon; } } /* remove absent bodies */ for (bod = dom->bod; bod; bod = next) { next = bod->next; if (bod->flags & BODY_ABSENT) { if (bod->label && !SET_Contains (usedlabel, bod->label, (SET_Compare)strcmp)) MAP_Delete (&dom->mapmem, &dom->lab, bod->label, (MAP_Compare) strcmp); MAP_Delete (&dom->mapmem, &dom->idb, (void*) (long) bod->id, NULL); if (bod->next) bod->next->prev = bod->prev; if (bod->prev) bod->prev->next = bod->next; else dom->bod = bod->next; dom->nbod --; } } SET_Free (NULL, &usedlabel); /* attach constraints to bodies */ dom_attach_constraints (dom); }
/* write domain state */ void dom_write_state (DOM *dom, PBF *bf, SET *subset) { /* mark domain output */ PBF_Label (bf, "DOM"); #if IOVER >= 3 /* write iover */ PBF_Label (bf, "IOVER"); int iover = ABS (dom->solfec->iover); PBF_Int (bf, &iover, 1); #endif /* write time step */ PBF_Label (bf, "STEP"); PBF_Double (bf, &dom->step, 1); /* write constraints merit */ PBF_Label (bf, "MERIT"); PBF_Double (bf, &dom->merit, 1); /* write complete data of newly created bodies and empty the newly created bodies set */ write_new_bodies (dom); /* writing is done to a separate file */ SET_Free (&dom->setmem, &dom->newb); /* write regular bodies (this also includes states of newly created ones) */ PBF_Label (bf, "BODS"); if (subset) { int nbod = SET_Size (subset); PBF_Int (bf, &nbod, 1); } else PBF_Int (bf, &dom->nbod, 1); for (BODY *bod = dom->bod; bod; bod = bod->next) { if (subset && !SET_Find (subset, (void*) (long) bod->id, NULL)) continue; PBF_Uint (bf, &bod->id, 1); if (bod->label) PBF_Label (bf, bod->label); /* label body record for fast access */ BODY_Write_State (bod, bf); } /* write constraints */ PBF_Label (bf, "CONS"); if (subset) { int ncon = 0; for (CON *con = dom->con; con; con = con->next) { if (subset) { if (!SET_Find (subset, (void*) (long) con->master->id, NULL)) continue; if (con->slave && !SET_Find (subset, (void*) (long) con->slave->id, NULL)) continue; } ncon ++; } PBF_Int (bf, &ncon, 1); } else PBF_Int (bf, &dom->ncon, 1); for (CON *con = dom->con; con; con = con->next) { if (subset) { if (!SET_Find (subset, (void*) (long) con->master->id, NULL)) continue; if (con->slave && !SET_Find (subset, (void*) (long) con->slave->id, NULL)) continue; } write_constraint (con, bf); } }