def detect_linear_regions(data, eps_r=0.01, run=10): """ Detect linear-like regions of stress-strain curve (i.e. the regions of small and large deformations). The first and last regions are identified with small and large deformation linear regions. Notes ----- Sets `strain_regions` and `strain_regions_iranges` attributes of `data`. """ stress = data.stress window_size = max(int(0.001 * stress.shape[0]), 35) ds = savitzky_golay(stress, window_size, 3, 1) de = savitzky_golay(data.strain, window_size, 3, 1) dstress = ds / de ddstress = savitzky_golay(dstress, window_size, 3, 1) p1 = np.where(dstress >= 0)[0] p2 = np.ediff1d(p1, to_end=2) p3 = np.where(p2 > 1)[0] if p3[0] == 0 or p3[0] == 1: index_value = p1[-1] else: index_value = p1[p3][0] output('index_value:', index_value) # Usually equal to data.iult. ddstress = ddstress[:index_value] addstress = np.abs(ddstress) eps = eps_r * addstress.max() ii = np.where(addstress < eps)[0] idd = np.ediff1d(ii) ir = np.where(idd > 1)[0] run_len = int((run * index_value) / 100.) regions = [] ic0 = 0 for ic in ir: region = slice(ii[ic0], ii[ic] + 1) ic0 = ic + 1 if (region.stop - region.start) >= run_len: regions.append(region) output('%d region(s)' % len(regions)) data.strain_regions_iranges = regions data.strain_regions = [(data.strain[ii.start], data.strain[ii.stop]) for ii in data.strain_regions_iranges] return data
def list_commands(namespace=None, name='filters', arg0_name='data', ikw=1): """ List all available commands in a given namespace. """ if namespace is None: namespace = globals() head = 'available %s' % name output(head) output('-' * len(head)) output.level += 1 names = sorted(namespace.keys()) for name in names: fun = namespace[name] if not inspect.isfunction(fun): continue if name.startswith('_'): continue (args, varargs, keywords, defaults) = inspect.getargspec(fun) if not len(args) or (args[0] != arg0_name): continue if defaults is not None: args_str = ', '.join(['%s=%s' % (args[ii], defaults[ii - ikw]) for ii in range(ikw, len(args))]) else: args_str = '' output('%s(%s)' % (name, args_str)) output.level -= 1 output('.')
def get_ultimate_values(data, eps=0.1): """ Get ultimate stress and strain. """ stress = data.stress dstress = np.diff(stress, n=1)/ np.diff(data.strain, n=1) ii = np.where(dstress < 0)[0] if len(ii) == 0: output('warning: stress does not decrease') iult = stress.shape[0] - 1 else: iult = np.where(stress[ii] > (eps * stress.max()))[0] if len(iult) == 0: iult = ii[0] output('warning: ultimate stress is less then %f*max stress' % eps) else: iult = ii[iult[0]] data.iult = iult output('index of ultimate strength:', iult) data.ultimate_strain = data.strain[iult] data.ultimate_stress = stress[iult] output('ultim. strain, ultim. stress:', data.ultimate_strain, data.ultimate_stress) return data
def _find_irange(values, val0, val1, msg='wrong range'): """ Find the first consecutive range [i0, i1] in `values` such that values[i0] is the first value such that `val0 <= values[i0]` and values[i1] is the last value such that `values[i1] <= val1`. """ assert(val0 < val1) i0 = np.where((values[:-1] <= val0) & (val0 <= values[1:]))[0] i1 = np.where((values[:-1] <= val1) & (val1 <= values[1:]))[0] if len(i0) and len(i1): irange = slice(i0[0] + 1, i1[-1] + 1) else: raise ValueError('%s! ([%.2e, %.2e] in [%.2e, %.2e])' % (msg, val0, val1, values.min(), values.max())) output('required: [%s, %s], found: [%s, %s]' % ((val0, val1, values[irange.start], values[irange.stop - 1]))) return irange
def select_cycle(data, cycle=-1): """ Select current cycle. Notes ----- Calls automatically :func:`detect_strain_cycles()` if needed. Sets `irange` attribute of `data`. """ if not len(data.cycles): data = detect_strain_cycles(data) data.icycle = cycle try: data.irange = data.cycles[cycle] except IndexError: output('cycle %d is not present, using the last one!' % cycle) data.icycle = -1 data.irange = data.cycles[-1] return data
def fit_stress_strain(data, region_kind='strain', which=[-999]): """ Determine Young's modulus of elasticity in the selected regions. Special value of `which` equal to [-999] means all regions. Notes ----- Sets `strain_regions_lin_fits` or `stress_regions_lin_fits` attribute of `data`, according to `region_kind`. """ if region_kind == 'strain': iranges = data.strain_regions_iranges lin_fits = data.strain_regions_lin_fits = [] elif region_kind == 'stress': iranges = data.stress_regions_iranges lin_fits = data.stress_regions_lin_fits = [] else: raise ValueError('unknown region kind! (%s)' % region_kind) if which == [-999]: which = range(len(iranges)) for ii in which: try: indx = iranges[ii] except IndexError: raise IndexError('%s region %d does not exist!' % (region_kind, ii)) output('%s index range: (%d, %d)' % (region_kind, indx.start, indx.stop)) out = _fit_stress_strain(data.stress[indx], data.strain[indx]) lin_fits.append((ii, out)) return data
def run_pipeline(filters, plots, saves, datas): """ Apply filters and then plots to datas. """ for ii, flt in enumerate(filters): fun, kwargs = flt aux = ', '.join(['%s=%s' % kw for kw in kwargs.iteritems()]) output('applying: %s(%s) ...' % (fun.__name__, aux)) for ir, data in enumerate(datas): output('processing: %s ...' % data.name) # The filter action modifies data in-place. data = fun(data, **kwargs) output('...done') output('...done') datas[ir] = data ax = None for ii, plot in enumerate(plots): fun, kwargs = plot kwargs = copy.copy(kwargs) aux = ', '.join(['%s=%s' % kw for kw in kwargs.iteritems()]) output('applying: %s(%s) ...' % (fun.__name__, aux)) shared_ax = kwargs.pop('ax', None) if shared_ax is not None: # True plot command. ax = ax if shared_ax else None is_legend = False for ir, data in enumerate(datas): output('plotting: %s ...' % data.name) is_legend = is_legend or kwargs.get('label', '') _ax = fun(data, ax=ax, **kwargs) output('...done') if _ax is None: if len(datas) > 1: output('non-plot command, skipping other data') break else: ax = _ax output('...done') if is_legend: plt.legend() for ii, save in enumerate(saves): fun, kwargs = save aux = ', '.join(['%s=%s' % kw for kw in kwargs.iteritems()]) output('executing: %s(%s) ...' % (fun.__name__, aux)) fun(datas, **kwargs) output('...done')
def parse_filter_pipeline(commands, get=None, name='filters', ikw=1): """ Parse commands string defining a pipeline. """ if commands is None: return [] cmds = commands.split(':') if get is None: get = globals().get output('parsing %s...' % name) filters = [] for ic, cmd in enumerate(cmds): output('cmd %d: %s' % (ic, cmd)) aux = cmd.split(',') filter_name = aux[0].strip() filter_args = aux[1:] fun = get(filter_name) if fun is None: raise ValueError('filter "%s" does not exist!' % filter_name) (args, varargs, keywords, defaults) = inspect.getargspec(fun) if defaults is None: defaults = [] if len(defaults) < len(filter_args): raise ValueError('filter "%s" takes only %d arguments!' % (filter_name, len(defaults))) # Process args after data. kwargs = {} arg_parser = getattr(fun, '_elfpy_arg_parsers', {}) for ia, arg in enumerate(args[ikw:]): if ia < len(filter_args): farg = filter_args[ia].strip() if arg in arg_parser: parser = arg_parser[arg] try: kwargs[arg] = parser(farg) except ValueError: msg = 'argument "%s" cannot be converted to %s(%s)!' raise ValueError(msg % (arg, type(defaults[ia]), type(defaults[ia][0]))) else: try: kwargs[arg] = type(defaults[ia])(farg) except ValueError: msg = 'argument "%s" cannot be converted to %s!' raise ValueError(msg % (arg, type(defaults[ia]))) else: kwargs[arg] = defaults[ia] output('using arguments:', kwargs) filters.append((fun, kwargs)) output('...done') return filters