【MASON】ABM仿真笔记(二)预备篇——Mason核心之概述

本文翻译并提炼自官方文档

MASON的核心模拟代码在sim.engine包中,该包主要包含以下类:

  • sim.engine.SimState:保存Agent模型的全局对象。
  • sim.engine.Schedule:离散事件调度队列(Scheduling Queue)。
  • sim.engine.Stepable:由Agent实现的接口,step方法将作为Schedule的任务
  • 其他工具类。

SimState模拟实体,Schedule模拟时间,而fields模拟空间和Agent之间的关系。fields相关类不在sim.engine中,而在以下包中:

  • sim.field.grid:保存二维或三维网格。
  • sim.field.continuous:保存连续的二维或三维网格数据。
  • sim.field.network:保存图形和网络。

(一)模型

启动主程序需要创建一个sim.engine.SimState的子类,模拟所需的所有元素将组合在此类中。包括模型参数、自定义类型数据等,可以作为SimState子类的一个成员变量保存。
UML diagram of MASON’s core simulation and discrete-event schedule facility.
由于模型中的所有数据最终都存储在SimState子类的某个成员变量上,MASON可以将整个模型序列化为checkpoint文件,这意味着可以随时冻结模拟将其全部保存到文件中,并可以从此文件重新启动模型。为了实现这一点,所有MASON模型对象都实现了java.io.Serializable,这意味着它们可以写入流或从流中读取。
SimState已经包含了以下两个成员变量:

public MersenneTwisterFast random;
public Schedule schedule;

random是采用Mersenne Twister算法实现的随机数快速生成器。与java.util.Random的伪随机数不同,这是一个高质量的随机数生成器(尽管MersenneTwisterFast也是伪随机数生成器)。

MersenneTrusterFast不是线程同步的。通常MASON模拟是单线程的,也就没有问题。但如果模拟被分解为多个线程,需要确以线程安全的方式访问random,示例代码如下:

double val = 0;
// state是SimState的实例
synchronized(state.random) { 
	val = random.nextDouble(); 
}

schedule将在下文介绍。

(二)循环

MASON通过SimState来进行模拟,它加载设定好步骤的Schedule,重复执行时间表直到没有step可执行,然后清理。具体步骤如示例代码所示:

public static void main(String[] args) {
	int jobs = 100; // 迭代次数上限
	// 创建SimState子类的实例,System.currentTimeMillis()将作为随机数生成器的种子
	SimState state = new MyModel(System.currentTimeMillis());
	for(int job = 0; job < jobs; job++) {
		state.setJob(job);
		state.start();
		do
			if (!state.schedule.step(state)) break;
		while(state.schedule.getSteps() < 5000);
		state.finish();
	}
	// 退出,需要终止所有可能意外创建的线程
	System.exit(0);
}

doLoop()方法

如果从命令行运行模型(没有GUI),有一种更简单的方法:使用SimStatedoLoop方法:

public static void main(String[] args) {
	doLoop(MyModel.class, args);
	System.exit(0);
}

doLoop的优点是它提供了许多命令行工具:

  • 工作处理。运行模拟指定次,并可以将它们放入并行批中处理。
  • 检查点。保存检查点并从检查点文件启动。
  • 指定随机数种子。
  • 指定模拟时长或步长。
  • 运行时自动打印时间戳,以便确定模型运行了多久。

完整参数作用可在启动SimState时追加-help参数查看。

java MyModel -help

启动和完成

模拟开始时,首先调用(构造函数除外)start()。结束时最后调用finish()。其定义如下:

// 在迭代之前立即调用。可能需要重写此方法来设置模拟(或者清理并重新准备)。
// 一定要先调用super.start()
public void start();
// schedule用完后立即调用。您可能希望覆盖此方法以在以后进行清理:例如关闭各种流。
// 一定要先调用super.finish()
public void finish();

通常需要重写的方法是start(),一般覆写需要完成以下任务:

  • 重置全局变量以再次使用;
  • 用初始agent重载schedule,schedule将会在super.start()中被清除。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值