cleaner shutdown (*g* .. still segfaulting) if SIGTERM
[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 t_net *gnet;
63 d3_lattice *gd3_l;
64 info *gmy_info;
65 int *gi;
66 unsigned char dc;
67 unsigned char shut_down;
68
69 int get_data_and_calc(t_event *event,void *allineed);
70 int nop(t_event *event,void *allineed);
71
72 int usage(char *prog)
73 {
74  puts("usage:");
75  printf("%s -i ip -p port -r/P/n random/profile/neloss file\n",prog);
76  return 1;
77 }
78
79 /*
80  * nlsop internal functions
81  */
82
83 int sputter(d3_lattice *d3_l)
84 {
85  int i,size;
86  int offh,offl;
87
88  size=d3_l->max_x*d3_l->max_y;
89  offl=0;
90  offh=size;
91
92  for(i=0;i<d3_l->max_z-1;i++)
93  {
94   memcpy(d3_l->status+offl,d3_l->status+offh,size);
95   memcpy(d3_l->extra+offl,d3_l->extra+offh,size*sizeof(int));
96   offl=offh;
97   offh+=size;
98  }
99  memset(d3_l->status+offl,0,size);
100  memset(d3_l->extra+offl,0,size);
101
102  return 1;
103 }
104
105 int process_cell(d3_lattice *d3_l,u32 x,u32 y,u32 z,info *my_info,u32 nel_z)
106 {
107  unsigned char *thiz;
108  int *conc;
109  int i,j;
110  int off;
111  double p,q;
112
113  thiz=d3_l->status+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y;
114  conc=d3_l->extra+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y;
115  //p=my_info->b*nel_z; // energieuebertrag prop zu nukl. bk
116  p=my_info->b*URAND_MAX; // konstanter energieuebertrag
117  for(i=-(my_info->range);i<=my_info->range;i++)
118  {
119   for(j=-(my_info->range);j<=my_info->range;j++)
120   {
121    if(!(i==0 && j==0))
122    {
123     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;
124     if(*(d3_l->status+off)&AMORPH) p+=my_info->s*(*(d3_l->extra+off))*URAND_MAX/(i*i+j*j);
125    } 
126   }
127  }
128  p+=*conc*my_info->c*URAND_MAX;
129  if(p>=URAND_MAX) MAKE_AMORPH(thiz);
130  else {
131   if(!(*thiz&AMORPH)) {
132    if(get_rand(URAND_MAX)<=p) MAKE_AMORPH(thiz);
133   }
134   else {
135    /* assume 1-p probability */
136    /* also look for neighbours ! */
137    q=(URAND_MAX-p)>0?URAND_MAX-p:0;
138    j=0;
139    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;
140    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;
141    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;
142    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;
143    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;
144    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;
145  
146    p+=((q/6)*j);
147    if(p<=URAND_MAX) {
148     if(get_rand(URAND_MAX)>p) MAKE_CRYST(thiz);
149    }
150   }
151  }
152  
153  return 1;
154 }
155
156 int distrib_c(d3_lattice *d3_l,info *my_info,int step,u32 rj_m,u32 *rj_g)
157 {
158  u32 x,y,z;
159  int i,j,k,c;
160  int offset,off;
161  int carry;
162
163  /* put one c ion somewhere in the lattice */
164  x=get_rand(d3_l->max_x);
165  y=get_rand(d3_l->max_y);
166  z=get_rand_reject(d3_l->max_z,rj_m,rj_g);
167  *(d3_l->extra+x+y*d3_l->max_x+z*d3_l->max_x*d3_l->max_y)+=1;
168  (my_info->cc)++;
169
170  if(step%my_info->diff_rate==0)
171  {
172
173  for(i=0;i<d3_l->max_x;i++)
174  {
175   for(j=0;j<d3_l->max_y;j++)
176   {
177    for(k=0;k<d3_l->max_z;k++)
178    {
179     offset=i+j*d3_l->max_x+k*d3_l->max_x*d3_l->max_y;
180     /* case amorph: amorph <- cryst diffusion */
181     if(*(d3_l->status+offset)&AMORPH)
182     {
183      for(c=-1;c<=1;c++)
184      {
185       if(c!=0)
186       {
187        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;
188        carry=0;
189        if(!(*(d3_l->status+off)&AMORPH)) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
190        if(carry!=0)
191        {
192         *(d3_l->extra+offset)+=carry;
193         *(d3_l->extra+off)-=carry;
194        }
195       }
196      }
197      for(c=-1;c<=1;c++)
198      {
199       if(c!=0)
200       {
201        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;
202        carry=0;
203        if(!(*(d3_l->status+off)&AMORPH)) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
204        if(carry!=0)
205        {
206         *(d3_l->extra+offset)+=carry; 
207         *(d3_l->extra+off)-=carry; 
208        }
209       }
210      }
211      /* diff in z direction */
212      if(k!=0)
213      {
214       off=i+j*d3_l->max_x+(k-1)*d3_l->max_x*d3_l->max_y;
215       carry=0;
216       if(!*(d3_l->status+off)&AMORPH) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
217       if(carry!=0)
218       {
219        *(d3_l->extra+off)-=carry;
220        *(d3_l->extra+offset)+=carry;
221       }
222      }
223      if(k!=d3_l->max_z-1)
224      {
225       off=i+j*d3_l->max_x+(k+1)*d3_l->max_x*d3_l->max_y;
226       carry=0;
227       if(!*(d3_l->status+off)&AMORPH) carry=(int)(my_info->dr_ac*(*(d3_l->extra+off)));
228       if(carry!=0)
229       {
230        *(d3_l->extra+off)-=carry;
231        *(d3_l->extra+offset)+=carry;
232       }
233      }
234     }
235    } /* for z */
236   } /* for y */
237  } /* for x */
238
239  } /* if step modulo diff_rate == 0 */
240
241  return 1;
242 }
243
244 u32 get_reject_graph(info *my_info,d3_lattice *d3_l,char *file,u32 *graph) {
245  double a,b;
246  int i,j,k;
247  int fd;
248  char buf[32],*p;
249  unsigned char *flag;
250  u32 max;
251
252  max=0;
253  if((fd=open(file,O_RDONLY))<0)
254  {
255   puts("cannot open file to calculate rejection graph");
256   return -1;
257  }
258  if((flag=(unsigned char *)malloc(d3_l->max_z))==NULL)
259  {
260   puts("cannot malloc flag memory for rejection graph");
261   return -1;
262  }
263  memset(flag,0,d3_l->max_z);
264  memset(graph,0,d3_l->max_z*sizeof(u32));
265  /* get fixpoints */
266  k=1;
267  while(k)
268  {
269   for(i=0;i<32;i++)
270   {
271    k=read(fd,&buf[i],1);
272    if((buf[i]=='\n')||(k==0)) break;
273   }
274   if(k)
275   {
276    p=strtok(buf," ");
277    a=atof(p)/10; /* nm */
278    p=strtok(NULL," ");
279    b=atof(p);
280    if(a>d3_l->max_z*CELL_LENGTH) k=0;
281    else 
282    {
283     graph[(int)(a/CELL_LENGTH)]=(int)(URAND_MAX/100*b);
284     flag[(int)(a/CELL_LENGTH)]=1;
285    }
286   }
287  }
288  /* do (linear) interpolation here! */
289  i=0;
290  a=0;
291  while(i<d3_l->max_z)
292  {
293   /* graph[0] is 0! */
294   j=i;
295   i++;
296   while(flag[i]==0&&i<d3_l->max_z) i++;
297   for(k=j+1;k<i;k++) graph[k]=(int)((k-j)*((int)graph[i]-(int)graph[j])/(i-j))+graph[j];
298   if(graph[i]>max) max=graph[i];
299  }
300
301  free(flag);
302
303 #ifdef DEBUG_INTERPOL_PROFILE
304  printf("debug: %s (interpolated profile)\n",file);
305  for(i=0;i<d3_l->max_z;i++) printf("%d %d\n",i,graph[i]);
306 #endif
307
308  return max;
309 }
310
311 void send_data(int signum) {
312
313   int c;
314
315   c=gd3_l->max_x*gd3_l->max_y*gd3_l->max_z;
316
317   network_send_chan(gnet,0,&dc,1);
318   network_send_chan(gnet,0,(unsigned char *)gd3_l,sizeof(d3_lattice));
319   network_send_chan(gnet,0,(unsigned char *)gmy_info,sizeof(info));
320   network_send_chan(gnet,0,gd3_l->status,c*sizeof(unsigned char));
321   network_send_chan(gnet,0,(unsigned char *)gd3_l->extra,c*sizeof(int));
322   network_send_chan(gnet,0,(unsigned char *)gi,sizeof(int));
323
324   if(dc==DC_QUIT) shut_down=1;
325 }
326
327
328 /*
329  * main program
330  */
331
332 int main(int argc,char **argv)
333 {
334
335   char server_ip[16];
336   int port;
337   t_net net;
338   t_event event;
339   unsigned char data[256];
340   int i;
341
342   gnet=&net;
343
344   /* default values */
345   strcpy(server_ip,"137.250.82.105");
346   strcpy(p_file,IMP_PROFILE);
347   strcpy(n_e_file,NEL_PROFILE);
348   strcpy(r_file,"");
349   port=1025;
350
351   /* parse/check argv */
352   for(i=1;i<argc;i++) {
353     if(argv[i][0]=='-') {
354       switch(argv[i][1]) {
355         case 'h':
356           usage(argv[0]);
357           return -1;
358         case 'i':
359           strncpy(server_ip,argv[++i],16);
360           break;
361         case 'r':
362           strcpy(r_file,argv[++i]);
363           break;
364         case 'P':
365           strcpy(p_file,argv[++i]);
366           break;
367         case 'n':
368           strcpy(n_e_file,argv[++i]);
369           break;
370         case 'p':
371           port=atoi(argv[++i]);
372           break;
373         default:
374           usage(argv[0]);
375           return -1;
376       }
377     }
378   }
379   if(!strcmp(server_ip,"")) {
380     usage(argv[0]);
381     return -1;
382   }
383
384   /* event init */
385   event_init(&event,1);
386   event_set_timeout(&event,0,0);
387
388   /* connect to server */
389   network_init(&net,1);
390   network_set_connection_info(&net,0,server_ip,port);
391   if(network_connect(&net,0)==N_E_CONNECT) {
392     printf("unable to connect to server, aborting ...\n");
393     return -1;
394   }
395   network_select(&net,0);
396
397   /* tell server: i am a client, i may work for you */
398   data[0]=NLSOP_CLIENT;
399   network_send(net.connection[0].fd,data,1);
400
401   /* wait for job */
402   event_math(net.connection[0].fd,&event,READ,ADD);
403   printf("idle, waiting for jobs ...\n");
404   event_start(&event,NULL,get_data_and_calc,nop);
405
406   network_shutdown(&net);
407
408   return 1;
409 }
410
411 int nop(t_event *event,void *allineed) {
412
413   printf("\ni did a nop :)\n");
414
415   return 1;
416 }
417
418 int get_data_and_calc(t_event *event,void *allineed) {
419
420   d3_lattice d3_l;
421   info my_info;
422   u32 *c_profile;
423   u32 *n_e_loss;
424   u32 ne_max,ip_max;
425   u32 *nel_z;
426   u32 x_c,y_c,z_c;
427   int i,j;
428   int c_step;
429   unsigned char data;
430
431   t_net *net;
432
433   c_step=0;
434   ne_max=0;
435   ip_max=0;
436
437   net=gnet;
438   gd3_l=&d3_l;
439   gmy_info=&my_info;
440   gi=&i;
441   dc=0;
442   shut_down=0;
443
444   printf("got a new job ...\n");
445   
446   /* get info (+data) */
447   network_receive(net->connection[0].fd,&data,sizeof(unsigned char));
448   if(data==NLSOP_NJOB || data==NLSOP_CJOB) {
449     network_receive(net->connection[0].fd,(unsigned char *)&d3_l,
450                     sizeof(d3_lattice));
451     network_receive(net->connection[0].fd,(unsigned char *)&my_info,
452                     sizeof(info));
453     c_step=0;
454     j=d3_l.max_x*d3_l.max_y*d3_l.max_z;
455     d3_l.status=(unsigned char *)malloc(j*sizeof(unsigned char));
456     if(d3_l.status==NULL) {
457       printf("status alloc failed\n");
458       return -1;
459     }
460     d3_l.extra=(int *)malloc(j*sizeof(int));
461     if(d3_l.extra==NULL) {
462       printf("extra malloc failed\n");
463       return -1;
464     }
465     if(data==NLSOP_CJOB) {
466       data=DATA_OK;
467       network_receive(net->connection[0].fd,d3_l.status,
468                       j*sizeof(unsigned char));
469       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
470       network_receive(net->connection[0].fd,(unsigned char *)d3_l.extra,
471                       j*sizeof(int));
472       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
473       network_receive(net->connection[0].fd,(unsigned char *)&c_step,
474                       sizeof(int));
475       network_send(net->connection[0].fd,&data,sizeof(unsigned char));
476     }
477   }
478   else {
479     printf("unknown instruction, restarting ...\n");
480     return -1;
481   }
482
483   printf("starting simulation with following parameters:\n");
484   printf("b = %f | c = %f | s = %f\n",my_info.b,my_info.c,my_info.s);
485   printf("diff every %d steps | diff rate = %f\n",my_info.diff_rate,
486                                                   my_info.dr_ac);
487   printf("current step: %d | total steps: %d\n",c_step,my_info.steps);
488   printf("...\n");
489
490   /* care for signals */
491   dc=DC_QUIT;
492   signal(SIGTERM,send_data);
493
494   /* rand init */
495   if(!strcmp(r_file,"")) rand_init(NULL);
496   else rand_init(r_file);
497
498   /* compute graphs for random number rejection method */
499   if((c_profile=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int)))==NULL) {
500     puts("failed allocating memory for carbon profile graph");
501     return -1;
502   }
503   if((n_e_loss=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int)))==NULL) {
504     puts("failed allocating memory for nuclear energy loss graph");
505     return -1;
506   }
507   ip_max=get_reject_graph(&my_info,&d3_l,p_file,c_profile);
508   ne_max=get_reject_graph(&my_info,&d3_l,n_e_file,n_e_loss);
509
510   /* array nel_z[] keeping nuclear energy loss values scaled to URAND_MAX */
511   nel_z=(u32 *)malloc(d3_l.max_z*sizeof(unsigned int));
512   if(nel_z==NULL) {
513     printf("failed allocating nel_z array mem\n");
514     return -1;
515   }
516   for(i=0;i<d3_l.max_z;i++) nel_z[i]=URAND_MAX*(1.0*n_e_loss[i]/ne_max);
517
518   /* this should be obsolete - z is high enough - we check now! */
519   if(c_profile[d3_l.max_z-1]!=0) {
520     printf("max_z (%d) too small - sputtering not possible\n",d3_l.max_z);
521     return -1;
522   }
523
524   /* sputtering really possible ?*/
525   if(n_e_loss[d3_l.max_z-1]!=0)
526     printf("warning: max_z (%d) too small, there may be amorphous volumes\n",
527            d3_l.max_z);
528
529   /*
530    * start of simulation
531    */
532
533   i=(c_step?c_step:0);
534   while(i<my_info.steps) {
535     for(j=0;j<my_info.cpi;j++) {
536       x_c=get_rand(d3_l.max_x);
537       y_c=get_rand(d3_l.max_y);
538       z_c=get_rand_reject(d3_l.max_z,ne_max,n_e_loss);
539       //z_c=get_rand(d3_l.max_z);
540       process_cell(&d3_l,x_c,y_c,z_c,&my_info,nel_z[z_c]);
541     }
542     distrib_c(&d3_l,&my_info,i,ip_max,c_profile);
543     i++;
544     if(i%my_info.save_rate==0) {
545       dc=DC_OK;
546       send_data(0);
547       dc=DC_QUIT;
548     }
549     if(i%my_info.s_rate==0) sputter(&d3_l);
550     if(shut_down) {
551       free(d3_l.status);
552       free(d3_l.extra);
553       free(c_profile);
554       free(n_e_loss);
555       free(nel_z);
556       event_stop(event); 
557     }
558   }
559
560   /* finished */
561   dc=DC_END;
562   send_data(0);
563   dc=DC_QUIT;
564
565   /* shutdown/free/close everything now ... */
566   free(d3_l.status);
567   free(d3_l.extra);
568   free(c_profile);
569   free(n_e_loss);
570   free(nel_z);
571
572   return 1;
573 }