nishiru3の日記

備忘録です。ネットのゴミ。

Perlで移流方程式

PerlPythonみたいなモジュールがないかと思ってましたが、
「PDL」というものを使うと、描画までいけるみたいです。
「いや、pythonで良いじゃん!」というのもありますが・・・。
ソース自体は、リファレンスとか使えば、もうちょっと短くなるかと思います。

どうもPDLだとScilabなんかも使えるみたいです。
結構、更新されてるみたいですね。

公式?
http://pdl.perl.org/


インストール
http://d.hatena.ne.jp/perlcodesample/20121214/1355388288

移流方程式は下記のとおりとしました。

\frac{\partial f}{\partial t} + u\frac{\partial f}{\partial x} = 0
移流速度uは一定値の線形移流です。

移流項は1次風上、時間積分オイラーの陽積分です。
面白くはないですが、ちょっとしたアルゴリズムを書いてみて、すぐ可視化する場合、
pythonのような使い方もできるようです。あと、CPANにはもっと多くのモジュールがあるようなので、
さらに便利にできるかもしれません。

use strict;
use warnings;
use PDL::Lite;
use PDL::NiceSlice;
use PDL::Graphics::PLplot;
my $dx = 1.0;
my $dt = 1.0;
my $u  = 0.2;
my @f;
my @fini;
my @fn;
my @x;
for my $i(0..99){
    if ($i >10 && $i < 20){
	$f[$i] = 1.0;
    } else {
	$f[$i] = 0.0;  
    }$fn[$i] = $f[$i];
    $fini[$i] = $f[$i];
    $x[$i] = $i;
}
# 100ステップ
for my $n (1..100){
    # 1次風上+eulerの陽解法
    for my $i(1..99){
	$fn[$i] = $f[$i] - $u/$dx*$dt*($f[$i]-$f[$i-1]);
    }
    # 変数の更新
    for my $i(1..99){
  	$f[$i] = $fn[$i];
    }
}
# 数値データの出力
for my $i (0..99){
    print $i.",".$f[$i]."\n";
}
#
# 描画
my $pl = PDL::Graphics::PLplot->new(DEV => 'png', FILE => 'adv.png');
my $x1 = pdl->zeros(100);
for my $i(0..99){
    $x1($i) .= $i;
}
my $y1 = pdl->zeros(100);
my $y2 = pdl->zeros(100);
for my $i(0..99){
    $y1($i) .= $f[$i];
    $y2($i) .= $fini[$i];
}
$pl->xyplot($x1,$y1);
$pl->xyplot($x1,$y2);

$pl->close;

f:id:nishiru3:20141022090245p:plain

Fortranの構造体

今日はFortranです。
転職してから仕事で使うことは皆無ですが・・・。

f90以降では構造体を使えます。
正直、C++で良いじゃん!って思いますが、
一応機能として使えるので、簡単な使い方だけ説明します。

ここでは、構造体にx、yの座標(real)を持たせるものとし、その座標をlocateとする配列にしています。

このlocateはimax(=10)個持たせ、各locateのx,yに値を入力しています。

最後に出力して確認しています。
(面白くもないですが・・・)

構造体でデータを持たせた場合のパフォーマンスについては、調査してません。
どうなんでしょうかね。。。
もしかしたら、大規模な計算だとパフォーマンスが落ちるかもしれません。

program main
  implicit none
  integer i,imax
  ! 構造体の宣言
  type point
     real(8) :: x,y
  end type point
  type(point),allocatable :: locate(:)
  ! 座標の数(=10)
  imax = 10
  ! 構造体配列の確保
  allocate( locate(imax) )
  ! 座標の入力 構造体のメンバー変数には「%」でアクセス
  do i = 1,imax
     locate(i)%x = real(i)
     locate(i)%y = real(i)*2.0d0
  end do
  ! 入力値の確認
  do i = 1,imax
     print *,locate(i)%x,locate(i)%y
  end do
end program main

Perl入学式3の練習問題

最近、毎日、会社に早めに行って、30分くらいperlを触るようにしています。

仕事上、業務で使うことはないPerlですが、なるべく使うようにしたいですね。
Perl入学式に参加しているので、少し書いてみました。

Perl入学式の校長、サポーターの皆様、参加者の皆様に感謝いたします。
次回も、日程が合えば、参加させていただきます。

ソースコードについてはもっと美しく書けますが、ご勘弁を。
「考えて書く」ことが、プログラム上達のコツかと思います。
(「考えて書く」は私自身の戒めだったりします。)

中級者向けのPerl勉強会が開催された模様ですが、
まだラクダ本を読んでないので。。。

Perlについては、いろいろ言われていますが、
好きな言語を使うのが一番だと思います。
仕事だとそういうわけにもいきませんが・・・。

まあ、「すごいプログラマ」は、いろんな言語をハックしてると思いますし、
「なぜその言語を使うのか?」の回答をしっかり持ってると思います。

use strict;
use warnings;
use utf8;
use Data::Dumper;
#1. 「自分の名前 (name)」と「好きな食べ物の配列のリファレンス (favorite_foods)」を持ったハッシュリファレンスを作成しましょう (つまり、好きな食べ物は複数個書いてください)
#2. 同様のハッシュリファレンスを2, 3個作ってみましょう (周りの人のリアルデータを使ってハッシュrefを作ると良いかもしれません)
#3. 作成した複数のハッシュリファレンスを1つの配列に格納しましょう (配列を操作する関数を使っても良いですし、直で代入しても良いです)
#4. どんな方法でも良いので、好きな食べ物のランキングを作って表示してみて下さい
my $h1 = {
    name => 'I',
    favorite_foods => ['egg', 'orange', 'apple'],
};
my $h2 = {
    name => 'You',
    favorite_foods => ['egg', 'beaf', 'apple'],
};
my @array = ($h1,$h2);
my @name = qw(Kei You);
#print Dumper @array;

my $index = {
    egg    => 0 ,
    orange => 0 ,
    apple  => 0 ,
    beaf   => 0 ,
};
# 好きなものを各個人から抽出し、集計
for my $hash (@array) {
    my %rank;
    for my $foods ($hash->{favorite_foods}) {
	# デリファレンスを使って配列作成
	my @foods_arr = @$foods;
	for my $food ( @foods_arr ) {
	    for my $in ( keys $index ) {
		print $in,",",$food."\n";
		if ($in eq $food ) {
		    $index->{$in} += 1;
		}
	    }
	}
    }
}
# ランキングの作成
print Dumper $index;
my $ranking;
for my $key (sort { $index->{$b} <=> $index->{$a} } keys $index) {
    print "$ranking"."$key, $index->{$key}\n";
}
binmode STDOUT, ":utf8"; 
use strict;
use warnings;
use utf8;
use Data::Dumper;
#1 各人物の  perl ,  ruby ,  python  ... といった言語の合計値を key  sum  の value としてリファレンスに追加しましょう
#2  @people  や  @languages  といった変数に各人物のリファレンスや言語を格納してからやってみましょう

#1 新たに $average といったハッシュリファレンスを作り、各人物の名前を key として  perl 、 ruby 、 python の平均値を格納してください
#2 出力には  Data::Dumper  などを使って表示させてください

#1 それぞれの人物の言語毎の成績を上記を参考に5段階表示して出力して下さい
#2 全角文字を出力するので冒頭に binmode STDOUT, ":utf8"; と書いておくとよいでしょう

# ハッシュのハッシュリファレンス
my $papix = { 
    name        => 'papix', 
    affiliation => 'namba.pm', 
    perl        => 60, 
    python      => 50, 
    ruby        => 50, 
    php         => 80, 
    binary      => 30, 
}; 
my $boolfool = { 
    name        => 'boolfool', 
    affiliation => 'namba.pm', 
    perl        => 40, 
    python      => 10, 
    ruby        => 20, 
    php         => 30, 
    binary      => 10, 
}; 
my $moznion = { 
    name        => 'moznion', 
    affiliation => 'hachioji.pm', 
    perl        => 100, 
    python      => 70, 
    ruby        => 80, 
    php         => 50, 
    binary      => 50, 
}; 
my $binarian = { 
    name        => 'binarian', 
    affiliation => 'hachioji.pm', 
    perl        => 10, 
    python      => 11, 
    ruby        => 1, 
    php         => 100, 
    binary      => 100, 
}; 
my $uzulla = { 
    name        => 'uzulla', 
    affiliation => 'hachioji.pm', 
    perl        => 1, 
    python      => 0.01, 
    ruby        => 0.5, 
    php         => 4, 
    binary      => 0.01, 
};
my @persons = ($papix, $boolfool, $moznion, $binarian, $uzulla); 
for my $person (@persons) { 
    my $average = 0;
    my $evaluation = '';
    my @languages = qw/perl python php ruby binary/;
    print $person->{name}.":\n"; 
    for my $language (@languages) { 
	if ( $language eq 'perl' or $language eq 'python' or $language eq 'ruby') {
	    $average = $person->{$language};
	}
	my $score = $person->{$language};
	if( $score <= 19 ) { # ★
	    print $language.": "."\n";
	} elsif( $score >= 20 && $score <= 39 ) { # ★
	    print $language.": "."★\n";
	} elsif( $score >= 40 && $score <= 59 ) { # ★
	    print $language.": "."★★\n";
	} elsif( $score >= 60 && $score <= 79) { # ★
	    print $language.": "."★★★\n";
	} elsif( $score >= 80 && $score <= 99) {
	    print $language.": "."★★★★\n";
	} else {
	    print $language.": "."★★★★★\n";
	}
    }
    print "\n";
    $average /= 3;		# 3言語の平均
    $person->{average} = $average; 
}
#4. 所属毎の perl のスコアが 60 以上の人の名前を格納する
# $highscore  と言ったハッシュリファレンスを用意し、所属毎に優秀な人物の名前を push して下さい
# $highscore における key を所属として配列のリファレンスにするのがいいですね
my $highscore = {
    namba    => [0],
    hachioji => [0],
};
print Dumper $highscore;
my @affiliations = qw/namba.pm hachioji.pm/;
for my $person ( @persons ) {
    for my $affiliation ( @affiliations ){
	if( $person->{affiliation} eq $affiliation ) { # 文字列の場合は、eq
	    if ( $person->{perl} >= 60 ) {
		my @affiliationpm = split(/./, $affiliation);
	    }
	}
    }
}