private void OptimizationLoop()
        {
            population = new List <OptimizableStructure>();
            scoreList  = new List <double>();

            if (optimizationMethod == OptimizationMethod.GA)
            {
                stopWatch.Start();
                running = true;
                double elapsedOptimizationTime;
                SetUpGeneticAlgorithm();
                creepMutationRate = 0;

                bestScore      = double.MinValue;
                iterationIndex = 0;
                numberOfEvaluatedIndividuals = 0;

                double minimumParameterValue = optimizationSettings.MinimumSpeedValue;
                double maximumParameterValue = optimizationSettings.MaximumSpeedValue;
                double desiredAverageSpeed   = optimizationSettings.DesiredAverageSpeed;

                while (running)
                {
                    for (int ii = 0; ii < populationSize; ii++)
                    {
                        OptimizableStructure individual = population[ii].Copy();
                        speedProfileEvaluator = new PiecewiseLinearSpeedProfileEvaluator();
                        speedProfileEvaluator.AssignMetricMap(metricMap);
                        speedProfileEvaluator.AssignMetricPath(metricPath);
                        speedProfileEvaluator.MaximumAllowedSpeed = maximumParameterValue;
                        speedProfileEvaluator.MinimumAllowedSpeed = minimumParameterValue;
                        speedProfileEvaluator.DesiredAverageSpeed = desiredAverageSpeed;
                        speedProfileEvaluator.AssignPossibleSpeedList(possibleSpeedList);

                        double score = speedProfileEvaluator.EvaluateGA(individual);
                        scoreList[ii]    = score;
                        cumulativeScore += score;

                        List <int> individualSpeedIndexList = new List <int>();
                        for (int kk = 0; kk < individual.ParameterList.Count; kk++)
                        {
                            individualSpeedIndexList.Add(((IntParameter)individual.ParameterList[kk]).ParameterValue);
                        }
                        long speedProfileIndex = ConvertToBase10(individualSpeedIndexList);

                        OnIndividualEvaluated(individualSpeedIndexList, speedProfileIndex, 0, score, individual.Copy(), ii, iterationIndex, true);

                        if (score >= bestScore)
                        {
                            // MW 20180206
                            if (score > bestScore)
                            {
                                OnNewBestIndividualFound(individualSpeedIndexList, speedProfileIndex, 0, score, individual.Copy(), ii, iterationIndex, true);
                            }


                            bestScore           = score;
                            bestIndividualIndex = ii;
                            // Copy the best individual here, in case the algorithm exits due to maximum time reached.
                            optimizedSpeedProfile = individual.Copy();
                        }
                        numberOfEvaluatedIndividuals++;
                        elapsedOptimizationTime = stopWatch.ElapsedTicks / (double)Stopwatch.Frequency;
                        if (elapsedOptimizationTime >= optimizationTime | numberOfEvaluatedIndividuals >= optimizationSettings.NumberOfGenerations * optimizationSettings.PopulationSize)
                        {
                            running = false;
                            OnStopped();
                            break;
                        }
                        if (!running)
                        {
                            break;
                        }
                    }

                    // Make new generation:
                    OptimizableStructure        bestIndividual = population[bestIndividualIndex].Copy();
                    List <OptimizableStructure> oldPopulation  = new List <OptimizableStructure>();
                    foreach (OptimizableStructure individual in population)
                    {
                        OptimizableStructure copiedIndividual = individual.Copy();
                        oldPopulation.Add(copiedIndividual);
                    }
                    population = new List <OptimizableStructure>();
                    int counter = 0;
                    while (counter < oldPopulation.Count)
                    {
                        int firstIndex = TournamentSelection.Select(randomNumberGenerator, scoreList, OptimizationObjective.Maximization,
                                                                    tournamentSize, tournamentSelectionParameter);
                        int secondIndex = TournamentSelection.Select(randomNumberGenerator, scoreList, OptimizationObjective.Maximization,
                                                                     tournamentSize, tournamentSelectionParameter);
                        double r = randomNumberGenerator.NextDouble();
                        OptimizableStructure parent1 = oldPopulation[firstIndex];
                        OptimizableStructure parent2 = oldPopulation[secondIndex];
                        if (r < crossoverProbability)
                        {
                            List <OptimizableStructure> newIndividualsList = null;
                            newIndividualsList = Crossover.ExecuteSinglePoint(parent1, parent2, unitLength, randomNumberGenerator);
                            population.Add(newIndividualsList[0]);
                            population.Add(newIndividualsList[1]);
                        }
                        else
                        {
                            population.Add(parent1);
                            population.Add(parent2);
                        }
                        counter += 2;
                    }
                    if (population.Count > oldPopulation.Count)
                    {
                        population.RemoveAt(population.Count - 1);
                    }                                                                                          // If the population size is odd..

                    for (int jj = 0; jj < population.Count; jj++)
                    {
                        OptimizableStructure individual        = population[jj];
                        OptimizableStructure mutatedIndividual = (OptimizableStructure)Modification.Execute(individual,
                                                                                                            mutationRate, creepMutationRate, randomNumberGenerator);
                        population[jj] = mutatedIndividual;
                    }
                    if (useElitism)
                    {
                        population[0] = bestIndividual;
                    }

                    double     bestFitness    = bestScore;
                    double     averageFitness = scoreList.Average();
                    List <int> bestIndividualSpeedIndexList = new List <int>();
                    for (int kk = 0; kk < bestIndividual.ParameterList.Count; kk++)
                    {
                        bestIndividualSpeedIndexList.Add(((IntParameter)bestIndividual.ParameterList[kk]).ParameterValue);
                    }

                    long bestSpeedProfileIndex = ConvertToBase10(bestIndividualSpeedIndexList);

                    List <int> populationAverageIndividual = new List <int>();

                    OnGenerationEvaluated(bestFitness, averageFitness, iterationIndex, bestIndividualIndex,
                                          numberOfEvaluatedIndividuals, bestIndividualSpeedIndexList, bestSpeedProfileIndex);
                    iterationIndex++;
                    if (numberOfEvaluatedIndividuals >= optimizationSettings.NumberOfGenerations * optimizationSettings.PopulationSize)
                    {
                        running = false;
                        OnStopped();
                        break;
                    }
                }
                OnStopped();
            }
            OnStopped();
        }