private float[] ComputeFriction(IZone[] zones, IDemographicCategoryGeneration cat, float[] friction) { var numberOfZones = zones.Length; float[] ret = friction == null ? new float[numberOfZones * numberOfZones] : friction; var rootModes = this.Root.Modes; var numberOfModes = rootModes.Count; var minFrictionInc = (float)Math.Exp(-10); // let it setup the modes so we can compute friction cat.InitializeDemographicCategory(); try { Parallel.For(0, numberOfZones, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate(int i) { int index = i * numberOfZones; var origin = zones[i]; int vIndex = i * numberOfZones * numberOfModes; for (int j = 0; j < numberOfZones; j++) { double c = 0f; var destination = zones[j]; int feasibleModes = 0; for (int mIndex = 0; mIndex < numberOfModes; mIndex++) { var mode = rootModes[mIndex]; if (!mode.Feasible(zones[i], zones[j], this.SimulationTime)) { vIndex++; continue; } var inc = mode.CalculateV(zones[i], zones[j], this.SimulationTime); if (!(double.IsInfinity(inc) | double.IsNaN(inc))) { feasibleModes++; c += inc >= 0 ? 1.0 : Math.Exp(inc); } } if (feasibleModes == 0) { throw new XTMFRuntimeException("There was no valid mode to travel between " + zones[i].ZoneNumber + " and " + zones[j].ZoneNumber); } else { ret[index++] = (float)Math.Exp(this.ImpedianceParameter * Math.Log(c)); } } }); } catch (AggregateException e) { throw e.InnerException; } // Use the Log-Sum from the V's as the impedence function return(ret); }
private float[] ComputeFriction(IZone[] zones, IDemographicCategoryGeneration cat, float[] friction) { var numberOfZones = zones.Length; float[] ret = friction == null ? new float[numberOfZones * numberOfZones] : friction; var rootModes = this.Root.Modes; var numberOfModes = rootModes.Count; var minFrictionInc = (float)Math.Exp( -10 ); // let it setup the modes so we can compute friction cat.InitializeDemographicCategory(); try { Parallel.For( 0, numberOfZones, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate(int i) { int index = i * numberOfZones; var origin = zones[i]; int vIndex = i * numberOfZones * numberOfModes; for ( int j = 0; j < numberOfZones; j++ ) { double c = 0f; var destination = zones[j]; int feasibleModes = 0; for ( int mIndex = 0; mIndex < numberOfModes; mIndex++ ) { var mode = rootModes[mIndex]; if ( !mode.Feasible( zones[i], zones[j], this.SimulationTime ) ) { vIndex++; continue; } var inc = mode.CalculateV( zones[i], zones[j], this.SimulationTime ); if ( !( double.IsInfinity( inc ) | double.IsNaN( inc ) ) ) { feasibleModes++; c += inc >= 0 ? 1.0 : Math.Exp( inc ); } } if ( feasibleModes == 0 ) { throw new XTMFRuntimeException( "There was no valid mode to travel between " + zones[i].ZoneNumber + " and " + zones[j].ZoneNumber ); } else { ret[index++] = (float)Math.Exp( this.ImpedianceParameter * Math.Log( c ) ); } } } ); } catch ( AggregateException e ) { throw e.InnerException; } // Use the Log-Sum from the V's as the impedence function return ret; }
/// <summary> /// Assign workers to zones /// </summary> /// <param name="workplaceDistribution"></param> /// <param name="occupation"></param> private void AssignToWorkers(SparseTwinIndex<float> workplaceDistribution, IDemographicCategoryGeneration cat) { /* * -> For each zone * 1) Load the population * 2) Count the number of people * 3) Count the number of jobs for the zone * 4) Compute the ratio of people to jobs and Balance it by normalizing @ population level * 5) Shuffle the people to avoid bias * 6) Apply the random split algorithm from the Population Synthesis to finish it off */ var zoneIndexes = this.ZoneArray.ValidIndexies().ToArray(); var flatZones = this.ZoneArray.GetFlatData(); var numberOfZones = zoneIndexes.Length; var flatWorkplaceDistribution = workplaceDistribution.GetFlatData(); var flatPopulation = this.Root.Population.Population.GetFlatData(); try { Parallel.For( 0, numberOfZones, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate() { return new Assignment() { dist = this.ZoneArray.CreateSimilarArray<float>(), indexes = null }; }, delegate(int z, ParallelLoopState unused, Assignment assign) { var dist = assign.dist; var indexes = assign.indexes; var flatDist = dist.GetFlatData(); var distributionForZone = flatWorkplaceDistribution[z]; Random rand = new Random( ( this.RandomSeed * z ) * ( this.CurrentOccupationIndex * numberOfZones ) ); IZone zoneI = flatZones[z]; var zonePop = flatPopulation[z]; int popLength = zonePop.Length; if ( indexes == null || indexes.Length < popLength ) { indexes = new int[(int)( popLength * 1.5 )]; assign.indexes = indexes; } int totalPeopleInCat = 0; // 1+2) learn who is qualified for this distribution for ( int i = 0; i < popLength; i++ ) { var person = zonePop[i]; if ( cat.IsContained( person ) ) { indexes[totalPeopleInCat] = i; totalPeopleInCat++; } } // 3) Count how many jobs are expected to come from this zone double totalJobsFromThisOrigin = 0; for ( int i = 0; i < numberOfZones; i++ ) { totalJobsFromThisOrigin += ( flatDist[i] = distributionForZone[i] ); } if ( totalJobsFromThisOrigin == 0 ) { return assign; } // 4) Calculate the ratio of people who work to the number of jobs so we can balance it again float normalizationFactor = 1 / (float)totalJobsFromThisOrigin; for ( int i = 0; i < numberOfZones; i++ ) { flatDist[i] = flatDist[i] * normalizationFactor; } // 5) card sort algo for ( int i = totalPeopleInCat - 1; i > 0; i-- ) { var swapIndex = rand.Next( i ); var temp = indexes[i]; indexes[i] = indexes[swapIndex]; indexes[swapIndex] = temp; } // 6) Apply the random split algorithm from the Population Synthesis to finish it off var flatResult = this.SplitAndClear( totalPeopleInCat, dist, rand ); int offset = 0; for ( int i = 0; i < numberOfZones; i++ ) { var ammount = flatResult[i]; for ( int j = 0; j < ammount; j++ ) { if ( offset + j >= indexes.Length || indexes[offset + j] > zonePop.Length ) { throw new XTMFRuntimeException( "We tried to assign to a person that does not exist!" ); } zonePop[indexes[offset + j]].WorkZone = flatZones[i]; } offset += ammount; } return assign; }, delegate(Assignment unused) { } ); } catch ( AggregateException e ) { throw new XTMFRuntimeException( e.InnerException.Message + "\r\n" + e.InnerException.StackTrace ); } }
/// <summary> /// Assign workers to zones /// </summary> /// <param name="workplaceDistribution"></param> /// <param name="category"></param> private void AssignToWorkers(SparseTwinIndex <float> workplaceDistribution, IDemographicCategoryGeneration category) { /* * -> For each zone * 1) Load the population * 2) Count the number of people * 3) Count the number of jobs for the zone * 4) Compute the ratio of people to jobs and Balance it by normalizing @ population level * 5) Shuffle the people to avoid bias * 6) Apply the random split algorithm from the Population Synthesis to finish it off */ var zoneIndexes = ZoneArray.ValidIndexies().ToArray(); var flatZones = ZoneArray.GetFlatData(); var numberOfZones = zoneIndexes.Length; var flatWorkplaceDistribution = workplaceDistribution.GetFlatData(); var flatPopulation = Root.Population.Population.GetFlatData(); Parallel.For(0, numberOfZones, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate { return(new Assignment { Dist = ZoneArray.CreateSimilarArray <float>(), Indexes = null }); }, delegate(int z, ParallelLoopState unused, Assignment assign) { var dist = assign.Dist; var indexes = assign.Indexes; var flatDist = dist.GetFlatData(); var distributionForZone = flatWorkplaceDistribution[z]; Random rand = new Random((RandomSeed * z) * (CurrentOccupationIndex * numberOfZones)); var zonePop = flatPopulation[z]; int popLength = zonePop.Length; if (indexes == null || indexes.Length < popLength) { indexes = new int[(int)(popLength * 1.5)]; assign.Indexes = indexes; } int totalPeopleInCat = 0; // 1+2) learn who is qualified for this distribution for (int i = 0; i < popLength; i++) { var person = zonePop[i]; if (category.IsContained(person)) { indexes[totalPeopleInCat] = i; totalPeopleInCat++; } } // 3) Count how many jobs are expected to come from this zone double totalJobsFromThisOrigin = 0; for (int i = 0; i < numberOfZones; i++) { totalJobsFromThisOrigin += (flatDist[i] = distributionForZone[i]); } if (totalJobsFromThisOrigin == 0) { return(assign); } // 4) Calculate the ratio of people who work to the number of jobs so we can balance it again float normalizationFactor = 1 / (float)totalJobsFromThisOrigin; for (int i = 0; i < numberOfZones; i++) { flatDist[i] = flatDist[i] * normalizationFactor; } // 5) card sort algo for (int i = totalPeopleInCat - 1; i > 0; i--) { var swapIndex = rand.Next(i); var temp = indexes[i]; indexes[i] = indexes[swapIndex]; indexes[swapIndex] = temp; } // 6) Apply the random split algorithm from the Population Synthesis to finish it off var flatResult = SplitAndClear(totalPeopleInCat, dist, rand); int offset = 0; for (int i = 0; i < numberOfZones; i++) { var ammount = flatResult[i]; for (int j = 0; j < ammount; j++) { if (offset + j >= indexes.Length || indexes[offset + j] > zonePop.Length) { throw new XTMFRuntimeException(this, "We tried to assign to a person that does not exist!"); } zonePop[indexes[offset + j]].WorkZone = flatZones[i]; } offset += ammount; } return(assign); }, delegate { }); }