ちろる

理系大学生が自由気ままに

Swift4でMac上のlocalhostにPOST

実行環境

・Swift4
PHP 7.1.16
MAMP 4.4.1
Xcode 9.4.1
macOS High Sierra 10.13.6

MaciPhoneが同一のWiFiに接続していること

サーバーサイド

MAMP(MAMP & MAMP PRO)をインストールし、起動したら下記の画面の"Start Servers"をクリック。
f:id:tsupiano:20180907083441p:plain


"/Applications/MAMP/htdocs"のフォルダ内に以下のようなa.phpを作成する。

<?php 
$title = $_GET["title"];
$note = $_GET["note" ];
print "$title$note";

テストとして、以下のURLをMacのブラウザで検索し、"title : note"と表示されれば成功である。

http://localhost:8888/a.php?title=title&note=note

これでサーバー側は完了。

クライアントサイド

以下のコマンドをterminalで実行し、ipアドレスをメモる。

ifconfig | grep mask

Info.plistのソースコードを開き、末尾に以下を追加する。

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>192.168.100.70</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <false/>
        </dict>
    </dict>
</dict>

f:id:tsupiano:20180907084102p:plain

次に、Main.StoryboardとViewControllerを作成する。
f:id:tsupiano:20180907084943p:plain

import UIKit

class ServerController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBOutlet weak var resultLabel: UILabel!
    @IBOutlet weak var inputText1: UITextField!
    @IBOutlet weak var inputText2: UITextField!
    
    @IBAction func onButtonTap(_ sender: UIButton) {
        if inputText1.text != "" && inputText2.text != "" {
            let title = inputText1.text!
            let note  = inputText2.text!
            
            let stringUrl = "http://192.168.1.9:8888/a.php?title=\(title)&note=\(note)"
            // Swift4からは書き方が変わりました。
            let url = URL(string: stringUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!
            let req = URLRequest(url: url)
            
            let task = URLSession.shared.dataTask(with: req, completionHandler: {
                (data, res, err) in
                if data != nil {
                    let text = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
                    DispatchQueue.main.async(execute: {
                        self.resultLabel.text = text as String?
                    })
                }else{
                    DispatchQueue.main.async(execute: {
                        self.resultLabel.text = "ERROR"
                    })
                }
            })
            task.resume()
        }else{
            // 未入力
            alert("error", messageString: "It is not entered.", buttonString: "OK")
        }
    }
    // 標準のアラートを表示させる
    func alert(_ titleString: String, messageString: String, buttonString: String){
        //Create UIAlertController
        let alert: UIAlertController = UIAlertController(title: titleString, message: messageString, preferredStyle: .alert)
        //Create action
        let action = UIAlertAction(title: buttonString, style: .default) { action in
            NSLog("\(titleString):Push button!")
        }
        //Add action
        alert.addAction(action)
        //Start
        present(alert, animated: true, completion: nil)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool{
        //Close keyboard.
        textField.resignFirstResponder()
        
        return true
    }
}

実行結果

2つのテキストボックスに値を入力してボタンを押すと、下にinputText1 : inputText2が返され表示される。
f:id:tsupiano:20180907085253j:plain

インフラの知識が欲しい!SSH編

※本ブログは知識を蓄えた直後に執筆されているので、間違った情報が載っていることも多々あります。そのため、メディアリテラシーを必須とします。ご了承ください。

SSHとは

SSHは、暗号や認証の技術を利用して、安全にリモートコンピュータと通信するためのプロトコル。パスワードなどの認証部分を含むすべてのネットワーク上の通信が暗号化される。インストールに関してはUbuntu及びMacを用いているので、Windowsなどの場合には各自検索して行ってください。インストール以外は基本的に本記事のコマンドで動くと思います。

SSHの認証方式

接続するための認証方式はパスワード認証方式公開鍵認証方式 の2通りがある。パスワード認証方式の方が簡単だが、公開鍵認証方式の方がセキュリティ面では良い。

SSHDSSH

SSHSSHDの違いは以下のようになる。

SSH(クライアント):他のサーバにSSHで接続する設定
SSHD(デーモン):他のサーバからSSHで接続されるときの設定

ログインしたいマシン側にSSHDを、クライアントとなるマシン側にSSHの設定を行う。

SSHDのサービスの設定と開始

まずは、SSHDの設定・管理に必要なaptitudeをインストールする。

$ sudo apt-get install aptitude

次にaptitudesshをインストールする。

$ sudo aptitude install ssh

/etc/ssh/sshd_configを編集し、PermitRootLoginの行を次のように書き換える。僕の環境でデフォルトは"PermitRootLogin prohibit-password"のようになっていた。

PermitRootLogin no

以下のコマンドでSSHDのサービスを開始することができる。

$ sudo /etc/init.d/ssh restart

これでデーモン側の設定が完了した。デーモン側で以下のコマンドにより、IPアドレスを取得しメモする。

$ ifconfig

クライアントからログイン

sshのインストールされているクライアントPCで、以下のコマンドを実行。

$ ssh user名@メモしたipアドレス

これだけでログインが完了。$の前がデーモンのターミナルと同じような表記になっていれば成功だ。

ファイルの転送

scpコマンドを用いることによってリモート・ホスト間でファイルを転送することができる。

クライアントからファイルを送信

$ scp file名 user名@ipアドレス:$home

デーモンからファイルを受信

$ scp user名@ipアドレス:file名 保存先のディレクトリ

ディレクトリは-rオプションをつけると送れる。

ドメイン名の設定

いちいちipアドレスを入力するのは面倒なのでドメイン名を紐づける。
/etc/ssh/ssh_configに以下を追記。

Host 任意のドメイン名
  hostname ipアドレス
  user ユーザー名

以上により"ssh ユーザー名@ipアドレス"と入力していたのが以下だけでログインできるようになる。

ssh 設定したドメイン名




qiita.com
qiita.com
takuya-1st.hatenablog.jp
【 scp 】 リモート・マシン間でファイルをコピーする | 日経 xTECH(クロステック)

PyQtにおけるクラス設計 -MVCパターン-

MVCパターン

MVCパターンとはUIをもつアプリケーションにおけるデザインパターンである。クラスをModel、View、Controllerの3つに分ける。'単一責任原則'を考えるとそれぞれのクラスは以下の責務をもつ。

Model: データの格納とそのデータを用いた処理。
View: Modelのデータを描画。
Controller: Model、Viewに司令を出す。

f:id:tsupiano:20171207001756p:plain

MVCパターンは上の図のようになる。記事によってはModelとViewを繋いでいないものがある。どちらも不正解ではなく、その状況によって繋ぐか繋がないかの選択をする。ここに関しては以下の記事の後半が参考になった。
qiita.com

まずはMVCパターンのベースを構築

ContollerとViewはそれぞれ他2つにアクセスできるが、Modelは他クラスの情報にアクセスできない。この状態をコードに落としてみたのが以下。

# -*- coding: utf-8 -*-

class View(object): # 何も継承しないときは'object'を継承することが推奨されている
  def __init__(self,model):
    self.model = model

  def register(self,controller):
    self.controller = controller


class Model(object):
  def __init__(self):
    pass


class Controller(object):
  def __init__(self,view,model):
    self.view = view
    self.model = model

    self.view.register(self)


if __name__ == '__main__':
  model = Model()
  view = View(model)
  controller = Controller(view,model)

ベースに簡単なGUIを載せてみる

PyQtについては以下のページなどを参照してほしい。

qiita.com
myenigma.hatenablog.com
d.hatena.ne.jp


実際に処理をそれぞれのクラスに乗せるときに、各クラスの役割の規範を超えたことをしないように注意して以下のプログラムを作成した。

# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLabel
import sys

class View(QWidget): 
  def __init__(self, model):
    super().__init__()

    self.model = model

  def register(self,controller):
    self.controller = controller
    # controller生成後にinitUIしないとcontrollerのメソッドにバインドできない
    # これであってるかは不明...
    self.initUI() 
  
  def initUI(self):
    self.setGeometry(200,200,150,100)
    button = QPushButton('sayHello!!',self)
    button.clicked.connect(self.controller.pushButton)
    self.label = QLabel("none",self)
    self.label.setGeometry(20,50,50,20)

  def updateUI(self):
    self.label.setText(model.word)


class Model(object): # 何も継承しないときは'object'を継承することが推奨されている
  def __init__(self):
    self.word = 'none'
  
  def sayHello(self):
    # Modelは自身のデータを処理するだけ
    self.word = 'Hello'


class Controller(object):
  def __init__(self, view, model):
    self.view = view
    self.model = model

    self.view.register(self)
  
  def pushButton(self):
    # 複数の処理を行いたい際などに直接Modelに渡すのでなくControllerを挟むということが活きてくる
    self.model.sayHello()
    self.view.updateUI()


if __name__ == '__main__':
  app = QApplication(sys.argv)

  model = Model()
  view = View(model)
  controller = Controller(view,model)

  view.show()
  sys.exit(app.exec_())

PyQt お絵かきツール その1

PyQtとは?

PyQtは、クロスプラットフォームGUIツールキットであるQtのPythonバインディングにして、PythonGUIプログラミングをするときの選択肢の一つである。PyQtの他には、PySide・PyGTK・wxPythonTkinterなどのGUIツールキットが存在する。Qtと同様にPyQtフリーソフトウェアである。PyQtPythonプラグインとして実装されている。

PyQt|Wikipedia

PyQtとはPythonGUIのソフトを作るための一手段。GUIツールキットは他にも種類がありますので特徴を列挙しておきます。

Kivy

最近話題のやつでスマホアプリとかにも使われてるし、めちゃめちゃ見た目がかっちょいい。

wxPython

wxWidgetsというC++で書かれたやつのラッパー。wxPythonを覚えればC++でもすぐにGUIが書けるようになる。日本語情報はかなり多いしシェア率もトップレベル。

PyQt

wxPythonにとても似ているけど、PyQt自体の日本語情報は少ない。wxPython同様にC++書かれたQtのラッパーなので、それ向け記事を読んで自分でPythonで動くように読み換える能力があれば使える。(関数名と引数が把握できれば使える)

Tkinter

Pythonに標準で付属しているGUIライブラリなので環境構築は楽(というか何もしなくても使える)が、あまりデザインが綺麗ではない。
多くの参考書はGUIでこれを用いているので、入門にはとってもおすすめ。

PyGTK

GTK+のラッパー。GTK自体古い(?)らしくもうあまり使われてないみたい。(詳しくは知らない)


他にも色々あるが、メジャーなのはこんな感じ。難易度が高すぎずデザイン性も確保したいということでPyQtwxPythonの2択から選んだ。wxPythonの方が若干簡単そうだったのでそちらを使おうとしたら、インストールでなぜか上手くいかなかったので諦めてPyQtを使ってる。
f:id:tsupiano:20171125194935p:plain

PyQt入門

素晴らしき先人様の記事がたくさんあるのでそちらを読んでください。本記事ではPyQt5を使うけど、PyQt4のプログラムも多少変更すれば使えるので、読めるよ!C++のQtに関する記事は関数と引数が何かを知るのに役に立つ!
qiita.com
myenigma.hatenablog.com
d.hatena.ne.jp

いよいよ本題、お絵かきツールのベース作り

まずは完成したお絵かきツールのベース。ザーッと目を通す。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication,QWidget 

class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.points = []
        self.psets = []
        self.setMinimumSize(500, 500)
        self.setMaximumSize(500, 500)

    def mousePressEvent(self, event):
        self.points.append(event.pos())
        self.update()

    def mouseMoveEvent(self, event):
        self.points.append(event.pos())
        self.update()

    def mouseReleaseEvent(self, event):
        self.psets.append(self.points)
        self.points = []
        self.update()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Space:
            self.points = []
            self.psets = []
            self.update()        

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(Qt.black)

        for points in self.psets:
            painter.drawPolyline(*points)

        if self.points:
            painter.drawPolyline(*self.points)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

関数paintEvent、 keyPressEvent、mouseReleaseEvent、mousePressEvent、mouseMoveEventがそれぞれPyQtの中に最初からあり、各イベントごとにその名前の関数を呼び出してくれる。それぞれの役割は以下の通り。

・paintEvent / 画面を描画
・keyPressEvent / キーを押した時のイベント処理
・mousePressEvent / マウスを押した時のイベント処理
・mouseMoveEvent / マウスを動かした時のイベント処理
・mouseReleaseEvent / マウスを離した時のイベント処理

mouse*の関数でマウスの座標をリストに登録、paintEventで描画、というシンプルなプログラム。Spaceを押すことによってリストが空にされ、白紙に戻せる。

painter = QPainter(self)

でキャンバスを用意して、

painter.setPen(Qt.black)

でペンを用意。このときに線の太さとかも変えられるのでsetPenでググってみるといいかも。

painter.drawPolyline(*self.points)

QPointのリストに*をつけて渡してやると線が表示される。

※モジュールをインポートするときによく"from PyQt5.QtCore import *"みたいに"*"でインポートするプログラムを見るけど、あれは練習だからそうしてあるのであって、実際は名前空間を汚してしまう(関数名とかかごっちゃになる)ので実践で使うときは必ず特定のものだけインポートするようにする。

Latex入門

Latexとは?

 Latex(ラテフもしくはラテックと読む。ラテックスとは読まない。)は数式などをWordに比べて非常に簡単に入力できるだけでなく、表紙および目次の自動生成、式番号や文献参照などを自動で行ってくれる便利なフリーウェア。また、Webページを書く場合でも数式などはほとんどLatexが使われている。まずは例を下に示す。Latexから生成されるPDF(の写真)も同時に載せてあるので、これからこれが生成されるのかと見比べてみると良いと思われる。

- 見出し

f:id:tsupiano:20171102150905p:plain

\section{夏目漱石の小説から}
吾輩は猫である。名前はまだ無い。
どこで生れたかとんと見当がつかぬ。
何でも薄暗いじめじめした所で
ニャーニャー泣いていた事だけは記憶している。
吾輩はここで始めて人間というものを見た。

\section{特殊相対論}
日本で漱石が「吾輩は猫である」を発表したころ,
ドイツではAlbert Einsteinが特殊相対論を発表した。

\section{}で見出しを生成できる。この\sectionや\subsectionさえあれば、\tableofcontentsを記入するだけで勝手に目次を作ってくれる。

- 簡単な式

f:id:tsupiano:20171102151048p:plain

この理論によれば,エネルギー $E$ と質量 $m$\begin{equation}
  E = mc^{2}
\end{equation}
で関係づけられる。ここに $c$ は光速で,
\begin{equation}
  c = 299{,}792{,}458 \, \mathrm{m/s^2}
\end{equation}
である。

 文章に含める数式は$(数式)$、文章とは分ける場合は\begin{equation}及び\end{equation}で囲むことで生成できる。

- 複雑な式

f:id:tsupiano:20171102151440p:plain

\section{複雑な数式}
\[
  \frac{\pi}{2} =
  \left( \int_{0}^{\infty} \frac{\sin x}{\sqrt{x}} dx \right)^2 =
  \sum_{k=0}^{\infty} \frac{(2k)!}{2^{2k}(k!)^2} \frac{1}{2k+1} =
  \prod_{k=1}^{\infty} \frac{4k^2}{4k^2 - 1}
\]

\frac{}{}:分数、\int_{}^{}:インテグラル、\infty:無限、\sqrt:根号、、、
(全部理解しなくても使うときに調べればおk)
 Wordでマウスを使ってこれを入力するのは嫌だよね...
(僕はもともと数値計算する分野の人間だからこういうプログラムチックなLatexの表記にある程度は慣れてるけどどうだろう


 自動的にフォントを選んでもらえることに気づいただろうか。このフォントはLatexファイルの一番上部にそれぞれ見出しや本文などでまとめて定義することができ、Wordのように一部だけフォントが違うということが起こらなくなる。形式を普遍化できるのもLatexの特徴の一つだ。他にももっと機能は沢山あるが、それらは使うときに調べながら覚えていけばいい。


インストール

 まずはLatex(tex)のインストールを行う必要がある。本記事でつらつらと書くよりも分かりやすい記事があったので、以下にWindowsMacOSLinuxのそれぞれ3種類に関して書かれた記事を掲載しておく。自分のOSにあったものを選んでインストール。
windows.blogo.jp
qiita.com
medemanabu.net

PDF生成の方法

 まずは正しくインストールできていることの確認も含めサンプルをPDFファイルを生成してみる。LatexはWordのように直接文書を書くわけではないので、コンパイルという作業が必要になる。とりあえず、"sample.tex"というファイル名で内容は以下のURLからダウンロードしてファイルを作成する。
http://kitadake.net/u-gakugei/2005-04/10/example.tex

 次にWindowsならコマンドプロンプトMac or Linuxならterminalを開きcdコマンドでsample.texのおいてあるディレクトリに移動する。
cdコマンドがわからなければ次のページを参照。
作業ディレクトリを移動するcdコマンドの詳細まとめました【Linuxコマンド集】

 sample.texの存在するディレクトリに移動できたら、コマンドプロンプトもしくはterminalで以下のコマンドを入力。

$ platex sample.tex
$ dvipdf sample.dvi

※$マークは入力待ちを表す記号でコマンドプロンプトもしくはterminalに表されているので入力の必要はない。

これでsample.texと同じディレクトリにsample.pdfというファイルが生成されているはずなので、正しく生成できたか確認。



 
www.latex-cmd.com

C++からgnuplot -リアルタイムなグラフ描画-

使用環境: macOS Sierra ver 10.12.6、g++ 4.2.1
前提条件: gnuplotのPATHが通っている

まずは、C++からgnuplotを呼び出すプログラム

FILE* gnuplot = popen("gnuplot", "w"); 
fprintf(gnuplot, "plot 'Position_log.dat' using 1:4 with lines\n"); 
fflush(gnuplot); 

return EXIT_SUCCESS;

popen関数でプロセスへのパイプをオープンする。
Position_log.datには1列目に時間、2列目〜4列目に3次元で位置が記述されている。
fflushはバッファのフラッシュ(データの書き出し)を行なっている。

時間-高度グラフのリアルタイム表示

gnuplotでは以下のようにすると後から点を増やすことができる。eを入力すると終了する。

gnuplot> plot "-"
input data ('e' ends) > 2, 10
input data ('e' ends) > 4, 2
input data ('e' ends) > 3, 8
input data ('e' ends) > 8, 20
input data ('e' ends) > e

この機能を使って少しずつプロットするデータを増やしていけば良い。

FILE* gnuplot = popen("gnuplot", "w"); 
fprintf(gnuplot, "set xrange [0:15]\n");
fprintf(gnuplot, "set yrange [0:150]\n");

int step = 40000;

for (int j=1;j<step;j=j+100){  //j=0ではlineを作れないのでj=1からとする
	fprintf(gnuplot, "plot '-' with lines\n");
	for(int i=0; i<j; i=i+100){
		fprintf(gnuplot, "%lf, %lf\n",data[0][i],data[3][i]);
	}
	fprintf(gnuplot, "e\n"); 
	fflush(gnuplot);
	usleep(20000);
}

return EXIT_SUCCESS;

実時間と一致させるためには、描画時間を測って毎ループでjに足す数やusleepの時間を調整してやるか、
※data[0][:]に時間、data[3][:]に高度が入っている。

LinuxでOpenFOAMのソースをビルドする(dockerを使わずに入れる)

追記(2019.8.15): 公式サイトに書いてある環境すでに整っている程で書かれています。gccが古かったりすると希望のバージョンが入らないかもしれない。

1.必要なファイルをダウンロード

以下のコマンドを実行し、"OpenFOAM-2.1.1.tgz"と"ThirdParty-2.1.1.tgz"をダウンロードする。

wget "http://downloads.sourceforge.net/foam/OpenFOAM-2.1.1.tgz?use_mirror=mesh" -O OpenFOAM-2.1.1.tgz
wget "http://downloads.sourceforge.net/foam/ThirdParty-2.1.1.tgz?use_mirror=mesh" -O ThirdParty-2.1.1.tgz

2.ダウンロードしたファイルを解凍

mkdir $HOME/OpenFOAM
tar xvzf OpenFOAM-2.1.1.tgz -C $HOME/OpenFOAM
tar xvzf ThirdParty-2.1.1.tgz -C $HOME/OpenFOAM

3."$HOME/.cshrc"を編集

追記(2019.8.15): echo $SHELLで自分のシェルが何なのか(bashとかzshとかcshとか)を確認して、それに合わせた設定ファイルにOpenFOAM/OpenFOAM-○.○.○/etc/内のシェルを読み込ませる作業。

以下のコードを.cshrcに書き込む。(ない場合は新規作成)
※".cshrc"は再ログインしないと変更が適用されないので注意。

source $HOME/OpenFOAM/OpenFOAM-2.1.1/etc/cshrc

4.ThirdPartyとOpenFOAMをビルド

あとは、以下のコマンドでそれぞれをビルドすれば完了
(3時間くらいかかる)

追記(2019.8.15): もしかしたらエラー吐くかもしれない。適宜足りないものインストールしたりして対応してくれ。

$HOME/OpenFOAM/ThirdParty-2.1.1/Allwmake
$HOME/OpenFOAM/OpenFOAM-2.1.1/Allwmake

以上でOpenFOAMのインストールは終了しているはずなので、OpenFOAMのホームページにしたがってUser Configulationを行えばよい。

OpenFOAMによる熱移動と流れの数値解析

OpenFOAMによる熱移動と流れの数値解析