NetLogo 踩坑系列(二):奇技淫巧
NetLogo 踩坑系列(二):奇技淫巧
__includes
匯入 .nls
檔案
當模型包含多個例程時,全部寫在一個 .nlogo
檔案會顯得臃腫、結構不清晰、可讀性差,這就產生了拆分檔案的需求。NetLogo 提供了一個實驗性的 keyword __includes
,根據官方文件,用法如下
#! model.nlogo
__includes [ "directory/lib.nls" "directory/package.nls" ]
其中 lib.nls
和 package.nls
是兩個 NetLogo 原始檔(source file),directory
是存放該檔案的目錄。為更好展示其用法,本部落格設計了以下例子,原始碼放在
單個檔案
下面例子將一個列印 "Hello World!" 的程式複雜化,拆分成宣告全域性變數、初始化全域性變數和應用全域性變數、主例程 4 個步驟。這個例子雖然很愚蠢,但抽象自複雜 Model。
#! model.nlogo
; 宣告全域性變數
globals [
greeting
]
; 初始化全域性變數
to setup
set greeting "Hello World!"
end
; 應用全域性變數
to say-hi
print greeting
end
; 主例程
to go
say-hi
end
多個檔案
當各個步驟變得複雜時,拆分檔案可以讓邏輯變得更清晰。下面把前 3 個步驟放到 3 個不同的 .nls
#! libs/global.nls
globals [
greeting
]
#! libs/setup.nls
to setup
set greeting "Hello World!"
end
#! libs/package.nls
to say-hi
print greeting
end
然後在主例程中匯入 3 個原始檔(假設均放在目錄 libs
下)
#! split_model.nlogo
__includes ["libs/global.nls" "libs/setup.nls" "libs/package.nls" ]
to go
say-hi
end
下面對上述拆分做簡單的分析。可以看到,.nlogo
__includes
似乎只起到了“合併”檔案的作用。這和 Python 中 .py
檔案的地位有很大差別。
Headless 模式最佳實踐
有時我們不關心互動式介面,希望在後臺執行 model.nlogo
,比如希望重複試驗,希望在沒有桌面的伺服器上執行。通過 NetLogo 的 Headless 模式(無頭模式)可以實現。推薦使用 Java 呼叫 NetLogo,好處是使用簡單,可以結合 Java 實現更復雜的功能的。參考官方文件,寫了 Test.java
檔案進行測試,程式碼放在 github 上。
package com.test;
import org.nlogo.headless.HeadlessWorkspace;
public class Test {
public static void main (String[] args) {
System.out.println("Testing the headless mode...");
// model.nlogo 的路徑
String model = args[0];
try {
// 初始化
HeadlessWorkspace workspace = HeadlessWorkspace.newInstance();
// 開啟模型檔案
workspace.open(model);
// 執行 NetLogo 命令
workspace.command("setup");
workspace.command("repeat 1 [ go ]");
// 關閉模型檔案
workspace.dispose();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
該方法需要通過 -classpath
正確指定 NetLogo 的 jar 包的位置。此外可能遇到的坑是,模型檔案無法正確匯入 Java 擴充套件,需要將相應的 jar 包放到模型檔案所在的目錄下。
指定 Java 環境變數
BehaviorSpace 固然靈活,但有時需要在 GUI 裡面檢視視覺化結果,那如何在 NetLogo GUI 中設定環境變數、命令列傳參呢?其實跟 BehaviorSpace 的道理是一樣的。注意到 NetLogo 可以通過 netlogo.sh
或 netlogo-gui.sh
執行,那麼我們只需在 .sh
指令碼中指定環境變數和傳參就可以了。因為 NetLogo 5.1.0 的 shell 指令碼比較簡單,僅以該版本為例。在筆者的專案中,有一個第三方擴充套件需要呼叫 R 語言做統計分析,需要指定 JRI 的路徑。原始指令碼為
#!/bin/sh
cd "`dirname "$0"`" # the copious quoting is for handling paths with spaces
# -Djava.library.path=./lib ensure JOGL can find native libraries
# -Djava.ext.dirs= ignore any existing JOGL installation
# -XX:MaxPermSize=128m avoid OutOfMemory errors for large models
# -Xmx1024m use up to 1GB RAM (edit to increase)
# -Dfile.encoding=UTF-8 ensure Unicode characters in model files are compatible cross-platform
# -jar NetLogo.jar specify main jar
# "$@" pass along any command line arguments
java -Djava.library.path=./lib -Djava.ext.dirs= -XX:MaxPermSize=128m -Xmx1024m -Dfile.encoding=UTF-8 -jar NetLogo.jar "$@"
指定 JRI 目錄後的指令碼為
#!/bin/sh
cd "`dirname "$0"`" # the copious quoting is for handling paths with spaces
# -Djava.library.path=./lib ensure JOGL can find native libraries
# -Djava.ext.dirs= ignore any existing JOGL installation
# -XX:MaxPermSize=128m avoid OutOfMemory errors for large models
# -Xmx1024m use up to 1GB RAM (edit to increase)
# -Dfile.encoding=UTF-8 ensure Unicode characters in model files are compatible cross-platform
# -jar NetLogo.jar specify main jar
# "$@" pass along any command line arguments
java -Djava.library.path=./lib -Djava.ext.dirs= -XX:MaxPermSize=128m -Xmx1024m -Dfile.encoding=UTF-8 -Djava.library.path=/home/rotopia/R/x86_64-pc-linux-gnu-library/4.1/rJava/jri -jar NetLogo.jar "$@"
經過上述的改動,筆者專案中需要呼叫 JRI 的第三方擴充套件可以正常工作。