見出し画像

【Djangoを使ってWebアプリ練習日記(1)】1次元移流方程式の計算

こんにちは(@t_kun_kamakiri

最近、Djangoを使ってWebアプリを作るのにはまっています。

Djangoの勉強をはじめて2か月ほど経ちましたが、時間を見つけてはちょっとずつできる幅を増やしていっています。

本日は、1次元の移流方程式をDjangoを使って計算させる

【読者対象者】
Pythonの基礎がわかっている人
最近Djangoをはじめたのでコードを見ただけでだいたいわかる人

Django:3.1
Pyhton:3.6

流れだけ記載しているので、いちから丁寧に解説する記事ではないですが参考になればよいです。

プロジェクトを作成する

まずは、プロジェクトを作成します。

django-admin startproject calcu_django

このようにすると、プロジェクトが作成されます。

アプリを作成する

次にアプリを管理するファイルを作成します。

python3 manage.py startapp calcu_app

これでアプリが作成できました。

urlのつなぎこみ

「calcu_django/urls.py」を以下のようにして、urlのアプリへのつなぎを行います。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
   path('admin/', admin.site.urls),
   path('index/', include('calcu_app.urls') ),
]

これで、「/index」にアクセスがあると、「calcu_app.urls」の中のURLに従って動作されます。

URLリクエストに対応した処理を指定

calcu_app/urls.pyを以下のようにします。

from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
   path('admin/', admin.site.urls),
   path('',  views.index, name = 'index'),
   path('calcu', views.calcu, name = 'calcu'),
   path('result', views.result, name = 'result'),
]

このようにすると、
●「/index/calcu」は計算設定する処理
●「/index/result」は計算結果を見るところ
まだWeb上で結果を見れるようにしていません。

処理を書く

URLのリクエストに対応した処理を「calcu_app/views.py」に書きます。

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(requset):
   # return HttpResponse('Hello World')
   params = {
       'title': 'ようこそ',
       'msg' : '計算をするWebアプリです。',
       'next' : '計算ページへ'
   }
   return render(requset, 'calcu/index.html' , params)

def calcu(requset):
   # return HttpResponse('Hello World')
   params = {
       'title': '計算を実行プログラム',
       'msg' : 'ここからが計算できます。',
       'param_title' : 'パラメータ設定'
   }
   return render(requset, 'calcu/calcu.html' , params)

def result(requset):
   nx = int(requset.POST['nx'])
   xmax = int(requset.POST['xmax'])
   c = int(requset.POST['c'])
   alpha = int(requset.POST['alpha']   )

   params = {
       'title':'計算結果',
       'param_title': 'パラメータ',
       'nx': nx,
       'xmax' : xmax,
       'c' : c,
       'alpha': alpha
   }
   
   AdvectionEquation(nx, xmax ,c , alpha)
   
   return render(requset, 'calcu/result.html', params)

import numpy as np
import matplotlib.pyplot as plt

def AdvectionEquation(nx, xmax ,c , alpha):
   nx = nx
   xmax = xmax
   dx = xmax / (nx-1)
   nt = 25
   c = c
   alpha = alpha
   dt = alpha * (dx/c) 
   
   x = np.linspace(0,2,nx)
   
   un = []
   u = np.ones(nx)
   u[int(.5 / dx):int(1 / dx + 1)] = 2
   
   
   for n in range(nt): 
       un = u.copy()
       for i in range(1, nx):
           u[i] = un[i] - c * dt / dx * (un[i] - un[i-1])
   
   u_final = u.copy()
   
   u_initial  = np.ones(nx)
   u_initial[int(.5 / dx):int(1 / dx + 1)] = 2
   
   plt.plot(x,u_initial,label = 'initial')
   plt.plot(x,u_final, label = 'final')
   plt.legend()
   plt.grid()
   # plt.show()
   plt.savefig('figure01.jpg')
   plt.close()

「AdvectionEquation」関数に1次元移流方程式の処理を書いています。
別のファイルに分けても良いかもしれませんが、今回はファイル構成を複雑にしないようにしておくため、このままいきます。

ベースのHMTLを書く

htmlのファイルを読むことでWeb上に表示することができます。

htmlをページごとに書くのは面倒ですよね。
なので、ベースのhtmlをひとつ書いておいてそれを利用するという方法をとります。

「templates/calcu/layout.html」を以下のように書きます。

{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>計算アプリ</title>
   <link rel="stylesheet" href="{% static 'calcu/style.css' %}">
   <script type="text/javascript"
   src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_CHTML">
   </script>

   <script type="text/x-mathjax-config">
       MathJax.Hub.Config({
           TeX: { equationNumbers: { autoNumber: "AMS" }},
           tex2jax: {
       inlineMath: [ ['$','$'], ["\\(","\\)"] ],
       processEscapes: true
           },
           "HTML-CSS": { matchFontHeight: false },
           displayAlign: "center",
           // displayIndent: "2em"
       });
   </script>

</head>
<body>
   {% block header %}
   {% endblock header %}

   {% block content %}
   {% endblock content %}
</body>
</html>

cssが読み込めるように冒頭に、
●{% load static %}を書く
●<link rel="stylesheet" href="{% static 'calcu/style.css' %}">としてcssファイルを読み込んでいる。

index.htmlの作成

では、先ほどのlayout.htmlをベースにしてindex.htmlを作成します。

「templates/index.html」で「/index」とアクセスがあった時の表示を書いています。

{% extends 'calcu/layout.html' %} 

{% block header %}
<h1>{{ title }}</h1>
{% endblock header %}

{% block content %}
<p>{{ msg }}</p>
<a href="{% url 'calcu' %}">{{ next }}</a>
{% endblock content %}

記述がとても少なくて済みますね。

計算設定のページを作成

「templates/calcu/calcu.html」を以下のように書きます。

{% extends 'calcu/layout.html' %} 

{% block header %}
<h1>{{ title }}</h1>
{% endblock header %}

{% block content %}
<p>{{ msg }}</p>
<form action="{% url 'result' %}" method="POST" >{% csrf_token %}
   <!-- {{form.as_table}} -->
   <table>
       <thead>
           <tr>
               <th colspan="2">{{ param_title }}</th>
           </tr>
       </thead>
       <tbody>
           <tr>
               <td>$n_{x}$</td>
               <td><input type="text" name="nx" id=""></td>
           </tr>
           <tr>
               <td>$x_{max}$</td>
               <td><input type="text" name="xmax" id=""></td>
           </tr>
           <tr>
               <td>$c$</td>
               <td><input type="text" name="c" id=""></td>
           </tr>
           <tr>
               <td>$\alpha$</td>
               <td><input type="text" name="alpha" id=""></td>
           </tr>
       </tbody>
   </table>
   <div class="cal_submit"><input type="submit" value="計算開始"></div>
</form>
\begin{align*}
\frac{\partial u}{\partial t}+c\frac{\partial u}{\partial x}=0\tag{1}
\end{align*}

(1)式の離散化は以下のようになります。

\begin{align*}
\frac{u^{n+1}_{i}-u^{n}_{i}}{\Delta t}+c\frac{u^{n}_{i}-u^{n}_{i-1}}{\Delta x}=0
\end{align*}

\begin{align*}
u^{n+1}_{i}=u^{n}_{i}+\frac{c\Delta t}{\Delta x}\big(u^{n}_{i}-u^{n}_{i-1}\big)\tag{2}
\end{align*}

ここで、\(\alpha=\frac{c\Delta t}{\Delta x}\)として時間刻み空間の分割幅\(\Delta x\)と\(c\)で決まるものとしておきます。
{% endblock content %}

formタグ内が少し複雑ですね。
今回はこれでも動くのですが、後ほどdjangoが用意しているFormクラスを使って書き換えたいと思います。

今はこのままいきます。

結果の表示のぺージを作成

次に結果の結果を表示するページを表示するために「templates/calcu/result.html」を以下のように書きます。

{% extends 'calcu/layout.html' %} 

{% block header %}
<h1>{{ title }}</h1>
{% endblock header %}

{% block content %}
<table>
   <thead>
       <tr>
           <th colspan="2">{{ param_title }}</th>
       </tr>
   </thead>
   <tbody>
       <tr>
           <td>$n_{x}$</td>
           <td>{{ nx }}</td>
       </tr>
       <tr>
           <td>$x_{max}$</td>
           <td>{{ xmax }}</td>
       </tr>
       <tr>
           <td>$c$</td>
           <td>{{ c }}</td>
       </tr>
       <tr>
           <td>$\alpha$</td>
           <td>{{ alpha }}</td>
       </tr>
   </tbody>
   <a href="{% url 'calcu' %}">設定に戻る</a>
{% endblock content %}

まだ、結果をWeb上で見るように実装していないです。
おいおいやっていきます_(._.)_

できたものを確認する

python manage.py runserver

として結果をかくにんすれば以下のようになります。

本日の内容は以上です。

「templates/calcu/calcu.html」のformタグがじゃっかん記述が多かったので、Djangoが用意しているFormクラスを使ってシンプルに書き直してみようと思います。

こういうのをgitで管理したいですね('ω')

↓こちらの参考書で勉強しています。
とてもわかりやすいのでDjangoを勉強してみたいという方にはお勧めですね。

Twitter➡@t_kun_kamakiri
ブログ➡宇宙に入ったカマキリ(物理ブログ)
ココナラ➡物理の質問サポートサービス

この記事が気に入ったらサポートをしてみませんか?