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])))
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')
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