/* 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; }
/* 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; }
/* write fracture state */ static void fracture_state_write (DOM *dom) { char path [1024]; double R[3], r, (*disp) [3]; int i, n, dofs; MESH *msh; SET *item; BODY *bod; CON *con; #if HDF5 int numbod; PBF *f; snprintf (path, 1024, "%s/fracture", dom->solfec->outpath); ASSERT (f = PBF_Write (path, PBF_ON, PBF_ON), ERR_FILE_OPEN); PBF_Time (f, &dom->time); for (numbod = 0, bod = dom->bod; bod; bod = bod->next) { if (bod->fracture) { msh = bod->shape->data; dofs = 3 * msh->nodes_count; ERRMEM (disp = malloc (msh->nodes_count * sizeof (double [3]))); for (i = 0; i < msh->nodes_count; i ++) { SUB (msh->cur_nodes [i], msh->ref_nodes [i], disp [i]); } PBF_Uint (f, &bod->id, 1); PBF_Int (f, &dofs, 1); PBF_Double (f, (double*)disp, dofs); n = SET_Size (bod->con); PBF_Int (f, &n, 1); for (item = SET_First (bod->con); item; item = SET_Next (item)) { con = item->data; r = sqrt (con->area/ALG_PI); PBF_Double (f, &r, 1); if (bod == con->master) { PBF_Double (f, con->mpnt, 3); } else { PBF_Double (f, con->spnt, 3); } NVMUL (con->base, con->R, R); PBF_Double (f, R, 3); } bod->fracture = 0; free (disp); numbod ++; } PBF_Int2 (f, "numbod", &numbod, 1); } PBF_Close (f); #else FILE *f; XDR x; #if MPI snprintf (path, 1024, "%s/fracture%d.dat", dom->solfec->outpath, dom->rank); #else snprintf (path, 1024, "%s/fracture.dat", dom->solfec->outpath); #endif ASSERT (f = fopen (path, "a"), ERR_FILE_OPEN); xdrstdio_create (&x, f, XDR_ENCODE); for (bod = dom->bod; bod; bod = bod->next) { if (bod->fracture) { msh = bod->shape->data; dofs = 3 * msh->nodes_count; ERRMEM (disp = malloc (msh->nodes_count * sizeof (double [3]))); for (i = 0; i < msh->nodes_count; i ++) { SUB (msh->cur_nodes [i], msh->ref_nodes [i], disp [i]); } ASSERT (xdr_u_int (&x, &bod->id), ERR_FILE_WRITE); ASSERT (xdr_int (&x, &dofs), ERR_FILE_WRITE); ASSERT (xdr_vector (&x, (char*)disp, dofs, sizeof (double), (xdrproc_t)xdr_double), ERR_FILE_WRITE); n = SET_Size (bod->con); ASSERT (xdr_int (&x, &n), ERR_FILE_WRITE); for (item = SET_First (bod->con); item; item = SET_Next (item)) { con = item->data; r = sqrt (con->area/ALG_PI); ASSERT (xdr_double (&x, &r), ERR_FILE_WRITE); if (bod == con->master) { ASSERT (xdr_vector (&x, (char*)con->mpnt, 3, sizeof (double), (xdrproc_t)xdr_double), ERR_FILE_WRITE); } else { ASSERT (xdr_vector (&x, (char*)con->spnt, 3, sizeof (double), (xdrproc_t)xdr_double), ERR_FILE_WRITE); } NVMUL (con->base, con->R, R); ASSERT (xdr_vector (&x, (char*)R, 3, sizeof (double), (xdrproc_t)xdr_double), ERR_FILE_WRITE); } bod->fracture = 0; free (disp); } } xdr_destroy (&x); fclose (f); #endif }
/* 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; }
/* 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; }
/* write new bodies data */ static void write_new_bodies (DOM *dom) { if (dom->newb == NULL) return; /* nothing to write */ #if HDF5 PBF *bf = dom->solfec->bf; int isize = 0, ints = 0, *i = NULL; int dsize = 0, doubles = 0; double *d = NULL; SET *item; int n; PBF_Push (bf, "NEWBOD"); n = SET_Size (dom->newb); PBF_Int2 (bf, "count", &n, 1); for (item = SET_First (dom->newb); item; item = SET_Next (item)) { BODY_Pack (item->data, &dsize, &d, &doubles, &isize, &i, &ints); } PBF_Int2 (bf, "ints", &ints, 1); PBF_Int2 (bf, "i", i, ints); PBF_Int2 (bf, "doubles", &doubles, 1); PBF_Double2 (bf, "d", d, doubles); free (d); free (i); PBF_Pop (bf); #else char *path, *ext; FILE *file; XDR xdr; path = SOLFEC_Alloc_File_Name (dom->solfec, 16); ext = path + strlen (path); #if MPI sprintf (ext, ".bod.%d", dom->rank); #else sprintf (ext, ".bod"); #endif ASSERT (file = fopen (path, "a"), ERR_FILE_OPEN); xdrstdio_create (&xdr, file, XDR_ENCODE); int isize = 0, ints, *i = NULL; int dsize = 0, doubles; double *d = NULL; SET *item; for (item = SET_First (dom->newb); item; item = SET_Next (item)) { doubles = ints = 0; BODY_Pack (item->data, &dsize, &d, &doubles, &isize, &i, &ints); ASSERT (xdr_int (&xdr, &doubles), ERR_PBF_WRITE); ASSERT (xdr_vector (&xdr, (char*)d, doubles, sizeof (double), (xdrproc_t)xdr_double), ERR_PBF_WRITE); ASSERT (xdr_int (&xdr, &ints), ERR_PBF_WRITE); ASSERT (xdr_vector (&xdr, (char*)i, ints, sizeof (int), (xdrproc_t)xdr_int), ERR_PBF_WRITE); } free (d); free (i); xdr_destroy (&xdr); fclose (file); free (path); #endif }
/* create rank coloring using adjacency graph between processors derived from the W graph */ static int* processor_coloring (GAUSS_SEIDEL *gs, LOCDYN *ldy) { int i, n, m, ncpu, rank, *color, *size, *disp, *adj; SET *adjcpu, *item; MEM setmem; DIAB *dia; OFFB *blk; CON *con; adjcpu = NULL; rank = ldy->dom->rank; ncpu = ldy->dom->ncpu; MEM_Init (&setmem, sizeof (SET), 128); ERRMEM (color = MEM_CALLOC (ncpu * sizeof (int))); ERRMEM (disp = malloc (sizeof (int [ncpu + 1]))); ERRMEM (size = malloc (sizeof (int [ncpu]))); /* collaps W adjacency into processor adjacency */ for (dia = ldy->dia; dia; dia = dia->n) { for (blk = dia->adjext; blk; blk = blk->n) { con = (CON*) blk->dia; SET_Insert (&setmem, &adjcpu, (void*) (long) con->rank, NULL); } } n = SET_Size (adjcpu); MPI_Allgather (&n, 1, MPI_INT, size, 1, MPI_INT, MPI_COMM_WORLD); for (i = disp [0] = 0; i < ncpu - 1; i ++) disp [i+1] = disp [i] + size [i]; for (i = 0, item = SET_First (adjcpu); item; i ++, item = SET_Next (item)) color [i] = (int) (long) item->data; m = disp [ncpu] = (disp [ncpu-1] + size [ncpu-1]); ERRMEM (adj = malloc (sizeof (int [m]))); MPI_Allgatherv (color, n, MPI_INT, adj, size, disp, MPI_INT, MPI_COMM_WORLD); /* gather graph adjacency */ for (i = 0; i < ncpu; i ++) color [i] = 0; /* zero colors */ for (i = 0; i < ncpu; i ++) /* simple BFS coloring */ { int *j, *k; do { color [i] ++; /* start from first color */ for (j = &adj[disp[i]], k = &adj[disp[i+1]]; j < k; j ++) /* for each adjacent vertex */ { if (color [*j] == color [i]) break; /* see whether the trial color exists in the adjacency */ } } while (j < k); /* if so try next color */ } for (m = i = 0; i < ncpu; i ++) m = MAX (m, color [i]); /* compute number of colors */ gs->colors = m; /* record number of colors */ if (rank == 0 && ldy->dom->verbose && gs->verbose) { #if DEBUG for (i = 0; i < ncpu; i ++) { int *j, *k; printf ("GAUSS_SEIDEL: RANK %d [%d] ADJCPU:", i, color [i]); for (j = &adj[disp[i]], k = &adj[disp[i+1]]; j < k; j ++) printf (" %d [%d]", *j, color [*j]); printf ("\n"); } #endif printf ("GAUSS_SEIDEL: PROCESSOR COLORS = %d\n", m); } MEM_Release (&setmem); free (size); free (disp); free (adj); return color; }