int run(int round, bool tracking, bool skipUntracked) {
		runge_kutta_dopri5<Phase> stepper;
		auto ctrdStepper = make_controlled(absoluteStepperError, relativeStepperError, stepper);
		Simulator<decltype(ctrdStepper)> simulator(ctrdStepper, &bbsystem);

		uniform_real_distribution<double> distributionNullB2Max(0, b2max);
		double b = sqrt(distributionNullB2Max(randomEngine));

		hydrogen->randomize(randomEngine);
		hydrogen->setPosition(vector3D(0, 0, 0));
		hydrogen->setVelocity(vector3D(0, 0, 0));

		bbsystem.setBodyPosition(projectile, vector3D(0, b, -50.0));
		bbsystem.setBodyVelocity(projectile, vector3D(0, 0, projectileVelocity));

		if (skipUntracked && !tracking) {
			return 0;
		}

		stream << bbsystem.phase;
		stream.flush();

		if (tracking) {
			printer = new Printer(to_string(round) + ".csv");
			printer->addField(&printField);
			simulator.setObserver(*printer);
		}

		if (condition->evaluate(bbsystem.phase, 0)) {
			stream << "\t" << "Initial condition error" << endl;
			return -3;
		}

		double energy = bbsystem.getSystemEnergy();
		double time = simulator.simulate(0.0, 1.0, 0.0001, *condition, 100);
		bool eBoundToTarget;
		bool eBoundToProjec;

		while (true) {

			if (time < 0.0) {
				stream << "\t" << "Distance not reached error" << endl;
				return -1;
			}

			if (abs((energy - bbsystem.getSystemEnergy()) / energy) > relativeEnergyError) {
				stream << "\t" << "Energy error: " << energy << " vs. " << bbsystem.getSystemEnergy() << endl;
				return -2;
			}

			eBoundToTarget = Utils::isBound(bbsystem, hydrogen->getElectron("1s1"), hydrogen->getNucleus());
			eBoundToProjec = Utils::isBound(bbsystem, hydrogen->getElectron("1s1"), projectile);

			if (!eBoundToTarget || !eBoundToProjec) {
				break;
			}

			stream << " " << round << " Extend Run";
			simulator.simulate(time, time + 1.0, 0.0001);
			time += 1.0;
			extended++;
		}

		if (eBoundToTarget && !eBoundToProjec) {
			stream << endl;
		}

		if (!eBoundToTarget && eBoundToProjec) {
			stream << "\t" << round << " --> Electron Capture" << endl;
			ecapture++;
		}

		if (!eBoundToTarget && !eBoundToProjec) {
			stream << "\t" << round << " --> Ionization" << endl;
			ionization++;
		}

		if (printer != nullptr)
			delete printer;

		stream.flush();
		return 0;
	}
	int run(int round, bool tracking, bool skipUntracked) {
		runge_kutta_dopri5<Phase> stepper;
		auto ctrdStepper = make_controlled(absoluteStepperError, relativeStepperError, stepper);
		Simulator<decltype(ctrdStepper)> simulator(ctrdStepper, &bbsystem);

		uniform_real_distribution<double> distributionNullB2Max(0, b2max);
		double b = sqrt(distributionNullB2Max(randomEngine));

		helium->randomize(randomEngine);
		helium->setPosition(vector3D(0, 0, 0));
		helium->setVelocity(vector3D(0, 0, 0));

		bbsystem.setBodyPosition(projectile, vector3D(0, b, -initialDistance));
		bbsystem.setBodyVelocity(projectile, vector3D(0, 0, projectileVelocity));

		DistanceCondition condition(projectile, helium->getNucleus(), initialDistance + 1.0);

		if (skipUntracked && !tracking) {
			return 0;
		}

		stream << bbsystem.phase;
		stream.flush();

		if (tracking) {
			printer = new Printer(to_string(round) + ".csv");
			printer->addField(&printField);
			simulator.setObserver(*printer);
		}

		if (condition.evaluate(bbsystem.phase, 0)) {
			stream << "\t" << "Initial condition error" << endl;
			return -3;
		}

		int maxRounds = (int) (1.2 * (2.0 * initialDistance + 1.0) / projectileVelocity + 1.0);
		double energy = bbsystem.getSystemEnergy();
		double time = simulator.simulate(0.0, 1.0, 0.0001, condition, maxRounds);
		bool e1s1BoundToTarget, e1s2BoundToTarget;
		bool e1s1BoundToProjec, e1s2BoundToProjec;

		while (true) {

			if (time < 0.0) {
				stream << "\t" << "Distance not reached error" << endl;
				return -1;
			}

			if (abs((energy - bbsystem.getSystemEnergy()) / energy) > relativeEnergyError) {
				stream << "\t" << "Energy error: " << energy << " vs. " << bbsystem.getSystemEnergy() << endl;
				return -2;
			}

			e1s1BoundToTarget = Utils::isBound(bbsystem, helium->getElectron("1s1"), helium->getNucleus());
			e1s2BoundToTarget = Utils::isBound(bbsystem, helium->getElectron("1s2"), helium->getNucleus());
			e1s1BoundToProjec = Utils::isBound(bbsystem, helium->getElectron("1s1"), projectile);
			e1s2BoundToProjec = Utils::isBound(bbsystem, helium->getElectron("1s2"), projectile);

			if ((!e1s1BoundToTarget || !e1s1BoundToProjec) && (!e1s2BoundToTarget || !e1s2BoundToProjec)) {
				break;
			}

			stream << " " << round << " Extend Run";
			simulator.simulate(time, time + 1.0, 0.0001);
			time += 1.0;
			extended++;
		}

		string bindings;
		for (bool bound : { e1s1BoundToTarget, e1s2BoundToTarget, e1s1BoundToProjec, e1s2BoundToProjec }) {
			if (bound)
				bindings.append("-");
			else
				bindings.append("+");
		}

		switch (Utils::hash(bindings.c_str())) {
		case Utils::hash("--++"):
			stream << endl;
			break;
		case Utils::hash("+-++"):
		case Utils::hash("-+++"):
			stream << "\t" << round << " --> Single Ionization" << endl;
			ionization1++;
			break;
		case Utils::hash("++++"):
			stream << "\t" << round << " --> Dual Ionization" << endl;
			ionization2++;
			break;
		case Utils::hash("+--+"):
		case Utils::hash("-++-"):
			stream << "\t" << round << " --> Single electron Capture" << endl;
			ecapture1++;
			break;
		case Utils::hash("++--"):
			stream << "\t" << round << " --> Dual electron Capture" << endl;
			ecapture2++;
			break;
		case Utils::hash("++-+"):
		case Utils::hash("+++-"):
			stream << "\t" << round << " --> Ionization And Capture" << endl;
			ionizationAndCapture++;
			break;
		default:
			throw std::logic_error("Unhandled energy configuration.");
		}

		if (printer != nullptr)
			delete printer;

		stream.flush();
		return 0;
	}