#! python
# -*- coding: utf-8 -*-
"""Package for simulator related classes and objects.
Authors:
* Daniel Cosmo Pizetta <daniel.pizetta@usp.br>
Since:
2018/06/07
Todo:
Maybe remove old_plot module.
"""
import logging
import numpy as np
_logger = logging.getLogger(__name__)
[docs]def reduce_magnetization_in_frequency(mx, my, mz, freq_shift, fsa_size):
"""Reduces the magnetization vector by summing frequency components.
Args:
mx (np.array): Array of magnetization x without reduction in frequency.
my (np.array): Array of magnetization y without reduction in frequency.
mz (np.array): Array of magnetization z without reduction in frequency.
freq_shift (np.array): Array of frequency shift.
fsa_size (int): Size of array of frequency shift.
Returns:
tuple: (mx, my, mz) arrays of magnetization reduced
Todo:
Shape size different of 2.
Better solution for freq_shift array.
Set physical unit for each args.
"""
fsa_size = fsa_size - 1
fsa_size_half = int(fsa_size / 2)
if len(mx.shape) >= 2:
mx_neg = np.sum(mx[:fsa_size_half], axis=0)
mx_pos = np.sum(mx[fsa_size_half + 1:], axis=0)
mx_f = mx_neg + mx_pos + mx[fsa_size_half]
else:
mx_f = mx
if len(my.shape) >= 2:
my_neg = np.sum(my[:fsa_size_half], axis=0)
my_pos = np.sum(my[fsa_size_half + 1:], axis=0)
my_f = my_neg + my_pos + my[fsa_size_half]
else:
my_f = my
if len(mz.shape) >= 2:
mz_neg = np.sum(mz[:fsa_size_half], axis=0)
mz_pos = np.sum(mz[fsa_size_half + 1:], axis=0)
mz_f = mz_neg + mz_pos + mz[fsa_size_half]
else:
mz_f = mz
max_global = np.max((np.max(mx_f), np.max(my_f), np.max(mz_f)))
return mx_f / max_global, my_f / max_global, mz_f / max_global
[docs]def reduce_magnetization_in_position(mx, my, mz, position, freq_shift):
"""Reduces the magnetization vector by summing position components.
Args:
mx (np.array): Array of x magnetization without reduction in frequency.
my (np.array): Array of y magnetization without reduction in frequency.
mz (np.array): Array of z magnetization without reduction in frequency.
position (np.array): Array of positions.
freq_shift (np.array): Array of frequency shift.
Returns:
tuple: (mx, my, mz) arrays of magnetization reduced.
Todo:
Test shape size different of 2.
Set physical unit for each args.
"""
_logger.debug("Shapes for mxyz {}, freq_shift {} and position {}".format(mx.shape,
freq_shift.shape,
position.shape))
mxf, myf, mzf = reduce_magnetization_in_frequency(mx, my, mz, freq_shift, freq_shift.size)
mxf, myf, mzf = reduce_magnetization_in_frequency(mxf, myf, mzf, position, position.shape[1])
return mxf, myf, mzf
[docs]def create_positions(size=(1, 1, 1), step=(1., 1., 1.), offset=(0., 0., 0.), dtype=np.float32):
"""Creates array of positions.
Args:
size (tuple(int)): Size in x, y and z. The minimum number is one for each axis.
step (tuple(float)): Step for each axis.
offset (tuple(float)): Offset for each axis. If zero, the final vector begins in
zero and ends in size plus offset.
Returns:
np.array: Position array in this format [[gr_x_plotx gr_y_plotx gr_z_plotx ...]
[gr_x_ploty gr_y_ploty gr_z_ploty ...][gr_x_plotz gr_y_plotz gr_z_plotz ...]],
where p is the number of position (from offset to size plus offset).
Todo:
Set physical unit for each args.
"""
if np.min(step) <= 0.:
raise ValueError("Step values must be greater then zero")
size_scaled = size[0] / step[0], size[1] / step[1], size[2] / step[2]
xposf = np.array([])
yposf = np.array([])
zposf = np.array([])
if (size_scaled[0] >= 1. and size_scaled[1] >= 1. and size_scaled[2] >= 1.):
nelements = np.prod(np.array(size_scaled))
xpos = np.arange(offset[0], size[0] + offset[0], step[0])
ypos = np.arange(offset[1], size[1] + offset[1], step[1])
zpos = np.arange(offset[2], size[2] + offset[2], step[2])
for element in np.arange(0, nelements):
xposf = np.append(xposf, xpos[int(element % xpos.size)])
yposf = np.append(yposf, ypos[int((element / xpos.size) % ypos.size)])
zposf = np.append(zposf, zpos[int((element / (xpos.size * ypos.size)) % zpos.size)])
else:
raise ValueError("Step values must be equal or greater than size values.")
posf = np.array([xposf, yposf, zposf])
return posf
[docs]def frequency_shift(freq_shift, freq_step=1., offset=0., symetric=True, dtype=np.float32):
"""Generates an array of frequency shift, from -frequency_shift to +frequency_shift, between offset.
Args:
freq_shift (float [Hz]): Maximum frequency to shift.
freq_step (float [Hz]): Spacing between values.
offset (float [Hz]): Offset frequency.
symetric (bool): If true, generates the array between offset (-maximum shift,
maximum shift), otherwise from offset to maximum frequency. Default is True.
dtype (np.dtype): Data type for the array. Default is np.float32.
Returns:
np.array [Hz]: Array of frequency shift value.
Todo:
Use the key symetric for something.
"""
f_neg = np.arange(-freq_step, -freq_shift, -freq_step, dtype=dtype)[::-1]
f_pos = np.arange(freq_step, freq_shift, freq_step, dtype=dtype)
f_zero = np.arange(0., 1., dtype=dtype)
frequency_shift = np.concatenate((f_neg, f_zero, f_pos)) + offset
return frequency_shift
[docs]def calculate_t2_star(t2, freq_shift):
"""Returns the value for t2*, considering the range of frequencies.
Args:
t2 (float [s]): T2 value in seconds.
freq_shift (float [Hz]): Frequency shift from resonance - symetric
between zero (in resonance).
Returns:
float [s]: T2 star value.
Todo:
Confirm if it is the right way to calculate or if it has a weight function for t2star
Pass freq_shift as a number?
"""
shift = np.max(freq_shift) + np.abs(np.min(freq_shift))
t2star = 1. / (1. / t2 + shift)
return t2star