Zuletzt geändert: Mi, 27.12.2006

«K12/K13» Simulation des Franck-Hertz-Versuchs.pl «PDF», «POD»



Download
#!/usr/bin/perl

use warnings;
use strict;

use Getopt::Long;

GetOptions(
  "width=f" => \my $width,
  "acc=f"   => \my $acc,
  "input=i" => \my $input,
  "coll=f"  => \my $coll_prob,
  "emit=f"  => \my $emission_energy,
);

use constant ELECTRON_MASS   => 1;
use constant ELECTRON_CHARGE => 1;
use constant TIME_PER_STEP   => 0.1;
use constant EPSILON_0       => 1;

my $id  = "franck-hertz-$width-$acc-$input-$coll_prob-$emission_energy";
my $sid = "franck-hertz-$width-$input-$coll_prob-$emission_energy";

{
  my @colls = (0) x $width;

  sub register_coll {
    use constant ROUNDER => 1;

    my $pos     = shift;
    my $rounded = sprintf '%0.f', $pos / ROUNDER;

    $colls[ROUNDER*$rounded + $_]++ for 0..(ROUNDER - 1);
  }

  sub output_colls {
    open my $fh, ">", "$id-colls.txt" or die $!;
    print $fh "$_ $colls[$_]\n" for 0..$#colls;
  }
}

{
  my @kins = (0) x $acc;

  sub register_kin {
    use constant ROUNDER => 1;

    my $kin     = shift;
    my $rounded = sprintf '%0.f', $kin / ROUNDER;

    $kins[ROUNDER*$rounded + $_]++ for 0..(ROUNDER - 1);
  }

  sub output_kins {
    {
      open my $fh, ">", "$id-kins.txt" or die $!;
      print $fh "$_ $kins[$_]\n" for 0..$#kins;
    }

    {
      use constant TRESHOLD => 8;
      my $sum = 0;
      $sum += $kins[$_] for TRESHOLD..$#kins;

      open my $fh, ">>", "$sid-diag.txt" or die $!;
      print $fh "$acc $sum\n";
    }
  }
}

my @electrons = ({ x => 0, v => 0 }) x $input;

my $step = 0;
while(@electrons = grep { $_ } @electrons) {
  $step++;
  warn "$step...\n" if $step % 10 == 0;

  for my $e (@electrons) {
    next unless $e;

    my ($x, $v) = @$e{"x", "v"};
    my $F       = (EPSILON_0 * $acc / $width) / ELECTRON_CHARGE;
    my $a       = $F / ELECTRON_MASS;
    $v += $a * TIME_PER_STEP;

    my $delta_x = $v * TIME_PER_STEP;
    $delta_x = $width - $x if $x + $delta_x > $width;
    $x += $delta_x;

    my $kin = 1/2 * ELECTRON_MASS * $v**2;

    if($coll_prob * $delta_x > rand) {
      #warn "kin: $kin\n";
      if($kin >= $emission_energy) {
        $kin -= $emission_energy;
        $v    = sqrt(2 * $kin / ELECTRON_MASS);

        register_coll($x);
      } else {
        # nichts
      }
    }

    if($x >= $width) {
      register_kin($kin);
      $e = undef;
    } else {
      $e = { x => $x, v => $v };
    }
  }
}

output_colls();
output_kins();