dynamicsoar's log

主に研究関係のメモ

pythonはじめました(今度こそ)

背景

どうもいつまでたっても python を覚える時間が取れない(取る気がない)なぁと思っていたが、ふと「そうだ、論文用の図を描くのに使ってみよう」と思い立った。グラフの作図、今まではずっと ExcelPowerpoint だった。一度だけ ExcelAdobe Illustrator にしたことがあるが、きれいにはなるのだがさらに作業的な意味でのしんどさが増すばかりだった。まぁ、最終的な論文や学会ポスタ用に一回だけ描くなら超美麗にしていいんだけど、普段からやるのはつらすぎる。自動でそこそこ整形、ってのがいいに決まってる。

候補は

といったところか。で、ちょうどいいので python にしよう、と。

パッケージの種類とインストール

一応前提として僕は Mac OS X 10.9 Mavericks.

ちょっと調べたところ、

  • matplotlibというのがよさそうだ→seabornていうwrapperがもっとよさそうだ→(ちょっと試してみた)おおーたしかにきれいだ
  • homebrew使ってiTerm 2でpython 2.7を使って(お試しで)いたが、どうやら IPython てのがよさそうだ→名前がJupyterに変わっていた。あと別に複雑なことしないし、もう時期的にもいいかげん python 3 でいいだろう、とも思った
  • パッケージ管理ソフトは、homebrewのおかげかpipてのが入っていた(pip3てのではなさげ)→condaてのがよさそうだ

どうやら IPython という python 専用の統合開発環境的なやつ(ちがうかも)だったのが、他の言語にも対応してるよってのが Jupyter みたいだ。が、肝心の Fortran まだか…*1

というわけで、まず Jupyter のインストールのとこにいくと、初めてなら Anaconda を入れるのを highly recommend というので入れた。この anaconda と conda の違いがよくわからんけど(コマンド名が conda?)、まぁとにかく pip と同様のパッケージ管理ソフトみたいで、後発な分ちょっと上等みたいだ。そうすると、あとは iTerm をひらいて、

$ conda install jupyter

してから、

$ conda install seaborn

すると、matlibplot やら numpy やら pandas やらの必要なパッケージは全部自動で入れてくれるっぽい。楽ちん(これは pip でも同じだったが)。自分の場合、Linux (CentOS) で yum に慣れてたので、こういうパッケージ管理ソフトには抵抗感がないのは助かる。

と、いってる間にインストール終わったみたいだ。さて…とりあえず寝るか(駄目パタン)

*1:まだっていうか…ね…うん…わかってる…いいんだ別に…sublimetextでendsubroutineみたいにスペース空けずにつなげて書いたらシンタックスハイライトに認識されないとかね、うん。わかってる。

連番ファイルを個別に xz で圧縮/解凍

natures flyers: コマンドライン (linux, cygwin) での個別ファイルのバッチ圧縮解凍 → xargs使う に書いたんだけどゴチャゴチャしてるので、必要な部分のみメモ。

前提

  • ファイル名は 00001.xyz, 00002.xyz, ... だったとする。 00001.q の場合は下記の .xyz を .q に変えれば良い。
  • ファイルはそれぞれがでかいため個別に圧縮することにする。まとめて一つのアーカイブにしたい場合は tar を使ってください

圧縮

元ファイルを消す場合

$ ls *.xyz | xargs -n1 -I{} xz {} &

元ファイルを残す場合

$ ls *.xyz | xargs -n1 -I{} xz -k {} &

解凍

アーカイブファイルを消す場合

$ ls *.xz | xargs -n1 -I{} xz -d {} &

アーカイブファイルを残す場合

$ ls *.xz | xargs -n1 -I{} xz -dk {} &

応用

上では簡単のため、ファイルのあるディレクトリに移動した後にコマンド実行するケースを想定した。しかし、いちいち cd するのは面倒なので、もっと上層から ls ./foo/bar/output/*.xyz のようにやってもよい。さらにいうと、たとえば計算結果が複数のケースにわたって

  • ./case1/output/00001.xyz , ./case1/output/00002.xyz , ...
  • ./case2/output/00001.xyz , ./case2/output/00002.xyz , ...

のようにあって、ディレクトリ構造が同じであれば、

$ ls ./case*/output/*.xyz | xargs -n1 -I{} xz {} &

で一気に圧縮できる。

このように、アステリスクでのワイルドカードはかなり便利なので、なるべくディレクトリ(フォルダ)名は連番とか構造を保つような名前にしておくとよい。

ただし、マルチスレッドで同時に(並行に)圧縮したい場合はわざとバラバラにジョブを投入するべき。計算機じゃなくて普段使いのPCの場合1スレッドは残しとかないと動作がかなり重くなるで注意。

du でサイズ順にソート

ググったらあったので自分用に僅かに変えてメモ。

基本的には
shell - duコマンドのサイズをわかりやすく表示してサイズ順にソートする - Qiita
にあるとおり。
手元の Cygwin だとすんなりできたけど、別のPCの Cygwin には GNU coreutils が入ってなかったのでインストールが必要だった。

自分の場合、普段はカレントの直下のディレクトリだけ見たいから

$ du -sh ./*

としていた。
上記ページのコマンドは

$ du -b | sort -n | numfmt --to=iec --suffix=B --padding=5

だが、これだとカレントより下の全部のファイルが表示されてしまう(du に -s オプションをつけてないので)。したがって、これを

$ du -sb ./* | sort -n | numfmt --to=iec --suffix=B --padding=5

と書き換えればうまくいった。

しかしこれ、長くて覚えづらいよな…まてよ…表示は汚くなるけど、順番だけ見たいなら後半の整形部分をなくして

$ du -sb ./* | sort -n

これでいいわけだな。

余談。最近、Fortranコンパイルオプションの参考にしてたウェブページがアクセス制限かかって見れなくなった(イントラのみ閲覧可っぽい)ので、ほとんど同じ内容でもメモしとくのは無駄ではないなと。まぁ EverNote にキャプチャしとくだけでもいいっちゃいいけど、微妙に違うことしたい場合はこうしてブログエントリにメモしておくのもありだろう。

Fortran で、form="unformatted", access="stream" で wirte されたファイルを read する

前置き

natures flyers: Fortran でのバイナリ (unformatted, binary) の扱いについてのメモ では write しか考えてなかった。なぜなら FIELDVIEW という可視化ソフトで読み込むことだけ考えてたので。でも今ちょっと、書きだしたデータを読み込んで処理したいなと思ってる。なので読み込み方を例によって trial & error で調べてみた。

Reference

参考にしたのはこのページくらい→ streamIO

バイナリエディタ

あと書きだしたファイルを見るにはバイナリエディタというのが必要なんだけど、僕が使ってる Notepad++ というエディタの場合、プラグインで HEX-Editor というのをインストールして、ファイルを選択した状態でメニューバーの Plugins > HEX-Editor > View in HEX で見れた。

open

ファイルの open 自体はそんな難しくない。こんな感じ。

  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "read" &
      & , form     = "unformatted" &
      & , access   = "stream" &
      & , status   = "old" &
      & , position = "rewind" &
  & )

ちゃんと動くコードはこのエントリ後半に掲載した。

read

これがちょっと面倒。read( ファイル名, pos=現在位置 ) のようにする必要がある。ポイントは「ファイル内での現在位置」を常に把握しておく、ということ。

そのために、loc という変数を用意してみた。これをまず 0 で初期化する。で、ファイルの先頭から読みとりを始めるわけだけど、pos は1から始まる正の整数。そこで、常に pos=loc+1 として、読み取った直後にいま読んだ変数の長さ分 loc にたしてやることにする。

とりあえず int, real(4), real(8) の3パタンだけ短いサブルーチンを作って、モジュールにまとめてみた。

読み取りモジュール

module mod__scan_str
  implicit none
  private
  
  public :: scan_int_str
  public :: scan_real_str
  public :: scan_dble_str
  
  integer, parameter :: len_int  = 4
  integer, parameter :: len_real = 4
  integer, parameter :: len_dble = 8
  
contains


subroutine scan_int_str( &
      &   n_file_in &
      & , loc &
      & , scanned_int &
  & )
  implicit none
  integer, intent(in) :: n_file_in
  integer, intent(inout) :: loc
  integer, intent(out) :: scanned_int
  !!------------------------------
  
  read(n_file_in, pos=loc+1) scanned_int
  loc = loc +len_int
  
  return
endsubroutine scan_int_str


subroutine scan_real_str( &
      &   n_file_in &
      & , loc &
      & , scanned_real &
  & )
  implicit none
  integer, intent(in) :: n_file_in
  integer, intent(inout) :: loc
  real(4), intent(out) :: scanned_real
  !!------------------------------
  
  read(n_file_in, pos=loc+1) scanned_real
  loc = loc +len_real
  
  return
endsubroutine scan_real_str


subroutine scan_dble_str( &
      &   n_file_in &
      & , loc &
      & , scanned_dble &
  & )
  implicit none
  integer, intent(in) :: n_file_in
  integer, intent(inout) :: loc
  real(8), intent(out) :: scanned_dble
  !!------------------------------
  
  read(n_file_in, pos=loc+1) scanned_dble
  loc = loc +len_dble
  
  return
endsubroutine scan_dble_str


endmodule mod__scan_str

注意事項

正直、自分は kind 関係のことはよくわかってない。なので len_int とかのとこはたぶん本当は selected_int_kind とかなんとかやるべきなんだろうけど(環境依存性に対処するために?)、 4 とかベタ書きしちゃってる。

テストコード

上のモジュールをテストするためのコード。

include 'mod__open_to_read.f90'
include 'mod__open_to_write.f90'
include 'mod__scan_str.f90'

module mod__sub
  use mod__open_to_read, only : open_to_read_unform_str
  use mod__open_to_write, only : open_to_write_unform_str_rewind
  use mod__scan_str
  implicit none
  private
  
  public :: main_part
contains


subroutine main_part
  implicit none
  integer, parameter :: n_int  = 1 !! テスト用変数の数。任意。以下同様
  integer, parameter :: n_real = 2
  integer, parameter :: n_dble = 3
  integer :: arr_int( n_int)
  real(4) :: arr_real(n_real)
  real(8) :: arr_dble(n_dble)
  
  !! temporary
  integer :: i
  
  !! 現在位置
  integer, save :: loc
  
  !! file numbers & names
  integer, save :: n_file_out
  integer, save :: n_file_in
  character(len=72), save :: file_out
  character(len=72), save :: file_in
  
  !! 結果の表示
  integer :: scanned_int
  real(4) :: scanned_real
  real(8) :: scanned_dble
  !!-------------------
  
  !! set numbers
  do i=1,n_int
    arr_int(i) = i
  enddo
  
  do i=1,n_real
    arr_real(i) = real(i,4)
  enddo
  
  do i=1,n_dble
    arr_dble(i) = dble(i)
  enddo
  
  
  !! unformatted, stream で書き出し
  n_file_out = 30
  file_out = 'unformatted_stream.dat'
  call open_to_write_unform_str_rewind( n_file_out, file_out )
    write(n_file_out) (arr_dble(i)*1, i=1,n_dble)
    write(n_file_out) (arr_real(i)*1, i=1,n_real)
    write(n_file_out) (arr_int(i) *1, i=1,n_int )
  close(n_file_out)
  
  
  
  !! 上で書き出したものを読み込んで表示し、確認する
  n_file_in = 40
  file_in = file_out
  call open_to_read_unform_str( n_file_in, file_in )
    
    !! save 属性指定するだけで 0 に初期化されるが、念の為に再度初期化しておく。
    loc = 0
    
    !! 以下の読み込み順は write した時に合わせないともちろんダメ
    
    !! double
    do i=1,n_dble
      call scan_dble_str(n_file_in,loc,scanned_dble) !! intent(in,inout,out)
      write(*,*) scanned_dble
    enddo
    
    !! real
    do i=1,n_real
      call scan_real_str(n_file_in,loc,scanned_real) !! intent(in,inout,out)
      write(*,*) scanned_real
    enddo
    
    !! integer
    do i=1,n_int
      call scan_int_str(n_file_in,loc,scanned_int) !! intent(in,inout,out)
      write(*,*) scanned_int
    enddo
    
  close(n_file_in)
  
  return
endsubroutine main_part


endmodule mod__sub


program test_unform_str
  use mod__sub, only : main_part
  implicit none
  
  call main_part
  
  stop
endprogram test_unform_str

ただしここで、以下のファイルオープンモジュール(read用、write用)を使っている。

read用

module mod__open_to_read
  implicit none
  private
  
  public :: open_to_read__run
  public :: open_to_read_unform_seq
  public :: open_to_read_unform_str
  
contains

subroutine open_to_read__run( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber            !! filenumber to assign
  character(len=72), intent(in) :: filename_in !! filename as variable (not the actual text file name)
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  
  !! file open, w/ error handling
  ! open(filenumber,file=filename_in,status="old",iostat=istat,form="formatted",position="rewind",action="read")
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "read" &
      & , status   = "old" &
      & , position = "rewind" &
      & , form     = "formatted" &
      ! & , access   = "sequential" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a48,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_read__run


subroutine open_to_read_unform_seq( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber        !! filenumber to assign
  character(72), intent(in) :: filename_in !! filename as variable (not the actual text file name)
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  
  !! file open, w/ error handling
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "read" &
      & , status   = "old" &
      & , position = "rewind" &
      & , form     = "unformatted" &
      & , access   = "sequential" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a48,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_read_unform_seq


subroutine open_to_read_unform_str( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber        !! filenumber to assign
  character(72), intent(in) :: filename_in !! filename as variable (not the actual text file name)
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  
  !! file open, w/ error handling
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "read" &
      & , form     = "unformatted" &
      & , access   = "stream" &
      & , status   = "old" &
      & , position = "rewind" &
  & )

  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a48,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_read_unform_str


endmodule mod__open_to_read

write用

module mod__open_to_write
  implicit none
  private
  
  public :: open_to_write_form_rewind       !! formatted, rewind
  public :: open_to_write_form_append       !! formatted, append
  public :: open_to_write_unform_seq_rewind !! unformatted, sequential, rewind
  public :: open_to_write_unform_seq_append !! unformatted, sequential, append
  public :: open_to_write_unform_str_rewind !! unformatted, stream,     rewind
  
contains


subroutine open_to_write_form_rewind( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber
  character(len=72), intent(in) :: filename_in
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "write" &
      & , form     = "formatted" &
      & , status   = "replace" &
      & , position = "rewind" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a36,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_write_form_rewind


subroutine open_to_write_form_append( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber
  character(len=72), intent(in) :: filename_in
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "write" &
      & , form     = "formatted" &
      & , status   = "old" &
      & , position = "append" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a36,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_write_form_append


subroutine open_to_write_unform_seq_rewind( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber
  character(len=72), intent(in) :: filename_in
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "write" &
      & , form     = "unformatted" &
      & , access   = "sequential" &
      & , status   = "replace" &
      & , position = "rewind" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a36,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_write_unform_seq_rewind


subroutine open_to_write_unform_seq_append( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber
  character(len=72), intent(in) :: filename_in
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "write" &
      & , form     = "unformatted" &
      & , access   = "sequential" &
      & , status   = "old" &
      & , position = "append" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a36,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_write_unform_seq_append


subroutine open_to_write_unform_str_rewind( filenumber, filename_in )
  implicit none
  integer, intent(in) :: filenumber
  character(72), intent(in) :: filename_in
  integer :: istat=0
  !!---------------------
  
  write(*,"(2x,'opening [ ',a48,' ]... ',$)") filename_in
  open( &
      &   unit     = filenumber &
      & , file     = filename_in &
      & , iostat   = istat &
      & , action   = "write" &
      & , form     = "unformatted" &
      & , access   = "stream" &
      & , status   = "replace" &
      & , position = "rewind" &
  & )
  
  if( istat == 0 ) then
    write(*,"('... [ ',a48,' ] was successfully opened.')") filename_in
    return
  else
    write(*,"(/,2x,'Error: The file  [ ',a36,' ] ',/,' does not exist (istat =',i2,'). Aborting...',/)") filename_in, istat
    stop
  endif
  
  return
endsubroutine open_to_write_unform_str_rewind


endmodule mod__open_to_write

汚いけど、とりあえず公開。あ、こういうのこそ github 使うべきなのか…(いまさら)

実行結果

こんな感じになるはず

$ ./a.exe
  opening [ unformatted_stream.dat                           ]... ... [ unformatted_stream.dat                           ] was successfully opened.
  opening [ unformatted_stream.dat                           ]... ... [ unformatted_stream.dat                           ] was successfully opened.
   1.0000000000000000
   2.0000000000000000
   3.0000000000000000
   1.00000000
   2.00000000
           1

Fortranで出力したデータを、call system() とシェルスクリプトを使ってその場ですぐに xz で圧縮し、元データは削除する

まえがき

前にも書いたかもだけど忘れそうなのでメモしとく。

まず Fortran 側で FV_00001.xyz, ...(グリッド)とか FV_00001.func, ...(流れ場)とか FV_00001.q, ...(時刻)といったファイルを出力している。これらは流れの可視化用のデータで、そのままだとでかい。計算機からローカルへの転送時間を短縮したいというのもあるけど、それ以上に、計算機自体の/homeディレクトリの節約のために、計算を続けながら、その場ですぐに圧縮したい。圧縮には xz を使ってるけど、お好みで gzip なり bzip2 なりにしてください。

前に書いた
システムコールとシェルスクリプトを利用して、Fortranのコードから「ディレクトリがなければ作る」を実行 - dynamicsoarの日記

natures flyers: Fortran で call system() するときに変数 (variable) を渡す方法
も参照。

注意点

Fotran 側でやるのは「シェルスクリプトのコール」までであって、圧縮作業は別のプロセス(ジョブ)になる。なので、特に OpenMP(というか並列計算)してるときは、圧縮のためにスレッドを使うので、ファイルサイズによっては流れ場計算の方が多少遅くなる可能性がある。なので、/home のサイズに余裕があるならこんなことしないで、計算終わってから一気に圧縮した方が流れ場計算は速い気がする(計算が全部終わってから、全部のファイルを圧縮するスクリプトをコールすればよい)。

Fortran側のコード

変数の意味

n_file_FV
ファイルの番号(連番)で、保存するごとに増えてくやつ
if_compress_FV_grid, if_compress_FV_flow, if_compress_FV_q
いずれも設定ファイルから読み込むパラメタ (integer) で、0, 1, 2 のいずれかを取る。意味は、0=圧縮しない, 1=圧縮してオリジナルデータは残す, 2=圧縮してオリジナルデータは削除。本来の目的からいって、僕は基本的には 2 を使ってるけど、グリッドの位置調整とかには 0 が便利だし、容量節約よりも計算機上での可視化&後でのデータ転送高速化を目的として 1 を使うこともある。

グリッド保存用サブルーチン

  !! ファイル名(パスを含む)を設定
  write(out_grid,"('./output/FV_grid/FV_',i5.5,'.xyz')") n_file_FV
  <実際の出力作業は省略>

  !! 圧縮
  write(command,"('sh ./src/compress_output_file.sh ',i1,1x,'grid',1x,i5.5)") if_compress_FV_grid, n_file_FV
  call system(command)

流れ場保存用サブルーチン

function ファイルなんだけど僕らは伝統的に q ファイルでなくこっちに流れ場を書いてるので。

  !! ファイル名(パスを含む)を設定
  write(out_func,"('./output/FV_func/FV_',i5.5,'.func')") n_file_FV
  <実際の出力作業は省略>

  !! 圧縮
  write(command,"('sh ./src/compress_output_file.sh ',i1,1x,'func',1x,i5.5)") if_compress_FV_func, n_file_FV
  call system(command)

その他データ(自分の場合は時刻のみ)保存用サブルーチン

  !! ファイル名(パスを含む)を設定
  write(out_q,"('./output/FV_q/FV_',i5.5,'.q')") n_file_FV
  <実際の出力作業は省略>

  !! 圧縮
  write(command,"('sh ./src/compress_output_file.sh ',i1,1x,'q',1x,i5.5)") if_compress_FV_q, n_file_FV
  call system(command)

いま考えたらこれら3つのサブルーチンはまとめるべきだな…ほとんど同じなんだから。まぁとりあえずこのまま書いておく。

シェルスクリプト側のコード

シェルスクリプトbash以外は知らないが)ではイコールの前後に半角スペースを入れたらダメなので注意。参考:bashの変数代入の=の前後にスペースを入れてはいけない理由 - mollifier delta blog

compress_output_file.sh

これが Fortran の call system() で呼ばれる。引数を3つ取る。if_compress_FV_grid/func/q と、ファイルの種類と、n_file_FV の3つ。
そのまま functions.sh という別のファイルにある compress_output_file という関数に全部横流しする(だけ)。

#!/bin/bash

## 関数の読み込み
. ./src/functions.sh

compress_output_file $1 $2 $3

functions.sh

compress_output_file の部分のみ抜粋。他にもいろいろな関数をまとめておいている。

#!/bin/bash

#// if_compress: 0=no compress; 1=compress only; 2=compress & delete original file
#// kind: either one of: "grid", "func", or "q"
#// FVnum: FV number(Fortran側でいう n_file_FV)
#// option: xz のオプション。要は -k を使うかどうか
#//  参考: http://shellscript.sunone.me/case.html
compress_output_file()
{
  # 引数を変数にセット
  if_compress=$1
  kind=$2
  FVnum=$3
  
  ## if_compress に応じて、圧縮の際の option をセット
  case ${if_compress} in
    0 ) return ;; ## 何もしないで関数を抜ける
    1 ) option="-f -k" ;; ## 圧縮。元ファイルは残す
    2 ) option="-f" ;;   ## 圧縮 & 元ファイル削除
    * ) "Something's wrong. Check [compress_output_file] in ./src/functions.sh" ;; ## * は case default の意味
  esac
  
  ## ファイルの種類に応じた圧縮作業
  case ${kind} in
    "grid" )          xz ${option} ./output/FV_${kind}/FV_${FVnum}.xyz & ;; # {kind}はgridなんだけど拡張子はxyzなので場合分けしてる。
    "func" | "q" )    xz ${option} ./output/FV_${kind}/FV_${FVnum}.${kind} & ;; # | は or の意味
    * ) "Something's wrong. Check [compress_output_file] in ./src/functions.sh" ;;
  esac
}

「ハチドリは一秒間に80回も羽ばたく」は本当か → たぶん本当だけど一般的な速さではなく、上限付近

ちょくちょく出典なしで出てくる表現なので、気になったので調べてる。まだ途中だけどたぶんいまメモっとかないと永遠に書かないので書いとく。

羽ばたき回数の計測例

自分の Mendeley に入ってた論文のうち、ハチドリの「ホバリング前進速度0)」について軽く調べたところ、

  • 7種(6研究グループ程度)
  • 体重 3-5 g 程度
  • 翼長(片翼)50-70 mm程度
  • 羽ばたき周波数(1秒間の羽ばたき回数)は 30-50 Hz 程度

だった。ただし主に北米のハチドリ (ruby-throated, rufous, Anna's が多い)である点には注意が必要かもしれない。

References(順番はランダム)

  • Hedrick, T. L., Cheng, B., & Deng, X. (2009). Wingbeat Time and the Scaling of Passive Rotational Damping in Flapping Flight. Science, 324(5924), 252–255. 

    http://doi.org/10.1126/science.1168431

  • Altshuler, D. L., Quicazán-Rubio, E. M., Segre, P. S., & Middleton, K. M. (2012). Wingbeat kinematics and motor control of yaw turns in Anna’s hummingbirds (Calypte anna). Journal of Experimental Biology, 215(Pt 23), 4070–4084. 

    http://doi.org/10.1242/jeb.075044

  • Tobalske, B. W., Warrick, D. R., Clark, C. J., Powers, D. R., Hedrick, T. L., Hyder, G. A., & Biewener, A. A. (2007). Three-dimensional kinematics of hummingbird flight. Journal of Experimental Biology, 210, 2368–2382. 

    http://doi.org/10.1242/jeb.005686

  • Chai, P., & Dudley, R. (1995). Limits to vertebrate locomotor energetics suggested by hummingbirds hovering in heliox. Nature. 

    http://doi.org/10.1038/377722a0

  • Personal observation
  • あと他にも多少はありそうだけどあんまり違いが期待できないのでやめた

じゃあ 80 Hz って何よ

ググったところ、80 Hz というのはどうやら Greenewalt という有名なアマチュア研究者による Hummingbirds という本(1960 年)にあるらしく、これは最小のハチドリである bee hummingbird(Mellisuga helenae, マメハチドリ)についてらしい。残念ながらこの本はまだ読めてない。体重は 1.6-2 g とのこと(英語版 Wikipedia 情報)。

傾向として、体重が小さい(軽い)ほど周波数が大きいのはわかるし、翼長も短くなるのだから、80 Hz が異常に高速とは言えない。

というわけで、日本語版ウィキペディアハチドリ に今現在書いてあるように 80 Hzは「最大で」なのではないかというのが一応の結論。

ただ、既述したように今回調べられたのは北米の種が多くて、実際には南米の方が種としては(個体数も?)たくさんいることを考えると、「30-50 Hzが一般的」と言い切るにはまだ早いかもしれない。でも「80 Hz が一般的」というのはちょっと誤解に近いのではないかと。まぁ30 Hzでも肉眼で動きは見えないけどね…

200 Hz !?

あと、Handbook of the Birds of the World - Volume 5 という本には 200 Hz という記述があるらしい。しかも、 bee hummingbird ではなく北米でよく研究されているはずの rufous hummingbird(ふつうの論文は 40 Hz程度)でそれとか…ちょっと信じがたい。

というか200 Hzってハチ(ミツバチが190-230 Hz程度)とかハエショウジョウバエで220 Hz程度)の領域で、筋肉の出力の限界から厳しいのでは?という気がする。少なくとも継続的には。翼端の平均速度は周波数に比例して、抗力が速度の2乗に比例するから、80 Hz の時に比べても抗力が4倍以上にもなるわけだ。更にパワー(仕事率)は速度の3乗に比例…。しかもおそらく rufous の方が bee より翼が多少は長いし重いはずで…。うーん……。一瞬なら出せるのかなぁ…?

余談:翼端速度は音速より十分小さい

なお、

  • 翼長(片翼) 50 mm
  • 羽ばたき振幅 140 deg(やや控えめ。max は 180 度超える)
  • 羽ばたき周波数 200 Hz

の場合でも、羽ばたき運動にサイン波を仮定すると翼端の速度は平均で 50 m/s 程度、最大の瞬間でも 80 m/s 程度なので、音速よりは十分に小さく(海面上標準大気くらいの状況で、それぞれ M = 0.14, 0.24 程度)、圧縮性の影響は考慮しなくて良さそう。アンデスの高地だと音速ちょっと低いけどまぁ大丈夫でしょう…。

ホバリングできる羽ばたき周波数の下限は?

じゃあ逆に一番ゆっくり羽ばたいてホバリングできるのは?というのが気になるところ。最大のハチドリである giant hummingbird(Patagona gigas, オオハチドリ)は 15 Hz とのこと(英語版 Wikipedia 経由だけど論文があった→ http://dx.doi.org/10.1016/0010-406X(67)90342-8 )。

これが下限なのかはハッキリわからないけど、たとえばトンボで 35 Hz程度、スズメガが25 Hz程度、チョウ*1で10-15 Hz程度(いずれも種によって違うが)、ということですでにこれらよりも低い。体重も 19.1 g とツバメくらいある。とんでもねーな。研究してみたい感はあるけど南米行かなきゃか。

 

*1:butterfly frequency で google scholar すると人間の遊泳ばっかりヒットした… "stroke frequency" でもダメ(←これたぶん両者とも困る)。"wingbeat freqeuency" ならいける。

Win 7 (Enterprise) が夜中に勝手にリスタートされてた → Group Policy で No auto-restart を Enabled してみた

今回だけならいいのだが、最近どうも頻繁すぎて、毎回フォルダとかアプリを色々立ち上げ直しになるので、困る。普段は Windows+L で画面ロックだけして帰宅するので。

 

環境は、Windows 7 Enterprise 64 bit.

 

まず Event Viewer で Windows Logs > System 内を見たところ、

Level: Information

Date: 今日の朝ごろ

Source: USER32

Event ID: 1074

Task Category: None

として、

The process C:\windows\system32\svchost.exe (myPC) has initiated the restart of computer myPC on behalf of user NT AUTHORITY\SYSTEM for the following reason: Operating System: Recovery (Planned)
Reason Code: 0x80020002
Shutdown Type: restart
Comment:  

 というのがあった。これでググると、

www.windows-noob.com

てのが見つかった。エラーではないので止められるということか。ほんとにこれで直るかわからんけどやってみるか。しかし Group Policy というのが admin でないと見ることしかできない。場所がわからん。

Control Panel\All Control Panel Items\Administrative Tools

にもエイリアスないし。ちょっとググったら、

C:\windows\SysWOW64\gpedit.msc

というのが本体と判明。これを右クリックから Run as admin して実行。あとはリンク先の画像の通り、

Computer Configuration > Administrative Templates > Windows Components > Windows Update

と下って行き、

No auto-restart with logged on users for scheduled automatic updates installations

をダブルクリック、左上の方にあるラジオボタンを Enabled に変えた。これで解決するといいんだが。まぁといってもたまには再起動しないとまずいんだけども。

 

ところでこれとは別に、ロック画面で放置してたらスリープ→復帰→スリープってのを30分ごとくらいに繰り返していて、不穏だったのだが、Event Viewer で見たらどうも Ethernet が起こしてるようだ。うーむ。ていうか電源の設定で Never sleep に設定した気がしてたんだがなぁ…これもなんとかした方がいいか…