【雑記】50cc 原付 YAMAHA JOG SA36J メンテナンス

前置き

20年前ぐらいに買って、走行距離12000 kmのヤマハの原付 New JOG SA36Jのメンテナンスを行いました。最近2か月ほど乗っていなかったこともあってかバッテリが上がってしまい、充電したのですがすぐにまたバッテリ上がりになってしまいました。バッテリーがダメになったのでしょう。そこで、バッテリー交換をするついでに、いつ交換したのかよく覚えていない部分も見ておきました。その記録です。

メンテナンス

 下記のとおり。

  • オイル: きれいだったので交換せず
  • プラグ: NGKのCR7E。それほど黒くはなかったが、交換。ネジ部にローコルペーストをつけた。
    • ローコルペーストは、二硫化モリブデン (MoS2) でできた潤滑剤。焼き付き防止に使われる。
    • 今回使ったのは、住鉱潤滑剤 (SUMICO) 株式会社製の、私が持っていたかなり古いもの。200℃程度でベーキングする真空装置のネジ部に塗っていた。「ルブリカント」と呼んでいた。
    • いま入手するとなると、やはりSUMICO製で、モリペーストASかBNが適当だろう(耐熱1100℃まである)。BNならばスプレータイプもあるが、少数本のネジに塗るだけなら不要だと思う。
    • 点火プラグにグリスを塗るというのは、する人もいればしない人もいる。そもそも不要だという人もいれば、グリスのせいで規定トルクよりも強く締め付けることになるからプラグを傷める、という人もいる。
    • 50cc原付は製造されなくなったし、長期にわたることになろうメンテナンスを考えて、今回はローコルペーストを塗布した。
  • バッテリ: GS Yuasa YT4L-GS相当のところ、YT5L-GS相当のものを間違えて注文してしまった。高さが違うだけなのですが入りました。ケーブル類が少し窮屈になった。
    • 注文したのは、中国系のRAIJIN BATTERYという会社のもの。GS YUASAのものより3割ぐらい安かった。
    • 調べたら、つけていたバッテリーGS Yuasa YT4L-GSは2024年2月に購入していた。つまり、1年8か月前だ。こんな2年ももたないんだったら、中国メーカー製でも変わらないでしょう、と思う。
  • エアフィルタ: たいして汚れていなかったので交換せず。
    • 一応、KITAKOのJOG(3P3)を用意した。純正だと5ST-E4451-00が型番。

オイル

オイルの状態。たいして汚れていなかったので交換しない。

プラグ

プラグの状態。左が新品、右が使用していたもの。中央の円筒部がほとんど摩耗していなかったこと、その付け根のガイシ部がそれほど黒くなっていなかったことから、たいして悪くなっていないと思った。今回は、念のため交換。

プラグのネジ部に、ローコルペーストを塗った。塗るか塗らないかは議論があるところだが。

バッテリ

左がいままで使っていたYT4L-BS。右が新しく買った中国製のバッテリ。2680円。間違えて買ってしまいました。高さが違います。さて、入るかどうか。

なんとか入りました。よかった。

エアフィルタ

エアフィルタ。たいして汚れていないので、今回の交換は見送ることにしました。

2025-12-15 【試験研究】第一原理計算セットアップ(8)VASP 6.5.1インストール/サポートプログラムのインストールまとめ

VASP.6.5.1構築

  • VASP 6.5 releasedは2024年12月20日(金)だったが、油断をしていたら、2025年3月11日のタイムスタンプで、VASP 6.5.1が出ていた。
  • 更新された点はVASP WikiのChangelogを参照。
  • これまではサポートプログラムのインストール方法をバラバラに説明していたが、ここではまとめた形で紹介する。

VASP.6.5.1 構築手順

  • サポートプログラムのインストール (この文書の最後にまとめて書いてある)
  • vasp.6.5.1.tar.gzをダウンロード
  • Intel compilerは、2023年度にiccなどが廃止になっている。CC, FCを指定してconfigureする。

展開と準備

tar zxvf vasp.6.5.1.tar.gz
cd vasp.6.5.1
cp arch/makefile.include.intel makefile.include

makefile.include

makefile.include.intelの最下行に、# For machine learning library vaspml (experimental)というのがあり、コメントアウトしてコンパイルオプションを選ぶようになっていた。とりあえず、コメントアウトのままとする。

# For machine learning library vaspml (experimental)
#CPP_OPTIONS += -Dlibvaspml
#CPP_OPTIONS += -DVASPML_USE_CBLAS
#CPP_OPTIONS += -DVASPML_USE_MKL
#CPP_OPTIONS += -DVASPML_DEBUG_LEVEL=3
#CXX_ML      = mpiicpc -cxx=icpx
#CXXFLAGS_ML = -O3 -std=c++17 -Wall
#INCLUDE_ML  =

makefile.includeの変更点は下記のとおり。

FC          = mpiifx
FCL         = mpiifx
CC_LIB    = icx
CXX_PARS    = icpx

# HDF5-support (optional but strongly recommended)
CPP_OPTIONS+= -DVASP_HDF5
HDF5_ROOT  ?=  /usr/local/hdf5-1.14.4
LLIBS      += -L$(HDF5_ROOT)/lib -lhdf5_fortran
INCS       += -I$(HDF5_ROOT)/include

# For the VASP-2-Wannier90 interface (optional)
CPP_OPTIONS    += -DVASP2WANNIER90
WANNIER90_ROOT ?= /usr/local/vasp/tools
LLIBS          += -L$(WANNIER90_ROOT)/lib -lwannier

makeとmake test

time make DEPS=1 -j4
time make test
time make test_all
  • time make DEPS=1 -j4などと、timeをつけているのは実行時間を計測するため。計測しないのなら不要。
  • make cleanがないので、rm -rf buildとする。
  • testのクリーンアップは、cd testsuite; make cleantest; cd ..とする。
  • ubuntuにはデフォルトでは管理用のpython3はあるが、pythonがない。testsuitesディレクトリ内のruntestではpythonとなっているので、ubuntuではエラーが出てしまう。
    • pythonを自分でインストールし、runtest内のpythonとなっている部分を、/usr/local/bin/python3.13などとして指定する必要がある。runtestの1597行以降。
    • cat runtest | sed s/python/python3.13/g > runtest-p, mv runtest runtest.org, mv runtest-p runtest, chmod 775 runtestとする。
    • 環境変数PYTHON_EXEによる指定はmake testでは効かない。

make testの結果

  • Core i7-14700 (2.1 GHz-5.3 GHz/ 20 cores/ 28 threads), DDR5-4800 16GBx2, 1TB-SSD
    • 所要時間は、real 21m0.654s, user 78m 18.341s, sys 1m52.679s。ALL SELECTED TESTS PASSWDだった。
  • Core i7-13700F (1.5 GHz-5.2 GHz/ 16 cores/ 24 threads), DDR4-3200 16GBx2, 500GB-SSD(NVMe Gen3)
    • 所要時間は、real 25m4.287s, user 92m 25.139s, sys 3m24.198s。ALL SELECTED TESTS PASSWDだった。

make test_allの結果

  • Core i7-14700 (2.1 GHz-5.3 GHz/ 20 cores/ 28 threads), DDR5-4800 16GBx2, 1TB-SSD
    • 所要時間は、1時間44分だった。(timeコマンドを使わずに時計で。)
  • Core i7-13700F (1.5 GHz-5.2 GHz/ 16 cores/ 24 threads), DDR4-3200 16GBx2, 500GB-SSD(NVMe Gen3)
    • 所要時間は、1時間58分だった。(timeコマンドを使わずに時計で。)
  • テストが通らなかったのは下記のテスト。Core i7-14700, Core i7-13700Fともに同じエラー。
    • bulk_BN_PBE_Libxc : libxcを入れていないため
    • bulk_BN_PBExSCANc_Libxc : libxcを入れていないため
    • bulk_BN_SCAN_Libxc : libxcを入れていないため
    • mlwf_lif_scdm_optics : フッ化リチウム(LiF)の誘電率の計算の例。VASP6.4.3のときからエラーが出る。NaNの扱いの問題だと思う。

特定のテストのみをしたいとき

  • export VASP_TESTSUITE_TEST="elphon_lif_allinone"としてから、make testとする。
  • 環境変数解除は unset VASP_TESTSUITE_TEST とする。

インストール

  • sudo makedir /usr/local/vasp/vasp651mpibin
  • sudo cp bin/* /usr/local/vasp/vasp651mpibin

適当なディレクトリ(foo)を切り、そこで動くかどうかをテストする。

  • mkdir foo
  • cd foo
  • /usr/local/vasp/vasp651mpibin/vasp_std
  • ERRORが大きく表示される。

ポテンシャルファイルのインストール

PAW54

mkdir pot
cd pot
tar zxvf ../potpaw_PBE.54.tar.gz
sudo mkdir /usr/local/vasp/potpawPBE54
sudo mv * /usr/local/vasp/potpawPBE54
ls /usr/local/vasp/potpawPBE54
rm -rf *
tar zxvf ../potpaw_LDA.54.tar.gz
sudo mkdir /usr/local/vasp/potpawLDA54
sudo mv * /usr/local/vasp/potpawLDA54
ls /usr/local/vasp/potpawLDA54
cd ..
rmdir pot

サポートプログラムのインストールまとめ

Intel OneAPI (Intel Fortran, C, C++, MKL)

  • GPU driverを入れておく(不要かもしれないが念のため)。Installing Data Center GPUUbuntuページに書いてある手順どおり。丁寧に書かれている。
  • Intel® oneAPI Toolkits Installation Guide for Linux* OSに手順が書いてある。インストールするのは、最低限、下記の2つ。下の方に、Get Started Intel oneAPI Base Toolkitというページがある。(リンクを示さないのは、同一コンテンツに見えるがバージョン管理されたページになっているため、固定リンクだと古いものを参照してしまうから。)
    • Intel® oneAPI Base Toolkit
    • Intel® oneAPI HPC Toolkit
  • 一度インストールすると、upgradeがあるとsudo apt upgradeIntel Compiler, MKLも更新してもらえる。

Python

  • VASPではmake test_allで使う。VASPで使わなくても入れておいたほうがいい。
  • Ubuntuでのpythonは/usr/bin/python3に入っているが、これはシステム管理用なので、触らない。
  • ソースをダウンロードして、コンパイルする。あらかじめaptで入れておくものがあるので入れておく。
sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev
sudo apt install liblzma-dev libgdbm-compat-dev tk-dev libzstd-dev
 wget https://www.python.org/ftp/python/3.13.11/Python-3.13.11.tgz
tar zxvf Python-3.13.11.tgz
cd Python-3.13.11
./configure --enable-optimizations
make -j4
make test
sudo make altinstall
  • Pythonコンパイル前にlzma関係のライブラリをインストールする。VASP計算の支援ソフトviseを使うときに要求される。
    • libzstd-devは3.14以降で必要になる。
  • configure時に、--prefix=を指定していないので、/usr/local/bin/python3.13がバイナリとなる。
  • make -j4は、4並列でコンパイルするということ。
  • sudo make installではなく、sudo make altinstallとして、pip3.13でユーザー権限でモジュールをインストールできるようにしておく。
  • vaspのためには、pip3.13 install py4vaspをしておく。

zlib

  • データ圧縮/復元(伸張)のためのライブラリ。Deflate (RFC 1951) を実装している。
  • 2023年のインストールでは、zlibは ver. 1.3だった。
  • 2024年には1.3.1になっていた。
wget http://www.zlib.net/zlib-1.3.1.tar.gz
tar zxvf zlib-1.3.1.tar.gz
cd zlib-1.3.1
./configure --prefix=/usr/local
make
sudo make install

szip (不要)

  • データ圧縮/復元(伸張)のためのライブラリ。Deflate (RFC 1951) を実装している。
  • HDF5の生成に必要だが、HDF5を自分でインストールするならば不要。代わりにAEC (szlib)を入れることがHDF5開発サイドから要求されている。
    • HDF5の./configureオプションに--with-szlibとすることでszlibが導入される。
  • HDF5を、バイナリでインストールするとき、バイナリ側がszipを要求する場合があるかもしれないので、忘備録も兼ねてインストール方法を紹介する。。
wget  wget https://support.hdfgroup.org/ftp/lib-external/szip/2.1.1/src/szip-2.1.1.tar.gz
tar zxvf szip-2.1.1.tar.gz
cd szip-2.1.1
./configure --prefix=/usr/local
make
sudo make install

AEC (szlib)

  • HDF5は圧縮のためにgzip形式を使っているが、szlib形式も使われる可能性がある。念のためインストールしておく。
  • HDF5にszlibを入れるかどうかは、HDF5コンパイルの際の configure--with-szlib にて指定すると入る。
  • szlib形式については、HDF5のダウンロードページに、「HDF5はHDF5-1.10.7からAECライブラリをSZIP圧縮に使用している。AECはSZIPの実装を行った使用制限のないオープンソースである。SZIPを使ってもHDF5は動作するが、我々はAECライブラリを使うことを推奨する。」と記されている。
  • AEC (libaec) は、German Climate Computing Center が開発しており、gitからダウンロードできる。HDF5の開発チームは https://github.com/MathisRosenhauer/libaecからダウンロードしている。ここにアクセスするとgithubに飛ぶが、右上にあるCodeというところに飛んでzip形式をダウンロードすると良い。
  • cmakeが必要なので、which cmakeとしてcmakeの有無を確認し、なければsudo apt install cmakeとしてインストールする。
wget https://github.com/MathisRosenhauer/libaec/archive/refs/heads/master.zip
unzip master.zip
cd libaec-master
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
make
make test
sudo make install

これで、/usr/local/lib/libaec.soなどがインストールされる。

HDF5

HDF5 1.14

  • HDF5は、大規模データを取り扱うためのライブラリ。
  • zlib, szip, aec が必要。
  • 作業前に source /opt/intel/oneapi/setvars.sh が実行されて、コンパイラ関係の環境変数が設定されていることが必要。
wget https://github.com/HDFGroup/hdf5/releases/download/hdf5_1.14.4.3/hdf5-1.14.4-3.tar.gz
tar zxvf hdf5-1.14.4-3.tar.gz
cd hdf5-1.14.4-3/
FC=ifort ./configure --prefix=/usr/local/hdf5-1.14.4  --enable-fortran --enable-cxx --with-szlib=/usr/local
make
make check
sudo bash
source /opt/intel/oneapi/setvars.sh
make install
make check-install
exit
  • LD_LIBRARY_PATHのための設定は下記のとおり。.bashrcなどに入れておく。
export LD_LIBRARY_PATH=/usr/local/hdf5-1.14.4/lib:/usr/local/lib:$LD_LIBRARY_PATH

HDF5 2.0.0 (参考)

  • Nov. 10, 2025にHDF5は2.0.0になっていた。
  • インストールしてみたが、vasp 6.5.1ではコンパイルが通らなかったので参考までに記す。
  • cmakeはversion 3.26以上が必要。3.28だった。
  • hdf5のサイトからソースコードをダウンロードする。hdf5-2.0.0.tar.gz (40.1 MB)をPCにダウンロードしてから、ftpで。
  • tar zxvf hdf5-2.0.0.tar.gz
  • cd hdf5-2.0.0
  • sudo apt install ninja-build でNinjaというビルドツールをインストール。(なければ)
  • sudo apt install default-jdkJava Compilerをインストール。(なければ)
  • 下記の詳細は、release_docs/INSTALL_CMake.txtにある。
  • cmake --workflow --preset ci-StdShar-GNUC --fresh で、Linux/Mac with gccなビルドができる。
  • ../build/ci-StdShar-GNUCにインストールパッケージができている。
  • cd ../build/ci-StdShar-GNUC
  • sudo ./HDF5-2.0.0-Linux.sh --prefix=/usr/localとすると、/usr/local/HDF5-2.0.0-Linuxにインストールされる。ただし、実体は/usr/local/HDF5-2.0.0-Linux/HDF_Group/HDF5/2.0.0と、もっと深いところにあり、ここにbin, cmake, include, lib, mod, shareがある。

wannier90

  • Dec. 15, 2025現在、last stableはWannier90 (v.3.1.0)のままだった。このバージョンは、Mar. 5, 2020のリリース。
  • いろいろなパターンを試したが、make testsでエラーが1つ消えない。
    • 最善は、ifx使用、最適化はなし (-O0)、MKL使用の場合だった。
    • これが原因かはわからないが、vaspのmake test_allで、mlwf_lif_scdm_optics のテストが通らない。
    • 数値そのものが問題ではなく、nan (not a number) の処理の問題のようにも見える。
  • 手順は下記のとおり。
wget https://github.com/wannier-developers/wannier90/archive/v3.1.0.tar.gz
tar zxvf v3.1.0.tar.gz
cd wannier90-3.1.0/

下記の内容をmake.incとする。config/make.inc.ifortをmpi非対応版に改造したもの。

#=====================================================
# For Linux with intel version 11/12 on 64bit machines
#=====================================================
F90 = ifx
#COMMS=mpi
MPIF90=ifx
FCOPTS=-O0
LDOPTS=-O0

#========================================================
# Intel mkl libraries. Set LIBPATH if not in default path
#========================================================

LIBDIR =  /opt/intel/oneapi/mkl/latest/lib/intel64
LIBS   =  -L$(LIBDIR) -lmkl_core -lmkl_intel_lp64 -lmkl_sequential -lpthread

#=======================
# ATLAS Blas and LAPACK
#=======================
#LIBDIR = /usr/local/lib
#LIBS = -L$(LIBDIR)  -llapack -lf77blas -lcblas -latlas

続いて、make, そしてinstall (手動) する。

make; make lib
sudo mkdir /usr/local/vasp
sudo mkdir /usr/local/vasp/tools
sudo mkdir /usr/local/vasp/tools/lib
sudo cp libwannier.a /usr/local/vasp/tools/lib
sudo cp wannier90.x /usr/local/vasp/tools
sudo cp postw90.x /usr/local/vasp/tools

wannier90のtestsはpythonを使っている。しかしUbuntupythonは "python3" なので、 3つのファイルの1行目を "python"→"python3"とした。変更を加えたのは下記の3ファイル。

  • test-suite/clean_tests
  • test-suite/run_tests
  • test-suite/testcode/bin/testcode.py

make testsした結果、でエラーが1つ出た。下記のエラー。いろいろやったが消えなかった。たとえば gfortran にすると悪化した。

tests/testpostw90_pt_kpathbandsshc - Pt.win: **FAILED**.
shc
    ERROR: absolute error 1.08e-02 greater than 1.00e-02. (Test: -8.1625987.  Benchmark: -8.1517891.)
shc
    ERROR: absolute error 1.08e-02 greater than 1.00e-02. (Test: -8.719545.  Benchmark: -8.7303551.)
All done. ERROR: only 61 out of 62 tests passed.
Failed test in:
        /home/kuno/vasp-compile/wannier90-3.1.0/test-suite/tests/testpostw90_pt_kpathbandsshc/
make: *** [Makefile:186: test-serial] Error 1

libxc

  • libxcは7.0.0のままだった (2025/12/15)。vasp.6.5.1生成の際には更新せず。
  • 交換相関汎関数の汎用ライブラリ。現在進行形で議論・改良が進められている。vaspでは libxc1, libxc2 タグで動作を指定できる。交換相互作用の処理はvasp自身もいろいろもっているので重複する機能となる。HPC社のベンチマークからは、特には高速化されないというレポートがある。
  • 交換相互作用の処理方法は新しい方法が考案されており、up-to-dateなものを導入したいときはlibxcを使うほうが有利かもしれない。Quantum espressoからもlibxcを使うことができる。さらにはvaspのmake test_allすると libxc関係のテスト項目が結構ある。
  • 下記の手順で行った。あらかじめsudo apt install autogen autoconf libtool をしておくこと。configure生成のために必要である。(インストール手順にはそこまで書かれていない)
  • --disable-fhcはvaspに組み込むために必要だが、これのせいでmake checkでエラーが1つ出る。
  • /usr/local/vasp/toolsはなければmkdirする。
wget https://gitlab.com/libxc/libxc/-/archive/6.2.2/libxc-6.2.2.tar.bz2
bunzip2 libxc-6.2.2.tar.bz2
tar xvf libxc-6.2.2.tar
cd libxc-6.2.2
autoreconf -i
CC=icx FC=ifx ./configure --prefix=/usr/local/vasp/tools --disable-fhc
make
make check
sudo make install

make checkの結果、mgga_xc_otpss_dでFAILとなる。ここ1か所だけ。最適化オプションを -O0 にしても結果は同じである。

libbeef

  • とりあえず入れておくだけ。
  • githubにあるlibbeefのサイトから最新版をダウンロードする。[CODE]>{Download ZIP]から。2023年10月現在、6年ぐらいメンテされてない感じ。
  • 以下手順。デフォルトでは、/usr/local/libにインストールされる。ここでは、/usr/local/vasp/toolsにインストールする。toolsディレクトリはなければmkdirする。
unzip libbeef-master.zip
cd libbeef-master
./configure --prefix=/usr/local/vasp/tools
make
make install

ChatGPTの領収書に日本語コメントを入れるPythonスクリプト

作成経緯

 ChatGPTの有料プランは、今のところ月額払いしかありません。私費で立て替えて経費で落とすとき、毎月書類を提出しなければなりません。ドル建て金額が書かれた領収書はオンラインでダウンロードできるのですが、中身は英語の領収書 (Receipt) です。先日、私の職場の経理担当部署から、日本語コメントを記入することを求められました。日本のインボイス制度対応であることが分からないという理由からです。私のようなことを言われている人は多いのではと思い、ChatGPTのOpenAI社の領収書に日本語コメントを入れるPythonスクリプトを書いたので公開します。

簡単なものですが、位置合わせなどが面倒だったので、公開しようと思った次第です。Windowsを念頭に、メイリオフォントで日本語コメントを入れるものです。PDFにコメントを入れるスクリプトのサンプルとしてもお使い下さい。

メモ

  • 領収書のダウンロードは次のとおり。ブラウザのChatGPTの左に履歴欄があるが、その一番下の自分の名前のところをクリック、そして[パーソナライズ]をクリック。[アカウント]メニューから[支払い]の[管理する]をクリック。下に「請求書の履歴」が表示されるので、該当月をクリック。[領収書をダウンロード]をクリックすると "Receipt" がダウンロードされる。[請求書をダウンロード]もここにある。
  • ChatGPTのOpenAI社の適格請求書発行者情報はここにある。登録番号が大事。
  • インボイス対応の請求書/領収書とはどのようなものか?」については、国税庁のインボイス制度説明サイトにあるインボイス記載事項チェックシートを参照すると良い。

サンプル(赤字がコメント、最下部に国税庁のチェックシート画像を挿入した)

このスクリプトでコメントを入れた領収書

スクリプトのために用意するもの

  • Pythonに、PyMuPDFをpip install しておく。この記事を書いている時点でのバージョンは、pymupdf-1.26.4です。
  • OpenAI社の領収書。Receipt.pdfという名前になっていると仮定する。
  • 国税庁の説明画像を入れる場合には、Invoice.pngとして用意しておく。下記の画像です。

国税庁インボイス対応チェックシートにある説明画像

Pythonスクリプト

適当に改変しつつ使って下さい。receipt_withcomment.pdf というファイルが生成されます。

# pip install pymupdf
# 2025/9/5 pymupdf-1.26.4

import fitz   # PyMuPDF
import os

orgfilename = "./Receipt.pdf"
doc = fitz.open(orgfilename)
page = doc[0]
font = "C:/Windows/Fonts/meiryo.ttc"
page.insert_font(fontname="jpn", fontfile=font)

black = (0,0,0)
red = (1,0,0)
insert_texts = [
    ((120, 47), "領収書", 14, "jpn", red),
    ((200, 79), "請求書番号", 11, "jpn", red),
    ((200, 93), "取引年月日", 11, "jpn", red),
    (( 30,110), "発行者の名称,住所,登録番号", 11, "jpn", red),
    ((250,110), "宛名(請求先)", 11, "jpn", red),
    (( 30,220), "登録番号 T4700150127989", 11, "jpn", red),
    (( 30,270), "支払額と支払日", 11, "jpn", red),
    (( 75,292), "取引内容 (Chat GPT Plus Subscription, 数量 1, 単価 $20.00)", 11, "jpn", red),
    ((305,340), "取引の総額および適用税率", 11, "jpn", red),
    ((250,385), "消費税額", 11, "jpn", red),
    ((370,414), "取引の総額", 11, "jpn", red),
    ((100,490), "支払い方法", 11, "jpn", red),
    ((340,490), "支払日", 11, "jpn", red),
    ((470,490), "支払額", 11, "jpn", red),
]

for t in insert_texts:
    page.insert_text(t[0], t[1], fontsize=t[2], fontname=t[3], color=t[4])

# 画像埋め込み
rect = fitz.Rect(30,500,400,800)
page.insert_image(rect, filename="Invoice.png")

newfilename = os.path.splitext(os.path.basename(orgfilename))[0] + "_withcomment.pdf"
doc.save(newfilename)
doc.close()

2024-12-25 【試験研究】第一原理計算セットアップ(7)VASP 6.5.0インストール

VASP.6.5

  • 2024年12月20日(金)に、VASP Software GmbH (licensing@vasp.at) から、"VASP 6.5 released" の案内が来た。
  • すでにVASPのライセンスをもつ人はupgradeできる。私の場合はVASP 6.4のupgrade後なので無料でアップグレードできる。
  • 特徴は下記のとおり。
    • 電子格子相互作用 (electron-phonon coupling) の計算ができる。
    • VASP Pluginsの導入
    • Bethe-Salpeter Equation (ベーテ・サルピータ方程式) の取り扱い
    • その他
      • 交換相互作用関数の追加。MS-PBEI, TASK, xc-B-fieldなど。
      • Coulomb kernel truncationの計算の導入。ダイポール、2D物質や表面の計算に有効。論文は執筆中なので詳細は不明。
      • 機械学習関連の計算の誤差低減、他のファイル形式とのインターフェース改善、バグ修正など。

VASP.6.5 構築手順

  • サポートプログラムのチェック
    • 6.4.3をインストールしているのならば、作業はない。6.5.0から新規インストールの場合は、6.4.3の手順をまねる。szip, libxcは省略してよい。
    • hdf5はaptでも入るが、コンパイルして生成する必要がある。1.14.4を使うのが良い。
      • 1.14.5がリリースされていたが、./configureでfortran用ライブラリが生成されない、--prefixで指定したインストールディレクトリが存在しないときにmkdirされないなど、今のところ使い物にならない。
    • zlibはzlib 1.3.1 (January 22, 2024) のままだった。zlibはUbuntuにデフォルトで入っているものを使ってもよいが、インストールしてもよい。
    • szipは特に必要ない。インストールするのなら、AECをインストールすることをHDFが推奨している。
    • libxcは入れなくてもよい。VASPのmakefileのひな形から姿を消している。あまりメリットがないのだろう。
    • wannier90はバージョンアップがなかった。試していないが、aptでも入るようだ。

AEC (szlib)

HDF5は圧縮のためにgzip形式を使っているが、szlib形式も使われる可能性がある。 念のためインストールしておく。 なお、HDF5にszlibを入れるかどうかは、HDF5コンパイルの際の configure--with-szlib にて指定すると入る。

なお、szlib形式については、HDF5のダウンロードページに、「HDF5はHDF5-1.10.7からAECライブラリをSZIP圧縮に使用している。AECはSZIPの実装を行った使用制限のないオープンソースである。SZIPを使ってもHDF5は動作するが、我々はAECライブラリを使うことを推奨する。」と記されている。 AEC (libaec) は、German Climate Computing Center が開発しており、 gitからダウンロードできる。HDF5の開発チームは https://github.com/MathisRosenhauer/libaecからダウンロードしている。 ここにアクセスするとgithubに飛ぶが、右上にあるCodeというところに飛んでzip形式をダウンロードすると良い。 cmakeが必要なので、which cmakeとしてcmakeの有無を確認し、なければsudo apt install cmakeとしてインストールする。

wget https://github.com/MathisRosenhauer/libaec/archive/refs/heads/master.zip
unzip master.zip
cd libaec-master
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
make
make test
sudo make install

これで、/usr/local/lib/libaec.soなどがインストールされる。

VASP.6.5.0ダウンロード

  • vasp.6.5.0.tar.gzをダウンロードすると7.5 MBytesである。

展開と準備

tar zxvf vasp.6.5.0.tar.gz
cd vasp.6.5.0
cp arch/makefile.include.intel makefile.include

makefile.include

makefile.include.intelの最下行に、# For machine learning library vaspml (experimental)というのがあり、コメントアウトしてコンパイルオプションを選ぶようになっていた。とりあえず、コメントアウトのままとする。

# For machine learning library vaspml (experimental)
#CPP_OPTIONS += -Dlibvaspml
#CPP_OPTIONS += -DVASPML_USE_CBLAS
#CPP_OPTIONS += -DVASPML_USE_MKL
#CPP_OPTIONS += -DVASPML_DEBUG_LEVEL=3
#CXX_ML      = mpiicpc -cxx=icpx
#CXXFLAGS_ML = -O3 -std=c++17 -Wall
#INCLUDE_ML  =

makefile.includeの変更点は下記のとおり。

FC          = mpiifx
FCL         = mpiifx
CC_LIB    = icx
CXX_PARS    = icpx

# HDF5-support (optional but strongly recommended)
CPP_OPTIONS+= -DVASP_HDF5
HDF5_ROOT  ?= /usr/local/hdf5-1.14.4
LLIBS      += -L$(HDF5_ROOT)/lib -lhdf5_fortran
INCS       += -I$(HDF5_ROOT)/include

# For the VASP-2-Wannier90 interface (optional)
CPP_OPTIONS    += -DVASP2WANNIER90
WANNIER90_ROOT ?= /usr/local/vasp/tools
LLIBS          += -L$(WANNIER90_ROOT)/lib -lwannier

makeとmake test

  • time make DEPS=1 -j4などと、timeをつけているのは実行時間を計測するため。計測しないのなら不要。
  • testのクリーンアップは、cd test suite; make cleantest; cd ..とする。
  • testsuite/runtest にいくつかある pythonpython3 に変更する。
time make DEPS=1 -j4
time make test
time make test_all

test_allの結果

  • 所要時間は、135分=2時間15分でした。テスト内容が増えているようです。
  • テストに失敗したのは下記のテストです。一番下のエラーは6.4.3のときからです。誘電関数がうまく求まっていないようです。その他は、問題のないエラー(エラーになって当然のエラー)です。
    • bulk_BN_PBE_Libxc : libxcを入れていないため
    • bulk_BN_PBExSCANc_Libxc : libxcを入れていないため
    • bulk_BN_SCAN_Libxc : libxcを入れていないため
    • elphon_lif_allinone : testsuite/runtestのpythonをpython3にしていないため
    • elphon_si_allinone : testsuite/runtestのpythonをpython3にしていないため
    • mlwf_lif_scdm_optics : VASP.6.4.3のときからエラーが出る

【試験研究】RigakuのX線回折データファイル形式のRASとRASXをテキストデータに変換するPythonプログラム, Converting RAS and RASX files generated by Rigaku XRD machines to text files with measurement conditions as comments.

 Rigakuの薄膜用および粉末用X線回折装置のデータ記録には、現在、RASXファイルというファイル形式が採用されています。その特徴は下記の点です。

  • RASXファイルの実体はzipファイルである。拡張子を .rasx から .zip に変更してダブルクリックなどをすると分かる。
    • ファイルをバイナリで見ることでもすぐに分かります。私が行ったのはこちら。
  • RASファイルでは、複数の測定が単一のテキストファイルにブロック分けされて記録されていたが、RASXではフォルダに分かれて記録されている。
  • データはxmlで記録されている。
  • リガクからRASXやRAS形式をCSVに変換するプログラムが提供されている。しかし、測定条件がデータの中にコメントとして記録されない。

特に最後の点に問題を感じ、RASXファイルをテキストデータに変換するPythonプログラムを書きました。RASファイルも扱えます。測定条件をすべて書き出しているわけではありませんので、必要に応じて改造してください。使い方と特徴は下記のとおりです。

  • Pythonモジュールとして、zipfile, xml が必要ですので、pipなりcondaなりで入れておいてください。
  • RAS, RASXファイルがあるフォルダにこのプログラム (ras2dat_all.py) を置く。
  • 実行すると、プログラムのあるフォルダのRAS, RASXデータをすべて .dat に置き換えるという単機能動作をする。
    • ファイルダイアログが出てきたりはしない。昔は出てくるようにしていたが、面倒ということに気が付いた。
    • 強制なので、残したい .dat ファイルがある場合はご注意ください。
  • 測定条件はファイルの最初に、行頭に # がついた形で入っています。
    • たいていのグラフ描画ソフトではコメント行として読み飛ばされるはずです。
import os
import zipfile
import xml.etree.ElementTree as ET

def getFilename():
    root = tkinter.Tk()
    root.withdraw()
    fTyp = [("Rigaku Ascii", "ras")]
    iDir = os.path.abspath(os.path.dirname(__file__))
    filename = tkinter.filedialog.askopenfilename(filetypes=fTyp, initialdir=iDir)
    return filename

# get item from header
def getItem(str, lines):
    item = ""
    str += " "
    for line in lines:
        if line[0:len(str)] == str:
            item = line[len(str)+1:].replace('"', '')
    return item

def _ras2dat(headlines, datalines):
    output_data = []
    tmp1 = getItem("*MEAS_SCAN_START_TIME", headlines)
    tmp2 = getItem("*MEAS_SCAN_END_TIME", headlines)
    output_data.append("# Scan Date   : {0} - {1}\n".format(tmp1, tmp2))
    tmp1 = getItem("*FILE_SAMPLE", headlines)
    output_data.append("# File Sample : {0}\n".format(tmp1))
    tmp1 = getItem("*FILE_MEMO", headlines)
    output_data.append("# File Memo   : {0}\n".format(tmp1))
    output_data.append("# User Comment : \n")
    tmp1 = getItem("*MEAS_COND_OPT_NAME", headlines)
    output_data.append("# Optical     : {0}\n".format(tmp1))
    tmp1 = getItem("*HW_COUNTER_SELECT_NAME", headlines)
    output_data.append("# Counter     : {0}\n".format(tmp1))
    for ii in range(100):
        tmp1 = getItem("*MEAS_COND_AXIS_NAME-{}".format(ii), headlines)
        if len(tmp1) == 0:
            continue
        tmp2 = getItem("*MEAS_COND_AXIS_STATE-{}".format(ii), headlines)
        tmp3 = getItem("*MEAS_COND_AXIS_POSITION-{}".format(ii), headlines)
        tmp4 = getItem("*MEAS_COND_AXIS_UNIT-{}".format(ii), headlines)
        tmp5 = getItem("*MEAS_COND_AXIS_OFFSET-{}".format(ii), headlines)
        tmp6 = getItem("*MEAS_COND_AXIS_RESOLUTION-{}".format(ii), headlines)
        tmp2 = " (Scan)" if tmp2 == "Scan" else ""
        tmp6 = "resolution {0} {1}".format(tmp6, tmp4) if len(tmp6) != 0 else ""
        output_data.append("# Condition {0:24} : {1} {2} (offset {3}), {4}\n".format(tmp1+tmp2, tmp3, tmp4, tmp5, tmp6))
    tmp1 = getItem("*MEAS_SCAN_AXIS_X", headlines)
    output_data.append("# Data X axis : {0}\n".format(tmp1))
    tmp1 = getItem("*MEAS_SCAN_MODE", headlines)
    output_data.append("# Scan mode   : {0}\n".format(tmp1))
    tmp1 = getItem("*MEAS_SCAN_START", headlines)
    tmp2 = getItem("*MEAS_SCAN_UNIT_X", headlines)
    output_data.append("# Scan start  : {0} {1}\n".format(tmp1, tmp2))
    tmp1 = getItem("*MEAS_SCAN_STOP", headlines)
    tmp2 = getItem("*MEAS_SCAN_UNIT_X", headlines)
    output_data.append("# Scan stop   : {0} {1}\n".format(tmp1, tmp2))
    tmp1 = getItem("*MEAS_SCAN_STEP", headlines)
    scan_step = float(tmp1)   # deg/step
    tmp2 = getItem("*MEAS_SCAN_UNIT_X", headlines)
    output_data.append("# Scan step   : {0} {1}\n".format(tmp1, tmp2))
    tmp1 = getItem("*MEAS_SCAN_SPEED", headlines)
    tmp2 = getItem("*MEAS_SCAN_SPEED_UNIT", headlines)
    output_data.append("# Scan speed  : {0} {1}\n".format(tmp1, tmp2))
    scan_speed = float(tmp1) / 60.0    # deg/min -> deg/sec
    count2cps = scan_step / scan_speed   # sec/step
    output_data.append("# Scan time per step : {0:.3f}\n".format(count2cps))
    tmp1 = getItem("*MEAS_SCAN_UNIT_Y", headlines)
    output_data.append("# Scan Y unit : {0}\n".format(tmp1))
    tmp1 = getItem("*MEAS_SCAN_START_TIME", headlines)
    tmp2 = getItem("*MEAS_SCAN_END_TIME", headlines)
    tmp_date, tmp_starttime = tmp1.split(' ')
    tmp_endtime = tmp2.split()[1]
    output_data.append("# Scan Date and Time: {0} {1} - {2}\n".format(tmp_date, tmp_starttime, tmp_endtime))
    #-------------------------------------------------
    for line in datalines:
        tmp1, tmp2, tmp3 = line.split(' ')
        output_data.append("{0} {1:.3f} {2} {3}\n".format(tmp1, float(tmp2) * float(tmp3) / count2cps, tmp2, tmp3))
    return output_data

def ras2dat(filename):
    # read file 
    with open(filename, 'r') as fh:
        datalines = fh.readlines()
    for i in range(len(datalines)):
        datalines[i] = datalines[i].rstrip('\n')
    if datalines[0] != '*RAS_DATA_START':
        print("Not a RAS file.")
        return
    status = "none"
    blocks = []
    for dataline in datalines:
        if dataline == '*RAS_HEADER_START':
            status = "header"
            headblock = []
            continue
        if dataline == '*RAS_HEADER_END':
            status = "none"
            continue
        if dataline == '*RAS_INT_START':
            status = "data"
            datablock = []
            continue
        if dataline == '*RAS_INT_END':
            status = "none"
            blocks.append(_ras2dat(headblock, datablock))
            del headblock, datablock
            continue
        if status == "header":
            headblock.append(dataline)
        if status == "data":
            datablock.append(dataline)
    return blocks

def _rasx2dat_head(root):
    outstr = []
    #----------- General Information ----------
    outstr.append("# [General Info] Operator: {}\n".format(root.find('./GeneralInformation/Operator').text))
    outstr.append("# [General Info] {0} Ver.{1}\n".format(root.find('./GeneralInformation/Type').text, root.find('./GeneralInformation/Version').text))
    outstr.append("# [General Info] Memo: {}\n".format(root.find('./GeneralInformation/Memo').text))
    outstr.append("# [General Info] System Name: {}\n".format(root.find('./GeneralInformation/SystemName').text))
    #---------- Scan Information ----------
    outstr.append("# [Scan Info] Axis Name:  {}\n".format(root.find('./ScanInformation/AxisName').text))
    outstr.append("# [Scan Info] Axis Mode:  {}\n".format(root.find('./ScanInformation/Mode').text))
    outstr.append("# [Scan Info] Scan Start: {0} {1}\n".format(root.find('./ScanInformation/Start').text, root.find('./ScanInformation/PositionUnit').text))
    outstr.append("# [Scan Info] Scan Stop:  {0} {1}\n".format(root.find('./ScanInformation/Stop').text, root.find('./ScanInformation/PositionUnit').text))
    outstr.append("# [Scan Info] Scan Step:  {0} {1}\n".format(root.find('./ScanInformation/Step').text, root.find('./ScanInformation/PositionUnit').text))
    outstr.append("# [Scan Info] Scan Speed: {0} {1}\n".format(root.find('./ScanInformation/Speed').text, root.find('./ScanInformation/SpeedUnit').text))
    outstr.append("# [Scan Info] Scan Start Time: {0}\n".format(root.find('./ScanInformation/StartTime').text))
    outstr.append("# [Scan Info] Scan End Time:   {0}\n".format(root.find('./ScanInformation/EndTime').text))
    outstr.append("# [Scan Info] Attenuator Auto: {0}\n".format(root.find('./ScanInformation/AttenuatorAutoMode').text))
    #---------- Hardware Configurations ----------
    hw_root = root.findall('./HWConfigurations/Categories/Category')
    for hw in hw_root:
        outstr.append("# [HW Config] {0}: {1}\n".format(hw.attrib['Name'], hw.attrib['SelectedUnit']))
    outstr.append("# [Xray] Type: {0}, Focus Type: {1}, Focus Size: {2}\n".
        format(root.find('./HWConfigurations/XrayGenerator/Type').text, root.find('./HWConfigurations/XrayGenerator/FocusType').text, root.find('./HWConfigurations/XrayGenerator/FocusSize').text))
    outstr.append("# [Xray] Type: {0}, {1} {2}, {3} {4}\n".
                  format(root.find('./HWConfigurations/XrayGenerator/TargetName').text, root.find('./HWConfigurations/XrayGenerator/Voltage').text, root.find('./HWConfigurations/XrayGenerator/VoltageUnit').text, root.find('./HWConfigurations/XrayGenerator/Current').text, root.find('./HWConfigurations/XrayGenerator/CurrentUnit').text))
    ax_root = root.findall('./Axes/Axis')
    for ax in ax_root:
        name = ax.get('Name')
        state = ax.get('State', '')
        str_name = name + ' (Scan)' if state == 'Scan' else name
        pos = ax.get('Position', '')
        str_pos = "" if len(pos) == 0 else pos
        res = ax.get('Resolution', '')
        str_res = "" if len(res) == 0 else "Resolution {}".format(res)
        str_unit = ax.get('Unit', '')
        str_offset = ax.get('Offset', '')
        outstr.append("# [Axis] {0}: {1} {2}, offset {3}, {4}\n".format(str_name, str_pos, str_unit, str_offset, str_res))
    return outstr

def rasx2dat(filename):
    blocks = []
    with zipfile.ZipFile(filename) as zh:
        with zh.open('root.xml') as zf:
            tree = ET.parse(zf)
            root = tree.getroot()
            for child in root:
                if (child.tag)[0:4] == 'Data':
                    number = (child.tag)[4:]
                    with zh.open(child.tag + "/MesurementConditions{}.xml".format(number)) as zf_c:
                        tree_c = ET.parse(zf_c)
                        root_c = tree_c.getroot()
                        headblock = _rasx2dat_head(root_c)
                        scan_step = float(root_c.find('./ScanInformation/Step').text)
                        scan_speed = float(root_c.find('./ScanInformation/Speed').text) / 60.0   # deg/min -> deg/sec
                        count2cps = scan_step / scan_speed
                    with zh.open(child.tag + "/Profile{}.txt".format(number)) as zf_p:
                        datalines = zf_p.readlines()
                        datablock = []
                        for i in range(len(datalines)):
                            tmp1, tmp2, tmp3 = datalines[i].decode('utf-8-sig').rstrip('\r\n').split('\t')
                            datablock.append("{0} {1:.3f} {2} {3}\n".format(tmp1, float(tmp2) * float(tmp3) / count2cps, tmp2, tmp3))
                    blocks.append(headblock + datablock)
    return blocks
    
#==================================================================
# Program Body

#------------------------------------------------------------------
# get ras filenames in current directory
rasfiles = []
rasxfiles = []
for file in os.scandir(os.path.dirname(__file__)):
    base, ext = os.path.splitext(file)
    if ext == '.ras':
        rasfiles.append(file)
    if ext == '.rasx':
        rasxfiles.append(file)

#------------------------------------------------------------------
# Processing each ras files
for filename in rasfiles:
    blocks = ras2dat(filename)
    print("RAS Filename = {0}, Number of {1} block(s) found.".format(os.path.basename(filename), len(blocks)))
    filename_wo_ext = (os.path.splitext(filename))[0]
    for blocknum in range(len(blocks)):
        if len(blocks) == 1:
            outfilename = filename_wo_ext + ".dat"
        else:
            outfilename = filename_wo_ext + "_{0:03d}.dat".format(blocknum+1)
        with open(outfilename, "w") as fh:
            fh.writelines(blocks[blocknum])

for filename in rasxfiles:
    blocks = rasx2dat(filename)
    print("RASX Filename = {0}, Number of {1} block(s) found.".format(os.path.basename(filename), len(blocks)))
    filename_wo_ext = (os.path.splitext(filename))[0]
    for blocknum in range(len(blocks)):
        if len(blocks) == 1:
            outfilename = filename_wo_ext + ".dat"
        else:
            outfilename = filename_wo_ext + "_{0:03d}.dat".format(blocknum+1)
        with open(outfilename, "w") as fh:
            fh.writelines(blocks[blocknum])

input("Hit anykey to exit.")

【試験研究】キセノンランプ光源とランプハウスのセットアップ

 ランプ光源には大きく分けて2つあり、1つは黒体輻射を用いるハロゲンランプ、もう1つは放電現象を用いる放電管です。

 ハロゲンランプ白熱電球(今はほとんどLEDに置き換えられていますが)の1種です。タングステンフィラメントからの黒体輻射で光ります。ガラス管球の中には、ヨウ素や塩素といったハロゲンガスが封入されており、それによって生じるハロゲンサイクルと呼ばれるもので、長寿命化されています。しかし、大出力にすると、光よりも熱になる部分が大きくなるため、明るさに限界があったり、紫外光(400nm以下) の光の成分が弱いという問題があります。そこで、効率よく明るい光を得るために放電管が使われます。放電管は、管球の中に封じられたガスによって発光する波長パターンが異なります。

 今回は、紫外線の短波長側、具体的には190nm~600nm領域での明るい連続スペクトルが欲しかったので、キセノンランプとそのランプハウスを購入しました。キセノンランプは浜松ホトニクスのL2175を、ランプハウスは光軸調整もできるE7536を購入しました。二つ合わせて50万円でおつりぐらいです。

 L2175ではありませんが、同じ浜松ホトニクスの150Wキセノンランプ光源のスペクトルは下記です。700nmから長波長側に輝線があります。あとは470nmに少しピークがあります。400nm以下はつるんとしています。L2175は保証寿命1200時間、平均寿命2500時間です。また、放電管なので出力が安定するまでに10分ほどの暖気が必要です。

150Wキセノンランプのスペクトル

 組み立てたのですが、結論はこんな感じです。

  • 組み立てはとても簡単
  • 光軸合わせも簡単
  • これまで使っていたランプハウスE2419は熱くて大変でしたが、E7536は外側の温度は40℃にもならないぐらいで取り扱いが安全。
  • キセノンランプL2175はオゾンを発生します。それなりにオゾン臭がします。使い始めはそれほどでもなかったのですが…。ハイターの臭いはそれほど不快ではないという人は大丈夫です。

 最後に、「どうして紫外線光源に重水素ランプを採用しなかったのか?」と疑問に思われる方もいると思います。実は、浜松ホトニクス重水素ランプ光源L11798 (MgF2窓) も持っているのです。前方に鋭い強度分布をもつタイプのものです。しかし、180nm~400nmの出力が物足りないので購入しました。キセノンランプのほうも、使用感について追記できることがあれば追記します。

組み立て手順

ランプハウス内部

L2175キセノンランプ球を取り付け

放電中。Y軸方向の位置合わせをしたところ。反射光と透過光の輝点が出るが、これを重ねずに少しずらす。ミラーやレンズの温度が高くなってしまうから。紫外線ミラーは、普通はアルミミラーです。コーティングにもよりますが、大雑把には反射率90~95%です。ということは、5%ぐらいは熱になってしまうのです。今回のランプは150Wなので大したことはありませんが、もっと強力なものを使うと話は別でしょう。
レンズの焦点付近の発光パターン

【映画】きみの色 (The Colors Within)

有給休暇をとったので、2024年8月30日に公開された、山田尚子監督のアニメーション映画「きみの色」を見てきました。おっさんの感想文を書きます。平日の11:30からの上映ということもあって、私を入れて観客は6名ほど。大学生カップル、オタク大学生、おっさん、おばちゃん、そして私(おっさん)、という感じです。パンフレットによると「山田尚子監督 音楽×青春の集大成となる待望の完全オリジナル長編最新作」というのが謳い文句です。「けいおん」に続くという位置づけ。集大成なんて言われると、これで最終到着地点のように感じるのでよくないです。新海誠監督の「すずめの戸締り」にも似たようなことが書かれていたのを思い出しました。

公式HPにも書かれていますが、主人公はミッションスクールに通う高校生で、人が色で見えるトツ子、トツ子が青い色として認識するきみ、緑色として認識する少年ルイの3名です。優等生だったが高校を中退して常識的な道から外れつつあるきみ、親の病院を継ぐことを覚悟しているが音楽を捨てられないルイ。トツ子は自分の色が見えず、この2名とかかわることで、ラストに自分の色が赤であると認識することになります。赤と言っても鮮やかな赤、波長でいうと660nmぐらいでしょう。

作品を貫くキーワードは、ニーバーの祈り「神様、変えることのできないものについて、それを受け入れるだけの心の平穏をお与えください。変えることのできるものについては、変えるだけの勇気を、変えることのできるものとできないものとを、区別できる知恵をお与えください。」です。主人公のトツ子は、最初の一文、「変えることのできないものについて、それを受け入れるだけの心の平穏をお与えください。」だけを最初唱えています。それをミッションスクールのシスターである日吉子(ひよこ)先生が後半部分があると諭します。見守りながらも、一歩を踏み出そうとする高校生たちを応援する立場です。学校の教員は生徒を抑制的に導く存在として描かれることが多いですが、この作品ではそうではないです。作品そのものが、日吉子先生の立ち位置で鑑賞する作品と言ってもいいように思います。

トツ子、きみ、ルイは他者の目を気にしたり、身内に気を遣いながら抑制的に行動します。しかし、好きなものは好きなのです。そういう気持ちを否定的に取り扱わない、安心して鑑賞できる良作です。各シーンについて。日吉子先生がトツ子のベッドを見つめるシーン、あれは誰かが隠れているかということに感づいたのではなく、自分の落書き "God Almighty" が気になったためなんでしょう。合宿でろうそくの灯りを使うシーンでは、火事にならないかハラハラしました。ライブシーンは「天使にラブソングを」を思い出させます。大型船で大学受験に向かうルイに「がんばれー」もよかったです。ラストにトツ子がバレエを踊りながら自分の色を見つけるシーンでは、作品そのものがストンと着地した感がありました。

アニメーション映画としては、全体にパステル調です。境界線が黒でない色トレスを多用していますから、かなり細かな指定が入っていたのではないでしょうか。原画は大変だったのではないでしょうか。公開が遅れたのもそのせいかもしれません。エンドテロップからは非常にたくさんのアニメーション会社の協力によって作られたことが分かります。キャラクターデザインは小島崇史さんです。山田監督の前作「平家物語」と同じ。特に目の周りにあえてスケッチライクな線を描く手法です。リアルから一歩退くことで、逆に感情移入させられます。

戦闘シーンがあるとか、自己犠牲があるとか、そういう作品ではありませんが、良作です。内的葛藤を描くこういう作品は良いですね。そしてそれを音楽が救う。いいですね。芸事の経験は人を救い、心のバランスをもたらすというのは私の持論です。最後に、やっぱり山田尚子さんは天才ですね。