B.1. Simulationsprogramme zur Kontrastinversion
An dieser Stelle ist das im Rahmen dieser Diplomarbeit erstellte Programm zur
Simulation der Kontrastinversion mit und ohne Abschattungseffekt aufgelistet. Es
wird das hexagonale harmonische Potential, das in Anhang D abgebildet ist,
verwendet. Bei den Programmen zu den anderen Simulationen, insbesondere dem
Programm zur Verdeutlichung der abgeschatteten Bereiche, handelt es sich um
Modifikationen auf der Basis des folgenden Programms, die aus Platzgründen nicht
im einzelnen abgedruckt werden.
Die folgende Datei enthält einige Definitionen und Funktionsprototypen.
/* sim.h
Author: Peter Münster, 1996
Kopf für alle Module
*/
#if !defined( __SIM__ )
#define __SIM__
// #include <curses.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "/home/peter/c/mystd.h"
#include <math.h>
/*
#pragma warn -pia
#pragma warn -rvl
*/
typedef unsigned unsgnd;
typedef struct proc
{
pid_t pid;
char name[DAT_NAME_MAX];
}
proc_struct;
typedef struct info
{
char doc[DAT_NAME_MAX]; // Info-String
// char dir[DAT_NAME_MAX]; // current working directory
doub phi; // "Barrierenhöhe"
doub cut; // Abbruchkriterium
doub ant; /* Anteil der nichtabgeschatteten Punkte im
letzten Kreisring */
int rmax; // maximaler Radius für Abschattung in Pixeln
doub scal; // Skalierungsfaktor = Pixel pro Ångstrøm
int dim; // Breite = Höhe in Pixeln
doub c[2]; // Gitterkonstante und Korrugation in Ångstrøm
doub d0; // Abstand in Ångstrøm
doub dd0; // Schrittweite
doub d0max; // maximaler Abstand in Ångstrøm
int flag; // Schalter: 0=normal, 1=genau0, 2=genau1
}
info_struct;
#define MAX(x,y) ((x)>(y)?(x):(y))
// 3 nützliche Makros falls curses benutzt wird
#define pf1(x,y) printf(x,y);fflush(NULL)
#define pf2(x,y,z) printf(x,y,z);fflush(NULL)
#define mywrite(x) write(1, x, strlen(x))
// lese Zeichen mit oder ohne Echo
int getche(void); // in simhilf.c
int getchne(void); // in simhilf.c
// von Max
void schreibedim(int dim, FILE *ausdp); // in simhilf.c
// gibt max bzw. min aus Array zurück
doub maximum(doub *val, int j); // in simhilf.c
doub minimum(doub *val, int j); // in simhilf.c
// weil in math.h kein round ist:
doub round(doub x); // in simhilf.c
/*liest globale Info-Struktur aus datei,
oder schreibt sie in datei */
int ladeinf(char *datei, char *mode,
size_t (*func)(void *ptr,
size_t size,
size_t nmemb,
FILE *stream)); // in siminfo.c
// zeigt Info-Struktur an
int zeigeinfo(char *datei); // in siminfo.c
// rechnet und erzeugt die Ausgabedateien
void rechne(char *kontrastfile); // in simcalc.c
// kleine Hilfsfunktion für die Eingabe
void my_doub_scan(char *s, doub *d_ptr); // in siminput.c
// Eingabe der Info-Struktur per Hand
int eingabe(void); // in siminput.c
// noch zu erledigen
int ausgabe(char *datei); // in simoutput.c
// durchrechnen von Serien
void serie(proc_struct **pr_ptr, int *cnt); // in simserie.c
// Hilfsfunktion für serie
void serienfunc(char *str); // in simserie.c
#endif
Das anschließende C-Modul enthält die Hauptfunktion main, in der bereits
zusätzlich einige Menüpunkte wie etwa bestimmte Ausgaberoutinen vorgesehen
sind, die jedoch nicht mehr implementiert wurden.
Weitere Eigenschaften sind
- die Möglichkeit, Rechnungen im Hintergrund laufen zu lassen,
- automatische Wiederaufnahme der Rechnung nach einem
Systemneustart,
- Eingabe über Kommandozeilenargumente oder interaktiv und
- Speicherung von Vorgabewerten.
/* simmain.c
Author: Peter Münster, 1996
Hauptmodul für die Simmulation des Tunnelstromes beim STM
*/
#include "sim.h"
#include <signal.h>
#if DEBUG
#define FORK_UND_RECHNE(xxx) /* nur Textersatz */ \
fork_ret=fork(); /* wird für wait gespeichert */\
switch(fork_ret){ \
case -1: \
FPF("fork-Aufruf in main %s", "ohne Erfolg!\n");\
break; \
case 0: \
exit(0); /* ohne Interesse für’s Debuggen */\
forkcount++; /* Prozeßinfos abspeichern: */ \
proc_ptr=(proc_struct *)realloc(proc_ptr,\
sizeof(proc_struct)*forkcount); \
proc_ptr[forkcount-1].pid=fork_ret; \
strncpy(proc_ptr[forkcount-1].name,\
xxx, DAT_NAME_MAX); \
proc_ptr[forkcount-1].name[DAT_NAME_MAX-1]=’\0’;\
default: \
rechne(""); /* rechne = Vaterprozeß */ \
exit(0); \
}
#else
#define FORK_UND_RECHNE(xxx) /* nur Textersatz */ \
fork_ret=fork(); /* wird für wait gespeichert */\
switch(fork_ret){ \
case -1: \
FPF("fork-Aufruf in main %s", "ohne Erfolg!\n");\
break; \
case 0: \
rechne(""); \
exit(0); \
default: \
forkcount++; /* Prozeßinfos abspeichern: */ \
proc_ptr=(proc_struct *)realloc(proc_ptr,\
sizeof(proc_struct)*forkcount); \
proc_ptr[forkcount-1].pid=fork_ret; \
strncpy(proc_ptr[forkcount-1].name,\
xxx, DAT_NAME_MAX); \
proc_ptr[forkcount-1].name[DAT_NAME_MAX-1]=’\0’;\
}
#endif
char progname[DAT_NAME_MAX];
extern info_struct inf;
void finish(int sig){
char str[DAT_NAME_MAX];
sprintf(str, ".simrc.%2.0lf", inf.cut);
ladeinf(str, "w", fwrite);
sleep(3);
#if ABSCHATTUNG
sprintf(str,
"echo nice %s .simrc.%2.0lf|at now+2hours 2>/dev/null",
"/home/peter/bin/simma", inf.cut);
#else
sprintf(str,
"echo nice %s .simrc.%2.0lf|at now+2hours 2>/dev/null",
"/home/peter/bin/simoa", inf.cut);
#endif
system(str);
#if DEBUG
FPF("finish: erhielt Signal Nummer %d!\n", sig);
#endif
exit(0);
}
int main(int argc, char **argv) {
int i, c=1, forkcount=0;
pid_t fork_ret;
char str[DAT_NAME_MAX];
FILE *fp; /* in proc_struct werden Prozeßinfos
gespeichert */
proc_struct *proc_ptr=(proc_struct *)
malloc(sizeof(proc_struct));
signal(SIGTERM, finish); // für die Automatik
strncpy(progname, argv[0], DAT_NAME_MAX-1); /* progname ist
global!
(für Fehlermeldungen) */
ladeinf(".simrc", "r", fread); /* inf-Struktur laden
(enthält
Probeninformationen) */
if(argc==2){ // falls ein Parameter, gehe auf Automatik!
ladeinf(argv[1], "r", fread);
for(; inf.d0<inf.d0max; inf.d0+=inf.dd0)
rechne("");
ladeinf(argv[1], "w", fwrite);
return 0;
}
#if CURSES
initscr(); /* initialize the curses library */
nocbreak(); /* take input chars one at a time,
no wait for \n */
echo();
#endif
if(argc>2){ // falls mehrere Parameter, kein In- und Output
while(--argc){
if(ladeinf(argv[argc], "r", fread)) /* lädt die
inf-Struktur */
continue; // Fehler!
FORK_UND_RECHNE(argv[argc]);
}
return 0; /* Programmende, auf Sohnprozesse
wird NICHT gewartet */
}
// system("clear"); // Clear-Home
pf1("\t\t\tSTM-Simulation\n%s",
"\t\t\t--------------\n\n"); // pf1: in sim.h
mywrite(
"Dateien werden in im Arbeitsverzeichnis gesucht!\n\n");
ladeinf(".simrc", "r", fread); /* inf-Struktur laden
(enthält Probeninformationen) */
while (c) {
switch (c) {
case 1:
while(c){
mywrite("\n Eingabe\n");
mywrite( " ---------\n\n");
mywrite(" 0.) Keine\n");
mywrite(" 1.) Per Hand\n");
mywrite(" 2.) Aus Datei laden\n");
mywrite(" 3.) Serie\n\n ? ");
scanf("%d", &c);
getchar(); /* das Returnzeichen bleibt
sonst im Puffer */
switch(c){
case 1:
if(!eingabe()){ /* lädt die inf-Struktur
neu (0 bei Erfolg) */
pf1(
"\nAls %s.inf im Verzeichnis daten speichern? (j/n)",
inf.doc);
scanf("%c", str); // "Mißbrauch" von str
if(*str != ’n’){
ladeinf(inf.doc, "w", fwrite);
mywrite("\nRechnen? (j/n)");
scanf("%s", str); /* "Mißbrauch"
von str */
if(*str == ’n’)
break;
}
FORK_UND_RECHNE(inf.doc); /* wenn nicht
gespeichert wird, wird auf jeden Fall gerechnet */
}
break;
case 2:
mywrite("Aus welcher? (ohne .inf!)\n");
system("ls *.inf");
mywrite("\n? ");
scanf("%s", str);
str[DAT_NAME_MAX-1]=’\0’;// zur Sicherheit
if(!ladeinf(str, "r", fread))
FORK_UND_RECHNE(inf.doc);
break;
case 3:
if(!eingabe())
serie(&proc_ptr, &forkcount);
// Parameter dienen
break; // nur dem Aktualisieren
} // der Prozeßinformationen
}
case 2:
while(c){
mywrite(" Doku erzeugen\n");
mywrite(" ---------------\n\n");
mywrite(" 0.) Keine\n");
mywrite(" 1.) Die aktuelle\n");
mywrite(" 2.) Andere\n");
scanf("%d", &c);
switch(c){
case 1:
//makedocu(); noch zu erledigen
break;
case 2:
system("ls *.inf");
mywrite("\n ? ");
scanf("%s", str);
str[DAT_NAME_MAX-1]=’\0’;
/*if(! ladeinf(str, "r", fread))
makedocu();*/
break;
}
}
case 3:
while(c){
mywrite(" Ausgabe\n");
mywrite(" ---------\n\n");
mywrite(" 0.) Keine\n");
mywrite(" 1.) Eine\n");
mywrite(" 2.) Mehrere\n");
scanf("%d", &c);
switch(c){
case 1:
system("ls x*");
mywrite("\n? ");
scanf("%s", str);
str[DAT_NAME_MAX-1]=’\0’;
//ausgabe(str); noch zu erledigen
break;
case 2:
#if 0
do{ noch zu erledigen
system("ls x*");
mywrite("\n(Return für Ende) ? ");
scanf("%s", str);
str[DAT_NAME_MAX-1]=’\0’;
}while(! ausgabe(str));
#endif
break;
}
}
break;
default:
mywrite("\n Und nochmal!\n");
}
mywrite("\n\n Menu:\n");
mywrite(" 0.) Ende\n");
mywrite(" 1.) Eingabe\n");
mywrite(" 2.) Doc-Datei erzeugen\n");
mywrite(" 3.) Ausgabe\n\n ? ");
scanf("%d", &c);
}
// endwin(); // falls curses benutzt wird
getchar(); // wegen letztem scanf
ladeinf(".simrc", "w", fwrite);
pf1(
"\nSoll auf die %d noch laufenden Prozesse gewartet werden? ",
forkcount);
scanf("%c", &c);
#if ! HP
if(c!=’n’) // OK, es wird gewartet
while(forkcount--){
pid_t pid=wait(&fork_ret);
for(i=0; proc_ptr[i].pid != pid; i++);
printf("\n%s: wait-Status: | %x | %x |\n",
proc_ptr[i].name,
(fork_ret>>8) & 0xff, fork_ret & 0xff);
}
#endif
return 0;
}
Die folgenden Dateien enthalten jeweils Funktionen für die Eingabe, das
Schreiben und Lesen von Parametern, die eigentliche Simulationsrechnung, die
Unterstützung von Simulationsserien sowie weitere nützliche Funktionen.
Zu dem Algorithmus für die Abschattung ist zu erwähnen, daß dazu Linien
erzeugt werden, die daraufhin geprüft werden, ob sie komplett oberhalb der
Oberfläche liegen oder nicht. Um Rechenzeit zu sparen —was wichtig ist, da diese
Überprüfung innerhalb der innersten Schleife stattfindet—, wurden die bereits
berechneten Punkte zur Linienerzeugung verwendet, was dazu führt, daß diese
nicht mehr gerade, sondern treppenförmig wird, falls sie nicht auf der x-
oder y-Achse liegt. Dies hatte zur Folge, daß die Simulationsbilder keine
hexagonale Symmetrie mehr aufwiesen, denn diagonale Linien wurden schlechter
aufgelöst als waagerechte oder senkrechte. Um diesem Fehler zu begegnen,
durften Linien nicht mehr gerastert werden, sondern mußten nun für jeden
Punkt analytisch ausgewertet werden, was zu dem Makro „SURFUNC(x,y)“
führte.
/* siminput.c
Author: Peter Münster, 1996
Eingabemodul für simmain.c
*/
#include "sim.h"
extern info_struct inf;
char progname[DAT_NAME_MAX];
// schreibt nach dp neuen Wert, oder läßt Default-Wert
void my_doub_scan(char *s, doub *dp){
char str[DAT_NAME_MAX+1];
pf1(s, *dp);
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)) // \n ist min-
// destens das
*dp=(doub)strtod(str, NULL); // erste Zeichen (-> ..+1)
}
// Hauptfunktion für die Eingabe (noch ohne Fehlerbehandlung)
int eingabe(){
char str[DAT_NAME_MAX+1];
my_doub_scan(
"\nBitte die Barrierenhöhe eingeben!\n(default=%lf): ",
&inf.phi);
my_doub_scan("\nWann ist Abbruch?\n(default=%lf): ",
&inf.cut);
printf("\nBitte Modus eingeben!\n");
pf1("(default=%d):\n0=normal, 1=genau0, 2=genau1: ",
inf.flag);
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)) // \n ist
// mindestens das
inf.flag=atoi(str); // erste Zeichen (-> ..+1)
/* my_doub_scan(
"\nBitte die Gewichtung eingeben!\n(default=%lf): ",
&inf.g); */
my_doub_scan(
"\nSkalierungsfaktor (Pixel/Å) eingeben!\n(default=%lf): "
,&inf.scal);
/* pf1("\nBitte rmax eingeben!\n(default=%d): ", inf.rmax);
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)) // \n ist
// mindestens das
inf.rmax=atoi(str); // erste Zeichen (-> ..+1)
pf1(
"\nBitte Breite (=Höhe) in Pixel eingeben!\n(default=%d): ",
inf.dim);
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)) // \n ist
// mindestens das
inf.dim=atoi(str); // erste Zeichen (-> ..+1)
*/
my_doub_scan(
"\nBitte Gitterkonstante eingeben!\n(default=%lf): ",
&inf.c[0]);
my_doub_scan(
"\nBitte Korrugation eingeben!\n(default=%lf): ",
&inf.c[1]);
my_doub_scan("\nBitte Abstand eingeben!\n[%lf]: ", &inf.d0);
sprintf(inf.doc,
"%1.1lf#%1.6lf#%1.1lf#%1.1lf#%1.1lf#%1.1lf",
inf.phi,inf.cut,inf.scal,inf.c[0],
inf.c[1],inf.d0);
#if 0
pf2(
"\nBitte Doku bis zu %d Zeichen eingeben!\n(default=%s): ",
DAT_NAME_MAX, inf.doc);
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)){ // wegen Return
strcpy(inf.doc, str);
inf.doc[strlen(str)-1]=’\0’;
}
#endif
return 0;
}
/* siminfo.c
Author: Peter Münster, 1996
Hilfsmodul für simmain.c
*/
#include "sim.h"
info_struct inf;
extern char progname[];
// lädt die globale inf-Struktur
int ladeinf(char datei[DAT_NAME_MAX], char mode[3],
size_t (*func)(void *ptr, size_t size, size_t nmemb,
FILE *stream)){
FILE *fp;
if(!(fp=fopen(datei, mode)))
return 1;
if(!func((void *)(&inf.phi), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.cut), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.scal), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.c), SOD, 2, fp))
return 1;
if(!func((void *)(&inf.d0), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.d0max), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.dd0), SOD, 1, fp))
return 1;
if(!func((void *)(&inf.flag), SOI, 1, fp))
return 1;
fclose(fp);
return 0;
}
/*zeigt Indodatei in lesbarem Format und
füllt die globale Struktur inf */
int zeigeinfo(char datei[DAT_NAME_MAX]){
pf1("\nInhalt von %s.inf:\n\n", datei);
if(ladeinf(datei, "r", fread)){
FPF("\nzeigeinfo: aus %s.inf konnte nicht gelesen werden!",
datei);
return 1;
}
pf1("Barrierenhöhe: %lf\n", inf.phi);
pf1("Skalierungsfaktor (Pixel/Å): %lf\n", inf.scal);
// pf1("Breite und Höhe in Pixeln: %d\n", inf.dim);
pf1("Gitterkonstante: %lf\n", inf.c[0]);
pf1("Korrugation: %lf\n", inf.c[1]);
// pf1("Atomradius: %lf\n", inf.c[4]);
pf1("Abstand: %lf\n\n", inf.d0);
return 0;
}
/* simcalc.c
Author: Peter Münster, 1996
Rechenmodul für sim
*/
#include "sim.h"
extern char progname[];
extern info_struct inf;
static doub abstand; // vom Tal gemessen
static doub git; // in Pixel
static doub kor; // in Pixel
static doub *probfeld;
static short *flagfeld;
static doub sqrphi_scal; // für die exp-Funktion
static doub sq3; // für das Makro surfunc
static doub hilf; // für das Makro surfunc
// Erzeugen der Oberfläche
void surface(doub *probfeld){
register int i, j;
doub w0[2], w1[2], w2[2];
// die drei w#’s sind die reziproken Gittervektoren:
w0[0]=0 *2*M_PI/git;
w0[1]=1 *2*M_PI/git;
w1[0]=-sqrt(3)/2 *2*M_PI/git;
w1[1]=-0.5 *2*M_PI/git;
w2[0]=sqrt(3)/2 *2*M_PI/git;
w2[1]=-0.5 *2*M_PI/git;
// Hexagonale Cosinusfunktion, siehe Chen: Seite 132
for(j = 0; j < inf.dim; ++j)
for(i = 0; i < inf.dim; ++i){
probfeld[inf.dim*j + i] = 1.5;
probfeld[inf.dim*j + i] += cos(i*w0[0]+j*w0[1]);
probfeld[inf.dim*j + i] += cos(i*w1[0]+j*w1[1]);
probfeld[inf.dim*j + i] += cos(i*w2[0]+j*w2[1]);
probfeld[inf.dim*j + i] *= kor*2.0/9.0;
}
}
/*
// diese Funktion berechnet eine Linie zwischen (x,y) und
// (x+dy,y+dy)
void linie(int max, int dx, int dy, int x, int y,
point_struct *line){
register int i;
for(i=0; i<max; i++){
line[i].x=x+rint((doub)dx*(doub)i/(doub)max);
line[i].y=y+rint((doub)dy*(doub)i/(doub)max);
}
}
*/
// surfunc als Makro aus Geschwindigkeitsgründen
#define SURFUNC(x,y) ((1.5+cos((y)*2*hilf)+cos((x)*sq3* \
hilf+(y)*hilf)+cos((x)*sq3*hilf-(y)* \
hilf))*kor*2/9)
// nützliche Abkürzungen:
#define LINIE_XY(xy,dxy,m,i) ((xy)+(doub)(dxy)* \
(doub)(i)/(doub)(m))
#define LINIE_Z(x,y,dx,dy,m,i) (SURFUNC(LINIE_XY(x,dx,m,i), \
LINIE_XY(y,dy,m,i)))
// getstrom berechnet den Strom von (i,j) nach (x,y)
doub getstrom(int x, int y, int i, int j){
doub d, wert=probfeld[j*inf.dim+i]; // wert= Funktionswert
doub index; // am Aufpunkt
int dx=i-x;
int dy=j-y;
doub dist=sqrt(dx*dx+dy*dy);
#if ABSCHATTUNG
index=(abstand-1.01*kor)*dist/(abstand-wert);
/* 1.01 soll nur einen Sicherheitsabstand gewährleisten */
while(index < dist && abstand-index*(abstand-wert)/dist >
LINIE_Z(x,y,dx,dy,dist,index))
index++;
if(dist<=index){ // keine Abschattung
#endif
flagfeld[j*inf.dim+i]=2; // 2: schon berechnet
if(inf.flag)
d=sqrt(dx*dx+dy*dy+(abstand-wert)*(abstand-wert));
else
d=sqrt(dx*dx+dy*dy+(abstand)*(abstand));
if(inf.flag==1)
return(exp(-sqrphi_scal*d)/d);
else
return(wert*exp(-sqrphi_scal*d)/d);
#if ABSCHATTUNG
}
else{
flagfeld[j*inf.dim+i]=1; // abgeschattet
return 0.0;
}
#endif
}
// diese spezielle Version von getstrom erhöht außerdem die
// Variable anz_ring_ok, falls nicht abgeschattet wird, für
// checkdim
doub getstrom_special(int x, int y, int i, int j, int *anz){
doub d, wert=probfeld[j*inf.dim+i]; // wert= Funktionswert
int index; // am Aufpunkt
int dx=i-x;
int dy=j-y;
int dist=rint(sqrt(dx*dx+dy*dy));
index=floor((abstand-1.001*kor)*(doub)dist/(abstand-wert));
/* floor und "1.001" sollen nur einen
Sicherheitsabstand gewährleisten */
while(index < dist &&
abstand-(doub)index*(abstand-wert)/dist >
LINIE_Z(x,y,dx,dy,dist,index))
index++;
if(dist==index){
++*anz; // keine Abschattung
flagfeld[j*inf.dim+i]=2; // 2: schon berechnet
//d=sqrt(dx*dx+dy*dy+(abstand)*(abstand));
d=sqrt(dx*dx+dy*dy+(abstand-wert)*(abstand-wert));
return (wert*exp(-sqrphi_scal*d)/d);
}
else{
flagfeld[j*inf.dim+i]=1; // der eigentliche
return 0.0; // Punkt selbst
}
}
// setzt das flagfeld auf Null
void clearflagfeld(){
register i;
int help=inf.dim*inf.dim;
for(i=0; i<help; i++)
flagfeld[i]=0;
}
// hier wird der Anteil der nicht abgeschatteten Punkte
// im äußersten Kreisring abgeschätzt
int checkdim(){
int diff; // halbe Sehnenlänge
int anz_ring; // Anzahl der Punkte in einem Ring
int anz_ring_ok; // Anzahl der Punkte ohne Abschattung
doub cur_ring; // Strom eines Kreisrings
doub cur=0; // gesamter Strom
int punkte=0; // gesamte Anzahl der Punkte
doub dr=(doub)inf.rmax/10.0; /* Delta-r: Schrittweite
beim Vergrößern des
Radius */
doub r=dr; /* Radius: mit dr wird begonnen,
dann schrittweise erhöht */
doub r_alt; // der vorige Radius
int x=rint(inf.dim/2.0); // Spalte
int y=rint(inf.dim/2.0); // Zeile
// Es wird einfach der mittlere Punkt genommen !
int i, j;
clearflagfeld(); // Flags auf Null setzen
r_alt=0; /* das erste Gebiet ist kein Kreisring,
sondern eine Kreisfläche */
while(r <= (doub)inf.rmax){
j=y-rint(r);
anz_ring=0;
anz_ring_ok=0; // es beginnt ein neuer Ring
cur_ring=0;
while(j<=y+rint(r)){
i=0; // es wird erstmal ganz links angefangen
// gehe bis an den linken Rand des Kreises:
while((i-x)*(i-x)+(j-y)*(j-y) > rint(r)*rint(r) &&
++i <= x);
if (0 > (diff=x-i)) // diff= Abstand von der y-Achse
exit(3); // man weiß ja nie
while(i<=x+diff){
if(r_alt && i<=x &&
(i-x)*(i-x)+(j-y)*(j-y) <=
rint(r_alt)*rint(r_alt))
i += 2*(x-i)+1; /* überspringe die
innere Kreisfläche */
if (!flagfeld[j*inf.dim+i])
cur_ring+=getstrom_special(x, y, i, j,
&anz_ring_ok);
anz_ring++; /* die Anzahl der Punkte
im aktuellen Ring */
i++;
} // i-Schleife
j++;
} // j-Schleife
cur+=cur_ring;
punkte+=anz_ring;
r_alt=r;
r+=dr;
} // r-Schleife
inf.ant=(doub)anz_ring_ok / (doub)anz_ring; // nur zur Info
return 0; // Erfolg
}
// berechnet den Strom für den Punkt (x,y)
doub berechne(int x, int y){
register int i, j;
doub cur=0;
int diff;
clearflagfeld(); // Flags auf Null setzen
for(j=y-inf.rmax; j<=y+inf.rmax; j++){
i=0; // es wird erstmal ganz links angefangen
// gehe bis an den linken Rand des Kreises:
while((i-x)*(i-x)+(j-y)*(j-y) > inf.rmax*inf.rmax &&
i++ <= x);
if (0 > (diff=x-i)) /* diff = Abstand von
der y-Achse */
exit(4); // man weiß ja nie
while(i<=x+diff){
if (!flagfeld[j*inf.dim+i])
cur+=getstrom(x, y, i, j);
i++;
} // i-Schleife
} // j-Schleife
return cur;
}
// Hauptfuktion für die Rechnung
void rechne(char *kontrastfile){
register int i, j;
FILE *fp;
doub *feld;
doub max, min, hilf2;
char *tempfeld, *tempfeld2;
char str[DAT_NAME_MAX+20];
char str2[DAT_NAME_MAX+20];
abstand = (inf.c[1]/2+inf.d0)*inf.scal; // inf.d0 ist
// der Abstand
git = inf.scal*inf.c[0]; /* von Kern zu
Spitze */
kor = inf.scal*inf.c[1];
hilf2 = log(1.0 - inf.cut/100)/sqrt(inf.phi);
inf.rmax= rint(inf.scal*sqrt(hilf2*hilf2 - 2*hilf2*inf.d0));
inf.dim= (int)rint(3*git + 2*inf.rmax +3);
feld =(doub *)malloc(SOD*inf.dim*inf.dim);
probfeld =(doub *)malloc(SOD*inf.dim*inf.dim);
flagfeld =(short *)calloc(inf.dim*inf.dim, SOS);
sqrphi_scal=sqrt(inf.phi)/inf.scal; // Hilfsvariable
sq3=sqrt(3); // Hilfsvariable
hilf=M_PI/git; // für das Makro surfunc
#if DEBUG
printf("inf.cut=%lf\ninf.rmax=%d\ninf.dim=%d\n",
inf.cut, inf.rmax, inf.dim);
printf("abstand=%lf\ngit=%lf\nkor=%lf\n",
abstand, git, kor);
#endif
surface(probfeld);
// checkdim schätzt inf.ant ab
checkdim();
for(j = 0; j < inf.dim; ++j)
for(i = 0; i < inf.dim; ++i)
feld[inf.dim*j+i] =
inf.rmax<=j && j<inf.dim-inf.rmax &&
inf.rmax<=i && i<inf.dim-inf.rmax ?
berechne(i, j) : probfeld[inf.dim*j + i];
/* ---------------------------------- */
/* Es folgt das Erzeugen der Dateien xxx.tip,
xxx.sur und xxx.sim */
/* noch ein letztes Mal updaten, bevor Benutzung! */
sprintf(inf.doc,
"%1.1lf#%1.2lf#%1.6lf#%d#%1.1lf#%1.1lf#%1.1lf#%1.1lf",
inf.phi,inf.ant,inf.cut,inf.rmax,inf.scal,inf.c[0],inf.c[1],
inf.d0);
// xxx.sur
j=inf.dim*inf.dim;
tempfeld=tempfeld2=(char *)malloc(SOC*j);
max=maximum(probfeld, j);
min=minimum(probfeld, j);
for(i=0; i<j; i++)
tempfeld[i]=(int)((probfeld[i]-min)/(max-min)*255);
sprintf(str, "%s.sur", inf.doc);
#if 0
if(!(fp=fopen(str, "w")))
exit(1);
schreibedim(inf.dim, fp);
fwrite(tempfeld2, SOC, j, fp);
#endif
// xxx.sim
tempfeld=(char *)malloc(SOC*j);
max=feld[inf.rmax*inf.dim+inf.rmax];
min=feld[inf.rmax*inf.dim+inf.rmax];
for(j=inf.rmax; j<inf.dim-inf.rmax; j++)
for(i=inf.rmax; i<inf.dim-inf.rmax; i++){
if(feld[j*inf.dim+i] > max)
max=feld[j*inf.dim+i];
if(feld[j*inf.dim+i] < min)
min=feld[j*inf.dim+i];
}
#if DEBUG
printf("\n---> max=%le und min=%le <---\n", max, min);
printf("\n---> inf.rmax=%d und inf.rmax=%d <---\n",
inf.rmax, inf.rmax);
#endif
for(j=0; j<inf.dim; j++)
for(i=0; i<inf.dim; i++)
tempfeld[j*inf.dim+i]= inf.rmax<=j &&
j<inf.dim-inf.rmax && inf.rmax<=i &&
i<inf.dim-inf.rmax ?
(int)((feld[j*inf.dim+i]-min)/
(max-min)*255) :
tempfeld2[j*inf.dim+i];
sprintf(str, "%s.sim", inf.doc);
fp=fopen(str, "w");
schreibedim(inf.dim, fp); // provisorisch
fwrite(tempfeld, SOC, j*j, fp);
// Erst wird der Name für die Kontrastdatei erzeugt:
// (falls keine Datei benannt wurde wird "kontrast" benutzt)
#if ABSCHATTUNG
sprintf(str, "%s", *kontrastfile ? kontrastfile : "kont");
#else
sprintf(str, "%s", *kontrastfile ? kontrastfile : "kontoa");
#endif
if(!(*kontrastfile)){
sprintf(str2, ".%2.0lf", inf.cut);
strcat(str, str2);
}
freopen(str, "a", fp);
fprintf(fp, "%s: %lf %lf\n", inf.doc, inf.d0, 1.0- min/max);
fclose(fp);
#if HP
sprintf(str, "gzip %s.sim &", inf.doc);
system(str);
#endif
// Speicher freigeben:
free(feld);
free(flagfeld);
free(probfeld);
free(tempfeld);
free(tempfeld2);
}
/* simserie.c
Author: Peter Münster, 1996
Enthält Funktionen für Rechenserien
*/
#include "sim.h"
extern info_struct inf;
extern char progname[];
// paßt Parameter an und startet rechne
void serienfunc(char *str){
// inf.rmax=inf.d0 * tan(M_PI*inf.wmax /180);
// inf.dim = 3*(int)maximum(inf.c, 4) +
// 3+2*(int)(inf.scal*inf.rmax);
/* Das gescannte Feld beträgt also 3 Gitterkonstanten */
/* Der Summand dims ist nötig um die
Einflüsse von außerhalb */
/* des gescannten Feldes mit zu berücksichtigen */
rechne(str);
}
// vorläufig wird nur der Abstand variiert!
void serie(proc_struct **proc_ptr, int *count){
char str[DAT_NAME_MAX];
pid_t fork_ret;
my_doub_scan("\nKleinster Abstand?\n[%lf]: ", &inf.d0);
my_doub_scan("\nGrößter Abstand?\n[%lf]: ", &inf.d0max);
my_doub_scan("\nSchrittweite?\n[%lf]: ", &inf.dd0);
pf1(
"\nNamen der Kontrastdatei eingeben!\n(default=%s): ",
"kontrast");
if(*((fgets(str, DAT_NAME_MAX, stdin))+1)) // wegen Return
str[strlen(str)-1]=’\0’;
else
*str=’\0’;
fork_ret=fork();
switch(fork_ret){
case -1:
FPF("fork-Aufruf in serie %s", "ohne Erfolg!\n");
break;
case 0:
for(; inf.d0<inf.d0max; inf.d0+=inf.dd0)
serienfunc(str);
exit(0);
default:
(*count)++; /* Prozeßinfos abspeichern: */
*proc_ptr=(proc_struct *)realloc(*proc_ptr,
sizeof(proc_struct)* *count);
(*proc_ptr)[*count-1].pid=fork_ret;
strncpy((*proc_ptr)[*count-1].name,
str, DAT_NAME_MAX);
(*proc_ptr)[*count-1].name[DAT_NAME_MAX-1]=’\0’;
}
}
/* simhilf.c
Author: Peter Münster, 1996
Hilfsfunktionen für sim
*/
#include "sim.h"
extern char *progname;
#if 0
// getch() mit echo
int getche()
{
int c;
noecho();
cbreak();
c=getch();
nocbreak();
echo();
if (c == 127)
mywrite("\b");
else
pf1("%c", c);
return(c);
}
// getch() ohne echo
int getchne()
{
int c;
noecho();
cbreak();
c=getch();
nocbreak();
echo();
return(c);
}
#endif
// von Max
void schreibedim(int dim, FILE *ausdp){
/* schreibedim schreibt die Dimension zweimal */
/* d.h. es sind quadratische Bilder */
int i, low, high;
low = dim%256;
high = (dim - low)/256;
for(i = 0; i < 2; ++i){
putc(high,ausdp);
putc(low,ausdp);
}
}
// maximum des valeurs de p
doub maximum(doub *p, int j){
register unsgnd i;
doub m;
m = *p;
for (i=0; i<j; ++i)
if (m < *++p) m = *p;
return m;
}
// minimum des valeurs de p
doub minimum(doub *p, int j){
register unsgnd i;
doub m;
m = *p;
for (i=0; i<j; ++i)
if (m > *++p) m = *p;
return m;
}
Mit folgender kleiner Beispiel-Makedatei kann das Programm bequem übersetzt
werden:
# Makefile fuer die Übersetzung des Simulationsprogramms
CFLAGS = -g -DDEBUG
CFLAGS = -O6 -DABSCHATTUNG
LFLAGS = -lm # -lncurses
OBJS = simmain.o siminfo.o siminput.o simcalc.o simhilf.o simserie.o
sim: $(OBJS)
$(CC) -o $@ $(LFLAGS) $(OBJS)
cp sim $(HOME)/bin/simma
simmain.o: sim.h Makefile
siminfo.o: sim.h Makefile
siminput.o: sim.h Makefile
simcalc.o: sim.h Makefile
simhilf.o: sim.h Makefile
simserie.o: sim.h Makefile
clean:
rm -f sim*.o sim