/***********************************************************************//**
 * @brief Load cube into the model class
 *
 * @param[in] filename cube file.
 *
 * @exception GException::invalid_value
 *            Number of maps in cube mismatches number of energy bins.
 *
 * Loads cube into the model class.
 ***************************************************************************/
void GModelSpatialDiffuseCube::load(const std::string& filename)
{
    // Initialise skymap
    m_cube.clear();
    m_logE.clear();

    // Store filename of cube (for XML writing). Note that we do not
    // expand any environment variable at this level, so that if we write
    // back the XML element we write the filepath with the environment
    // variables
    m_filename = filename;

    // Get expanded filename
    std::string fname = gammalib::expand_env(filename);

    // Load cube
    m_cube.load(fname);

    // Load energies
    GEnergies energies(fname);

    // Extract number of energy bins
    int num = energies.size();

    // Check if energy binning is consistent with primary image hdu
    if (num != m_cube.nmaps() ) {
        std::string msg = "Number of energies in \"ENERGIES\" extension"
                          " ("+gammalib::str(num)+") does not match the"
                          " number of maps ("+gammalib::str(m_cube.nmaps())+""
                          " in the map cube.\n"
                          "The \"ENERGIES\" extension table shall provide"
                          " one enegy value for each map in the cube.";
        throw GException::invalid_value(G_LOAD, msg);
    }

    // Set log10(energy) nodes, where energy is in units of MeV
    for (int i = 0; i < num; ++i) {
        m_logE.append(energies[i].log10MeV());
    }

    // Signal that cube has been loaded
    m_loaded = true;

    // Set energy boundaries
    set_energy_boundaries();

    // Update Monte Carlo cache
    update_mc_cache();

    // Return
    return;
}
Beispiel #2
0
vec Solver::CCD_ReturnAllIterations(){
    // Variation of CCD() made to store correlation energy for every iteration
    vec energies = zeros<vec>(0);

    double E0 = CorrolationEnergy();
    UpdateAmplitudes();
    double E1 = CorrolationEnergy();

    NIterations = 0; tolerance = 1e-12;
    energies.insert_rows(NIterations,1);
    energies(NIterations) = E1; NIterations++;

    while ( AbsoluteDifference(E1,E0) > tolerance && NIterations < 50){

        E0 = E1;
        UpdateAmplitudes();
        E1 = CorrolationEnergy();
        energies.insert_rows(NIterations,1);
        energies(NIterations) = E1;

        NIterations ++;
    }
    return energies;
}
Beispiel #3
0
//TODO: add timer
void run(int size, double coupling, IsingModel<dimensions>::Algorithms algo, int sweeps){
  QElapsedTimer timer;
  timer.start();
  QVector<int> energies(nModels);
  QVector<int> absoluteMagnetism(nModels);
  QFile file(QString("./%3d_%0_%1_%2.dat").arg(size).arg(coupling).arg(algo).arg(dimensions));
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){
      std::cout << "Couldn't open file " << file.fileName().toStdString() << std::endl;
      return;
    }
  QTextStream out(&file);
  std::cout << "Starting with " << file.fileName().toStdString() << std::endl;
  IsingModel<dimensions> ising[nModels];
  QVector<double> magnetization, magnetizationVariance;
  QVector<double> energy, energyVariance;
  for(int k = 0; k < nModels; k++){
      ising[k].setSize(size);
      ising[k].setAlgorithm(algo);
      ising[k].setCoupling(coupling);
    }
  out << dimensions << " " << size << " " <<  coupling <<  " " << nModels << "\n\n";
  out << ising[0].getMagnetization() << " " << sqrt(0) << " " << ising[0].getEnergy() << " " << sqrt(0) << "\n";
  for(int i = 0; i < sweeps;i++){
    for(int k = 0; k < nModels;k++){
          ising[k].sweep();
          absoluteMagnetism[k] = abs(ising[k].getMagnetization());
          energies[k] =  ising[k].getEnergy();
        }
      double magneticMean = calculateMean(absoluteMagnetism);
      magnetization.append(magneticMean);
      magnetizationVariance.append(calculateVariance(absoluteMagnetism, magneticMean));
      double energyMean = calculateMean(energies);
      energy.append(energyMean);
      energyVariance.append(calculateVariance(energies, energyMean));
  }
  for(int i = 0; i < magnetization.size();i++)
    out << magnetization[i] << " " << magnetizationVariance[i] << " " << energy[i] << " "  << energyVariance[i] << "\n";
  std::cout << "Finished with " << file.fileName().toStdString() << " in " << timer.elapsed() << "ms" << std::endl;
}
Beispiel #4
0
int main(int argc, char *argv[])
{
	/* Welcome */
	welcome();

	test();
	/* Do step 0, initialization */
	db_open();
	printf("Step 0. Initialize enviroment\n"); fflush(stdout);
	if (init()) {
		db_close();
		printf("Help message: double check file \"run.prm\" in current directory.\n");
		return USERERR;
	}
	else printf("Step 0 Done.\n\n");


	/* Do step 1, premcce */
	if (env.do_premcce) {
		printf("Step 1. Test and format structral file\n"); fflush(stdout);
		if (premcce()) {db_close(); return USERERR;}
		else printf("Step 1 Done.\n\n");
	}
	else printf("Not doing \"Step 1. Test and format structral file\"\n\n");


	/* Do step 2. rotamers */
	if (env.do_rotamers) {
		printf("Step 2. Make multi side chain conformers\n"); fflush(stdout);
		if (env.sidechain_opt==1) {//genetic algorithm sidechain packing optimization
			printf("***Using Pascal Comte's (Brock University-Computer Science,2010) [Paper Ref.: ] Sidechain Packing GA & Bi-directional Evolutionary Sampling***\n");
			//        rotamers_GA(argc,argv);
		}

		else if (rotamers()) {
			db_close(); return USERERR;
		}
		else printf("Step 2 Done.\n\n");
	}
	else printf("Not doing \"Step 2. Make multi side chain conformers\"\n\n");

	/* Do step 3. energies */
	if (env.do_energies) {
		printf("Step 3. Compute energy lookup table\n"); fflush(stdout);
		if (energies()) {db_close(); return USERERR;}
		else printf("Step 3 Done.\n\n");
	}
	else printf("Not doing \"Step 3. Compute energy lookup table\"\n\n");

	/* Do step 4. Monte Carlo */
	if (env.do_monte) {
		printf("Step 4. Monte Carlo Sampling\n"); fflush(stdout);
		if (!env.monte_adv_opt) {
			if (monte()) {db_close(); return USERERR;}
			else printf("Step 4 Done.\n\n");
		}
		else {
			if (monte2()) {db_close(); return USERERR;}
			else printf("Step 4 Done.\n\n");
		}
	}
	else printf("Not doing \"Step 4. Monte Carlo Sampling\"\n\n");


	db_close();
	return 0;
}
void cmaxent_fortran( double* xqmc, double* xtau, int32_t len, double xmom1, double ( *xker ) ( const double&, double&, double& ),
		      double ( *backtrans ) ( double&, double&, double& ), double beta, double* alpha_tot, int32_t n_alpha, int32_t ngamma, double omega_start, double omega_end,
		      int32_t omega_points, int32_t nsweeps, int32_t nbins, int32_t nwarmup,/* double* u,*/ double* sigma)
{
  std::string fr("Aom"); std::string dA("dump_Aom"); std::string ml("max_stoch_log"); std::string energies("energies"); std::string bf("best_fit"); std::string dump("dump");
  cmaxent(xqmc, xtau, len, xmom1, xker, backtrans, beta, alpha_tot, n_alpha, ngamma, omega_start, omega_end, omega_points, nsweeps, nbins, nwarmup,
	  fr, dA, ml, energies, bf, dump, /*u*/NULL, sigma);
}
void CompleteExtendedHogFilter::buildDescriptors(Mat& descriptors, size_t cellRowCount, size_t cellColumnCount, size_t descriptorSize) const {
	size_t binHalfCount = binCount / 2;

	// compute gradient energy of cells
	Mat energies(descriptors.rows, descriptors.cols, CV_32FC1);
	if (signedGradients) {
		// gradient energy should be computed over unsigned gradients, so the signed parts have to be added up
		for (size_t rowIndex = 0; rowIndex < cellRowCount; ++rowIndex) {
			for (size_t colIndex = 0; colIndex < cellColumnCount; ++colIndex) {
				float energy = 0;
				float* histogramValues = descriptors.ptr<float>(rowIndex, colIndex);
				for (size_t binIndex = 0; binIndex < binHalfCount; ++binIndex) {
					float unsignedBinValue = histogramValues[binIndex] + histogramValues[binIndex + binHalfCount];
					energy += unsignedBinValue * unsignedBinValue;
				}
				energies.at<float>(rowIndex, colIndex) = energy;
			}
		}
	} else {
		for (size_t rowIndex = 0; rowIndex < cellRowCount; ++rowIndex) {
			for (size_t colIndex = 0; colIndex < cellColumnCount; ++colIndex) {
				float energy = 0;
				float* histogramValues = descriptors.ptr<float>(rowIndex, colIndex);
				for (size_t binIndex = 0; binIndex < binCount; ++binIndex)
					energy += histogramValues[binIndex] * histogramValues[binIndex];
				energies.at<float>(rowIndex, colIndex) = energy;
			}
		}
	}

	// build normalized cell descriptors
	if (signedGradients && unsignedGradients) { // signed and unsigned gradients should be combined into descriptor
		for (size_t rowIndex = 0; rowIndex < cellRowCount; ++rowIndex) {
			for (size_t colIndex = 0; colIndex < cellColumnCount; ++colIndex) {
				float* descriptor = descriptors.ptr<float>(rowIndex, colIndex);
				int r1 = rowIndex;
				int r0 = std::max(0, static_cast<int>(rowIndex) - 1);
				int r2 = std::min(rowIndex + 1, cellRowCount - 1);
				int c1 = colIndex;
				int c0 = std::max(0, static_cast<int>(colIndex) - 1);
				int c2 = std::min(colIndex + 1, cellColumnCount - 1);
				float sqn00 = energies.at<float>(r0, c0);
				float sqn01 = energies.at<float>(r0, c1);
				float sqn02 = energies.at<float>(r0, c2);
				float sqn10 = energies.at<float>(r1, c0);
				float sqn11 = energies.at<float>(r1, c1);
				float sqn12 = energies.at<float>(r1, c2);
				float sqn20 = energies.at<float>(r2, c0);
				float sqn21 = energies.at<float>(r2, c1);
				float sqn22 = energies.at<float>(r2, c2);
				float n1 = 1.f / sqrt(sqn00 + sqn01 + sqn10 + sqn11 + eps);
				float n2 = 1.f / sqrt(sqn01 + sqn02 + sqn11 + sqn12 + eps);
				float n3 = 1.f / sqrt(sqn10 + sqn11 + sqn20 + sqn21 + eps);
				float n4 = 1.f / sqrt(sqn11 + sqn12 + sqn21 + sqn22 + eps);

				// unsigned orientation features (aka contrast-insensitive)
				for (size_t binIndex = 0; binIndex < binHalfCount; ++binIndex) {
					float sum = descriptor[binIndex] + descriptor[binIndex + binHalfCount];
					float h1 = std::min(alpha, sum * n1);
					float h2 = std::min(alpha, sum * n2);
					float h3 = std::min(alpha, sum * n3);
					float h4 = std::min(alpha, sum * n4);
					descriptor[binCount + binIndex] = 0.5 * (h1 + h2 + h3 + h4);
				}

				float t1 = 0;
				float t2 = 0;
				float t3 = 0;
				float t4 = 0;

				// signed orientation features (aka contrast-sensitive)
				for (size_t binIndex = 0; binIndex < binCount; ++binIndex) {
					float h1 = std::min(alpha, descriptor[binIndex] * n1);
					float h2 = std::min(alpha, descriptor[binIndex] * n2);
					float h3 = std::min(alpha, descriptor[binIndex] * n3);
					float h4 = std::min(alpha, descriptor[binIndex] * n4);
					descriptor[binIndex] = 0.5 * (h1 + h2 + h3 + h4);
					t1 += h1;
					t2 += h2;
					t3 += h3;
					t4 += h4;
				}

				// energy features
				descriptor[binCount + binHalfCount] = 0.2357 * t1;
				descriptor[binCount + binHalfCount + 1] = 0.2357 * t2;
				descriptor[binCount + binHalfCount + 2] = 0.2357 * t3;
				descriptor[binCount + binHalfCount + 3] = 0.2357 * t4;
			}
		}
	} else { // only signed or unsigned gradients should be in descriptor
		for (size_t rowIndex = 0; rowIndex < cellRowCount; ++rowIndex) {
			for (size_t colIndex = 0; colIndex < cellColumnCount; ++colIndex) {
				float* descriptor = descriptors.ptr<float>(rowIndex, colIndex);
				int r1 = rowIndex;
				int r0 = std::max(0, static_cast<int>(rowIndex) - 1);
				int r2 = std::min(rowIndex + 1, cellRowCount - 1);
				int c1 = colIndex;
				int c0 = std::max(0, static_cast<int>(colIndex) - 1);
				int c2 = std::min(colIndex + 1, cellColumnCount - 1);
				float sqn00 = energies.at<float>(r0, c0);
				float sqn01 = energies.at<float>(r0, c1);
				float sqn02 = energies.at<float>(r0, c2);
				float sqn10 = energies.at<float>(r1, c0);
				float sqn11 = energies.at<float>(r1, c1);
				float sqn12 = energies.at<float>(r1, c2);
				float sqn20 = energies.at<float>(r2, c0);
				float sqn21 = energies.at<float>(r2, c1);
				float sqn22 = energies.at<float>(r2, c2);
				float n1 = 1.f / sqrt(sqn00 + sqn01 + sqn10 + sqn11 + eps);
				float n2 = 1.f / sqrt(sqn01 + sqn02 + sqn11 + sqn12 + eps);
				float n3 = 1.f / sqrt(sqn10 + sqn11 + sqn20 + sqn21 + eps);
				float n4 = 1.f / sqrt(sqn11 + sqn12 + sqn21 + sqn22 + eps);

				float t1 = 0;
				float t2 = 0;
				float t3 = 0;
				float t4 = 0;

				// orientation features
				for (size_t binIndex = 0; binIndex < binCount; ++binIndex) {
					float h1 = std::min(alpha, descriptor[binIndex] * n1);
					float h2 = std::min(alpha, descriptor[binIndex] * n2);
					float h3 = std::min(alpha, descriptor[binIndex] * n3);
					float h4 = std::min(alpha, descriptor[binIndex] * n4);
					descriptor[binIndex] = 0.5 * (h1 + h2 + h3 + h4);
					t1 += h1;
					t2 += h2;
					t3 += h3;
					t4 += h4;
				}

				// energy features
				descriptor[binCount] = 0.2357 * t1;
				descriptor[binCount + 1] = 0.2357 * t2;
				descriptor[binCount + 2] = 0.2357 * t3;
				descriptor[binCount + 3] = 0.2357 * t4;
			}
		}
	}
}
Beispiel #7
0
/**
 * mbsolve-tool main function.
 * \ingroup MBSOLVE_TOOL
 *
 * Specify the simulation setup using the -d parameter (The available setups
 * are described below.) and the solver method using the -m parameter
 * (Currently, the only option available is openmp-Xlvl-os-red. Replace X
 * with the number of levels.) For the complete list of parameters, run
 * mbsolve-tool -h.
 */
int main(int argc, char **argv)
{
    /* parse command line arguments */
    parse_args(argc, argv);

    try {
        ti::cpu_timer timer;
        double total_time = 0;

        std::shared_ptr<mbsolve::device> dev;
        std::shared_ptr<mbsolve::scenario> scen;

        if (device_file == "song2005") {
            /**
             * The song2005 setup features a three-level active region which
             * is excited by a sech pulse. For details see literature:
             * Song X. et al., Propagation of a Few-Cycle Laser Pulse
             * in a V-Type Three-Level System, Optics and Spectroscopy,
             * Vol. 99, No. 4, 2005, pp. 517–521
             * https://doi.org/10.1134/1.2113361
             */

            /* set up quantum mechanical description */
            std::vector<mbsolve::real> energies = {
                0,
                2.3717 * mbsolve::HBAR * 1e15,
                2.4165 * mbsolve::HBAR * 1e15
            };

            mbsolve::qm_operator H(energies);

            std::vector<mbsolve::complex> dipoles = {
                mbsolve::E0 * 9.2374e-11,
                mbsolve::E0 * 9.2374e-11 * sqrt(2),
                0
            };

            mbsolve::qm_operator u({0, 0, 0}, dipoles);

            mbsolve::real rate = 1e10;
            std::vector<std::vector<mbsolve::real> > scattering_rates = {
                { 0, rate, rate },
                { rate, 0, rate },
                { rate, rate, 0 } };

            auto relax_sop = std::make_shared<mbsolve::qm_lindblad_relaxation>
                (scattering_rates);

            auto qm = std::make_shared<mbsolve::qm_description>
                (6e24, H, u, relax_sop);

            auto mat_vac = std::make_shared<mbsolve::material>("Vacuum");
            mbsolve::material::add_to_library(mat_vac);
            auto mat_ar = std::make_shared<mbsolve::material>("AR_Song", qm);
            mbsolve::material::add_to_library(mat_ar);

            dev = std::make_shared<mbsolve::device>("Song");
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Active region", mat_ar, 0, 150e-6));

            /* default settings */
            if (num_gridpoints == 0) {
                num_gridpoints = 32768;
            }
            if (sim_endtime < 1e-21) {
                sim_endtime = 80e-15;
            }

            mbsolve::qm_operator rho_init({1, 0, 0});

            /* Song basic scenario */
            scen = std::make_shared<mbsolve::scenario>
                ("Basic", num_gridpoints, sim_endtime, rho_init);

            auto sech_pulse = std::make_shared<mbsolve::sech_pulse>
                ("sech", 0.0, mbsolve::source::hard_source, 3.5471e9,
                 3.8118e14, 17.248, 1.76/5e-15, -M_PI/2);
            scen->add_source(sech_pulse);

            scen->add_record(std::make_shared<mbsolve::record>
                             ("d11", mbsolve::record::type::density, 1, 1,
                              0, 0));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d22", mbsolve::record::type::density, 2, 2,
                              0, 0));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d33", mbsolve::record::type::density, 3, 3,
                              0, 0));
            scen->add_record(std::make_shared<mbsolve::record>("e", 0, 0.0));


        } else if (device_file == "ziolkowski1995") {
            /**
             * The ziolkowski1995 setup is a self induced transparency (SIT)
             * setup that consists of a two-level active region embedded in
             * two vacuum section. For details see literature:
             * https://doi.org/10.1103/PhysRevA.52.3082
             */

            /* set up quantum mechanical description */
            auto qm = std::make_shared<mbsolve::qm_desc_2lvl>
                (1e24, 2 * M_PI * 2e14, 6.24e-11, 1.0e10, 1.0e10);

            /* materials */
            auto mat_vac = std::make_shared<mbsolve::material>("Vacuum");
            auto mat_ar = std::make_shared<mbsolve::material>
                ("AR_Ziolkowski", qm);
            mbsolve::material::add_to_library(mat_vac);
            mbsolve::material::add_to_library(mat_ar);

            /* set up device */
            dev = std::make_shared<mbsolve::device>("Ziolkowski");
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Vacuum left", mat_vac, 0, 7.5e-6));
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Active region", mat_ar, 7.5e-6, 142.5e-6));
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Vacuum right", mat_vac, 142.5e-6, 150e-6));

            /* default settings */
            if (num_gridpoints == 0) {
                num_gridpoints = 32768;
            }
            if (sim_endtime < 1e-21) {
                sim_endtime = 200e-15;
            }

            mbsolve::qm_operator rho_init({1, 0, 0});

            /* Ziolkowski basic scenario */
            scen = std::make_shared<mbsolve::scenario>
                ("Basic", num_gridpoints, sim_endtime, rho_init);

            auto sech_pulse = std::make_shared<mbsolve::sech_pulse>
                //("sech", 0.0, mbsolve::source::hard_source, 4.2186e9/2, 2e14,
                ("sech", 0.0, mbsolve::source::hard_source, 4.2186e9, 2e14,
                 10, 2e14);
            scen->add_source(sech_pulse);

            scen->add_record(std::make_shared<mbsolve::record>
                             ("inv12", 2.5e-15));
            scen->add_record(std::make_shared<mbsolve::record>("e", 2.5e-15));

        } else if (device_file == "tzenov2018-cpml") {
            /**
             * The tzenov2018-cpml setup consists of an absorber region
             * embedded in two gain regions. Each region is modeled as a
             * two-level system. The results show that short pulses are
             * generated due to colliding pulse mode-locking (CPML).
             * For details see literature:
             * https://doi.org/10.1088/1367-2630/aac12a
             */

            /* set up quantum mechanical descriptions */
            auto qm_gain = std::make_shared<mbsolve::qm_desc_2lvl>
                (5e21, 2 * M_PI * 3.4e12, 2e-9, 1.0/10e-12, 1.0/200e-15, 1.0);

            auto qm_absorber = std::make_shared<mbsolve::qm_desc_2lvl>
                (1e21, 2 * M_PI * 3.4e12, 6e-9, 1.0/3e-12, 1.0/160e-15);

            /* materials */
            auto mat_absorber = std::make_shared<mbsolve::material>
                ("Absorber", qm_absorber, 12.96, 1.0, 500);
            auto mat_gain = std::make_shared<mbsolve::material>
                ("Gain", qm_gain, 12.96, 1.0, 500);
            mbsolve::material::add_to_library(mat_absorber);
            mbsolve::material::add_to_library(mat_gain);

            /* set up device */
            dev = std::make_shared<mbsolve::device>("tzenov-cpml");
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Gain R", mat_gain, 0, 0.5e-3));
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Absorber", mat_absorber, 0.5e-3, 0.625e-3));
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Gain L", mat_gain, 0.625e-3, 1.125e-3));

            /* default settings */
            if (num_gridpoints == 0) {
                num_gridpoints = 8192;
            }
            if (sim_endtime < 1e-21) {
                sim_endtime = 2e-9;
            }

            mbsolve::qm_operator rho_init({0.5, 0.5}, {0.001});

            /* basic scenario */
            scen = std::make_shared<mbsolve::scenario>
                ("basic", num_gridpoints, sim_endtime, rho_init);

            scen->add_record(std::make_shared<mbsolve::record>
                             ("inv12", 1e-12));
            scen->add_record(std::make_shared<mbsolve::record>("e", 1e-12));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("e0", mbsolve::record::electric, 1, 1, 0.0,
                              0.0));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("h0", mbsolve::record::magnetic, 1, 1, 0.0,
                              1.373e-7));

        } else if (device_file == "marskar2011") {
            /**
             * The marskar2011 setup is a 6-level anharmonic ladder system.
             * In the scenario, the interaction with a few-cycle Gaussian pulse
             * is simulated. For details see literature:
             * https://doi.org/10.1364/OE.19.016784
             */

            /* set up quantum mechanical description */
            std::vector<mbsolve::real> energies(6, 0.0);
            for (int i = 1; i < 6; i++) {
                energies[i] = energies[i - 1] + (1.0 - 0.1 * (i - 3)) *
                    mbsolve::HBAR * 2 * M_PI * 1e13;
            }

            mbsolve::qm_operator H(energies);

            mbsolve::real dipole = 1e-29;
            std::vector<mbsolve::complex> dipoles = {
                dipole,
                0, dipole,
                0, 0, dipole,
                0, 0, 0, dipole,
                0, 0, 0, 0, dipole
            };

            mbsolve::qm_operator u({0, 0, 0, 0, 0, 0}, dipoles);

            mbsolve::real rate = 1e12;
            std::vector<std::vector<mbsolve::real> > scattering_rates = {
                { rate, 1.0/(1.0e-12), 0, 0, 0, 0 },
                { 3.82950e+11, rate, 1.0/(1.1e-12), 0, 0, 0 },
                { 0, 3.77127e+11, rate, 1.0/(1.2e-12), 0, 0 },
                { 0, 0, 3.74488e+11, rate, 1.0/(1.3e-12), 0 },
                { 0, 0, 0, 3.74467e+11, rate, 1.0/(1.4e-12) },
                { 0, 0, 0, 0, 3.76675e+11, rate }
            };

            auto relax_sop = std::make_shared<mbsolve::qm_lindblad_relaxation>
                (scattering_rates);

            auto qm = std::make_shared<mbsolve::qm_description>
                (1e25, H, u, relax_sop);

            /* materials */
            auto mat_vac = std::make_shared<mbsolve::material>("Vacuum");
            mbsolve::material::add_to_library(mat_vac);
            auto mat_ar = std::make_shared<mbsolve::material>("AR_Marsk", qm);
            mbsolve::material::add_to_library(mat_ar);

            /* set up device */
            dev = std::make_shared<mbsolve::device>("Marskar");
            dev->add_region(std::make_shared<mbsolve::region>
                            ("Active region", mat_ar, 0, 1e-3));

            /* default settings */
            if (num_gridpoints == 0) {
                num_gridpoints = 8192;
            }
            if (sim_endtime < 1e-21) {
                sim_endtime = 2e-12;
            }

            mbsolve::qm_operator rho_init({0.60, 0.23, 0.096, 0.044, 0.02,
                        0.01});

            /* Marskar basic scenario */
            scen = std::make_shared<mbsolve::scenario>
                ("Basic", num_gridpoints, sim_endtime, rho_init);

            /* input pulse */
            mbsolve::real tau = 100e-15;
            auto pulse = std::make_shared<mbsolve::gaussian_pulse>
                ("gaussian",
                 0.0, /* position */
                 mbsolve::source::hard_source,
                 5e8, /* amplitude */
                 1e13, /* frequency */
                 3.0 * tau, /* phase: 3*tau */
                 tau /* tau */
                 );
            scen->add_source(pulse);

            /* select data to be recorded */
            mbsolve::real sample_time = 0.0;
            mbsolve::real sample_pos = 0.0;
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d11", mbsolve::record::type::density, 1, 1,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d22", mbsolve::record::type::density, 2, 2,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d33", mbsolve::record::type::density, 3, 3,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d44", mbsolve::record::type::density, 4, 4,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d55", mbsolve::record::type::density, 5, 5,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("d66", mbsolve::record::type::density, 6, 6,
                              sample_time, sample_pos));
            scen->add_record(std::make_shared<mbsolve::record>
                             ("e", mbsolve::record::type::electric, 0, 0,
                              sample_time, sample_pos));
        } else {
            throw std::invalid_argument("Specified device not found!");
        }
        /* tic */
        timer.start();

        mbsolve::writer writer(writer_method);
        mbsolve::solver solver(solver_method, dev, scen);

        /* toc */
        timer.stop();
        ti::cpu_times times = timer.elapsed();
        std::cout << "Time required (setup): " << 1e-9 * times.wall
                  << std::endl;
        total_time +=1e-9 * times.wall;

        std::cout << solver.get_name() << std::endl;

        /* tic */
        timer.start();

        /* execute solver */
        solver.run();

        /* toc */
        timer.stop();
        times = timer.elapsed();
        std::cout << "Time required (run): " << 1e-9 * times.wall << std::endl;
        total_time +=1e-9 * times.wall;

        /* grid point updates per second */
        double gpups = 1e-6 * 1e9/times.wall * scen->get_num_gridpoints() *
            scen->get_endtime()/scen->get_timestep_size();
        std::cout << "Performance: " << gpups << " MGPU/s" << std::endl;

        /* tic */
        timer.start();

        /* write results */
        writer.write(output_file, solver.get_results(), dev, scen);

        /* toc */
        timer.stop();
        times = timer.elapsed();
        std::cout << "Time required (write): " << 1e-9 * times.wall
                  << std::endl;
        total_time +=1e-9 * times.wall;

        std::cout << "Time required (total): " << total_time << std::endl;

    } catch (std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl;
        exit(1);
    }

    exit(0);
}