Coverage for physped/core/pedestrian_simulator.py: 84%

87 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-01 09:28 +0000

1import logging 

2from pathlib import Path 

3 

4import numpy as np 

5import pandas as pd 

6from tqdm import tqdm 

7from tqdm.contrib.logging import logging_redirect_tqdm 

8 

9from physped.core.langevin_model import LangevinModel 

10from physped.core.parametrize_potential import get_grid_indices 

11from physped.core.pedestrian_initializer import ( 

12 get_initial_dynamics, 

13 initialize_pedestrians, 

14) 

15from physped.core.piecewise_potential import PiecewisePotential 

16from physped.utils.functions import ( 

17 cartesian_to_polar_coordinates, 

18 periodic_angular_conditions, 

19) 

20 

21log = logging.getLogger(__name__) 

22 

23 

24def simulate_pedestrians( 

25 piecewise_potential: PiecewisePotential, 

26 config: dict, 

27) -> pd.DataFrame: 

28 parameters = config.params 

29 

30 # if config.read.simulated_trajectories: 

31 # return read_simulated_trajectories_from_file(config) 

32 

33 log.info("Simulate trajectories using the piecewise potential") 

34 initial_dynamics = get_initial_dynamics(config) 

35 origins = initialize_pedestrians(initial_dynamics) 

36 

37 # !Make sure that the potential is defined for the states we sample 

38 # states_to_sample_from = potential_defined_at_slow_state( 

39 # states_to_sample_from, piecewise_potential 

40 # ) 

41 # states_to_sample_from = states_to_sample_from[ 

42 # states_to_sample_from["potential_defined"] 

43 # ].copy() 

44 

45 evaluation_time = np.arange( 

46 parameters.simulation.start, 

47 parameters.simulation.end, 

48 parameters.simulation.step, 

49 ) 

50 trajectories = [] 

51 

52 model = LangevinModel(piecewise_potential, parameters) 

53 n_frames_back = config.params.fps // 2 # Go 0.5 second back 

54 with logging_redirect_tqdm(): 

55 for starting_state in tqdm( 

56 origins[:, :11], 

57 desc="Simulating trajectories", 

58 unit="trajs", 

59 total=origins.shape[0], 

60 miniters=1, 

61 ): 

62 first_trajectory_piece = simulate_trajectory_piece( 

63 model, starting_state, evaluation_time, 0 

64 ) 

65 pid = int(first_trajectory_piece.iloc[0]["Pid"]) 

66 trajectory_pieces = [first_trajectory_piece] 

67 

68 while check_restarting_conditions( 

69 trajectory_pieces[-1], n_frames_back, piecewise_potential 

70 ): 

71 last_trajectory_piece = trajectory_pieces[-1] 

72 no_last_trajectory_piece = int( 

73 last_trajectory_piece.iloc[0]["piece_id"] 

74 ) 

75 restarting_state = last_trajectory_piece.iloc[-n_frames_back] 

76 restarting_time = restarting_state["t"] 

77 log.info( 

78 "Pid %s piece %s: Reverting %s frames -> t = %.2f.", 

79 int(pid), 

80 no_last_trajectory_piece, 

81 n_frames_back, 

82 restarting_time, 

83 ) 

84 

85 last_trajectory_piece = last_trajectory_piece.iloc[ 

86 : -n_frames_back - 1 

87 ] # strip frames from last trajectory piece 

88 trajectory_pieces[-1] = last_trajectory_piece 

89 frame_to_restart_from = int(restarting_state["k"]) 

90 

91 new_evaluation_time = evaluation_time[frame_to_restart_from:] 

92 

93 no_new_traj_piece = no_last_trajectory_piece + 1 

94 new_trajectory_piece = simulate_trajectory_piece( 

95 model, 

96 restarting_state, 

97 new_evaluation_time, 

98 no_new_traj_piece, 

99 ) 

100 trajectory_pieces.append(new_trajectory_piece) 

101 

102 trajectory_pieces = pd.concat(trajectory_pieces) 

103 trajectories.append(trajectory_pieces) 

104 

105 trajectories = pd.concat(trajectories).dropna() 

106 trajectories["rf"], trajectories["thetaf"] = ( 

107 cartesian_to_polar_coordinates(trajectories.uf, trajectories.vf) 

108 ) 

109 trajectories["rs"], trajectories["thetas"] = ( 

110 cartesian_to_polar_coordinates(trajectories.us, trajectories.vs) 

111 ) 

112 trajectories["thetaf"] = periodic_angular_conditions( 

113 trajectories["thetaf"], config.params.grid.bins["theta"] 

114 ) 

115 trajectories["thetas"] = periodic_angular_conditions( 

116 trajectories["thetas"], config.params.grid.bins["theta"] 

117 ) 

118 # if config.save.simulated_trajectories: 

119 # log.debug( 

120 # "Configuration 'save.simulated_trajectories' is set to True." 

121 # ) 

122 # save_trajectories( 

123 # trajectories, 

124 # Path.cwd().parent, 

125 # config.filename.simulated_trajectories, 

126 # ) 

127 return trajectories 

128 

129 

130# def sample_trajectory_origins_from_trajectories(piecewise_potential: 

131# PiecewisePotential, parameters: dict) -> np.ndarray: 

132# ntrajs = np.min([parameters.simulation.ntrajs, parameters.input_ntrajs]) 

133# sampled_origins = piecewise_potential.trajectory_origins.sample(n=ntrajs) 

134# # Stacking to go from [x,y,u,v] to [x,y,u,v,xs,ys,us,vs] 

135# sampled_origins = np.hstack((sampled_origins, sampled_origins)) 

136# log.info("Sampled %d origins from the input trajectories.", ntrajs) 

137# return sampled_origins 

138 

139 

140def read_simulated_trajectories_from_file(config): 

141 log.debug("Configuration 'read.simulated_trajectories' is set to True.") 

142 filepath = Path.cwd().parent / config.filename.simulated_trajectories 

143 try: 

144 simulated_trajectories = pd.read_csv(filepath) 

145 log.warning("Simulated trajectories read from file") 

146 # log.debug("Filepath %s", filepath.relative_to(config.root_dir)) 

147 return simulated_trajectories 

148 except FileNotFoundError as e: 

149 log.error("Preprocessed trajectories not found: %s", e) 

150 

151 

152def heatmap_zero_at_slow_state( 

153 piecewise_potential: PiecewisePotential, slow_state 

154) -> bool: 

155 """Check if the heatmap is zero at the given position. 

156 

157 If the heatmap is zero it indicates that the spatial position was never 

158 visited by a pedestrian in the input data. 

159 

160 Parameters: 

161 piecewise_potential: The piecewise potential object. 

162 position: The position to check. 

163 

164 Returns: 

165 True if the heatmap is zero at the given position, False otherwise. 

166 """ 

167 heatmap = np.sum(piecewise_potential.histogram, axis=(2, 3, 4)) 

168 slow_state_index = get_grid_indices(piecewise_potential, slow_state) 

169 return heatmap[slow_state_index[0], slow_state_index[1]] == 0 

170 

171 

172def check_restarting_conditions(traj, n_frames_back, piecewise_potential): 

173 # traj is the last trajectory_piece 

174 last_trajectory_piece_too_short = len(traj) < n_frames_back 

175 if last_trajectory_piece_too_short: 

176 log.warning( 

177 "Last trajectory piece has only %s frames. Not reverting.", 

178 len(traj), 

179 ) 

180 return False 

181 

182 trajectory_already_left_the_measurement_domain = ( 

183 heatmap_zero_at_slow_state( 

184 piecewise_potential, traj.iloc[-1][["xs", "ys", "us", "vs", "k"]] 

185 ) 

186 ) 

187 if trajectory_already_left_the_measurement_domain: 

188 log.warning( 

189 "Last trajectory piece already left the measurement domain. " 

190 "Not reverting." 

191 ) 

192 return False 

193 

194 particle_left_the_lattice = np.all(np.isinf(traj.iloc[-1])) 

195 if particle_left_the_lattice: 

196 log.warning( 

197 "Last trajectory piece already left the lattice. Not reverting." 

198 ) 

199 return False 

200 

201 max_restarts = 2 

202 simulation_already_restarted_too_often = ( 

203 traj["piece_id"].iloc[0] > max_restarts 

204 ) 

205 if simulation_already_restarted_too_often: 

206 log.warning( 

207 "Simulation already restarted %s times. Not reverting.", 

208 max_restarts, 

209 ) 

210 return False 

211 

212 return True 

213 

214 

215def simulate_trajectory_piece( 

216 model: LangevinModel, 

217 starting_state: np.ndarray, 

218 evaluation_time: np.ndarray, 

219 no_traj_piece: int, 

220) -> pd.DataFrame: 

221 integration_output = model.simulate(starting_state[:11], evaluation_time) 

222 columns = ["xf", "yf", "uf", "vf", "xs", "ys", "us", "vs", "t", "k", "Pid"] 

223 trajectory_piece = pd.DataFrame(integration_output, columns=columns) 

224 trajectory_piece.replace([np.inf, -np.inf], np.nan, inplace=True) 

225 trajectory_piece.dropna(inplace=True) 

226 trajectory_piece["piece_id"] = no_traj_piece 

227 return trajectory_piece