Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code _for 2W #2

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

shoaibmahmod7
Copy link

`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)

`

commit b673e82
Author: Maged Eltorkoman <newmaged@gmail.com>
Date:   Fri Feb 25 11:10:39 2022 +0200

    Feat: save and load for alpha and conditions

commit 8d61187
Author: Maged Eltorkoman <newmaged@gmail.com>
Date:   Fri Feb 25 09:04:23 2022 +0200

    Bug: Make logger hidden in ci_matrix

commit 8433efc
Author: Maged Eltorkoman <newmaged@gmail.com>
Date:   Wed Feb 23 21:39:43 2022 +0200

    Tried SCIP solver in splitting benchmark_splitting

commit 65f66df
Merge: 900f087 2cbb1de
Author: Maged Turkoman <64289883+MagedMohamedTurk@users.noreply.github.com>
Date:   Tue Feb 15 10:29:54 2022 +0200

    Merge pull request #1 from MagedMohamedTurk/test-binder-env

    Update environment.yml

commit 2cbb1de
Author: Maged Turkoman <64289883+MagedMohamedTurk@users.noreply.github.com>
Date:   Tue Feb 15 10:20:46 2022 +0200

    added plotting packages

commit 493b835
Author: Maged Turkoman <64289883+MagedMohamedTurk@users.noreply.github.com>
Date:   Tue Feb 15 10:09:21 2022 +0200

    Update environment.yml

commit 900f087
Author: Maged Turkoman <64289883+MagedMohamedTurk@users.noreply.github.com>
Date:   Tue Feb 15 10:03:53 2022 +0200

    Docs: update readme with mybinder link
Self=(B-A) @ inv(U)
@@ -148,6 +148,7 @@ def _info(self):
index=_index, columns=_columns))
if self.U is not None:
_index = (f'Plane {n+1}' for n in range(self.U.shape[0]))
_columns = (f'Plane {n+1}' for n in range(self.U.shape[1])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing closing parenthesis

@@ -78,7 +78,7 @@ def add(self, direct_matrix:'np.array'=None, A:'initial_vibration numpy.array'=N
self.B = B
self.U = U
if not keep_trial:
self.value = (self.B - self.A) / self.U
self.value = (self.B - self.A) @ np.linalg.inv(self.U)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @shoaibmahmod7
Inverse matrix will only work on square matrices. I think to do your implementation of multiple trial weights on more than one plane, we need to make the square matrix to be the default.
So the original trial vector can be a square zero matrix with the diagonal to be the values of the trials at each plane.
U = [1, 2, 3] --> U =[[1, 0, 0], [0, 2, 0], [0, 0, 3]]
This will not break the structure of the package and still we can apply your idea.
I think this is doable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants