@@ -24,9 +24,10 @@ import Generation from '../../../evolutionaryAlgorithm/generation/Generation';
2424import * as AlgoTypes from '../../../evolutionaryAlgorithm/internalTypes' ;
2525import LineAndNumberOfVehiclesGeneration , { generateFirstCandidates , reproduceCandidates } from '../../../evolutionaryAlgorithm/generation/LineAndNumberOfVehiclesGeneration' ;
2626import TrError from 'chaire-lib-common/lib/utils/TrError' ;
27- import { collectionToCache as serviceCollectionToCache } from '../../../../models/capnpCache/transitServices.cache.queries' ;
28- import { objectsToCache as linesToCache } from '../../../../models/capnpCache/transitLines.cache.queries' ;
27+ import { collectionToCache as serviceCollectionToCache , collectionFromCache as serviceCollectionFromCache } from '../../../../models/capnpCache/transitServices.cache.queries' ;
28+ import { objectsToCache as linesToCache , objectFromCache as lineFromCache } from '../../../../models/capnpCache/transitLines.cache.queries' ;
2929import { prepareServices , saveSimulationScenario } from '../../../evolutionaryAlgorithm/preparation/ServicePreparation' ;
30+ import Line from 'transition-common/lib/services/line/Line' ;
3031
3132/**
3233 * Do batch calculation on a csv file input
@@ -67,6 +68,36 @@ class EvolutionaryTransitNetworkDesignJobExecutor extends TransitNetworkDesignJo
6768 this . options = this . parameters . algorithmConfiguration . config ;
6869 }
6970
71+ private _getSimulatedLineCollection = ( collections : {
72+ lines : LineCollection ;
73+ agencies : AgencyCollection ;
74+ services : ServiceCollection ;
75+ } ) : LineCollection => {
76+ const {
77+ nonSimulatedServices,
78+ simulatedAgencies,
79+ linesToKeep : linesToKeepParam
80+ } = this . parameters . transitNetworkDesignParameters ;
81+ const linesToKeep = linesToKeepParam || [ ] ;
82+
83+ const agencies = simulatedAgencies ?. map ( ( agencyId ) => collections . agencies . getById ( agencyId ) ) || [ ] ;
84+ const lines = agencies . flatMap ( ( agency ) => ( agency ? agency . getLines ( ) : [ ] ) ) ;
85+
86+ // Sort lines so lines to keep are at the beginning
87+ console . log ( 'Sorting lines...' ) ;
88+ lines . sort ( ( lineA , lineB ) =>
89+ linesToKeep . includes ( lineA . getId ( ) ) && linesToKeep . includes ( lineB . getId ( ) )
90+ ? 0
91+ : linesToKeep . includes ( lineA . getId ( ) )
92+ ? - 1
93+ : linesToKeep . includes ( lineB . getId ( ) )
94+ ? 1
95+ : 0
96+ ) ;
97+ const simulatedLineCollection = new LineCollection ( lines , { } ) ;
98+ return simulatedLineCollection ;
99+ }
100+
70101 /**
71102 * Prepare the data for the current simulation: Create services for the
72103 * lines to simulate and prepare collections containing only the required
@@ -98,28 +129,8 @@ class EvolutionaryTransitNetworkDesignJobExecutor extends TransitNetworkDesignJo
98129 */
99130 simulatedServices : ServiceCollection ;
100131 } > => {
101- const {
102- nonSimulatedServices,
103- simulatedAgencies,
104- linesToKeep : linesToKeepParam
105- } = this . parameters . transitNetworkDesignParameters ;
106- const linesToKeep = linesToKeepParam || [ ] ;
107-
108- const agencies = simulatedAgencies ?. map ( ( agencyId ) => collections . agencies . getById ( agencyId ) ) || [ ] ;
109- const lines = agencies . flatMap ( ( agency ) => ( agency ? agency . getLines ( ) : [ ] ) ) ;
110-
111- // Sort lines so lines to keep are at the beginning
112- console . log ( 'Sorting lines...' ) ;
113- lines . sort ( ( lineA , lineB ) =>
114- linesToKeep . includes ( lineA . getId ( ) ) && linesToKeep . includes ( lineB . getId ( ) )
115- ? 0
116- : linesToKeep . includes ( lineA . getId ( ) )
117- ? - 1
118- : linesToKeep . includes ( lineB . getId ( ) )
119- ? 1
120- : 0
121- ) ;
122- const simulatedLineCollection = new LineCollection ( lines , { } ) ;
132+
133+ const simulatedLineCollection = this . _getSimulatedLineCollection ( collections ) ;
123134
124135 // Prepare various services for lines
125136 console . log ( 'Preparing services...' ) ;
@@ -146,7 +157,7 @@ class EvolutionaryTransitNetworkDesignJobExecutor extends TransitNetworkDesignJo
146157
147158 // Add non simulated services to the collection, ie those used by the simulation, but not generated by it
148159 const existingServices =
149- nonSimulatedServices
160+ this . parameters . transitNetworkDesignParameters . nonSimulatedServices
150161 ?. map ( ( serviceId ) => collections . services . getById ( serviceId ) )
151162 . filter ( ( service ) => service !== undefined ) || [ ] ;
152163 existingServices . forEach ( ( service ) => services . add ( service as Service ) ) ;
@@ -162,55 +173,103 @@ class EvolutionaryTransitNetworkDesignJobExecutor extends TransitNetworkDesignJo
162173 return this . currentIteration > ( this . options . numberOfGenerations || 0 ) ;
163174 } ;
164175
165- private _run = async (
166-
167- ) : Promise < boolean > => {
176+ private _loadAndPrepareData = async ( ) :Promise < void > => {
168177
169- // Load the necessary data from the server
170- const jobId = this . job . id ;
171- console . time ( `Preparing data for evolutionary transit network design job ${ jobId } ` ) ;
172- // FIXME This loads everything! we don't need all that
173- await this . loadServerData ( serviceLocator . socketEventManager ) ;
174- console . timeEnd ( `Preparing data for evolutionary transit network design job ${ jobId } ` ) ;
178+ // Load the necessary data from the server
179+ const jobId = this . job . id ;
180+ console . time ( `Preparing data for evolutionary transit network design job ${ jobId } ` ) ;
181+ // FIXME This loads everything! we don't need all that
182+ await this . loadServerData ( serviceLocator . socketEventManager ) ;
183+ console . timeEnd ( `Preparing data for evolutionary transit network design job ${ jobId } ` ) ;
175184
176- // Prepare the cache data for this job
177- // FIXME Add checkpoint here
178- console . time ( `Preparing cache directory for job ${ jobId } ` ) ;
179- this . prepareCacheDirectory ( ) ;
180- console . timeEnd ( `Preparing cache directory for job ${ jobId } ` ) ;
181-
182-
183- console . time ( `Running evolutionary transit network design algorithm for job ${ jobId } ` ) ;
184- console . timeEnd ( `Running evolutionary transit network design algorithm for job ${ jobId } ` ) ;
185+ // Prepare the cache data for this job
186+ // FIXME Add checkpoint here
187+ console . time ( `Preparing cache directory for job ${ jobId } ` ) ;
188+ this . prepareCacheDirectory ( ) ;
189+ console . timeEnd ( `Preparing cache directory for job ${ jobId } ` ) ;
185190
186191 // FIXME Use a seed from the job data?
187192 const randomGenerator = random ;
188193 // Get the agencies data
189194
190- // FIXME Cache preparation and service preparation are linked. There should be a checkpoint after and data reloaded from there
191- // FIXME2 see if we need to keep anything in checkpoints
192- // FIXME3 Some of them might be in the class instead
193195 const { simulatedLineCollection, lineServices } =
194196 await this . prepareData ( { agencies : this . agencyCollection , lines : this . allLineCollection , services : this . serviceCollection } ) ;
195197 this . setLineServices ( lineServices ) ;
196198 this . simulatedLineCollection = simulatedLineCollection ;
197- // FIXME There's something to checkpoint here
198199
199200 // Initialize population size if not done yet, as well as results
200- if ( this . job . attributes . internal_data . populationSize === undefined ) {
201- const populationSize = randomInRange (
202- [ this . options . populationSizeMin , this . options . populationSizeMax ] ,
203- randomGenerator
204- ) ;
205- this . job . attributes . internal_data . populationSize = populationSize ;
206- // FIXME Make sure results structure is well defined
207- const algorithmResults : { generations : ResultSerialization [ ] , scenarioIds : string [ ] } = { generations : [ ] , scenarioIds : [ ] } ;
208- this . job . attributes . data . results = algorithmResults ;
209- this . job . save ( this . executorOptions . progressEmitter ) ;
201+ const populationSize = randomInRange (
202+ [ this . options . populationSizeMin , this . options . populationSizeMax ] ,
203+ randomGenerator
204+ ) ;
205+
206+ // Checkoint the data preparation and initialize results
207+ this . job . attributes . internal_data . populationSize = populationSize ;
208+ this . job . attributes . internal_data . dataPrepared = true ;
209+ this . job . attributes . internal_data . lineServices = Object . keys ( lineServices ) . reduce ( ( acc , lineId ) => {
210+ acc [ lineId ] = lineServices [ lineId ] . map ( ( lvlOfService ) => ( {
211+ serviceId : lvlOfService . service . getId ( ) ,
212+ numberOfVehicles : lvlOfService . numberOfVehicles
213+ } ) ) ;
214+ return acc ;
215+ } , { } ) ;
216+
217+ // FIXME Make sure results structure is well defined
218+ const algorithmResults : { generations : ResultSerialization [ ] , scenarioIds : string [ ] } = { generations : [ ] , scenarioIds : [ ] } ;
219+ this . job . attributes . data . results = algorithmResults ;
220+ this . job . save ( this . executorOptions . progressEmitter ) ;
221+ }
222+
223+ private _loadAndPrepareDataFromCache = async ( ) :Promise < void > => {
224+ // Load the necessary data from the server
225+ const jobId = this . job . id ;
226+ console . time ( `Preparing data for evolutionary transit network design job from cache ${ jobId } ` ) ;
227+ // FIXME Do we even need this? Or can we just start recovery at serviceCollectionFromCache call and get only required data?
228+ await this . loadServerData ( serviceLocator . socketEventManager ) ;
229+
230+ // Get the simulated lines
231+ const simulatedLineCollection = this . _getSimulatedLineCollection ( { agencies : this . agencyCollection , lines : this . allLineCollection , services : this . serviceCollection } ) ;
232+ this . simulatedLineCollection = simulatedLineCollection ;
233+
234+ // Read the services from the cache, with all individual line services
235+ // Save services and lines, with their schedules, to cache
236+ const serviceCollection = await serviceCollectionFromCache ( this . getCacheDirectory ( ) ) ;
237+ this . serviceCollection . setFeatures ( serviceCollection . getFeatures ( ) ) ;
238+ // Read each of the simulation line from cache
239+ for ( let i = 0 ; i < simulatedLineCollection . getFeatures ( ) . length ; i ++ ) {
240+ const line = simulatedLineCollection . getFeatures ( ) [ i ] ;
241+ const lineWithSchedule = await lineFromCache ( line . getId ( ) , this . getCacheDirectory ( ) ) as Line ;
242+ simulatedLineCollection . updateFeature ( lineWithSchedule ) ;
243+ }
244+ // Recreate the line level of services
245+ const lineServicesSerialized = this . job . attributes . internal_data . lineServices || { } ;
246+ const lineServices : AlgoTypes . LineServices = Object . keys ( lineServicesSerialized ) . reduce ( ( acc , lineId ) => {
247+ acc [ lineId ] = lineServicesSerialized [ lineId ] . map ( ( lvlOfService ) => {
248+ const service = serviceCollection . getById ( lvlOfService . serviceId ) ;
249+ if ( ! service ) {
250+ throw new TrError ( 'Service not found in cache while preparing evolutionary transit network design job' , 'ALGOCACHE001' ) ;
251+ }
252+ return { service, numberOfVehicles : lvlOfService . numberOfVehicles } ;
253+ } ) ;
254+ return acc ;
255+ } , { } ) ;
256+ this . setLineServices ( lineServices ) ;
257+
258+ console . timeEnd ( `Preparing data for evolutionary transit network design job from cache ${ jobId } ` ) ;
259+ }
260+
261+ private _run = async (
262+
263+ ) : Promise < boolean > => {
264+ // Prepare and load data, either from cache when resuming a started job or from server at first run
265+ if ( this . job . attributes . internal_data . dataPrepared !== true ) {
266+ await this . _loadAndPrepareData ( ) ;
267+ } else {
268+ await this . _loadAndPrepareDataFromCache ( ) ;
210269 }
270+
211271 const algorithmResults = this . job . attributes . data . results ! ;
212272
213-
214273 let candidates : NetworkCandidate [ ] = [ ] ;
215274 let previousGeneration : Generation | undefined = undefined ;
216275 // FIXME Add a checkpoint here and cancellation check
0 commit comments