Microscopic models : granular and social force model

Microscopic models : granular and social force model

cromosim.micro.add_people_in_box(Np, dom, xmin, xmax, ymin, ymax, rmin, rmax, rng)[source]

Adds new persons in the box [xmin,xmax]x[ymin,ymax] Be careful : overlaps can be occured…

Parameters:
Np: int

Number of persons

dom: Domain

contains everything for managing the domain

xmin: float

minimal abscissa of the box

xmax : float

maximal abscissa of the box

ymin: float

minimal ordinate of the box

ymax: float

maximal ordinate of the box

rmin: float

minimum radius for the individuals

rmax: float

maximum radius for the individuals

rng: scipy.random.RandomState

container for the Mersenne Twister pseudo-random number generator

Returns
——-
people : numpy array

people coordinates and radius

cromosim.micro.check_people_in_box(dom, box, p, rng)[source]

To check that people coordinates are in the given box (test 1) and in an usable space i.e. in an area accessible and not concerned by obstacles (test 2). On the other hand, we move the individual which do not satisfy these two tests.

Parameters:
dom: Domain

contains everything for managing the domain

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

p: numpy array

people coordinates x y r

rng: RandomState

scipy random state object (see scipy.random.RandomState)

Returns:
p: numpy array

new people coordinates x y r

cromosim.micro.compute_contacts(dom, people, dmax)[source]

This function uses a KDTree method to find the contacts  between individuals. Moreover the contacts with the walls are also determined from the wall distance (obtained by the fast-marching method).

Parameters:
dom: Domain

contains everything for managing the domain

people: numpy array

people coordinates and radius : x,y,r

dmax: float

threshold value used to consider a contact as active (dij<dmax)

Returns:
contacts: numpy array

all the contacts i,j,dij,eij_x,eij_y such that dij<dmax and i<j (no duplication)

cromosim.micro.compute_desired_velocity(dom, people)[source]

This function determines people desired velocities from the desired velocity array computed by Domain thanks to a fast-marching method.

Parameters:
dom: Domain

contains everything for managing the domain

people: numpy array

people coordinates and radius : x,y,r

Returns:
I : numpy array

people index i

J : numpy array

people index j

Vd : numpy array

people desired velocity

cromosim.micro.compute_forces(F, Fwall, people, contacts, U, Vd, lambda_, delta, k, eta)[source]

This function computes all the forces (isentropic interaction and friction) and sums them. The correcting pre-factor due to the vision angle is also used into the social force term.

Parameters:
F: float

social trend of an individual to keep apart from another (homogeneous to a force)

Fwall: float

social trend of an individual to keep apart from a wall (homogeneous to a force)

people: numpy array

people coordinates and radius : x,y,r

contacts: numpy array

all the contacts : i,j,dij,eij_x,eij_y

U: numpy array

people velocities

Vd: numpy array

people desired velocities

lambda_: float

quantifies the directional dependence when the vision angle is considered (between [0,1], if equal to 1 the fully isotropic case is recovered)

delta: float

maintains a certain distance between neighbors

k: float

used when there is overlapping, k is a stiffness constant of individuals seen as deformable bodies

eta: float

friction coefficient

Returns:
Forces: numpy array

sum of all forces for each individual

cromosim.micro.create_people_in_box(np, box, rmin, rmax, dom, rng)[source]

To create np persons in a given box. The overvalps are not treated for the moment but we check that the individuals are located in an area where  the desired velocity is well defined (outside inaccessible areas or obstacles). If it is not the case, we change their coordinates in consequence.

Parameters:
np: integer

number of individuals to create

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

rmin: float

people minimal radius

rmax: float

people maximal radius

dom: Domain

contains everything for managing the domain

rng: RandomState

scipy random state object (see scipy.random.RandomState)

Returns:
p: numpy array

new people coordinates x y r

cromosim.micro.exit_box(box, sexit, people, U, arrays=[])[source]

Removes individuals outside the box according to a threshold value.

Parameters:
box: numpy array

box vertice coordinates [xmin, xmax, ymin, ymax]

sexit: float

threshold value used to remove individuals close to the exit

people : numpy array

people coordinates and radius : x,y,r

U: numpy array

people velocities

arrays: list of numpy array

other arrays to resize similarly as people and U

Returns:
people: numpy array

new people coordinates (outside individuals had been removed)

U: numpy array

new people velocities (outside individuals had been removed)

arrays: list of numpy array

new resized arrays taking into account deleted individuals

cromosim.micro.exit_door(sexit, dom, people, U, arrays=[])[source]

Removes individuals who are at a distance less than sexit to the closest door

Parameters:
sexit: float

threshold value used to remove individuals close to the exit

dom: Domain

contains everything for managing the domain

people: numpy array

people coordinates and radius : x,y,r

U: numpy array

people velocities

arrays: list of numpy array

other arrays to resize similarly as people and U arrays

Returns:
people: numpy array

new people positions (outside individuals had been removed)

U: numpy array

new poeple velocities (outside individuals had been removed)

arrays: list of numpy array

new array resized

cromosim.micro.exit_out_of_domain(dom, people, arrays=[], box=None)[source]

Removes individuals who are outside the domain or outside a given box

Parameters:
dom: Domain

contains everything for managing the domain

people: numpy array

people coordinates and radius : x,y,r

arrays: list of numpy array

other arrays to resize similarly as people and U

box: numpy array

box coordinates [xmin,xmax,ymin,ymax] which replace the domain minimum and maximum coordinates

Returns:
people: numpy array

new people array (outside individuals had been removed)

arrays: list of numpy array

new arrays resized similarly as people array

cromosim.micro.move_people(time, dt, people, U, crosslines=[])[source]

Updates the people positions according to the new velocities U. If there exits crosslines (i.e. sensors), computes also the id, time, direction and impact points for the individuals who cross the lines.

Parameters:
time: float

current time

dt: float

time step

people: numpy array

people coordinates and radius : x,y,r

U: numpy array

people velocities

crosslines: list of numpy array

list of lines [[x0,y0,x1,y1], [x0,y0,x1,y1], …]

Returns:
people: numpy array

new people positions after moving

io_id: list of integers

indices of people who cross the lines (sensors)

io_times: list of floats

times when people cross the lines (sensors)

io_pts: list of floats

impact points for people crossing the lines (sensors)

io_dir: list of floats

directions for people crossing the lines (sensors), i.e. entry or exit

cromosim.micro.people_initialization(N, init_people_box, dom, dt, rmin, rmax, dmin=0, seed=0, itermax=10)[source]

To initialize people array (xyr) with coordinates in several boxes and without overlaps between them.

Parameters:
N: list

list of the numbers of persons to add in each box

init_people_box: list

list of the boxes [[xmin, xmax, ymin, ymax],…]

dom: Domain

contains everything for managing the domain

dt: float

time step

rmin: float

people minimal radius

rmax: float

people maximal radius

dmin: float

minimal distance allowed between individuals (0 by default)

seed: integer

seed to initialize the RandomState (0 by default means different seed at each run)

itermax: integer

maximal number of Uzawa projections (10 by default)

Returns:
people: numpy array

new people coordinates x y r

people_init_box_id: numpy array

box number for each individual

rng: RandomState

scipy random state object (see scipy.random.RandomState)

cromosim.micro.periodic_bc_vertical(ymin, ymax, people, U, xmin=None, xmax=None, rng=None)[source]

Does not exactly correspond to periodic boundary conditions (in the mathematical sense): the persons having an y-coordinate y less than ymin (respectively greater than ymax) are reinjected at y+(ymax-ymin) (respectively at y-(ymax-ymin)) with (optionally) random x-coordinates (between xmin and xmax, and with velocities equal to 0.

Parameters:
ymin: float

minimal ordinate of the box

ymax: float

maximal ordinate of the box

people: numpy array

people coordinates and radius : x,y,r

U: numpy array

people velocities

xmin: float

minimal abscissa of the box

xmax: float

maximal abscissa of the box

rng: RandomState

scipy random state object (see scipy.random.RandomState)

Returns:
people: numpy array

new people coordinates (outside individuals had been moved)

U: numpy array

new people velocities

cromosim.micro.plot_people(ifig, dom, people, contacts, U, colors, time=-1, axis=None, plot_people=True, plot_contacts=True, plot_velocities=True, plot_paths=False, paths=None, plot_sensors=False, sensors=[], savefig=False, filename='fig.png', cmap='winter')[source]

This function draws spheres for the individuals, lines for the active contacts and arrows for the (desired or real) velocities.

Parameters:
ifig: int

figure number

dom: Domain

contains everything for managing the domain

people: numpy array

people coordinates and radius : x,y,r

contacts: numpy array

all the contacts : i,j,dij,eij_x,eij_y

U: numpy array

people velocities

colors: numpy array

scalar field used to define people colors

time: float

time in seconds

axis: numpy array

matplotlib axis : [xmin, xmax, ymin, ymax]

plot_people: boolean

draws spheres for people if true

plot_paths: boolean

draws people paths if true

paths: numpy array

coordinates of the people paths

plot_sensors: boolean

draws sensor lines if true

sensors: numpy array

sensor line coordinates (see also the sensor function below)

savefig: boolean

writes the figure as a png file if true

filename: string

png filename used to write the figure

cmap: string

matplotlib colormap name

cromosim.micro.plot_sensor_data(ifig, sensor_data, time, initial_door_dist=None, axis=None, flux_timestep=1, savefig=False, filename='fig.png', cmap='winter')[source]

When a sensor line is defined this function allows to draw the repartition of the people exit times.

Parameters:
ifig: int

figure number

sensor_data : numpy array

[time, direction, intersection_point[2]] for each individual

time: float

time in seconds

initial_door_dist: numpy array

people initial distance to the door

axis: numpy array

matplotlib axis : [xmin, xmax, ymin, ymax]

flux_timestep: float

timestep for the fluxes : number of persons per flux_timestep seconds

savefig: boolean

writes the figure as a png file if true

filename: string

png filename used to write the figure

cmap: string

matplotlib colormap name

cromosim.micro.projection_uzawa(dt, people, contacts, Vd, dmin=0.0, nb_iter_max=100000, rho=0.1, tol=0.01, log=False)[source]

From the desired velocities Vd, this projection step consists to compute the global velocity field which shall be defined as the closest to the desired one among all those feasible fields (i.e. fields which do not lead  to overlapping of disks).

Parameters:
dt: float

time step

people: numpy array

people coordinates and radius : x,y,r

contacts: numpy array

all the contacts : i,j,dij,eij_x,eij_y

Vd: numpy array

people desired velocities

dmin: float

minimum distance guaranteed between individuals

nb_iter_max: integer

maximum number of iterations allowed

rho: float

parameter of the Uzawa method

tol: float

tolerance wished

log: boolean

to print the final accurancy, number of iterations,…

Returns:
B: numpy array

constraint matrix

U: numpy array

new people velocities ensuring there is no overlap between individuals

L: numpy array

Lagrange multipliers

P: numpy array

pressure on each individual

info: integer

number of iterations needed

cromosim.micro.remove_overlaps_in_box(dom, box, p, dt, rng, dmin, itermax=10)[source]

To remove the overlaps between individuals (spheres) in the given box. Several Uzawa projections are used to give a better robustness to this process when the number of overlaps is very high like during the initialization when the individuals have random positions.

Parameters:
dom: Domain

contains everything for managing the domain

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

p: numpy array

people coordinates x y r

dt: float

time step

rng: RandomState

scipy random state object (see scipy.random.RandomState)

dmin: float

minimal distance allowed between individuals

itermax: integer

maximal number of Uzawa projections (10 by default)

Returns:
p: numpy array

new people coordinates x y r

cromosim.micro.sensor(door, xy0, xy1, t0, t1)[source]

Compute the number of entries/exits through a door as a pedestrian sensor could do

Parameters:
door: numpy array

door coordinates [x0,y0,x1,y1]

t0: float

time

t1: float

time

xy0: numpy array

people coordinates at time t0

xy1: numpy array

people coordinates at time t1

Returns:
id: numpy array

index of persons who go through the door

p: numpy array

coordinates of intersection points between the door and people trajectories

io: numpy array

the exit direction is the normal direction, 1 = exit, -1 = entry

times: numpy array

exit or entry times

entries: int

number of entries

exits: int

number of exits