Proyek yang sudah terverifikasi masih perlu dikemas agar dapat dibangun dan dijalankan orang lain tanpa panduan lisan. Topik ini mengemas poisson1d sebagai proyek fpm yang lengkap, terdiri atas manifes fpm.toml, README, program utama dengan argumen baris perintah, uji otomatis, dan perintah build yang dapat direproduksi. Pohon proyek disiapkan di luar jalur konten, dibangun dengan fpm, lalu dijalankan dan diuji sungguhan sehingga setiap keluaran pada topik ini adalah hasil eksekusi asli.
Pohon proyek dan manifes fpm#
fpm menetapkan konvensi direktori untuk sebuah proyek: pustaka berada di src/, program yang dapat dieksekusi di app/, dan program uji di test/. Ketiga direktori ini dikenali fpm tanpa perlu diumumkan di mana pun, sehingga letak berkas sekaligus menyatakan perannya. Bagi proyek sekecil poisson1d, tiga direktori itulah satu-satunya yang perlu disiapkan. Struktur berikut adalah pohon lengkap poisson1d beserta manifes dan dokumentasinya.
poisson1d/
├── fpm.toml
├── README.md
├── src
│ └── poisson_mod.f90
├── app
│ └── main.f90
└── test
└── uji_poisson.f90Manifes fpm.toml adalah kontrak build proyek. Nama proyek sekaligus menjadi nama program yang dapat dieksekusi, sedangkan bagian [build] mengatur target yang dipindai fpm secara otomatis. Dengan kontrak ini, proyek dapat dibangun ulang di mesin lain tanpa pengaturan apa pun karena seluruh aturan build ikut tersimpan bersama kode sumber.
name = "poisson1d"
version = "0.1.0"
license = "MIT"
description = "Penyelesai PDE Poisson 1D dengan metode beda hingga orde dua"
[build]
auto-executables = true
auto-tests = true
auto-examples = falseEmpat kunci pertama menjelaskan proyek kepada registri dan pembaca manifes. Kunci name telah dijelaskan pada paragraf sebelumnya, kunci version dan license membuat setiap rilis dapat dirujuk secara unik dan dipakai ulang secara sah, sedangkan description merangkum fungsi proyek dalam satu baris bagi calon pengguna. Bagian [build] membiarkan fpm memindai src/, app/, dan test/ secara otomatis, dengan target examples dimatikan karena proyek ini tidak memiliki direktori example/. Dengan manifes sesempit ini, seluruh keputusan build proyek dapat dibaca dalam sekali pandang.
README dan dokumentasinya#
README adalah halaman pertama yang dibaca pengguna proyek, sehingga isinya harus menjawab tiga hal: apa yang dikerjakan program, bagaimana menjalankannya, dan bagaimana membangunnya. Untuk proyek CLI numerik, urutan itu sudah cukup, dan setiap perintah yang dicantumkan harus benar-benar pernah dijalankan. Susunan ringkas semacam ini juga mudah dipelihara, sebab setiap perubahan antarmuka cukup disunting pada beberapa baris dan langsung terbaca pengguna.
# poisson1d
Penyelesai persamaan Poisson satu dimensi -u'' = f pada [0, 1] dengan
syarat batas Dirichlet homogen. Diskretisasi memakai beda hingga orde dua
dan sistem tridiagonalnya diselesaikan dengan algoritma Thomas.
## Pemakaian
poisson1d [--n N] [--verifikasi] [--keluaran BERKAS]
## Membangun
fpm build
fpm run -- --n 63 --verifikasi
fpm testDokumentasi di atas sengaja memuat perintah yang sama dengan yang dieksekusi pada bagian akhir topik ini, sehingga apa yang tertulis di README dan apa yang benar-benar berjalan tidak pernah menyimpang. Tiga perintah pada bagian Membangun dipetakan satu per satu: fpm build ke blok kompilasi proyek, fpm run ke blok eksekusi program, dan fpm test ke blok uji penutup. Bagian Pemakaian melengkapinya dengan ringkasan ketiga opsi baris perintah, sehingga pengguna dapat menyusun pemanggilannya sendiri tanpa membaca ulang seluruh topik. Pembaca yang menyalin ketiga perintah itu ke terminal menerima keluaran yang sama dengan yang tercetak pada topik ini.
Program utama dengan argumen baris perintah#
Program di app/main.f90 menjadi antarmuka proyek. Perulangan get_command_argument memindai argumen satu per satu, select case memetakan opsi --n, --verifikasi, dan --keluaran, sedangkan prosedur gagal mencetak pesan beserta pemakaian program lalu menghentikannya dengan stop 1. Nilai bawaan ditetapkan di awal program, yaitu tanpa verifikasi dan tanpa keluaran berkas, sehingga pemanggilan tanpa satu pun argumen tetap menghasilkan solusi yang sah.
program poisson1d
use poisson_mod, only: dp, pi, jaring, buat_jaring, selesaikan, norma_inf, norma_l2
implicit none
type(jaring) :: g
real(dp), allocatable :: f(:), u(:), u_eksak(:)
real(dp) :: err_inf, err_l2
character(len=64) :: arg, nama_keluaran
integer :: n, argc, i, ios, unit_keluaran
logical :: verifikasi
! nilai bawaan opsi baris perintah
n = 63
verifikasi = .false.
nama_keluaran = ''
argc = command_argument_count()
i = 1
do while (i <= argc)
call get_command_argument(i, arg)
select case (trim(arg))
case ('--n')
i = i + 1
if (i > argc) call gagal('--n memerlukan nilai N')
call get_command_argument(i, arg)
read (arg, *, iostat=ios) n
if (ios /= 0 .or. n < 1) call gagal('nilai --n tidak valid: '//trim(arg))
case ('--verifikasi')
verifikasi = .true.
case ('--keluaran')
i = i + 1
if (i > argc) call gagal('--keluaran memerlukan nama berkas')
call get_command_argument(i, nama_keluaran)
case default
call gagal('argumen tidak dikenal: '//trim(arg))
end select
i = i + 1
end do
g = buat_jaring(n)
f = pi**2*sin(pi*g%x)
call selesaikan(g, f, u)
print '(A, I0, A, ES11.4)', 'n = ', n, ', h = ', g%h
print '(A, F9.6, A, F7.4)', 'maksimum u : ', maxval(u), ' pada x = ', &
g%x(maxloc(u, dim=1) - 1)
if (verifikasi) then
u_eksak = sin(pi*g%x)
err_inf = norma_inf(u, u_eksak)
err_l2 = norma_l2(u, u_eksak, g%h)
print '(A, ES12.5)', 'error L-inf : ', err_inf
print '(A, ES12.5)', 'error L2 : ', err_l2
end if
if (nama_keluaran /= '') then
open (newunit=unit_keluaran, file=nama_keluaran, status='replace', action='write')
write (unit_keluaran, '(A)') 'x,u,u_eksak'
do i = 0, n + 1
write (unit_keluaran, '(ES15.8, A, ES15.8, A, ES15.8)') &
g%x(i), ',', u(i), ',', sin(pi*g%x(i))
end do
close (unit_keluaran)
print '(A, A, A)', 'solusi ditulis ke ', trim(nama_keluaran), &
' (kolom: x, u, u_eksak)'
end if
contains
! mencetak pesan error beserta pemakaian program, lalu menghentikan program
subroutine gagal(pesan)
character(len=*), intent(in) :: pesan
print '(A, A)', 'error: ', pesan
print '(A)', 'pemakaian: poisson1d [--n N] [--verifikasi] [--keluaran BERKAS]'
stop 1
end subroutine gagal
end program poisson1dOpsi --keluaran menulis solusi sebagai berkas CSV dengan tiga kolom, yaitu koordinat , solusi numerik, dan solusi eksak. Berkas semacam itu dipakai untuk pemeriksaan lanjutan di luar program, misalnya digambar dengan alat lain. Penomoran unit berkas diserahkan ke newunit agar program aman dipanggil berulang tanpa menabrak unit yang sudah terbuka.
Uji otomatis dengan fpm test#
Program uji di test/ dijalankan fpm melalui perintah fpm test. Uji ini menyelesaikan masalah dengan , membandingkan hasilnya dengan solusi eksak, dan menyatakan gagal melalui stop 1 apabila error melampaui ambang 1.0e-3. Pemeriksaan sengaja memakai norma L-inf saja karena error terburuk itulah yang paling tajam membongkar kerusakan pada satu titik akibat regresi.
program uji_poisson
use poisson_mod, only: dp, pi, jaring, buat_jaring, selesaikan, norma_inf
implicit none
type(jaring) :: g
real(dp), allocatable :: f(:), u(:), u_eksak(:)
real(dp) :: err
! uji: solusi eksak sin(pi x) direproduksi dalam batas toleransi
g = buat_jaring(127)
f = pi**2*sin(pi*g%x)
call selesaikan(g, f, u)
u_eksak = sin(pi*g%x)
err = norma_inf(u, u_eksak)
if (err > 1.0e-3_dp) then
print '(A, ES12.5)', 'uji poisson1d GAGAL, error L-inf = ', err
stop 1
end if
print '(A, ES12.5)', 'uji poisson1d: LOLOS, error L-inf = ', err
end program uji_poissonAmbang ditetapkan jauh di atas error terukur, yang pada bernilai 5.020092E-05 menurut tabel konvergensi. Selama perakit sistem dan penyelesainya tidak diubah, error aktual akan tetap jauh di bawah ambang itu, sehingga uji hanya gagal ketika muncul regresi yang sungguh merusak jawaban. Kode keluar 1 pada kegagalan membuat uji ini dapat dipasang pada alat integrasi berkelanjutan tanpa penyesuaian apa pun.
Membangun dan menjalankan dengan fpm#
Seluruh rangkaian berikut dijalankan dari direktori yang memuat ketiga berkas sumber. Pohon proyek dibangun di /tmp sehingga jalur konten tetap bersih dari artefak. Perintah cp menempatkan tiap berkas sumber sesuai konvensi fpm, sedangkan dua heredoc menulis fpm.toml dan README.md dengan isi yang sama persis dengan blok di atas.
# menyiapkan pohon proyek fpm di luar jalur konten
PROYEK=/tmp/poisson1d
rm -rf "$PROYEK"
mkdir -p "$PROYEK/src" "$PROYEK/app" "$PROYEK/test"
cp poisson_mod.f90 "$PROYEK/src/poisson_mod.f90"
cp poisson1d.f90 "$PROYEK/app/main.f90"
cp uji_poisson.f90 "$PROYEK/test/uji_poisson.f90"
cd "$PROYEK"
# menulis manifes sesuai blok fpm.toml di atas
cat > fpm.toml <<'EOF'
name = "poisson1d"
version = "0.1.0"
license = "MIT"
description = "Penyelesai PDE Poisson 1D dengan metode beda hingga orde dua"
[build]
auto-executables = true
auto-tests = true
auto-examples = false
EOF
# menulis README sesuai blok README.md di atas
cat > README.md <<'EOF'
# poisson1d
Penyelesai persamaan Poisson satu dimensi -u'' = f pada [0, 1] dengan
syarat batas Dirichlet homogen. Diskretisasi memakai beda hingga orde dua
dan sistem tridiagonalnya diselesaikan dengan algoritma Thomas.
## Pemakaian
poisson1d [--n N] [--verifikasi] [--keluaran BERKAS]
## Membangun
fpm build
fpm run -- --n 63 --verifikasi
fpm test
EOF
# mengaktifkan peringatan kompiler lalu membangun proyek
export FPM_FFLAGS="-Wall -Wextra"
fpm build + mkdir -p build/dependencies
[ 0%] poisson_mod.f90
[ 25%] poisson_mod.f90 done.
[ 25%] libpoisson1d.a
[ 25%] main.f90
[ 50%] libpoisson1d.a done.
[ 75%] main.f90 done.
[ 75%] poisson1d
[100%] poisson1d done.
[100%] Project compiled successfully.Build pertama mengompilasi pustaka dari src/, kemudian program dari app/, lalu menyambung keduanya menjadi eksekusi bernama poisson1d sesuai name pada manifes. Persentase kemajuan pada keluaran menandai target yang selesai satu per satu, dari poisson_mod.f90, pustaka libpoisson1d.a, main.f90, hingga eksekusi poisson1d. Program kini dijalankan dengan verifikasi dan keluaran berkas.
# menjalankan program dengan verifikasi dan keluaran CSV
fpm run -- --n 63 --verifikasi --keluaran solusi.csv
# menampilkan empat baris pertama berkas solusi
head -4 solusi.csvProject is up to date
n = 63, h = 1.5625E-02
maksimum u : 1.000201 pada x = 0.5000
error L-inf : 2.00822E-04
error L2 : 1.42002E-04
solusi ditulis ke solusi.csv (kolom: x, u, u_eksak)
x,u,u_eksak
0.00000000E+00, 0.00000000E+00, 0.00000000E+00
1.56250000E-02, 4.90775282E-02, 4.90676743E-02
3.12500000E-02, 9.80368243E-02, 9.80171403E-02Error yang dilaporkan program, yaitu 2.00822E-04, sama dengan baris pada tabel konvergensi, sehingga program terkemas dan program studi menghasilkan angka yang konsisten. Tanda -- pada fpm run memisahkan argumen fpm dari argumen program, dan head menampilkan bahwa CSV berisi kepala kolom beserta pasangan nilai numerik dan eksak yang berdekatan. Uji otomatis dijalankan terakhir.
# menjalankan uji otomatis fpm
fpm test[ 0%] uji_poisson.f90
[ 50%] uji_poisson.f90 done.
[ 50%] uji_poisson
[100%] uji_poisson done.
[100%] Project compiled successfully.
uji poisson1d: LOLOS, error L-inf = 5.02009E-05Uji berjalan setelah target ujinya dikompilasi dan mengembalikan kode keluar 0 ketika lolos. Pencarian program uji oleh fpm pun minim pengaturan karena kunci auto-tests = true pada manifes membuat fpm memindai dan menjalankan program uji di test/ secara otomatis. Prosedur gagal pada program utama tetap berperan sebagai pengaman: setiap argumen yang tidak valid menghentikan program dengan kode keluar 1 sebelum perhitungan dimulai, sehingga pemanggil skrip dapat mendeteksi kegagalan dari kode keluar tersebut.
Kesalahan umum#
- Argumen program diteruskan tanpa
--. Perintahfpm run --n 63memberi--nkepada fpm, bukan kepada program, dan fpm menolaknya sebagai opsi yang tidak dikenal. Perbaikannya dengan menyisipkan--sebelum argumen pertama program. - Staging yang tidak dibersihkan. Menyalin sumber ke pohon proyek lama tanpa
rm -rfmenyisakan berkas versi sebelumnya, sehingga build tidak mencerminkan sumber terkini. Blok penyiapan pada topik ini selalu menghapus pohon target lebih dahulu. - Nama program diasumsikan bebas. Program dari
app/main.f90mewarisi nama proyek pada manifes. Menggantinametanpa memperbarui README dan skrip pemanggil membuat perintah dokumentasi gagal dijalankan.
Ringkasan#
- Proyek dikemas sebagai pohon fpm standar dengan manifes fpm.toml, README, pustaka di
src/, program CLI diapp/, dan uji ditest/. - Flag kompiler diteruskan melalui FPM_FFLAGS, sedangkan argumen program dipisahkan dari argumen fpm dengan
--. - fpm build, fpm run, dan fpm test dijalankan sungguhan, dan error program konsisten dengan tabel konvergensi pada verifikasi kebenaran.
- Kode keluar 1 pada kegagalan program dan uji membuat pengemasan ini siap dipasang pada alat integrasi berkelanjutan.
Referensi#
- fpm — Fortran Package Manager — Dokumentasi resmi fpm untuk manifes, konvensi direktori, dan perintah build, run, serta test.
- The GNU Fortran Compiler — GNU Project — Manual gfortran untuk get_command_argument, newunit, dan perilaku stop dengan kode keluar.
- Learn: tutorial resmi Fortran — fortran-lang — Rujukan fitur bahasa yang dipakai pada program utama dan uji otomatis.