2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Fortranパッケージhttp-clientを使う

Last updated at Posted at 2024-06-11

はじめに

http-clientはfortranでHTTPプロトコルを用いて情報を取得できるパッケージになります。
http-clientfortran-curlを利用しており、fortran-curllibcurlを利用しています。

環境構築

http-clientfortran-curllibcurlを利用していることから、自力でコンパイルを行うのは面倒なので公式サイトで推奨しているfpmを使ってコンパイルを行います。その前段階として環境構築を行います。

fpmのダウンロード

fpmはpythonで作成されているが、Linuxで一番簡単なのはバイナリデータをダウンロードして組み込むことです。MacOSの場合はHomebrew、Windowsの場合はWingetで行うとよい。Anacondaもあり。pythonからpipでインストールしても可。(環境によってはパスを張る必要がある。)

gitやlibcurlやlibcurlのヘッダーをインストール

# Ubuntu 22.04
sudo apt install git libcurl4-openssl-dev
# CentOS Stream 9
dnf install git libcurl-devel

※Windowsの場合はlibcurlやlibcurlのヘッダーどうすれば適切に実行できるのか不明。おとなしくMSYS2やWSL2使ってください。

gitの設定

git config --global user.name "<user>"
git config --global user.email "<e-mail>"
git config --global http.proxy "<[protocol://][user[:password]@]proxyhost[:port]>" #必要なら

http-clientの使用方法

ここではこの中のジオイド高を求めるAPIを用いて、httpリクエストを行い、json形式の文字列を取得し、そこからジオイド高を取得することを行う。APIの詳細については上記のURLを参照してください。

fpmの設定

fpmの詳しい使い方については

こちらを見ていただくとして一連の構築手順を提示する。

プロジェクトの作成

fpm new geoid_api

を実行すると、カレントディレクトリにgeood_apiディレクトリが作成される。中身は以下の通り、

.
├── .git
├── app
│   └── main.f90
├── src
│   └── geoid_api.f90
├── test
│   └── check.f90
├── fpm.toml
└── README.md

appディレクトリにあるものはメインルーチンが入っているソースコードを入れる。
srcディレクトリにあるものはモジュール形式で格納されているものを入れる。
testディレクトリにあるものは、srcディレクトリのモジュールをテストするためのメインルーチンが入っているソースコードが入る。

fpm.toml

dependencies項に今回使用するパッケージ名を指定する。
httpリクエストをするパッケージ名はhttp、jsonを扱うパッケージ名はjson-fortranなのでそのように記入する。
名前の見つけ方については、それぞれのgithubのコードのfpm.tomlに名前が記載されているのでそれを見るか使い方を見る。

fpm.toml
[dependencies]
http = { git = "https://github.com/fortran-lang/http-client" }
json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
stdlib = "*"

ソースコード

以下の通り作成する。

./app/main.f90
program main
    use, intrinsic :: iso_fortran_env, only: real64
    use geoid_api, only: get_geoidHeight
    implicit none
    real(real64) :: lon, lat, geoidHeight

    ! 国土地理院の座標
    lon = 140.084556_real64 ! f0.8
    lat = 36.104611_real64 ! f0.8
    geoidHeight = get_geoidHeight(lon, lat)

    print *, lon, " ", lat, " ", geoidHeight

end program main
./src/geoid_api.f90
module geoid_api
    use, intrinsic :: iso_fortran_env, only: real64
    use http, only: response_type, request
    use json_module, only: json_file
    use stdlib_strings, only: to_string, strip
    use stdlib_str2num, only: to_num
    implicit none
    private

    public :: get_geoidHeight

contains
    impure elemental function get_geoidHeight(lon, lat) result(geoidHeight)
        real(real64), intent(in):: lon !! lon
        real(real64), intent(in) :: lat !! lat
        real(real64) :: geoidHeight !! ジオイド高[m]
        type(json_file) :: json_f
        type(response_type) :: response
        character(:), allocatable :: lon_str, lat_str, geoidHeight_str
        character(*), parameter :: outputType = 'json'
        character(*), parameter :: baseurl = 'https://vldb.gsi.go.jp/sokuchi/surveycalc/geoid/calcgh/cgi/geoidcalc.pl'
        character(:), allocatable :: url

        ! 文字列に変換
        !allocate (character(len=12) :: lon_str) ! 140.08455600 f12.8型->12文字
        !allocate (character(len=12) :: lat_str) ! 36.10461100 f12.8型->12文字
        !write (lon_str, '(f0.8)') lon ! 左詰めにするためf0で設定
        !write (lat_str, '(f0.8)') lat ! 左詰めにするためf0で設定
        lon_str = strip(to_string(lon, '(f12.8)'))
        lat_str = strip(to_string(lat, '(f12.8)'))

        !url = baseurl//'?'//"outputType="//outputType//"&latitude="//trim(lat_str)//"&longitude="//trim(lon_str)
        url = baseurl//'?'//"outputType="//outputType//"&latitude="//lat_str//"&longitude="//lon_str

        response = request(url=url)
        if (.not. response%ok) then
            print *, 'Error message:', response%err_msg
            stop
        end if
        print *, 'Response Code    :', response%status_code
        print *, 'Response Length  :', response%content_length
        print *, 'Response Method  :', response%method
        print *, 'Response Content :', response%content
        !content ※lat,lon,geoidが文字列で格納されているので注意
        !--------------
        ! { "OutputData":
        !    {
        !        "latitude": "36.10461100" ,
        !        "longitude": "140.08455600",
        !        "geoidHeight": "40.1986"
        !    }
        ! }
        call json_f%initialize()
        call json_f%deserialize(response%content)
        call json_f%get(path='OutputData.geoidHeight', val=geoidHeight_str)
        call json_f%destroy()
        ! 文字列からrealに
        !read (geoidHeight_str, *) geoidHeight
        geoidHeight = to_num(geoidHeight_str, geoidHeight)

    end function get_geoidHeight
end module geoid_api

数値を文字列に、文字列を数値に変換する際面倒なことを行っているがstdlibを利用することにした、注意すべき点は、response%contentはhttpリクエストで返却された本体部分になっており、改行を含めた文字列がそこに格納されている。call json_f%deserialize(response%content)により、json文字列をjsonのポインタに変換し格納する。

ビルド

fpm build

buildディレクトリにgithubからダウンロードしたものやコンパイルしたものが一式格納されている。

インストール

fpm install --prefix .

binディレクトリにgeoid_apiプログラムが作成される。

実行

$ ./bin/geoid_api
 Response Code    :         200
 Response Length  :                   94
 Response Method  :GET
 Response Content :{"OutputData":{"latitude":"36.104611000","longitude":"140.084556000","geoidHeight":"40.1986"}}
   140.08455599999999          36.104610999999998          40.198599999999999  

詳しい使い方

このサイトのProceduresDerived Typesのうちglobalになっているものだけを見るとよい。
現時点で、globalで存在するものは以下の通り

Procedures

Derived Types

プロキシについて

直接プロキシを設定する項目は今のところないが、libcurlを利用しているので環境変数で設定する。~/.curlrcは読み込まないので注意

環境変数

  • http_proxy=scheme://[user:passwd@]proxy.server:port
  • HTTPS_PROXY
  • https_proxy
  • ALL_PROXY
  • NO_PROXY
  • no_proxy
  • CURL_CA_BUNDLE: CA証明書のパス

※http_prxoyは小文字のみ、それ以外は両方OK。両方ある場合は小文字優先。
※proxyにBasic認証がある場合はuser:passwdを入れる。userやpasswdに記号(" # < > ` { } ? =など)が入っている場合はURLエンコードを忘れずに。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?