File: wulff.c

package info (click to toggle)
evolver 2.30c.dfsg-3
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 9,800 kB
  • ctags: 10,247
  • sloc: ansic: 118,999; makefile: 100
file content (261 lines) | stat: -rw-r--r-- 6,985 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*************************************************************
*  This file is part of the Surface Evolver source code.     *
*  Programmer:  Ken Brakke, brakke@susqu.edu                 *
*************************************************************/

/****************************************************************
*
*  File: wulff.c
*
*  Purpose:  Routines dealing with surface energy as function
*             of normal direction.
*/

/*****************************************************************
*
*  Discussion:  For a chunk of surface represented by its
*  normal vector N (length is area of chunk), its energy is
*  the inner product of N with the Wulff vector W, which is a
*  function of N.  For a given set of Wulff vectors, W is the
*  one whose inner product with N is greatest.  The Wulff vectors
*  are the vertices of the Wulff crystal.  For simple area,
*  W is the normalization of N.
*
*  Force is energy gradient, so for N depending on a parameter u,
*
*        dE/du = <dN/du,W> + <N,dW/du>
*
*  However, the fact that W has maximal product with N implies
*  <N,dW/du> = 0, so  dE/du = <dN/du,W>.  So we need only
*  the Wulff vector to calculate both energy and force.
*/

#include "include.h"

/*******************************************************
*
*  wulff_initialize()
*
*  Purpose: Read in Wulff vectors from file and initialze
*           Wulff variables.  If special name, redirects
*           Wulff functions to  special functions in this 
*           file.
*
*  Input:    Name of file with Wulff vectors.
*
*  Output:  Array of Wulff vectors, wulff_flag set
*/

void wulff_initialize(wulffname)
char *wulffname;
{
  FILE *wfd;
  REAL *row; /* current Wulff vector */
  int k;         /* vector number */
  int j;         /* dimension number */

  if ( (web.representation != SOAPFILM ) || (SDIM != 3) )
     kb_error(1385,"Can only do Wulff energy for 2D surface in 3D.\n",RECOVERABLE);

  if ( !wulffname || (wulffname[0] == 0) )
     kb_error(2857,"Missing Wulff file name.\n",RECOVERABLE);
  web.wulff_flag = 1;

  /* save  name */
  strncpy(web.wulff_name,wulffname,sizeof(web.wulff_name));

  /* test special names */
  if ( (strncmp(wulffname,"hemisphere",10) == 0  )
      || (strcmp(wulffname,"hemi") == 0)  )
  { get_wulff = hemi_wulff;
    return;
  }
  else if ( strncmp(wulffname,"lens",4) == 0 )
  { get_wulff = lens_wulff;
    return;
  }

  /* default is from file */
  get_wulff = file_wulff;

  wfd = path_open(wulffname,NOTDATAFILENAME);
  if ( wfd == NULL )
     { sprintf(errmsg,"Cannot open Wulff vector file %s.\n",wulffname);
       kb_error(1386,errmsg,DATAFILE_ERROR);
       return;
     }

  for ( k = 0 ; k < MAXWULFF ; k++ )
     { row = wulff_vector[k];
       for ( j = 0 ; j < SDIM ; j++ )
#ifdef LONGDOUBLE
       if ( fscanf(wfd,"%Lf",row+j) != 1 ) break;
#else
       if ( fscanf(wfd,"%lf",row+j) != 1 ) break;
#endif
     }
  fclose(wfd);
  web.wulff_count = k;
}

/******************************************************************8
*
*  Function: file_wulff()
*
*  Purpose:  Finds Wulff vector that has maximum dot product
*                with given vector.
*
*  Input:     Pointer to given vector, 
*                pointer to destination of Wulff vector.
*
*  Output:    Components of Wulff vector put in place.
*/

void file_wulff(norm,wulff)
REAL *norm;
REAL *wulff;
{
  REAL maxw = -1e20;
  REAL *w; /* Wulff vector being tested */
  int k;
  int best = 0;

  for ( k = 0 ; k < web.wulff_count ; k++ )
     { w = wulff_vector[k];
        if ( SDIM_dot(w,norm) > maxw )
          { best = k;
             maxw = SDIM_dot(w,norm);
          }
     }
  memcpy((char *)wulff,(char *)wulff_vector[best],SDIM*sizeof(REAL));
}

/******************************************************************
*
*  Function: hemi_wulff()
*
*  Purpose:  Provide Wulff vector for upper hemisphere Wulff shape.
*/

void hemi_wulff(normal,wulff)
REAL *normal;
REAL *wulff;
{
  int i;
  REAL norm;

  wulff[0] = normal[0];
  wulff[1] = normal[1];
  if ( normal[2] < 0.0 )
     wulff[2] = 0.0;
  else wulff[2] = normal[2];
  norm = sqrt(SDIM_dot(wulff,wulff));
  if ( norm > 0.0 )
     for ( i = 0 ; i < SDIM ; i++ )
        wulff[i] /= norm;
}

/********************************************************************
*
*  Function: lens_wulff
*
*  Purpose:  Provide Wulff vector for lens-shaped Wulff shape.
*/

void lens_wulff(normal,wulff)
REAL *normal;
REAL *wulff;
{
  REAL norm;

  /* test whether interior or edge Wulff vector */  
  norm = dot(normal,normal,2);     /* x and y only */
  if ( norm < 3*normal[2]*normal[2] )
     { /* interior */
        norm = sqrt(norm + normal[2]*normal[2]);
        if ( norm > 0.0 )
          { wulff[0] = normal[0]/norm;
             wulff[1] = normal[1]/norm;
             wulff[2] = normal[2]/norm - 0.5;
          }
     }
  else
     { /* edge */
        norm = sqrt(norm/0.75);
        wulff[0] = normal[0]/norm;
        wulff[1] = normal[1]/norm;
        wulff[2] = 0.0;
     }
}

/************************************************************************

                 Wulff energy as method

**************************************************************************/

void wulff_method_init(mode,mi)
int mode;
struct method_instance *mi;
{ char response[200];

  if ( web.modeltype != LINEAR )
    kb_error(2859,"Wulff energy can only be done in LINEAR model.\n",
     RECOVERABLE);

  if ( web.wulff_flag == 0 ) 
  { prompt("Enter Wulff name (hemi,lens, or filename): ",response,sizeof(response));
     wulff_initialize(response);
  }
}

REAL facet_wulff_value(f_info)
struct qinfo *f_info;
{ REAL normal[MAXCOORD];
  REAL wulff [MAXCOORD];
  REAL density = get_facet_density(f_info->id);
  REAL energy;
  REAL side  [MAXCOORD][MAXCOORD];
  int i,j;

  for ( i = 0 ; i < FACET_EDGES ; i++ )
     { int ii = (i+1)%FACET_EDGES;
        for ( j = 0 ; j < SDIM ; j++ )
            side[i][j] = f_info->x[ii][j] - f_info->x[i][j];
     }
  /* calculate normal */ 
  cross_prod(side[0],side[1],normal);
  (*get_wulff)(normal,wulff);
  energy = SDIM_dot(wulff,normal)/2;
  return density*energy;
}

REAL facet_wulff_grad(f_info)
struct qinfo *f_info;
{ REAL normal[MAXCOORD];
  REAL wulff [MAXCOORD];
  REAL temp  [MAXCOORD];
  REAL side  [MAXCOORD][MAXCOORD];
  REAL density = get_facet_density(f_info->id);
  REAL energy;
  int i,j;

  for ( i = 0 ; i < FACET_EDGES ; i++ )
     { int ii = (i+1)%FACET_EDGES;
        for ( j = 0 ; j < SDIM ; j++ )
            side[i][j] = f_info->x[ii][j] - f_info->x[i][j];
     }
  /* calculate normal */ 
  cross_prod(side[0],side[1],normal);
  (*get_wulff)(normal,wulff);
  /* force on each vertex */
  for ( i = 0 ; i < FACET_VERTS ; i++ )  /* vertex loop */
      { int k;
         j = (i+1)%FACET_EDGES;  /* opposite side */
         cross_prod(side[j],wulff,temp);
         for ( k = 0 ; k < SDIM ; k++ ) 
             f_info->grad[i][k] -= density*temp[k]/2;
      }
  energy = SDIM_dot(wulff,normal)/2;
  return density*energy;
}