static void psc_write_shape (SHAPE *shp, FILE *f) { SHAPE *ptr; int n; for (ptr = shp, n = 0; ptr; ptr = ptr->next) n ++; ASSERT_TEXT (n == 1, "Compund shapes are not supported in PSC mode"); ASSERT_TEXT (shp->kind == SHAPE_MESH, "Only MESH shapes are supported in PSC mode"); /* TODO: support all shapes */ psc_write_mesh (shp->data, f); }
/* after the body has been imported via MPI calls, * read body data from file and compare */ void PSC_Test_Body (BODY *bod) { char txt [1024]; FILE *f; BODY a; int i; snprintf (txt, 1024, "%s/body%d.data", bod->dom->solfec->outpath, bod->id); ASSERT (f = fopen (txt, "r"), ERR_FILE_OPEN); fread (&a.kind, sizeof (a.kind), 1, f); if (a.kind != bod->kind) { ASSERT_TEXT (0, "PSC ERROR: kind"); } #if 0 fread (&i, sizeof (int), 1, f); fread (txt, sizeof (char), i, f); txt[i] = '\0'; if (strcmp (txt, bod->mat->label) != 0) { ASSERT_TEXT (0, "PSC ERROR: material"); } #endif fread (&a.ref_mass, sizeof (double), 1, f); if (a.ref_mass != bod->ref_mass) { ASSERT_TEXT (0, "PSC ERROR: ref_mass"); } fread (&a.ref_volume, sizeof (double), 1, f); if (a.ref_volume != bod->ref_volume) { ASSERT_TEXT (0, "PSC ERROR: ref_volume"); } fread (&a.ref_center, sizeof (double), 3, f); for (i = 0; i < 3; i ++) { if (a.ref_center [i]!= bod->ref_center [i]) { ASSERT_TEXT (0, "PSC ERROR: ref_center"); } } fread (&a.ref_tensor, sizeof (double), 9, f); for (i = 0; i < 9; i ++) { if (a.ref_tensor [i]!= bod->ref_tensor [i]) { ASSERT_TEXT (0, "PSC ERROR: ref_tensor"); } } fread (&a.dofs, sizeof (int), 1, f); if (a.dofs != bod->dofs) { ASSERT_TEXT (0, "PSC ERROR: dofs"); } fread (&a.form, sizeof (a.form), 1, f); if (a.form != bod->form) { ASSERT_TEXT (0, "PSC ERROR: form"); } int confsize = bod->kind != FEM ? 12 : bod->form == REDUCED_ORDER ? bod->dofs + 9 : bod->dofs; ERRMEM (a.conf = malloc (sizeof (double [confsize]))); fread (a.conf, sizeof (double), confsize, f); for (i = 0; i < confsize; i ++) { if (a.conf [i] != bod->conf [i]) { ASSERT_TEXT (0, "PSC ERROR: conf"); } } free (a.conf); ERRMEM (a.velo = malloc (sizeof (double [a.dofs]))); fread (a.velo, sizeof (double), a.dofs, f); for (i = 0; i < bod->dofs; i ++) { if (!DEQ(a.velo[i], bod->velo[i])) /* XXX: differs after 15th decimal place => why is ONLY velocity giving this kind of trouble? */ { double x = fabs (a.velo[i]-bod->velo[i]), y = DBL_EPSILON; printf ("%.17f > %.17f\n", x, y); ASSERT_TEXT (0, "PSC ERROR: velo => %d => %.17f != %.17f", i, a.velo[i], bod->velo[i]); } } free (a.velo); /* TODO => bod->forces */ /* TODO => bod->cra */ a.shape = psc_read_shape (f); if (psc_compare_shapes (a.shape, bod->shape) == 0) { ASSERT_TEXT (0, "PSC ERROR: shape"); } SHAPE_Destroy (a.shape); fread (&a.scheme, sizeof (a.scheme), 1, f); if (a.scheme != bod->scheme) { ASSERT_TEXT (0, "PSC ERROR: scheme"); } a.inverse = psc_read_matrix (f); if (psc_compare_matrices (a.inverse, bod->inverse) == 0) { ASSERT_TEXT (0, "PSC ERROR: inverse"); } psc_matrix_free (a.inverse); a.M = psc_read_matrix (f); if (psc_compare_matrices (a.M, bod->M) == 0) { ASSERT_TEXT (0, "PSC ERROR: M"); } psc_matrix_free (a.M); a.K = psc_read_matrix (f); if (psc_compare_matrices (a.K, bod->K) == 0) { ASSERT_TEXT (0, "PSC ERROR: K"); } psc_matrix_free (a.K); fread (&a.damping, sizeof (double), 1, f); if (a.damping != bod->damping) { ASSERT_TEXT (0, "PSC ERROR: damping"); } fread (&i, sizeof (int), 1, f); if (i && bod->evec == NULL) { ASSERT_TEXT (0, "PSC ERROR: evec existence"); } if (i) { a.evec = psc_read_matrix (f); if (psc_compare_matrices (a.evec, bod->evec) == 0) { ASSERT_TEXT (0, "PSC ERROR: evec"); } ERRMEM (a.eval = malloc (sizeof (double [a.evec->n]))); fread (a.eval, sizeof (double), a.evec->n, f); for (i = 0; i < a.evec->n; i ++) { if (a.eval [i]!= bod->eval [i]) { ASSERT_TEXT (0, "PSC ERROR: eval"); } } psc_matrix_free (a.evec); free (a.eval); } /* XXX: skip bod->label as non-essential */ /* XXX: skip bod->mesh for the moment */ /* XXX: skip bod->energy as non-essential */ /* XXX: skip bod->fracture as non-essential */ fclose (f); }
/* write body data to file before sending the body via MPI calles; * the file is SOLFEC->outpath/bodyID.data; */ void PSC_Write_Body (BODY *bod) { char txt [1024]; FILE *f; int i; ASSERT_TEXT (bod->kind == FEM, "Only FEM bodies are supported in PSC mode"); snprintf (txt, 1024, "%s/body%d.data", bod->dom->solfec->outpath, bod->id); ASSERT (f = fopen (txt, "w"), ERR_FILE_OPEN); fwrite (&bod->kind, sizeof (bod->kind), 1, f); #if 0 i = strlen(bod->mat->label); ASSERT_TEXT (i < 1024, "Material label is too long!"); fwrite (&i, sizeof (int), i, f); fwrite (bod->mat->label, sizeof (char), i, f); #endif fwrite (&bod->ref_mass, sizeof (double), 1, f); fwrite (&bod->ref_volume, sizeof (double), 1, f); fwrite (bod->ref_center, sizeof (double), 3, f); fwrite (bod->ref_tensor, sizeof (double), 9, f); fwrite (&bod->dofs, sizeof (int), 1, f); fwrite (&bod->form, sizeof (bod->form), 1, f); int confsize = bod->kind != FEM ? 12 : bod->form == REDUCED_ORDER ? bod->dofs + 9 : bod->dofs; fwrite (bod->conf, sizeof (double), confsize, f); fwrite (bod->velo, sizeof (double), bod->dofs, f); /* TODO => bod->forces */ /* TODO => bod->cra */ psc_write_shape (bod->shape, f); /* XXX => skip bod->extents (updated independently) */ fwrite (&bod->scheme, sizeof (bod->scheme), 1, f); psc_write_matrix (bod->inverse, f); psc_write_matrix (bod->M, f); psc_write_matrix (bod->K, f); fwrite (&bod->damping, sizeof (double), 1, f); if (bod->evec) { i = 1; fwrite (&i, sizeof (int), 1, f); psc_write_matrix (bod->evec, f); fwrite (bod->eval, sizeof (double), bod->evec->n, f); } else { i = 0; fwrite (&i, sizeof (int), 1, f); } /* XXX: skip bod->label as non-essential */ /* XXX: skip bod->mesh for the moment */ /* XXX: skip bod->energy as non-essential */ /* XXX: skip bod->fracture as non-essential */ fclose (f); }
static MESH* psc_read_mesh (FILE *f) { ELEMENT *ele, **tab, *tail; MESH *msh; int i, j; ERRMEM (msh = MEM_CALLOC (sizeof (MESH))); MEM_Init (&msh->elemem, sizeof (ELEMENT), 128); MEM_Init (&msh->facmem, sizeof (FACE), 128); MEM_Init (&msh->mapmem, sizeof (MAP), 128); fread (&msh->nodes_count, sizeof (int), 1, f); ERRMEM (msh->ref_nodes = malloc (2 * msh->nodes_count * sizeof (double [3]))); msh->cur_nodes = msh->ref_nodes + msh->nodes_count; fread (msh->ref_nodes, sizeof (double [3]), msh->nodes_count, f); fread (msh->cur_nodes, sizeof (double [3]), msh->nodes_count, f); fread (&msh->surfeles_count, sizeof (int), 1, f); fread (&msh->bulkeles_count, sizeof (int), 1, f); ERRMEM (tab = malloc ((msh->surfeles_count + msh->bulkeles_count) * sizeof (ELEMENT*))); for (i = 0, tail = NULL; i < msh->surfeles_count; i ++) { ele = psc_read_element (&msh->elemem, &msh->facmem, f); ele->flag = i; if (tail) ele->prev = tail, tail->next = ele; else msh->surfeles = ele; tail = ele; tab [i] = ele; } for (tail = NULL; i < msh->surfeles_count + msh->bulkeles_count; i ++) { ele = psc_read_element (&msh->elemem, &msh->facmem, f); ele->flag = i; if (tail) ele->prev = tail, tail->next = ele; else msh->bulkeles = ele; tail = ele; tab [i] = ele; } for (i = 0; i < msh->surfeles_count + msh->bulkeles_count; i ++) { ele = tab [i]; for (j = 0; j < ele->neighs; j ++) { int idx = (long) (void*) ele->adj[j]; ASSERT_TEXT (idx >= 0 && idx < msh->surfeles_count + msh->bulkeles_count, "INCONSITENT ELEMENT INDEXING"); ele->adj[j] = tab [idx]; } } free (tab); return msh; }
/* map rigid onto FEM state */ int dom_rigid_to_fem (DOM *dom, PBF *bf, SET *subset) { 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); } ASSERT_TEXT (iover >= 3, "Output files are too old for RIGID_TO_FEM to work"); /* read body states */ if (subset) { #if POSIX for (SET *item = SET_First (subset); item; item = SET_Next (item)) { regex_t xp; char *pattern = item->data; int error = regcomp (&xp, pattern, 0); if (error != 0) { char *message = get_regerror (error, &xp); fprintf (stderr, "-->\n"); fprintf (stderr, "Regular expression ERROR --> %s\n", message); fprintf (stderr, "<--\n"); regfree (&xp); free (message); return 0; } for (BODY *bod = dom->bod; bod; bod = bod->next) { if (bod->label && regexec (&xp, bod->label, 0, NULL, 0) == 0) { if (PBF_Label (bf, bod->label)) { double conf [12], velo [6], energy [4]; int rkind; int rconf; int rdofs; PBF_Int (bf, &rkind, 1); PBF_Int (bf, &rconf, 1); PBF_Int (bf, &rdofs, 1); if (bod->kind == FEM && rkind == RIG) { PBF_Double (bf, conf, 12); PBF_Double (bf, velo, 6); PBF_Double (bf, energy, 4); BODY_From_Rigid (bod, conf, conf+9, velo, velo+3); } else { ASSERT_TEXT (((bod->kind == RIG || bod->kind == OBS) && (rkind == RIG || rkind == OBS)) || bod->kind == (unsigned)rkind, "Body kind mismatch when reading state"); ASSERT_TEXT (BODY_Conf_Size (bod) == rconf, "Body configuration size mismatch when reading state"); ASSERT_TEXT (bod->dofs == rdofs, "Body dofs size mismatch when reading state"); BODY_Read_State (bod, bf, 0); /* use 0 state to skip reading of rkind, rnconf, rdofs */ } } } } regfree (&xp); } #else ASSERT_TEXT (0, "Regular expressions require POSIX support --> recompile Solfec with POSIX=yes"); return 0; #endif } else { ASSERT (PBF_Label (bf, "BODS"), ERR_FILE_FORMAT); int nbod; PBF_Int (bf, &nbod, 1); for (int n = 0; n < nbod; n ++) { double conf [12], velo [6], energy [4]; unsigned int id; BODY *bod; int rank; PBF_Uint (bf, &id, 1); bod = MAP_Find (dom->idb, (void*) (long) id, NULL); if (bod) /* update state of existing bodies only */ { int rkind; int rconf; int rdofs; PBF_Int (bf, &rkind, 1); PBF_Int (bf, &rconf, 1); PBF_Int (bf, &rdofs, 1); if (bod->kind == FEM && rkind == RIG) { PBF_Double (bf, conf, 12); PBF_Double (bf, velo, 6); PBF_Double (bf, energy, 4); if (bf->parallel == PBF_ON) { PBF_Int (bf, &rank, 1); } BODY_From_Rigid (bod, conf, conf+9, velo, velo+3); } else { ASSERT_TEXT (((bod->kind == RIG || bod->kind == OBS) && (rkind == RIG || rkind == OBS)) || bod->kind == (unsigned)rkind, "Body kind mismatch when reading state"); ASSERT_TEXT (BODY_Conf_Size (bod) == rconf, "Body configuration size mismatch when reading state"); ASSERT_TEXT (bod->dofs == rdofs, "Body dofs size mismatch when reading state"); BODY_Read_State (bod, bf, 0); /* use 0 state to skip reading of rkind, rnconf, rdofs */ } } else /* mock read */ { int rkind; int rconf; int rdofs; PBF_Int (bf, &rkind, 1); PBF_Int (bf, &rconf, 1); PBF_Int (bf, &rdofs, 1); double *conf; double *velo; double energy[10]; int rank; ERRMEM (conf = malloc (sizeof(double) * rconf)); ERRMEM (velo = malloc (sizeof(double) * rdofs)); PBF_Double (bf, conf, rconf); PBF_Double (bf, velo, rdofs); PBF_Double (bf, energy, BODY_ENERGY_SIZE(rkind)); if (bf->parallel == PBF_ON) { PBF_Int (bf, &rank, 1); } free (conf); free (velo); } } } } } return 1; }
/* initialize domain state */ int dom_init_state (DOM *dom, PBF *bf, SET *subset) { 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); } ASSERT_TEXT (iover >= 3, "Output files are too old for INITIALISE_STATE to work"); /* read body states */ if (subset) { #if POSIX for (SET *item = SET_First (subset); item; item = SET_Next (item)) { regex_t xp; char *pattern = item->data; int error = regcomp (&xp, pattern, 0); if (error != 0) { char *message = get_regerror (error, &xp); fprintf (stderr, "-->\n"); fprintf (stderr, "Regular expression ERROR --> %s\n", message); fprintf (stderr, "<--\n"); regfree (&xp); free (message); return 0; } for (BODY *bod = dom->bod; bod; bod = bod->next) { if (bod->label && regexec (&xp, bod->label, 0, NULL, 0) == 0) { if (PBF_Label (bf, bod->label)) { BODY_Read_State (bod, bf, iover); } } } regfree (&xp); } #else ASSERT_TEXT (0, "Regular expressions require POSIX support --> recompile Solfec with POSIX=yes"); return 0; #endif } else { 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; BODY *bod; PBF_Uint (bf, &id, 1); bod = MAP_Find (dom->idb, (void*) (long) id, NULL); if (bod) /* update state of existing bodies only */ { BODY_Read_State (bod, bf, iover); } else /* mock read */ { int rkind; int rconf; int rdofs; PBF_Int (bf, &rkind, 1); PBF_Int (bf, &rconf, 1); PBF_Int (bf, &rdofs, 1); double *conf; double *velo; double energy[10]; int rank; ERRMEM (conf = malloc (sizeof(double) * rconf)); ERRMEM (velo = malloc (sizeof(double) * rdofs)); PBF_Double (bf, conf, rconf); PBF_Double (bf, velo, rdofs); PBF_Double (bf, energy, BODY_ENERGY_SIZE(rkind)); if (bf->parallel == PBF_ON) { PBF_Int (bf, &rank, 1); } free (conf); free (velo); } } } } } return 1; }
/* update ellipsoid according to the given motion */ void ELLIP_Update (ELLIP *eli, void *body, void *shp, MOTION motion) { SGP sgp = {shp, eli, GOBJ_ELLIP, NULL}; double *ref = eli->ref_center, (*ref_pnt) [3] = eli->ref_point, *cur = eli->cur_center, (*cur_pnt) [3] = eli->cur_point; if (motion) { motion (body, &sgp, ref, cur); motion (body, &sgp, ref_pnt [0], cur_pnt [0]); motion (body, &sgp, ref_pnt [1], cur_pnt [1]); motion (body, &sgp, ref_pnt [2], cur_pnt [2]); BODY *bod = body; switch (bod->kind) { case OBS: case RIG: { double *R1 = bod->conf, *R0 = eli->ref_rot, *rot = eli->cur_rot; NNMUL (R1, R0, rot); } break; case PRB: { double *F = bod->conf, *sca0 = eli->ref_sca, *rot0 = eli->ref_rot, *sca1 = eli->cur_sca, *rot1 = eli->cur_rot; double U[9] = {1.0/(sca0[0]*sca0[0]), 0.0, 0.0, 0.0, 1.0/(sca0[1]*sca0[1]), 0.0, 0.0, 0.0, 1.0/(sca0[2]*sca0[2])}; double A0[9], iF[9], det, X[3], Y[9], A[9]; NTMUL (U, rot0, Y); NNMUL (rot0, Y, A0); TNCOPY (F, Y); /* T --> since deformation gradient is stored row-wise */ INVERT (Y, iF, det); ASSERT_TEXT (det > 0.0, "det(F) <= 0.0 during ellipsoid update"); NNMUL (A0, iF, Y); TNMUL (iF, Y, A); ASSERT_TEXT (lapack_dsyev ('V', 'U', 3, A, 3, X, Y, 9) == 0, "Eigen decomposition failed during ellipsoid update"); if (DET(A) < 0.0) /* det(A) is 1.0 or -1.0 */ { SCALE9 (A, -1.0); /* keep positive space orientation */ } NNCOPY (A, rot1); sca1[0] = 1.0/sqrt(X[0]); sca1[1] = 1.0/sqrt(X[1]); sca1[2] = 1.0/sqrt(X[2]); } break; default: { ASSERT_TEXT (0, "Invalid body kind during ellipsoid update"); } break; } } else { COPY (ref, cur); COPY (ref_pnt [0], cur_pnt [0]); COPY (ref_pnt [1], cur_pnt [1]); COPY (ref_pnt [2], cur_pnt [2]); sca_rot (eli->ref_center, eli->ref_point, eli->ref_sca, eli->ref_rot); COPY (eli->ref_sca, eli->cur_sca); NNCOPY (eli->ref_rot, eli->cur_rot); } }