示例#1
0
    def test_rho0(self):

        muexp = MuonExperiment(['e', 'mu'])
        rho0 = muexp.get_starting_state()

        self.assertTrue(
            np.all(
                np.isclose(rho0.matrix,
                           [[0.25, 0.25, 0, 0], [0.25, 0.25, 0, 0],
                            [0, 0, 0.25, 0.25], [0, 0, 0.25, 0.25]])))

        gmu = constants.MU_GAMMA
        ge = constants.ELEC_GAMMA

        T = 100
        muexp.set_magnetic_field(2.0e-6 * cnst.k * T / (ge * cnst.h))
        muexp.set_temperature(T)
        muexp.set_muon_polarization('z')

        rho0 = muexp.get_starting_state()

        Z = np.exp([-1, 1])
        Z /= np.sum(Z)

        self.assertTrue(
            np.all(np.isclose(np.diag(rho0.matrix), [Z[0], 0, Z[1], 0])))
示例#2
0
    def test_dissipation(self):

        # Simple system
        g = 1.0
        muexp = MuonExperiment(['mu'])
        muexp.set_dissipation_coupling(0, g)

        times = np.linspace(0, 10)

        results = muexp.run_experiment(times)
        evol = results['e']

        solx = np.real(0.5 * np.exp(-np.pi * g * times))
        self.assertTrue(np.all(np.isclose(evol[:, 0], solx)))

        # Check for temperature equilibrium
        T = 0.1
        muexp.set_magnetic_field(-1.0)
        muexp.set_temperature(T)

        beta = 1.0 / (cnst.k * T)
        Z = np.exp(-cnst.h * constants.MU_GAMMA * 1e6 * beta)

        # Just let it evolve, see the result at long times
        Sz = muexp.spin_system.operator({0: 'z'})
        rhoinf = muexp.run_experiment([20], Sz)['e']

        self.assertAlmostEqual(rhoinf[0, 0], 0.5 * (1 - Z) / (1 + Z))
示例#3
0
    def test_slices(self):

        gmu = constants.MU_GAMMA

        muexp = MuonExperiment(['mu'])
        muexp.spin_system.add_zeeman_term(0, 1.0 / gmu)
        muexp.set_powder_average(100)

        times = np.linspace(0, 1.0)

        cos = np.cos(2 * np.pi * times)
        signal = muexp.run_experiment(times)['e'][:, 0]

        self.assertTrue(
            np.all(
                np.isclose(signal,
                           0.5 * (2.0 / 3.0 + 1.0 / 3.0 * cos),
                           atol=1e-3)))

        # Now slice
        signal_0 = muexp.run_experiment(times,
                                        orient_slice=slice(0, 1))['e'][:, 0]

        self.assertTrue(
            np.all(
                np.isclose(signal_0, 0.5 * cos * muexp.weights[0], atol=1e-3)))
示例#4
0
    def test_run(self):

        # Empty system
        muexp = MuonExperiment(['e', 'mu'])
        times = np.linspace(0, 10)

        results = muexp.run_experiment(times)

        self.assertTrue(np.all(results['e'] == 0.5))

        # Simple system
        muexp.spin_system.add_linear_term(1, [0, 0, 1.0])
        results = muexp.run_experiment(times, acquire='ei')

        tau = constants.MU_TAU

        self.assertTrue(
            np.all(
                np.isclose(results['e'][:, 0],
                           0.5 * np.cos(2 * np.pi * times))))
        self.assertAlmostEqual(results['i'][0, 0],
                               0.5 / (1.0 + 4 * np.pi**2 * tau**2))
示例#5
0
    def test_create(self):

        muexp = MuonExperiment(['e', 'mu'])
        self.assertEqual(muexp.spin_system.elec_indices, {0})
        self.assertEqual(muexp.spin_system.muon_index, 1)

        gmu = constants.MU_GAMMA
        ge = constants.ELEC_GAMMA

        self.assertTrue(
            np.all(muexp._Hz.matrix == np.diag([
                0.5 * (ge + gmu), 0.5 * (ge - gmu), 0.5 * (-ge + gmu), 0.5 *
                (-ge - gmu)
            ])))
        self.assertTrue(isinstance(muexp._Hz, Hamiltonian))
示例#6
0
    def test_powder(self):

        muexp = MuonExperiment()

        N = 20
        muexp.set_powder_average(N)
        self.assertTrue(muexp.orientations.shape[0] == muexp.weights.shape[0])
        self.assertTrue(muexp.weights.shape[0] >= N)

        # Are these correct? Basic test
        muexp.set_powder_average(1000)
        o = muexp.orientations
        w = muexp.weights

        f = 3 * np.cos(o[:, 0])**2 - 1
        self.assertAlmostEqual(np.sum(f * w), 0.0, 5)
示例#7
0
import cProfile
import numpy as np
from muspinsim.experiment import MuonExperiment

exp = MuonExperiment(['e', 'mu', 'H'])
exp.spin_system.add_hyperfine_term(1, np.diag([1,1,4])*100)
exp.spin_system.add_hyperfine_term(2, np.diag([1,1,4])*100/3)
exp.set_powder_average(100)
exp.set_magnetic_field(5.0)
exp.set_dissipation_coupling(0, 1.0)
exp.set_muon_polarization('z')

times = np.linspace(0, 1, 1000)
op = exp.spin_system.operator({1: 'z'})

cProfile.run('exp.run_experiment(times, [op], "i")', sort='cumulative')
示例#8
0
    def __init__(self, params, logfile=None):
        self._log = logfile
        if logfile:
            logging.basicConfig(filename=logfile,
                    level=logging.INFO,
                    format='[%(levelname)s] [%(threadName)s] [%(asctime)s] %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')

        # Create
        self.experiment = MuonExperiment(params.spins)

        self.log('Hamiltonian created with spins:')
        self.log(', '.join(map(str, params.spins)))

        self.log('Adding Hamiltonian terms:')
        for i, B in params.zeeman.items():
            self.experiment.spin_system.add_zeeman_term(i, B)
            self.log('\tAdded zeeman term to spin {0}'.format(i+1))

        for (i, j), A in params.hyperfine.items():
            self.experiment.spin_system.add_hyperfine_term(i, np.array(A), j)
            self.log('\tAdded hyperfine term to spin {0}'.format(i+1))

        for (i, j), r in params.dipolar.items():
            self.experiment.spin_system.add_dipolar_term(i, j, r)
            self.log('\tAdded dipolar term to spins {0}, {1}'.format(i+1, j+1))

        for i, EFG in params.quadrupolar.items():
            self.experiment.spin_system.add_quadrupolar_term(i, EFG)
            self.log('\tAdded quadrupolar term to spin {0}'.format(i+1))

        for i, d in params.dissipation.items():
            self.experiment.spin_system.set_dissipation(i, d)
            self.log('\tSet dissipation parameter for spin '
                     '{0} to {1} MHz'.format(i+1, d))
        self.log('')

        # Ranges
        trange = _make_range(params.time)
        self.log('Using time range: '
                 '{0} to {1} us in {2} steps'.format(*trange))
        self.time_axis = np.linspace(*trange)

        brange = _make_range(params.field)
        self.log('Using field range: '
                 '{0} to {1} T in {2} steps'.format(*brange))
        self.field_axis = np.linspace(*brange)

        # Powder averaging
        if params.powder is None:
            self.experiment.set_single_crystal(0, 0)
        else:
            scheme = params.powder[0]
            N = params.powder[1]

            self.experiment.set_powder_average(N, scheme)

            self.log('Using powder averaging scheme '
                     '{0}'.format(scheme.upper()))
            self.log(
                '{0} orientations generated'.format(
                    len(self.experiment.weights)))

        if params.polarization == 'longitudinal':
            self.muon_axis = 'z'
        elif params.polarization == 'transverse':
            self.muon_axis = 'x'
        else:
            raise RuntimeError(
                'Invalid polarization {0}'.format(params.polarization))
        self.experiment.set_muon_polarization(self.muon_axis)
        self.log('Muon beam polarized along axis {0}'.format(self.muon_axis))

        # Temperature
        self.temperature = params.temperature
        self.experiment.set_temperature(self.temperature)
        self.log('Using temperature of {0} K'.format(self.temperature))

        # What to save
        ssys = self.experiment.spin_system
        self.observable = ssys.operator({ssys.muon_index: self.muon_axis})
        self.save = [p[0] for p in params.save]

        self.log('*'*20 + '\n')
示例#9
0
class MuonExperimentalSetup(object):

    @mpi.execute_on_root
    def __init__(self, params, logfile=None):
        self._log = logfile
        if logfile:
            logging.basicConfig(filename=logfile,
                    level=logging.INFO,
                    format='[%(levelname)s] [%(threadName)s] [%(asctime)s] %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')

        # Create
        self.experiment = MuonExperiment(params.spins)

        self.log('Hamiltonian created with spins:')
        self.log(', '.join(map(str, params.spins)))

        self.log('Adding Hamiltonian terms:')
        for i, B in params.zeeman.items():
            self.experiment.spin_system.add_zeeman_term(i, B)
            self.log('\tAdded zeeman term to spin {0}'.format(i+1))

        for (i, j), A in params.hyperfine.items():
            self.experiment.spin_system.add_hyperfine_term(i, np.array(A), j)
            self.log('\tAdded hyperfine term to spin {0}'.format(i+1))

        for (i, j), r in params.dipolar.items():
            self.experiment.spin_system.add_dipolar_term(i, j, r)
            self.log('\tAdded dipolar term to spins {0}, {1}'.format(i+1, j+1))

        for i, EFG in params.quadrupolar.items():
            self.experiment.spin_system.add_quadrupolar_term(i, EFG)
            self.log('\tAdded quadrupolar term to spin {0}'.format(i+1))

        for i, d in params.dissipation.items():
            self.experiment.spin_system.set_dissipation(i, d)
            self.log('\tSet dissipation parameter for spin '
                     '{0} to {1} MHz'.format(i+1, d))
        self.log('')

        # Ranges
        trange = _make_range(params.time)
        self.log('Using time range: '
                 '{0} to {1} us in {2} steps'.format(*trange))
        self.time_axis = np.linspace(*trange)

        brange = _make_range(params.field)
        self.log('Using field range: '
                 '{0} to {1} T in {2} steps'.format(*brange))
        self.field_axis = np.linspace(*brange)

        # Powder averaging
        if params.powder is None:
            self.experiment.set_single_crystal(0, 0)
        else:
            scheme = params.powder[0]
            N = params.powder[1]

            self.experiment.set_powder_average(N, scheme)

            self.log('Using powder averaging scheme '
                     '{0}'.format(scheme.upper()))
            self.log(
                '{0} orientations generated'.format(
                    len(self.experiment.weights)))

        if params.polarization == 'longitudinal':
            self.muon_axis = 'z'
        elif params.polarization == 'transverse':
            self.muon_axis = 'x'
        else:
            raise RuntimeError(
                'Invalid polarization {0}'.format(params.polarization))
        self.experiment.set_muon_polarization(self.muon_axis)
        self.log('Muon beam polarized along axis {0}'.format(self.muon_axis))

        # Temperature
        self.temperature = params.temperature
        self.experiment.set_temperature(self.temperature)
        self.log('Using temperature of {0} K'.format(self.temperature))

        # What to save
        ssys = self.experiment.spin_system
        self.observable = ssys.operator({ssys.muon_index: self.muon_axis})
        self.save = [p[0] for p in params.save]

        self.log('*'*20 + '\n')

    @mpi.execute_on_root
    def log(self, message):
        if self._log:
            logging.info(message)

    def broadcast(self):
        # Broadcast the contents of this object to other MPI threads
        mpi.broadcast_object(self, only=[
            'experiment',
            'field_axis',
            'time_axis',
            'muon_axis',
            'temperature',
            'observable',
            'save'
        ])

    def run(self):

        self.broadcast()

        exp = self.experiment
        ssys = self.experiment.spin_system

        if ssys.is_dissipative:
            self.log('Spin system is dissipative; using Lindbladian')

        # Now slicing the values
        N_f = len(self.field_axis)   # Fields
        N_o = len(exp.weights)       # Orientations

        results = {
            'e': None,
            'i': None
        }
        if 'e' in self.save:
            results['e'] = np.zeros((N_f, len(self.time_axis)))
        if 'i' in self.save:
            results['i'] = np.zeros(N_f)

        # Split the tasks
        tasks = mpi.split_2D(range(N_f), range(N_o))
        field_scan, orient_slice = tasks[mpi.rank]
        self.log(f"MPI: {mpi.rank} will run fields: {field_scan}")
        if len(tasks) > 1:
            tsizes = [len(t[0])*len(t[1]) for t in tasks]
            self.log('Splitting jobs over {0} cores'.format(mpi.size))
            self.log('Job sizes:\n\t' + ' '.join(map(str, tsizes)))

        # Loop over fields
        for i in field_scan:
            B = self.field_axis[i]

            if i%10 == 0:  # Reduces logfile spam
                self.log('Performing calculations for B = {0} T'.format(B))

            exp.set_magnetic_field(B)

            field_results = exp.run_experiment(self.time_axis,
                                               operators=[self.observable],
                                               acquire=self.save,
                                               orient_slice=orient_slice)

            if 'e' in self.save:
                results['e'][i] = field_results['e'][:, 0]
            if 'i' in self.save:
                results['i'][i] = field_results['i'][0]

        # Reduce results
        for k, v in results.items():
            if v is None:
                continue
            results[k] = mpi.sum_data(v)

        self.log('*'*20)

        return results