added support for starting file, added make_cryst tool
[physik/nlsop.git] / nlsop_client.c
1 /*
2  * client nlsop code
3  *
4  * author: frank zirkelbach (frank.zirkelbach@physik.uni-augsburg.de)
5  *
6  * this program tries helping to understand the amorphous depuration
7  * and recrystallization of SiCx while ion implantation at temperatures
8  * below 400 degree celsius.
9  * hopefully the program will simulate the stabilization of the
10  * selforganizing lamella structure in the observed behaviour.
11  *
12  * refs: 
13  *  - J. K. N. Lindner. Habil.Schrift, Universitaet Augsburg.
14  *  - Maik Haeberlen. Diplomarbeit, Universitaet Augsburg.
15  *
16  * Copyright (C) 2004 Frank Zirkelbach
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  *
32  */
33
34 #define _GNU_SOURCE
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42
43 #include <signal.h>
44
45 #include "nlsop.h"
46 #include "dfbapi.h"
47 #include "random.h"
48
49 #include "network.h"
50 #include "event.h"
51
52 #include "nlsop_general.h"
53
54 #define MAKE_AMORPH(N) *(N)|=AMORPH
55 #define MAKE_CRYST(N) *(N)&=~AMORPH
56
57 /* globals */
58
59 char p_file[MAX_CHARS];
60 char n_e_file[MAX_CHARS];
61 char r_file[MAX_CHARS];
62 char s_file[MAX_CHARS];
63 int start_fd;
64 t_net *gnet;
65 d3_lattice *gd3_l;
66 info *gmy_info;
67 int *gi;
68 unsigned char dc;
69 unsigned char shut_down;
70
71 int get_data_and_calc(t_event *event,void *allineed);
72 int nop(t_event *event,void *allineed);
73
74 int usage(char *prog)
75 {
76  puts("usage:");
77  printf("%s -i ip -p port -r/P/n/s random/profile/neloss/start file\n",prog);
78  return 1;
79 }
80
81 /*
82  * nlsop internal functions
83  */
84
85 int sputter(d3_lattice *d3_l)
86 {
87  int i,size;
88  int offh,offl;
89
90  size=d3_l->max_x*d3_l->max_y;
91  offl=0;
92  offh=size;
93
94  for(i=0;i<d3_l->max_z-1;i++)
95  {
96   memcpy(d3_l->status+offl,d3_l->status+offh,size);
97   memcpy(d3_l->extra+offl,d3_l->extra+offh,size*sizeof(int));
98   offl=offh;
99   offh+=size;
100  }
101  memset(d3_l->status+offl,0,size);
102  memset(d3_l->extra+offl,0,size);
103
104  return 1;
105 }
106
107 int process_cell(d3_lattice *d3_l,u32 x,u32 y,u32 z,info *my_info,u32 nel_z)
108 {
109  unsigned char *thiz;
110  int *conc;
111  int i,j;
112  int off;
113  double p,q;
114
115  thiz=d3_l->status+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y;
116  conc=d3_l->extra+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y;
117  //p=my_info->b*nel_z; // energieuebertrag prop zu nukl. bk
118  p=my_info->b*URAND_MAX; // konstanter energieuebertrag
119  for(i=-(my_info->range);i<=my_info->range;i++)
120  {
121   for(j=-(my_info->range);j<=my_info->range;j++)
122   {
123    if(!(i==0 && j==0))
124    {
125     off=((x+d3_l->max_x+i)%d3_l->max_x)+((y+d3_l->max_y+j)%d3_l->max_x)*d3_l->max_x+z*d3_l->max_x*d3_l->max_y;
126     if(*(d3_l->status+off)&AMORPH) p+=my_info->s*(*(d3_l->extra+off))*URAND_MAX/(i*i+j*j);
127    } 
128   }
129  }
130  p+=*conc*my_info->c*URAND_MAX;
131  if(p>=URAND_MAX) MAKE_AMORPH(thiz);
132  else {
133   if(!(*thiz&AMORPH)) {
134    if(get_rand(URAND_MAX)<=p) MAKE_AMORPH(thiz);
135   }
136   else {
137    /* assume 1-p probability */
138    /* also look for neighbours ! */
139    q=(URAND_MAX-p)>0?URAND_MAX-p:0;
140    j=0;
141    j+=(*(d3_l->status+((x+d3_l->max_x+1)%d3_l->max_x)+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
142    j+=(*(d3_l->status+((x+d3_l->max_x-1)%d3_l->max_x)+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
143    j+=(*(d3_l->status+x+((y+1+d3_l->max_y)%d3_l->max_y)*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
144    j+=(*(d3_l->status+x+((y-1+d3_l->max_y)%d3_l->max_y)*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
145    j+=(*(d3_l->status+x+y*d3_l->max_x+((z+1+d3_l->max_z)%d3_l->max_z)*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
146    j+=(*(d3_l->status+x+y*d3_l->max_x+((z-1+d3_l->max_z)%d3_l->max_z)*d3_l->max_x*d3_l->max_y)&AMORPH)?1:0;
147  
148    p+=((q/6)*j);
149    if(p<=URAND_MAX) {
150     if(get_rand(URAND_MAX)>p) MAKE_CRYST(thiz);
151    }
152   }
153  }
154  
155  return 1;
156 }
157
158 int distrib_c(d3_lattice *d3_l,info *my_info,int step,u32 rj_m,u32 *rj_g)
159 {
160  u32 x,y,z;
161  int i,j,k,c;
162  int offset,off;
163  int carry;
164
165  /* put one c ion somewhere in the lattice */
166  x=get_rand(d3_l->max_x);
167  y=get_rand(d3_l->max_y);
168  z=get_rand_reject(d3_l->max_z,rj_m,rj_g);
169  *(d3_l->extra+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)+=1;
170  (my_info->cc)++;
171
172  if(step%my_info->diff_rate==0)
173  {
174
175  for(i=0;i<d3_l->max_x;i++)
176  {
177   for(j=0;j<d3_l->max_y;j++)
178   {
179    for(k=0;k<d3_l->max_z;k++)
180    {
181     offset=i+j*d3_l->max_x+k*d3_l->max_x*d3_l->max_y;
182     /* case amorph: amorph <- cryst diffusion */
183     if(*(d3_l->status+offset)&AMORPH)
184     {
185      for(c=-1;c<=1;c++)
186      {
187       if(c!=0)
188       {
189        off=((i+d3_l->max_x+c)%d3_l->max_x)+j*d3_l->max_x+k*d3_l->max_x*d3_l->max_y;
190        carry=0;
191        if(!(*(d3_l->status+off)&AMORPH)) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
192        if(carry!=0)
193        {
194         *(d3_l->extra+offset)+=carry;
195         *(d3_l->extra+off)-=carry;
196        }
197       }
198      }
199      for(c=-1;c<=1;c++)
200      {
201       if(c!=0)
202       {
203        off=i+((j+c+d3_l->max_y)%d3_l->max_y)*d3_l->max_x+k*d3_l->max_x*d3_l->max_y;
204        carry=0;
205        if(!(*(d3_l->status+off)&AMORPH)) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
206        if(carry!=0)
207        {
208         *(d3_l->extra+offset)+=carry; 
209         *(d3_l->extra+off)-=carry; 
210        }
211       }
212      }
213      /* diff in z direction */
214      if(k!=0)
215      {
216       off=i+j*d3_l->max_x+(k-1)*d3_l->max_x*d3_l->max_y;
217       carry=0;
218       if(!*(d3_l->status+off)&AMORPH) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
219       if(carry!=0)
220       {
221        *(d3_l->extra+off)-=carry;
222        *(d3_l->extra+offset)+=carry;
223       }
224      }
225      if(k!=d3_l->max_z-1)
226      {
227       off=i+j*d3_l->max_x+(k+1)*d3_l->max_x*d3_l->max_y;
228       carry=0;
229       if(!*(d3_l->status+off)&AMORPH) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
230       if(carry!=0)
231       {
232        *(d3_l->extra+off)-=carry;
233        *(d3_l->extra+offset)+=carry;
234       }
235      }
236     }
237    } /* for z */
238   } /* for y */
239  } /* for x */
240
241  } /* if step modulo diff_rate == 0 */
242
243  return 1;
244 }
245
246 u32 get_reject_graph(info *my_info,d3_lattice *d3_l,char *file,u32 *graph) {
247  double a,b;
248  int i,j,k;
249  int fd;
250  char buf[32],*p;
251  unsigned char *flag;
252  u32 max;
253
254  max=0;
255  if((fd=open(file,O_RDONLY))<0)
256  {
257   puts("cannot open file to calculate rejection graph");
258   return -1;
259  }
260  if((flag=(unsigned char *)malloc(d3_l->max_z))==NULL)
261  {
262   puts("cannot malloc flag memory for rejection graph");
263   return -1;
264  }
265  memset(flag,0,d3_l->max_z);
266  memset(graph,0,d3_l->max_z*sizeof(u32));
267  /* get fixpoints */
268  k=1;
269  while(k)
270  {
271   for(i=0;i<32;i++)
272   {
273    k=read(fd,&buf[i],1);
274    if((buf[i]=='\n')||(k==0)) break;
275   }
276   if(k)
277   {
278    p=strtok(buf," ");
279    a=atof(p)/10; /* nm */
280    p=strtok(NULL," ");
281    b=atof(p);
282    if(a>d3_l->max_z*CELL_LENGTH) k=0;
283    else 
284    {
285     graph[(int)(a/CELL_LENGTH)]=(int)(URAND_MAX/100*b);
286     flag[(int)(a/CELL_LENGTH)]=1;
287    }
288   }
289  }
290  /* do (linear) interpolation here! */
291  i=0;
292  a=0;
293  while(i<d3_l->max_z)
294  {
295   /* graph[0] is 0! */
296   j=i;
297   i++;
298   while(flag[i]==0&&i<d3_l->max_z) i++;
299   for(k=j+1;k<i;k++) graph[k]=(int)((k-j)*((int)graph[i]-(int)graph[j])/(i-j))+graph[j];
300   if(graph[i]>max) max=graph[i];
301  }
302
303  free(flag);
304
305 #ifdef DEBUG_INTERPOL_PROFILE
306  printf("debug: %s (interpolated profile)\n",file);
307  for(i=0;i<d3_l->max_z;i++) printf("%d %d\n",i,graph[i]);
308 #endif
309
310  return max;
311 }
312
313 void send_data(int signum) {
314
315   int c;
316   unsigned char ack=DATA_OK;
317
318   c=gd3_l->max_x*gd3_l->max_y*gd3_l->max_z;
319
320   network_send_chan(gnet,0,&dc,1);
321   network_send_chan(gnet,0,(unsigned char *)gd3_l,sizeof(d3_lattice));
322   network_send_chan(gnet,0,(unsigned char *)gmy_info,sizeof(info));
323   network_send_chan(gnet,0,gd3_l->status,c*sizeof(unsigned char));
324   network_send_chan(gnet,0,(unsigned char *)gd3_l->extra,c*sizeof(int));
325   network_send_chan(gnet,0,(unsigned char *)gi,sizeof(int));
326   network_send_chan(gnet,0,&ack,sizeof(unsigned char));
327
328   if(dc==DC_QUIT) shut_down=1;
329 }
330
331
332 /*
333  * main program
334  */
335
336 int main(int argc,char **argv)
337 {
338
339   char server_ip[16];
340   int port;
341   t_net net;
342   t_event event;
343   unsigned char data[256];
344   int i;
345
346   gnet=&net;
347
348   /* default values */
349   strcpy(server_ip,"137.250.82.105");
350   strcpy(p_file,IMP_PROFILE);
351   strcpy(n_e_file,NEL_PROFILE);
352   strcpy(r_file,"");
353   strcpy(s_file,"");
354   start_fd=0;
355   port=1025;
356
357   /* parse/check argv */
358   for(i=1;i<argc;i++) {
359     if(argv[i][0]=='-') {
360       switch(argv[i][1]) {
361         case 'h':
362           usage(argv[0]);
363           return -1;
364         case 'i':
365           strncpy(server_ip,argv[++i],16);
366           break;
367         case 'r':
368           strcpy(r_file,argv[++i]);
369           break;
370         case 'P':
371           strcpy(p_file,argv[++i]);
372           break;
373         case 'n':
374           strcpy(n_e_file,argv[++i]);
375           break;
376         case 'p':
377           port=atoi(argv[++i]);
378           break;
379         case 's':
380           strcpy(s_file,argv[++i]);
381           break;
382         default:
383           usage(argv[0]);
384           return -1;
385       }
386     }
387   }
388   if(!strcmp(server_ip,"")) {
389     usage(argv[0]);
390     return -1;
391   }
392
393   /* try a file to start from */
394   if(strcmp(s_file,"")) {
395     start_fd=open(s_file,O_RDONLY);
396     if(start_fd>0) printf("using %s as a starting file ...\n",s_file);
397     else printf("errors opening %s!\n",s_file);
398   }
399
400   /* event init */
401   event_init(&event,1);
402   event_set_timeout(&event,0,0);
403
404   /* connect to server */
405   network_init(&net,1);
406   network_set_connection_info(&net,0,server_ip,port);
407   if(network_connect(&net,0)==N_E_CONNECT) {
408     printf("unable to connect to server, aborting ...\n");
409     return -1;
410   }
411   network_select(&net,0);
412
413   /* tell server: i am a client, i may work for you */
414   data[0]=NLSOP_CLIENT;
415   network_send(net.connection[0].fd,data,1);
416
417   /* wait for job */
418   event_math(net.connection[0].fd,&event,READ,ADD);
419   printf("idle, waiting for jobs ...\n");
420   event_start(&event,NULL,get_data_and_calc,nop);
421
422   network_shutdown(&net);
423   if(start_fd>0) close(start_fd);
424
425   return 1;
426 }
427
428 int nop(t_event *event,void *allineed) {
429
430   printf("\ni did a nop :)\n");
431
432   return 1;
433 }
434
435 int get_data_and_calc(t_event *event,void *allineed) {
436
437   d3_lattice d3_l;
438   info my_info;
439   u32 *c_profile;
440   u32 *n_e_loss;
441   u32 ne_max,ip_max;
442   u32 *nel_z;
443   u32 x_c,y_c,z_c;
444   int i,j;
445   int c_step;
446   unsigned char do_sputter;
447   unsigned char data;
448
449   t_net *net;
450
451   c_step=0;
452   ne_max=0;
453   ip_max=0;
454   do_sputter=1;
455
456   net=gnet;
457   gd3_l=&d3_l;
458   gmy_info=&my_info;
459   gi=&i;
460   dc=0;
461   shut_down=0;
462
463   printf("got a new job ...\n");
464   
465   /* get info (+data) */
466   network_receive(net->connection[0].fd,&data,sizeof(unsigned char));
467   if(data==NLSOP_NJOB || data==NLSOP_CJOB) {
468     network_receive(net->connection[0].fd,(unsigned char *)&d3_l,
469                     sizeof(d3_lattice));
470     network_receive(net->connection[0].fd,(unsigned char *)&my_info,
471                     sizeof(info));
472     c_step=0;
473     j=d3_l.max_x*d3_l.max_y*d3_l.max_z;
474     d3_l.status=(unsigned char *)malloc(j*sizeof(unsigned char));
475     if(d3_l.status==NULL) {
476       printf("status alloc failed\n");
477       return -1;
478     }
479     d3_l.extra=(int *)malloc(j*sizeof(int));
480     if(d3_l.extra==NULL) {
481       printf("extra malloc failed\n");
482       return -1;
483     }
484     if(data==NLSOP_CJOB) {
485       data=DATA_OK;
486       network_receive(net->connection[0].fd,d3_l.status,
487                       j*sizeof(unsigned char));
488       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
489       network_receive(net->connection[0].fd,(unsigned char *)d3_l.extra,
490                       j*sizeof(int));
491       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
492       network_receive(net->connection[0].fd,(unsigned char *)&c_step,
493                       sizeof(int));
494       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
495     }
496     if(c_step==0) {
497       printf("important: clear status/conc data!\n");
498       memset(d3_l.status,0,j*sizeof(unsigned char));
499       memset(d3_l.extra,0,j*sizeof(int));
500     }
501     /* check for file to start from ... */
502     if(start_fd>0) {
503       printf("starting from a save file!\n");
504       unsigned char *nullbuf;
505       nullbuf=(unsigned char *)malloc(sizeof(d3_lattice));
506       if(read(start_fd,nullbuf,sizeof(d3_lattice))!=sizeof(d3_lattice)) {
507         printf("read failed (start file d3l)\n");
508         return -1;
509       }
510       free(nullbuf);
511       nullbuf=(unsigned char *)malloc(sizeof(info));
512       if(read(start_fd,nullbuf,sizeof(info))!=sizeof(info)) {
513         printf("read failed (start file info)\n");
514         return -1;
515       }
516       free(nullbuf);
517       if(read(start_fd,d3_l.status,j*sizeof(unsigned char))!=j*sizeof(unsigned char)) {
518         printf("read failed (start file status)\n");
519         return -1;
520       }
521       if(read(start_fd,d3_l.extra,j*sizeof(int))!=j*sizeof(int)) {
522         printf("read failed (start file extra)\n");
523         return -1;
524       }
525     }
526   }
527   else {
528     printf("unknown instruction, restarting ...\n");
529     return -1;
530   }
531
532   printf("starting simulation with following parameters:\n");
533   printf("b = %f | c = %f | s = %f\n",my_info.b,my_info.c,my_info.s);
534   printf("diff every %d steps | diff rate = %f\n",my_info.diff_rate,
535                                                   my_info.dr_ac);
536   printf("current step: %d | total steps: %d\n",c_step,my_info.steps);
537   printf("...\n");
538
539   /* care for signals */
540   dc=DC_QUIT;
541   signal(SIGTERM,send_data);
542
543   /* rand init */
544   if(!strcmp(r_file,"")) rand_init(NULL);
545   else rand_init(r_file);
546
547   /* compute graphs for random number rejection method */
548   if((c_profile=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int)))==NULL) {
549     puts("failed allocating memory for carbon profile graph");
550     return -1;
551   }
552   if((n_e_loss=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int)))==NULL) {
553     puts("failed allocating memory for nuclear energy loss graph");
554     return -1;
555   }
556   ip_max=get_reject_graph(&my_info,&d3_l,p_file,c_profile);
557   ne_max=get_reject_graph(&my_info,&d3_l,n_e_file,n_e_loss);
558
559   /* array nel_z[] keeping nuclear energy loss values scaled to URAND_MAX */
560   nel_z=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int));
561   if(nel_z==NULL) {
562     printf("failed allocating nel_z array mem\n");
563     return -1;
564   }
565   for(i=0;i<d3_l.max_z;i++) nel_z[i]=URAND_MAX*(1.0*n_e_loss[i]/ne_max);
566
567   /* this should be obsolete - z is high enough - we check now! */
568   if(c_profile[d3_l.max_z-1]!=0) {
569     printf("max_z (%d) too small - sputtering not possible\n",d3_l.max_z);
570     do_sputter=0;
571   }
572
573   /* sputtering really possible ?*/
574   if(n_e_loss[d3_l.max_z-1]!=0)
575     printf("warning: max_z (%d) too small, there may be amorphous volumes\n",
576            d3_l.max_z);
577
578   /*
579    * start of simulation
580    */
581
582   i=(c_step?c_step:0);
583   while(i<my_info.steps) {
584     for(j=0;j<my_info.cpi;j++) {
585       x_c=get_rand(d3_l.max_x);
586       y_c=get_rand(d3_l.max_y);
587       z_c=get_rand_reject(d3_l.max_z,ne_max,n_e_loss);
588       //z_c=get_rand(d3_l.max_z);
589       process_cell(&d3_l,x_c,y_c,z_c,&my_info,nel_z[z_c]);
590     }
591     distrib_c(&d3_l,&my_info,i,ip_max,c_profile);
592     i++;
593     if(i%my_info.save_rate==0) {
594       dc=DC_OK;
595       send_data(0);
596       dc=DC_QUIT;
597     }
598     if((do_sputter)&(i%my_info.s_rate==0)) sputter(&d3_l);
599     if(shut_down) {
600       free(d3_l.status);
601       free(d3_l.extra);
602       free(c_profile);
603       free(n_e_loss);
604       free(nel_z);
605       event_stop(event); 
606     }
607   }
608
609   /* finished */
610   dc=DC_END;
611   send_data(0);
612   dc=DC_QUIT;
613
614   /* shutdown/free/close everything now ... */
615   free(d3_l.status);
616   free(d3_l.extra);
617   free(c_profile);
618   free(n_e_loss);
619   free(nel_z);
620
621   return 1;
622 }