Changeset 430 for trunk

Show
Ignore:
Timestamp:
02/24/2009 09:35:26 PM (3 years ago)
Author:
powell
Message:

Construct all phase boundaries in the convex hull (almost works).

Location:
trunk/matml/src/ternary
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/matml/src/ternary/ChangeLog

    r427 r430  
    33  * Overhauled the free energy interface and functions, adding derivative 
    44    implementations. 
    5   * Added phase_boundary typedef struct. 
     5  * Added phase_boundary object. 
    66  * Changed hull calculation interface to only hold the qhull variables during 
    77    hull calculation (with a lock to prevent attempts at multiple usage). 
    88  * Phase boundary refinement using a cool, and I think novel, Newton energy 
    99    minimization algorithm. 
     10  * Report all phase boundaries in the hull as phase_boundary objects. 
    1011  * Added WITH_DERIVATIVES and NO_INFINITY options to free energies(). 
    11   * Added spinodal.c with calc_spinodal function. 
     12  * Added spinodal.c with calc_spinodal function returning a phase_boundary. 
    1213 
    1314 -- 
  • trunk/matml/src/ternary/qhull.c

    r426 r430  
    677677 
    678678 
     679#ifndef MIN 
     680#define MIN(a,b) (((a) < (b)) ? (a) : (b)) 
     681#endif 
     682 
     683#ifndef MAX 
     684#define MAX(a,b) (((a) > (b)) ? (a) : (b)) 
     685#endif 
     686 
     687// For more than three points, qsort() is just easier! 
     688#define MIN3(a,b,c) (MIN (MIN (a,b), c)) 
     689#define MAX3(a,b,c) (MAX (MAX (a,b), c)) 
     690#define MID3(a,b,c) (((a) < (b)) ? \ 
     691                     (((a) < (c)) ? MIN (b,c) : (a)) : \ 
     692                     (((a) < (c)) ? (a) : MAX (b,c))) 
     693 
     694/*++++++++++++++++++++++++++++++++++++++ 
     695  This distills a set of facets to a list of phase boundaries. 
     696 
     697  int hullReturnPhaseBoundaries It returns zero or an error code. 
     698 
     699  ternary_point *points Array of points in the ternary system. 
     700 
     701  int n_points Number of points. 
     702 
     703  hull_facet *facets Facets from which to create phase boundaries. 
     704 
     705  int numfacets Number of facets. 
     706 
     707  phase_boundary **boundaries Pointer to array of phase_boundary objects.  This 
     708  is changed by realloc() each time the function is called, so it should be 
     709  NULL or a valid array. 
     710 
     711  int *n_bounds Number of phase boundaries returned in boundaries. 
     712  ++++++++++++++++++++++++++++++++++++++*/ 
     713 
     714int hullReturnPhaseBoundaries 
     715(ternary_point *points, int n_points, hull_facet *facets, int n_facets, 
     716 phase_boundary **boundaries, int *n_bounds) 
     717{ 
     718  int f; 
     719  *n_bounds = 0; 
     720 
     721  printf ("Starting ReturnPhaseBoundaries with %d facets, %d points\n", 
     722          n_facets, n_points); 
     723 
     724  printf ("Last facet %d vertices %d, %d, %d\n", n_facets-1, 
     725          facets[n_facets-1].vertex[0], facets[n_facets-1].vertex[1], 
     726          facets[n_facets-1].vertex[2]); 
     727 
     728  for (f=0; f<n_facets; f++) 
     729    { 
     730      int v0 = facets[f].vertex[0], v1 = facets[f].vertex[1], 
     731        v2 = facets[f].vertex[2]; 
     732 
     733      printf ("Last facet %d vertices %d, %d, %d\n", n_facets-1, 
     734              facets[n_facets-1].vertex[0], facets[n_facets-1].vertex[1], 
     735              facets[n_facets-1].vertex[2]); 
     736 
     737      printf ("Facet %d: type %d, vertices %d ",f, facets [f].type, v0); 
     738      fflush (stdout); 
     739      printf ("(%d), %d (%d), %d(%d)\n", 
     740              points[v0].efunc, v1, 
     741              points[v1].efunc, v2, points[v2].efunc); 
     742      fflush (stdout); 
     743 
     744      switch (facets [f].type) 
     745        { 
     746        case ONE_PHASE: 
     747          { 
     748            printf ("Type 0 facet\n"); fflush (stdout); 
     749            // Totally uninteresting 
     750            break; 
     751          } 
     752 
     753        case THREE_PHASE: 
     754          { 
     755            int b=0, bound=-1, 
     756              phase0 = MIN3 (points [v0].efunc, points [v1].efunc, 
     757                             points [v2].efunc), 
     758              phase1 = MID3 (points [v0].efunc, points [v1].efunc, 
     759                             points [v2].efunc), 
     760              phase2 = MAX3 (points [v0].efunc, points [v1].efunc, 
     761                             points [v2].efunc); 
     762 
     763            // Check for a boundary with the same three phases 
     764            for (b=0; b<*n_bounds; b++) 
     765              if ((*boundaries) [b].n_phases == 3) 
     766                if ((*boundaries) [b].compos = 3 && 
     767                    (*boundaries) [b].flags == TIE_SIMPLICES && 
     768                    (*boundaries) [b].phases[0] == phase0 && 
     769                    (*boundaries) [b].phases[1] == phase1 && 
     770                    (*boundaries) [b].phases[2] == phase2) 
     771                  bound = b; 
     772 
     773            if (bound == -1) 
     774              { 
     775                // No boundary with these three phases, make a new one 
     776                bound = *n_bounds; 
     777                printf ("Making new three-phase boundary %d\n", *n_bounds); 
     778                if (!(*boundaries = realloc 
     779                      (*boundaries, (*n_bounds+1) * sizeof (phase_boundary)))) 
     780                  return 1; 
     781 
     782                (*boundaries) [bound].compos = 3; 
     783                (*boundaries) [bound].n_phases = 3; 
     784                if (!((*boundaries) [bound].phases = malloc (3*sizeof (int)))) 
     785                  return 1; 
     786                (*boundaries) [bound].phases [0] = phase0; 
     787                (*boundaries) [bound].phases [1] = phase1; 
     788                (*boundaries) [bound].phases [2] = phase2; 
     789                (*boundaries) [bound].flags = TIE_SIMPLICES; 
     790                (*boundaries) [bound].n_edges = 1; 
     791                if (!((*boundaries) [bound].edges = malloc (3*sizeof (int)))) 
     792                  return 1; 
     793                (*boundaries) [bound].edges [0] = MIN3 (v0, v1, v2); 
     794                (*boundaries) [bound].edges [1] = MID3 (v0, v1, v2); 
     795                (*boundaries) [bound].edges [2] = MAX3 (v0, v1, v2); 
     796                (*n_bounds) ++; 
     797              } 
     798            else 
     799              { 
     800                // Boundary found, add to it; it's likely to be rare enough 
     801                // that we need not worry about the realloc overhead 
     802                int e = (*boundaries) [bound].n_edges; 
     803                printf ("Ternary boundary %d adding edge %d\n",bound,e); 
     804                // All of these reallocs are pretty expensive... 
     805                // Later use compos to store size of array, sort out later 
     806                if (!((*boundaries) [bound].edges = realloc 
     807                      ((*boundaries) [bound].edges, (3*e+3)*sizeof (int)))) 
     808                  return 1; 
     809                (*boundaries) [bound].edges [3*e]   = MIN3 (v0, v1, v2); 
     810                (*boundaries) [bound].edges [3*e+1] = MID3 (v0, v1, v2); 
     811                (*boundaries) [bound].edges [3*e+2] = MAX3 (v0, v1, v2); 
     812                (*boundaries) [bound].n_edges += 1; 
     813              } 
     814 
     815            // Need to handle the corner "boundaries" later... 
     816 
     817            break; 
     818          } 
     819 
     820        case TWO_PHASE: 
     821          { 
     822            int b=0, bound=-1, p0, p1, p2, 
     823              phase0 = MIN3 (points [v0].efunc, points [v1].efunc, 
     824                             points [v2].efunc), 
     825              phase1 = MAX3 (points [v0].efunc, points [v1].efunc, 
     826                             points [v2].efunc); 
     827 
     828            // Set p0 and p1 to index first and second vertices in same phase, 
     829            // p2 to lone vertex in the other phase. 
     830            if (points [v0].efunc == points [v1].efunc) 
     831              { 
     832                p0 = MIN (v0, v1); 
     833                p1 = MAX (v0, v1); 
     834                p2 = v2; 
     835                // If all three are on the same phase, need to check midpoint 
     836                // energies to determine which are one- and two-phase segments. 
     837                // Punt for the default case later! 
     838                if (points [v0].efunc == points [v2].efunc) 
     839                  { printf ("Miscibility gap!\n"); break; } 
     840              } 
     841            else if (points [v0].efunc == points [v2].efunc) 
     842              { 
     843                p0 = MIN (v0, v2); 
     844                p1 = MAX (v0, v2); 
     845                p2 = v1; 
     846              } 
     847            else 
     848              { 
     849                p0 = MIN (v1, v2); 
     850                p1 = MAX (v1, v2); 
     851                p2 = v0; 
     852              } 
     853 
     854            // Check for a boundary with tie lines between these two phases 
     855            for (b=0; b<*n_bounds; b++) 
     856              if ((*boundaries) [b].n_phases == 2 && 
     857                  (*boundaries) [b].flags == TIE_SIMPLICES && 
     858                  (*boundaries) [b].phases[0] == phase0 && 
     859                  (*boundaries) [b].phases[1] == phase1) 
     860                bound = b; 
     861 
     862            if (bound == -1) 
     863              { 
     864                bound = *n_bounds; 
     865                // No boundary with these two phases, make a new one 
     866                printf ("Making new tie-line boundary %d\n", *n_bounds); 
     867                if (!(*boundaries = realloc 
     868                      (*boundaries, (*n_bounds+1) * sizeof (phase_boundary)))) 
     869                  return 1; 
     870 
     871                (*boundaries) [bound].compos = 2; 
     872                (*boundaries) [bound].n_phases = 2; 
     873                if (!((*boundaries) [bound].phases = 
     874                      malloc (2*sizeof (int)))) 
     875                  return 1; 
     876                (*boundaries) [bound].phases [0] = phase0; 
     877                (*boundaries) [bound].phases [1] = phase1; 
     878                (*boundaries) [bound].n_edges = 2; 
     879                if (!((*boundaries) [bound].edges = 
     880                      malloc (4*sizeof (int)))) 
     881                  return 1; 
     882                (*boundaries) [bound].edges [0] = MIN (p0, p2); 
     883                (*boundaries) [bound].edges [1] = MAX (p0, p2); 
     884                (*boundaries) [bound].edges [2] = MIN (p1, p2); 
     885                (*boundaries) [bound].edges [3] = MAX (p1, p2); 
     886                (*boundaries) [bound].flags = TIE_SIMPLICES; 
     887                (*n_bounds) ++; 
     888              } 
     889            else 
     890              { 
     891                int e = (*boundaries) [bound].n_edges; 
     892                printf ("Tie-line boundary %d adding edges %d,%d\n",bound,e,e+1); 
     893                // All of these reallocs are pretty expensive... 
     894                // Later use compos to store size of array, sort out later 
     895                if (!((*boundaries) [bound].edges = realloc 
     896                      ((*boundaries) [bound].edges, (2*e+4)*sizeof (int)))) 
     897                  return 1; 
     898                (*boundaries) [bound].edges [2*e]   = MIN (p0, p2); 
     899                (*boundaries) [bound].edges [2*e+1] = MAX (p0, p2); 
     900                (*boundaries) [bound].edges [2*e+2] = MIN (p1, p2); 
     901                (*boundaries) [bound].edges [2*e+3] = MAX (p1, p2); 
     902                (*boundaries) [bound].n_edges += 2; 
     903              } 
     904 
     905            // Check for a boundary with an edge on the "majority" phase 
     906            for (b=0, bound=-1; b<*n_bounds; b++) 
     907              if ((*boundaries) [b].n_phases == 2 && 
     908                  (*boundaries) [b].flags == ONE_PHASE_EDGE && 
     909                  (*boundaries) [b].phases[0] == points[p0].efunc && 
     910                  (*boundaries) [b].phases[1] == points[p2].efunc) 
     911                bound = b; 
     912 
     913            if (bound == -1) 
     914              { 
     915                // No boundary with these two phases, make a new one 
     916                bound = *n_bounds; 
     917                printf ("Making new phase edge boundary %d\n", *n_bounds); 
     918                if (!(*boundaries = realloc 
     919                      (*boundaries, (bound+1) * sizeof (phase_boundary)))) 
     920                  return 1; 
     921 
     922                (*boundaries) [bound].compos = 2; 
     923                (*boundaries) [bound].n_phases = 2; 
     924                if (!((*boundaries) [bound].phases = 
     925                      malloc (2*sizeof (int)))) 
     926                  return 1; 
     927                (*boundaries) [bound].phases [0] = points[p0].efunc; 
     928                (*boundaries) [bound].phases [1] = points[p2].efunc; 
     929                (*boundaries) [bound].n_edges = 1; 
     930                if (!((*boundaries) [bound].edges = 
     931                      malloc (2*sizeof (int)))) 
     932                  return 1; 
     933                (*boundaries) [bound].edges [0] = MIN (p0, p1); 
     934                (*boundaries) [bound].edges [1] = MAX (p0, p1); 
     935                (*boundaries) [bound].flags = ONE_PHASE_EDGE; 
     936                (*n_bounds) ++; 
     937              } 
     938            else 
     939              { 
     940                int e = (*boundaries) [bound].n_edges; 
     941                printf ("Phase edge boundary %d adding edge %d\n",bound,e); 
     942                // All of these reallocs are pretty expensive... 
     943                if (!((*boundaries) [bound].edges = realloc 
     944                      ((*boundaries) [bound].edges, (2*e+2)*sizeof (int)))) 
     945                  return 1; 
     946                (*boundaries) [bound].edges [2*e]   = MIN (p0, p1); 
     947                (*boundaries) [bound].edges [2*e+1] = MAX (p0, p1); 
     948                (*boundaries) [bound].n_edges += 1; 
     949              } 
     950 
     951            break; 
     952          } 
     953 
     954        default: 
     955          { 
     956            printf ("Default case: type %s, phases %d, %d, %d\n", 
     957                    (facets [f].type == ONE_PHASE) ? "1-phase" : 
     958                    ((facets [f].type == CRITICAL_POINT) ? "critical" : 
     959                     ((facets [f].type == TWO_PHASE) ? "2-phase" : 
     960                      ((facets [f].type == THREE_PHASE) ? "3-phase" : 
     961                       "unknown"))), points [facets[f].vertex[0]].efunc, 
     962                    points [facets[f].vertex[1]].efunc, 
     963                    points [facets[f].vertex[2]].efunc); 
     964          } 
     965        } 
     966    } 
     967 
     968  printf ("Done!\n"); 
     969  return 0; 
     970} 
     971 
     972 
    679973/*++++++++++++++++++++++++++++++++++++++ 
    680974  This is what it sounds like. 
  • trunk/matml/src/ternary/ternary.c

    r424 r430  
    2828int main (int argc, char *argv[]) 
    2929{ 
    30   int i,j, index, loop_max=20, numpoints, *verts, hullnumfacets; 
     30  int i,j, index, loop_max=20, numpoints, *verts, hullnumfacets, numbounds; 
    3131  hull_facet *hullfacets = NULL; 
    3232  char gv_version[100]; 
     
    3434  double T=0.7, P=1.; 
    3535  ternary_point *points; 
    36   phase_boundary solid_spinodal; 
     36  phase_boundary solid_spinodal, *allbounds=NULL; 
    3737  /* eparams: R,T0, G1@T0,G2,G3, C1,C2,C3, M1,M2,M3, O12,O13,O23,O123 */ 
    3838  energy_params /* Solid, liquid */ 
     
    120120    { printf ("main: Error %d in Geomview Display\n", i); exit (i); } 
    121121 
     122  if (i=hullReturnPhaseBoundaries (points,numpoints, hullfacets,hullnumfacets, 
     123                                   &allbounds, &numbounds)) 
     124    { printf ("main: error %d in hullReturnPhaseBoundaries\n", i); exit (i); } 
     125 
     126  if (i=GeomviewDisplayPhaseBoundary 
     127      (pfd, "Boundary 0", "bd0", "-face +edge", 
     128       numpoints, points, allbounds)) 
     129    { printf ("main: Error %d in Geomview Display\n", i); exit (i); }   
     130 
     131  if (i=GeomviewDisplayPhaseBoundary 
     132      (pfd, "Boundary 1", "bd1", "-face +edge", 
     133       numpoints, points, allbounds+1)) 
     134    { printf ("main: Error %d in Geomview Display\n", i); exit (i); }   
     135 
     136  if (i=GeomviewDisplayPhaseBoundary 
     137      (pfd, "Boundary 2", "bd2", "-face +edge", 
     138       numpoints, points, allbounds+2)) 
     139    { printf ("main: Error %d in Geomview Display\n", i); exit (i); }   
     140 
     141  if (i=GeomviewDisplayPhaseBoundary 
     142      (pfd, "Boundary 3", "bd3", "-face +edge", 
     143       numpoints, points, allbounds+3)) 
     144    { printf ("main: Error %d in Geomview Display\n", i); exit (i); }   
     145 
    122146  printf ("Press <return> to close up... "); 
    123147  fflush (stdout); 
  • trunk/matml/src/ternary/ternary.h

    r424 r430  
    105105typedef enum { 
    106106  ONE_PHASE_EDGE=0, /*+ One phase's boundary edges +*/ 
    107   TIE_SIMPLICES,    /*+ Tie lines (ternary) or other simplices between two 
    108                       phases +*/ 
     107  TIE_SIMPLICES,    /*+ Tie lines between two phases, triangles between three, 
     108                      etc. +*/ 
    109109  SPINODAL          /*+ Spinodal boundary +*/ 
    110110} phase_boundary_flags; 
    111111 
    112112typedef struct { 
    113   int compos;   /*+ Number of components of the space (ternary binary etc.) +*/ 
     113  int compos;   /*+ Number of points in a boundary edge +*/ 
    114114  int *edges;   /*+ Edges with indices of ternary_points comprising a phase 
    115115                  boundary; each edge has compos points +*/ 
     
    174174 energy_params *eparams, int nparams, double T,double P, 
    175175 double newton_tolerance, double vertex_tolerance, int one_phase_refine); 
     176int hullReturnPhaseBoundaries 
     177(ternary_point *points, int n_points, hull_facet *facets, int n_facets, 
     178 phase_boundary **boundaries, int *n_bounds); 
    176179char *hullQHullVersion (); 
    177180