MagedMohamedTurk / Turbomachinery-Rotors-Balancing

Python Tools to Practically Model and Solve the Problem of High Speed Rotor Balancing.
MIT License
20 stars 9 forks source link

code _for 2W #2

Open shoaibmahmod7 opened 2 years ago

shoaibmahmod7 commented 2 years ago

`import logging import warnings import numpy as np import hsbalance.tools as tools import pandas as pd import pickle

_logger = logging.getLogger(name) _logger.propagate = False _logger.setLevel(logging.DEBUG) _console_handle = logging.StreamHandler() _console_handle.setLevel(logging.INFO) _logger.addHandler(_console_handle)

pd.set_option('display.max_columns', 1000) # Set maximum number of columns to 1000 class Alpha():

"""
Docstring for ALPHA.
Alpha is the an influence coefficient matrix
Influence coefficient matrix is a representation of the change of vibration
vector in a measuring point when putting a unit weight on a balancing plane.
"""

def __init__(self:'Influence matrix', name:'string'=''):
    """
    Instantiate an instance of Alpha
    name: optional name of Alpha
    """
    self.name = name
    self.value = None

def add(self, direct_matrix:'np.array'=None, A:'initial_vibration numpy.array'=None,
        B:'trial matrix numpy.array'=None, U:'trial weight row vector numpy.array'=None,
        keep_trial:'optional keep the previous trial weight in every succeeding trial'=False,
        name:'string'=''):
    '''
    Method to add new values for Alpha instance
    either the direct_matrix is needed or ALL of (A, B, U)
    Args:
        direct_matrix: numpy array M rows -> measuring points,
                    N columns -> balancing planes
        A: Initial vibration column array -> numpy array
        B: Trial matrix MxN array -> numpy array
    '''
    self.A = A
    self.B = B
    self.U = U
    self.keep_trial = keep_trial
    try:  # test if direct input
        _ = direct_matrix.shape
        if direct_matrix.ndim < 2:
            raise IndexError('Influence coefficient matrix should be of more than 1 dimensions.')
        if direct_matrix.shape[0] >= direct_matrix.shape[1]:
            self.value = direct_matrix
        else:
            raise tools.CustomError('Number of rows(measuring points) should be '
                              'equal or  more than the number of columns '
                              '(balancing planes)!')
        if self.A is not None or self.B is not None or self.U is not None:
            raise ValueError('Either (direct Matrix) or (A, B, U) should be input, but not both.')

    except AttributeError:
        # if direct matrix is not input calculate it from A, B, U
        # test the exstiance of A, A0, B, U to calculate ALPHA
        try:
            all([A.shape, B.shape, U.shape])
            # Test dimensions
            if A.shape[1] > 1:
                raise tools.CustomError('`A` should be column vector')
            elif U.ndim < 1 :
                raise tools.CustomError('`U` should be row vector')
            elif B.shape[0] != A.shape[0] or B.shape[1] != U.shape[0]:
                raise tools.CustomError('`B` dimensions should match `A`and `U`')
            else:
                self.A = A
                self.B = B
                self.U = U
                if not keep_trial:
                     self.value = np.matmul((self.B - self.A) ,np.linalg.inv(self.U))

                else:
                    _A_keep_trial = np.delete((np.insert(self.B, [0], self.A, axis=1)),
                                             -1, axis=1)
                    self.value = (self.B - _A_keep_trial) / self.U

        except AttributeError:
            raise tools.CustomError('Either direct_matrix or (A,B,U) '
                                    'should be passed "numpy arrays"')
    if self.value is not None:
        self.M = self.value.shape[0]
        self.N = self.value.shape[1]

def check(self, ill_condition_remove=False):
    '''
    Method to check the alpha value
        * check the symmetrical of the matrix (check for square matrix only,
        for square matrix it should be symmetric obeying the reciprocity law)
        * check for ill conditioned planes:
            if for any reason two or more planes has independent readings
            for example [[1, 2 , 3], [2, 4, 6]] this is named as ill-conditioned planes
            as they does not carry new information from the system and considering them
            cause solution infiltration.
        ill_condition_remove = True : remove the ill_condition planes after the check
    '''
    if self.M == self.N:
        _check_sym = np.allclose(self.value, self.value.T, 0.1, 1e-06)
        if not _check_sym:
            warnings.warn('\nWarning: Influence Matrix is asymmetrical!')
            _logger.info('\nInfluence Matrix is asymmetrical, check your data.')
        else:
            _logger.info('\nInfluence Matrix is symmetric --> OK')
    else:
        _logger.info('\nNot a square matrix --> no exact solution.')

    # Checking ILL-CONDITIONED planes
    ill_plane = tools.ill_condition(self.value)
    if ill_plane:
        _logger.info(f'\nIll-conditioned found in plane # {ill_plane}')
        if ill_condition_remove:
            _logger.warn(f'\nRemoving Ill-conditioned plane # {ill_plane}')
            _logger.info(f'\nIC matrix before removing\n{tools.convert_cart_math(self.value)}\n')
            self.value = np.delete(self.value,[ill_plane], axis=1)
            _logger.info(f'\nIC matrix after removing\n{tools.convert_cart_math(self.value)}\n')
    else:
        _logger.info('\nNo ill conditioned planes --> ok')

def _info(self):
    '''
    Method to summarize the results for alpha.
    return generator of tuples(title:str, item)
    '''
    if self.name:
        yield ('Name', self.name)
    if self.value is not None:
        _index = (f'Sensor {m+1}' for m in range(self.value.shape[0]))
        _columns = (f'Plane {n+1}' for n in range(self.value.shape[1]))
        yield ('Coefficient Values', pd.DataFrame(tools.convert_cart_math(self.value),
                    index=_index, columns=_columns))
    if self.A is not None:
        _index = (f'Sensor {m+1}' for m in range(self.A.shape[0]))
        yield ('Initial Vibration', pd.DataFrame(tools.convert_cart_math(self.A),
                    index=_index, columns=['Vibration']))
    if self.B is not None:
        _index = (f'Sensor {m+1}' for m in range(self.B.shape[0]))
        _columns = (f'Plane {n+1}' for n in range(self.B.shape[1]))
        yield ('Trial Runs Vibration', pd.DataFrame(tools.convert_cart_math(self.B),
                    index=_index, columns=_columns))
    if self.U is not None:
        _index = (f'Trail {n+1}' for n in range(self.U.shape[0]))
        _columns = (f'Plane {n+1}' for n in range(self.U.shape[1]))
        yield ('Trial Runs Vibration', pd.DataFrame(tools.convert_cart_math(self.U),
                    index=_index, columns=_columns))

def __repr__(self):
    '''
    Method to print out alpha value
    '''
    formatter = tools.InfoFormatter(name = 'Influence Coefficient Matrix', info_parameters=
                                    self._info())
    return ''.join(formatter.info())

def save(self, file:str):
    '''
    Method to save influence coefficient values
    '''
    if isinstance(file, str):
        self.file = file
    np.save(file, self.value)

def load(self, file:str):
    '''
    Method to load influence coefficient value
    '''
    if isinstance(file, str):
        self.file = file + '.npy'
    _matrix = np.load(self.file)
    self.add(direct_matrix=_matrix)

@property
def shape(self):
    '''
    returns shape of Influence coefficient matrix
    (no. Measuring Points, no. Balancing Planes)
    '''
    if (self.M is not None) and (self.N is not None):
        return (self.M, self.N)

class Condition():

"""
Docstring for conditions.
Condition is defined as speed or load or operating condition that is concerned in
the balancing process.
Conditions class is meant to be used for creating multispeed-multi_condition
It is designed to arrange the conditions speeds and loads in explicit way.
"""

def __init__(self:'condition', name:'string'=''):
    """
    Instantiate a conditions instance that will encapsulate all model speeds and loads
    name: optional name of Alpha
    """
    self.name = name

def add(self, alpha:'Alpha instance', A:'initial_vibration numpy.array'):
    '''
    Method to add a new condition
    Args:
        alpha: Alpha class instance
        A: Initial vibration column array -> numpy array
    '''
    if isinstance(alpha, Alpha):
        self.alpha = alpha
    else:
        raise TypeError('alpha should be class Alpha.')
    try:
        _A_shape = A.shape
        # Test dimensions
        if A.ndim != 2:
            raise IndexError('A should be column vector of Mx1 dimension.')
        elif _A_shape[1] != 1:
            raise IndexError('A should be column vector of Mx1 dimension.')
        elif _A_shape[0] != self.alpha.value.shape[0]:
            raise IndexError('A and alpha should have the same 0 dimension(M).')
        else:
            self.A = A
    except AttributeError:
        raise TypeError('`A` should be passed as "numpy array"')

def _info(self):
    '''
    Method to summarize the results for condition.
    '''
    if self.name:
        yield ('Name', self.name)
    if self.alpha is not None:
        yield ('Condition IC Matrix', str(self.alpha))
    if self.A is not None:
        _index = (f'Sensor {m+1}' for m in range(self.A.shape[0]))
        yield ('Initial Vibration', pd.DataFrame(tools.convert_cart_math(self.A),
                    index=_index, columns=['Vibration']))

def __repr__(self):
    '''
    Method to print out condition value
    '''

    formatter = tools.InfoFormatter(name = 'Operation Condition', info_parameters=
                                    self._info(), level=2)

    return ''.join(formatter.info())

def save(self, file:str):
    '''
    Method to save condition instance.
    '''
    if isinstance(file, str):
        self.file = file
    with open(self.file, 'wb') as f:
        pickle.dump(self, f)

def load(self, file:str):
    '''
    Method to load condition instance.
    '''
    if isinstance(file, str):
        self.file = file
    with open(self.file, 'rb') as f:
        _loaded_instance = pickle.load(f)
        self.add(_loaded_instance.alpha, _loaded_instance.A)

`