Repast Simphony——案例:僵尸感染人类

案例:僵尸感染人类

先放图
在这里插入图片描述
在这里插入图片描述

1. Repast Simphony

1.1 项目结构

修改项目为Repast Simphony视图

Window–>Perspective–>Open Perspective–>Other…–>Repast Simphony

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yj4p99D4-1619056046338)(image-20210421214919956.png)]

1.2 Projection

1.2.1 Continuous

描述空间,连续

ContinuousSpace<Object> space;
  • 构建

    ContinuousSpaceFactory spaceFactory = ContinuousSpaceFactoryFinder.createContinuousSpaceFactory(null);
    ContinuousSpace<Object> space = spaceFactory.createContinuousSpace("space", context,
    				new RandomCartesianAdder<Object>(), new repast.simphony.space.continuous.WrapAroundBorders(), 50, 50);
    
  • 某点位置

    NdPoint pt = space.getLocation(obj);
    
  • 位置移动

    space.moveByVector(object,distance,angle);
    //例
    space.moveByVector(this, 1, angle, 0);
    
    space.moveTo(object,newLocation);
    //例
    space.moveTo(zombie, spacePt.getX(), spacePt.getY());
    
1.2.2 Grid

描述空间,网格

Grid<Object> grid;
  • 构建

    GridFactory gridFactory = GridFactoryFinder.createGridFactory(null);
    Grid<Object> grid = gridFactory.createGrid("grid", context, new GridBuilderParameters<Object>(
    				new repast.simphony.space.grid.WrapAroundBorders(), new SimpleGridAdder<Object>(), true, 50, 50));
    
  • 某点位置

    GridPoint pt = grid.getLocation(obj);
    
  • 连续位置与网格位置相互转换

    • 网格位置–>连续位置
    NdPoint ptNd = new NdPoint(ptGrid.getX(), ptGrid.getY());
    
    • 连续位置–>网格位置
    GridPoint ptGrid = new GridPoint((int)ptNd.getX(), (int)ptNd.getY());
    
  • 位置移动

    grid.moveTo(obj,newLocation);
    //例
    grid.moveTo(zombie, ptGridPoint.getX(), ptGridPoint.getY());
    
1.2.3 Network

描述网络

  • 构建

    NetworkBuilder<Object> netBuilder = new NetworkBuilder<Object>("infection network", context, true);
    netBuilder.buildNetwork();
    
  • 添加边

    Network<Object> net = (Network<Object>) context.getProjection("infection network");
    net.addEdge(sourceObj, targetObj);
    

2. 构建模型

2.1 模型描述

僵尸

  1. 向人多的地方靠近
  2. 僵尸移动速度为1
  3. 僵尸接触到人会感染人

  1. 人向僵尸少的地方逃离
  2. 人移动速度为2,每次移动消耗1个能量
  3. 人的能量为0时,会在原地休息一个单位时间,能量恢复到最大

2.2 Agent

实体:僵尸、人

2.2.1 僵尸
  • 属性

    private ContinuousSpace<Object> space;	//连续位置
    private Grid<Object> grid;	//网格位置
    private boolean moved;	//是否移动
    
  • 构造函数

    public Zombie(ContinuousSpace<Object> space, Grid<Object> grid) {
    	this.space = space;
    	this.grid = grid;
    };
    
  • 成员函数

    • 移动一步

      public void step() {
      	// 获取Zombie的网格位置
      	GridPoint pt = grid.getLocation(this);
      
      	// 获取邻居
      	GridCellNgh<Human> nghCreator = new GridCellNgh<Human>(grid, pt, Human.class, 1, 1);
      	List<GridCell<Human>> gridCells = nghCreator.getNeighborhood(true);
      	SimUtilities.shuffle(gridCells, RandomHelper.getUniform());
      
      	GridPoint pointWithMostHumansGridPoint = null;
      	int maxCount = -1;
      	for (GridCell<Human> cell : gridCells) {
      		if (cell.size() > maxCount) {
      			pointWithMostHumansGridPoint = cell.getPoint();
      			maxCount = cell.size();
      		}
      	}
      	moveTowards(pointWithMostHumansGridPoint);
      	infect();
      }
      
      • 位置移动

        public void moveTowards(GridPoint pt) {
        	if (!pt.equals(grid.getLocation(this))) {
        		NdPoint myPoint = space.getLocation(this);
        		NdPoint otherPoint = new NdPoint(pt.getX(), pt.getY());// 网格点转连续点
        		double angle = SpatialMath.calcAngleFor2DMovement(space, myPoint, otherPoint);
        		space.moveByVector(this, 1, angle, 0);// 空间移动
        		myPoint = space.getLocation(this);
        		grid.moveTo(this, (int) myPoint.getX(), (int) myPoint.getY());// 网格移动
        
        		moved = true;
        	}
        }
        
      • 感染人类

        public void infect() {
        	GridPoint ptGridPoint = grid.getLocation(this);
        	List<Object> humans = new ArrayList<Object>();
        	for (Object obj : grid.getObjectsAt(ptGridPoint.getX(), ptGridPoint.getY())) {
        		if (obj instanceof Human) {
        			humans.add(obj);
        		}
        	}
        	if (humans.size() > 0) {
        		int index = RandomHelper.nextIntFromTo(0, humans.size() - 1);
        		Object obj = humans.get(index);
        		NdPoint spacePt = space.getLocation(obj);
        		Context<Object> context = ContextUtils.getContext(obj);
        		context.remove(obj);
        		Zombie zombie = new Zombie(space, grid);
        		context.add(zombie);
        		space.moveTo(zombie, spacePt.getX(), spacePt.getY());
        		grid.moveTo(zombie, ptGridPoint.getX(), ptGridPoint.getY());
        		Network<Object> net = (Network<Object>) context.getProjection("infection network");
        		net.addEdge(this, zombie);
        	}
        }
        
2.2.2 人
  • 属性

    private ContinuousSpace<Object> space;
    private Grid<Object> grid;
    private int energy, startingEnergy;
    
  • 构造函数

    public Human(ContinuousSpace<Object> space, Grid<Object> grid, int energy) {
    	this.space = space;
    	this.grid = grid;
    	this.energy = startingEnergy = energy;
    }
    
  • 成员函数

    • 躲避僵尸

      public void run() {
      	GridPoint pt = grid.getLocation(this);
      	GridCellNgh<Zombie> nghCreator = new GridCellNgh<Zombie>(grid, pt, Zombie.class, 1, 1);
      	List<GridCell<Zombie>> gridCells = nghCreator.getNeighborhood(true);
      	SimUtilities.shuffle(gridCells, RandomHelper.getUniform());
      
      	GridPoint pointWithLeastZombiesGridPoint = null;
      	int minCount = Integer.MAX_VALUE;
      	for (GridCell<Zombie> cell : gridCells) {
      		if (cell.size() < minCount) {
      			pointWithLeastZombiesGridPoint = cell.getPoint();
      			minCount = cell.size();
      		}
      	}
      	if (energy > 0) {
      		moveTowards(pointWithLeastZombiesGridPoint);
      	} else {
      		energy = startingEnergy;
      	}
      }
      
      • 位置移动

        public void moveTowards(GridPoint pt) {
        	if (!pt.equals(grid.getLocation(this))) {
        		NdPoint myPoint = space.getLocation(this);
        		NdPoint otherPoint = new NdPoint(pt.getX(), pt.getY());// 网格点转连续点
        		double angle = SpatialMath.calcAngleFor2DMovement(space, myPoint, otherPoint);
        		space.moveByVector(this, 2, angle, 0);// 空间移动
        		myPoint = space.getLocation(this);
        		grid.moveTo(this, (int) myPoint.getX(), (int) myPoint.getY());// 网格移动
        		energy--;
        	}
        }
        
2.2.3 为Agent添加动作触发条件

以给函数添加注解的方式添加触发条件

  • 僵尸移动:每隔1个时间触发一次

    @ScheduledMethod(start = 1, interval = 1)
    
  • 人类逃跑:当附近一个格子(1个摩尔距离)内有僵尸出现时发生

    @Watch(watcheeClassName = "jzombies.Zombie", 
           watcheeFieldNames = "moved",
           query = "within_moore 1",
           whenToTrigger = WatcherTriggerSchedule.IMMEDIATE)
    

2.3 Builder

构建环境:实现接口ContextBuilder<>的build函数

  • 设置id

    context.setId("jzombies");
    
  • 添加Projection

    ContinuousSpaceFactory spaceFactory = ContinuousSpaceFactoryFinder.createContinuousSpaceFactory(null);
    		ContinuousSpace<Object> space = spaceFactory.createContinuousSpace("space", context,
    				new RandomCartesianAdder<Object>(), new repast.simphony.space.continuous.WrapAroundBorders(), 50, 50);
    
    		GridFactory gridFactory = GridFactoryFinder.createGridFactory(null);
    		Grid<Object> grid = gridFactory.createGrid("grid", context, new GridBuilderParameters<Object>(
    				new repast.simphony.space.grid.WrapAroundBorders(), new SimpleGridAdder<Object>(), true, 50, 50));
    
    		NetworkBuilder<Object> netBuilder = new NetworkBuilder<Object>("infection network", context, true);
    		netBuilder.buildNetwork();
    
  • 添加Agent

    Parameters params = RunEnvironment.getInstance().getParameters();
    		int zombieCount = params.getInteger("zombie_count");
    		for (int i = 0; i < zombieCount; i++) {
    			context.add(new Zombie(space, grid));
    		}
    
    		int humanCount = params.getInteger("human_count");
    		for (int i = 0; i < humanCount; i++) {
    			int energy = RandomHelper.nextIntFromTo(4, 10);
    			context.add(new Human(space, grid, energy));
    		}
    
    		for (Object obj : context) {
    			NdPoint pt = space.getLocation(obj);
    			grid.moveTo(obj, (int) pt.getX(), (int) pt.getY());
    		}
    

2.4 context

在context.xml中注册projection便于GUI操作

<context id="jzombies"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="http://repast.org/scenario/context">
	<projection type="continuous space" id="space"/>
	<projection type="grid" id="grid"/>
	<projection type="network" id="infection network"/>
</context>

2.5 完整代码

  • Zombie.java

    /**
     * 
     */
    package jzombies;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import repast.simphony.context.Context;
    import repast.simphony.engine.schedule.ScheduledMethod;
    import repast.simphony.query.space.grid.GridCell;
    import repast.simphony.query.space.grid.GridCellNgh;
    import repast.simphony.random.RandomHelper;
    import repast.simphony.space.SpatialMath;
    import repast.simphony.space.continuous.ContinuousSpace;
    import repast.simphony.space.continuous.NdPoint;
    import repast.simphony.space.graph.Network;
    import repast.simphony.space.grid.Grid;
    import repast.simphony.space.grid.GridPoint;
    import repast.simphony.util.ContextUtils;
    import repast.simphony.util.SimUtilities;
    
    /**
     * @author 60382
     *
     */
    public class Zombie {
    
    	private ContinuousSpace<Object> space;
    	private Grid<Object> grid;
    	private boolean moved;
    
    	public Zombie(ContinuousSpace<Object> space, Grid<Object> grid) {
    		// TODO Auto-generated constructor stub
    		this.space = space;
    		this.grid = grid;
    	};
    
    	@ScheduledMethod(start = 1, interval = 1)
    	public void step() {
    		// 获取Zombie的网格位置
    		GridPoint pt = grid.getLocation(this);
    
    		// 获取邻居
    		GridCellNgh<Human> nghCreator = new GridCellNgh<Human>(grid, pt, Human.class, 1, 1);
    		List<GridCell<Human>> gridCells = nghCreator.getNeighborhood(true);
    		SimUtilities.shuffle(gridCells, RandomHelper.getUniform());
    
    		GridPoint pointWithMostHumansGridPoint = null;
    		int maxCount = -1;
    		for (GridCell<Human> cell : gridCells) {
    			if (cell.size() > maxCount) {
    				pointWithMostHumansGridPoint = cell.getPoint();
    				maxCount = cell.size();
    			}
    		}
    		moveTowards(pointWithMostHumansGridPoint);
    		infect();
    	}
    
    	public void moveTowards(GridPoint pt) {
    		if (!pt.equals(grid.getLocation(this))) {
    			NdPoint myPoint = space.getLocation(this);
    			NdPoint otherPoint = new NdPoint(pt.getX(), pt.getY());// 网格点转连续点
    			double angle = SpatialMath.calcAngleFor2DMovement(space, myPoint, otherPoint);
    			space.moveByVector(this, 1, angle, 0);// 空间移动
    			myPoint = space.getLocation(this);
    			grid.moveTo(this, (int) myPoint.getX(), (int) myPoint.getY());// 网格移动
    
    			moved = true;
    		}
    	}
    
    	public void infect() {
    		GridPoint ptGridPoint = grid.getLocation(this);
    		List<Object> humans = new ArrayList<Object>();
    		for (Object obj : grid.getObjectsAt(ptGridPoint.getX(), ptGridPoint.getY())) {
    			if (obj instanceof Human) {
    				humans.add(obj);
    			}
    		}
    		if (humans.size() > 0) {
    			int index = RandomHelper.nextIntFromTo(0, humans.size() - 1);
    			Object obj = humans.get(index);
    			NdPoint spacePt = space.getLocation(obj);
    			Context<Object> context = ContextUtils.getContext(obj);
    			context.remove(obj);
    			Zombie zombie = new Zombie(space, grid);
    			context.add(zombie);
    			space.moveTo(zombie, spacePt.getX(), spacePt.getY());
    			grid.moveTo(zombie, ptGridPoint.getX(), ptGridPoint.getY());
    			Network<Object> net = (Network<Object>) context.getProjection("infection network");
    			net.addEdge(this, zombie);
    
    		}
    	}
    }
    
  • Human.java

    /**
     * 
     */
    package jzombies;
    
    import java.util.List;
    
    import repast.simphony.engine.watcher.Watch;
    import repast.simphony.engine.watcher.WatcherTriggerSchedule;
    import repast.simphony.query.space.grid.GridCell;
    import repast.simphony.query.space.grid.GridCellNgh;
    import repast.simphony.random.RandomHelper;
    import repast.simphony.relogo.ide.dynamics.NetLogoSystemDynamicsParser.intg_return;
    import repast.simphony.space.SpatialMath;
    import repast.simphony.space.continuous.ContinuousSpace;
    import repast.simphony.space.continuous.NdPoint;
    import repast.simphony.space.grid.Grid;
    import repast.simphony.space.grid.GridPoint;
    import repast.simphony.util.SimUtilities;
    
    /**
     * @author 60382
     *
     */
    public class Human {
    
    	private ContinuousSpace<Object> space;
    	private Grid<Object> grid;
    	private int energy, startingEnergy;
    
    	public Human(ContinuousSpace<Object> space, Grid<Object> grid, int energy) {
    		// TODO Auto-generated constructor stub
    		this.space = space;
    		this.grid = grid;
    		this.energy = startingEnergy = energy;
    	}
    
    	@Watch(watcheeClassName = "jzombies.Zombie", watcheeFieldNames = "moved", query = "within_moore 1", whenToTrigger = WatcherTriggerSchedule.IMMEDIATE)
    	public void run() {
    		GridPoint pt = grid.getLocation(this);
    		GridCellNgh<Zombie> nghCreator = new GridCellNgh<Zombie>(grid, pt, Zombie.class, 1, 1);
    		List<GridCell<Zombie>> gridCells = nghCreator.getNeighborhood(true);
    		SimUtilities.shuffle(gridCells, RandomHelper.getUniform());
    
    		GridPoint pointWithLeastZombiesGridPoint = null;
    		int minCount = Integer.MAX_VALUE;
    		for (GridCell<Zombie> cell : gridCells) {
    			if (cell.size() < minCount) {
    				pointWithLeastZombiesGridPoint = cell.getPoint();
    				minCount = cell.size();
    			}
    		}
    		if (energy > 0) {
    			moveTowards(pointWithLeastZombiesGridPoint);
    		} else {
    			energy = startingEnergy;
    		}
    	}
    
    	public void moveTowards(GridPoint pt) {
    		if (!pt.equals(grid.getLocation(this))) {
    			NdPoint myPoint = space.getLocation(this);
    			NdPoint otherPoint = new NdPoint(pt.getX(), pt.getY());// 网格点转连续点
    			double angle = SpatialMath.calcAngleFor2DMovement(space, myPoint, otherPoint);
    			space.moveByVector(this, 2, angle, 0);// 空间移动
    			myPoint = space.getLocation(this);
    			grid.moveTo(this, (int) myPoint.getX(), (int) myPoint.getY());// 网格移动
    			energy--;
    		}
    	}
    }
    
  • JZombiesBuilder.java

    package jzombies;
    
    import repast.simphony.context.Context;
    import repast.simphony.context.space.continuous.ContinuousSpaceFactory;
    import repast.simphony.context.space.continuous.ContinuousSpaceFactoryFinder;
    import repast.simphony.context.space.graph.NetworkBuilder;
    import repast.simphony.context.space.grid.GridFactory;
    import repast.simphony.context.space.grid.GridFactoryFinder;
    import repast.simphony.dataLoader.ContextBuilder;
    import repast.simphony.engine.environment.RunEnvironment;
    import repast.simphony.parameter.Parameters;
    import repast.simphony.random.RandomHelper;
    import repast.simphony.space.continuous.ContinuousSpace;
    import repast.simphony.space.continuous.NdPoint;
    import repast.simphony.space.continuous.RandomCartesianAdder;
    import repast.simphony.space.grid.Grid;
    import repast.simphony.space.grid.GridBuilderParameters;
    import repast.simphony.space.grid.SimpleGridAdder;
    
    public class JZombiesBuilder implements ContextBuilder<Object> {
    
    	@Override
    	public Context build(Context<Object> context) {
    		// TODO Auto-generated method stub
    		context.setId("jzombies");
    
    		ContinuousSpaceFactory spaceFactory = ContinuousSpaceFactoryFinder.createContinuousSpaceFactory(null);
    		ContinuousSpace<Object> space = spaceFactory.createContinuousSpace("space", context,
    				new RandomCartesianAdder<Object>(), new repast.simphony.space.continuous.WrapAroundBorders(), 50, 50);
    
    		GridFactory gridFactory = GridFactoryFinder.createGridFactory(null);
    		Grid<Object> grid = gridFactory.createGrid("grid", context, new GridBuilderParameters<Object>(
    				new repast.simphony.space.grid.WrapAroundBorders(), new SimpleGridAdder<Object>(), true, 50, 50));
    
    		NetworkBuilder<Object> netBuilder = new NetworkBuilder<Object>("infection network", context, true);
    		netBuilder.buildNetwork();
    
    		Parameters params = RunEnvironment.getInstance().getParameters();
    		int zombieCount = params.getInteger("zombie_count");
    		for (int i = 0; i < zombieCount; i++) {
    			context.add(new Zombie(space, grid));
    		}
    
    		int humanCount = params.getInteger("human_count");
    		for (int i = 0; i < humanCount; i++) {
    			int energy = RandomHelper.nextIntFromTo(4, 10);
    			context.add(new Human(space, grid, energy));
    		}
    
    		for (Object obj : context) {
    			NdPoint pt = space.getLocation(obj);
    			grid.moveTo(obj, (int) pt.getX(), (int) pt.getY());
    		}
    		return context;
    	}
    }
    
  • context.xml

    <context id="jzombies"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:noNamespaceSchemaLocation="http://repast.org/scenario/context">
    	<projection type="continuous space" id="space"/>
    	<projection type="grid" id="grid"/>
    	<projection type="network" id="infection network"/>
    </context>
    

3. 模型运行

3.1 Data Loaders

添加数据加载器

  1. 右键Data Loaders

  2. Set Data Loader

  3. Custom ContextBuilder Implementation

  4. 选择实现ContextBuilder<>接口所建立的类JZombiesBuilder

3.2 Displays

  1. 右键Displays
  2. Add Display
  3. 定义名字、2D/3D图形、选择Projection(Continuous和Grid二选一)
  4. 选择Agent,Zombie在上面(Human的动作为被动触发的)
  5. 选择Agent样式
  6. Continuous或Grid样式
  7. Network样式
  8. 时间

3.3 Data Sets

添加需要记录的数据之后可以用图表显示或输出到文件

  • Aggregate数据

  • Non-Aggregate数据

Add Data Set选择要记录哪些数据

3.3.1 Charts

添加图表显示数据

  • Histogram Chart
  • Time Series Chart
3.3.2 Text Sinks

输出数据

  • Consloe Sink

  • File Sink

3.4 Run Options

运行时间、速度设置

  • 设置暂停时间

  • 设置结束时间(0表示无限)

  • 设置演示速度

3.5 Parameters

添加GUI参数

在代码中可以通过Parameters类根据id解析

Parameters params = RunEnvironment.getInstance().getParameters();
int zombieCount = params.getInteger("zombie_count");
int humanCount = params.getInteger("human_count");

3.6 模型打包

Build Installer for Model

可打包成jar

4. 参考

Repast Simphony DownLoads: https://repast.github.io/download.html

Repast Java Getting Started: https://repast.github.io/docs/RepastJavaGettingStarted.pdf

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Repast软件是一种基于Agent的建模和仿真工具,广泛应用于复杂的社会系统研究。以下是一个Repast软件的应用案例。 以城市交通系统为例,研究者可以使用Repast软件来模拟和分析交通流量、交通拥堵状况以及交通政策的效果。首先,研究者可以将城市划分为多个区域,并为每个区域创建相应的交通节点和道路网络。然后,他们可以根据实际情况设定不同车辆类型的属性和行驶规则,如车速、车辆数量和车辆出行意愿等。 基于这些设定,研究者可以运行模拟实验,观察不同的交通流量模式对道路拥堵的影响。例如,他们可以测试不同区域之间的车辆流动方式,以及不同道路容量对交通流量的影响。通过分析模拟结果,研究者可以评估不同策略和措施对交通系统性能的影响,并提出优化建议。 此外,Repast软件还可以用于研究城市规划和土地利用的影响。研究者可以创建不同类型的土地利用区域,例如商业区、住宅区和工业区,并设置相应的人口和就业密度。然后,他们可以模拟人口和就业的分布、流动和交通需求,以便研究不同规划方案对交通拥堵和环境影响的影响。 综上所述,Repast软件在城市交通系统研究中具有广泛应用。它不仅可以帮助研究者模拟交通流量、拥堵状况和交通政策的效果,还可以用于研究土地利用和城市规划对交通系统的影响。这些分析结果可以为决策者提供科学依据,以优化交通系统的运营和城市规划。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值