def quad(func, x0, x1, *oargs, args=(), **kwargs): """A wrapper on scipy.integrate.quad : - will check dimensions of x0 and x1 bounds - returned value's dimension is infered by calling func(x0) """ # Cast x bounds in Quantity and check dimension x0 = quantify(x0) x1 = quantify(x1) if not x0.dimension == x1.dimension: raise DimensionError(x0.dimension, x1.dimension) # Get output dimension res = func(x0, *args) res = quantify(res) res_dim = res.dimension # define a float-version for inputs and outputs def func_value(x_value, *oargs): # cast back in Quantity x = Quantity(x_value, x0.dimension) # compute Quantity result res_raw = func(x, *args) raw = quantify(res_raw) # return float-value return raw.value # compute integral with float-value version quad_value, prec = scipy.integrate.quad(func_value, x0.value, x1.value, *oargs, **kwargs) # cast back in Quantity with dimension f(x)dx return Quantity(quad_value, res_dim * x0.dimension).rm_dim_if_dimless(), prec
def asqarray(array_like): """The value returned will always be a Quantity with array value""" if isinstance(array_like, list): if isinstance(array_like[0], Quantity): dim = array_like[0].dimension val_list = [] for q in array_like: if q.dimension == dim: val_list.append(q.value) res_val = np.array(val_list) else: raise DimensionError(q.dim, dim) return Quantity(res_val, dim) else: return quantify(array_like) elif isinstance(array_like, np.ndarray): if isinstance(array_like[0], Quantity): dim = array_like[0].dimension val_list = [] for q in array_like: if q.dimension == dim: val_list.append(q.value) res_val = np.array(val_list) else: raise DimensionError(q.dim, dim) return Quantity(res_val, dim) else: return quantify(array_like) else: raise ValueError("Type {type(array_like)} not supported")
def dblquad(func, x0, x1, y0, y1, *oargs, args=(), **kwargs): x0 = quantify(x0) x1 = quantify(x1) y0 = quantify(y0) y1 = quantify(y1) if not x0.dimension == x1.dimension: raise DimensionError(x0.dimension, x1.dimension) if not y0.dimension == y1.dimension: raise DimensionError(y0.dimension, y1.dimension) res = func(y0, x0, *args) res = quantify(res) res_dim = res.dimension def func_value(y_value, x_value, *args): x = Quantity(x_value, x0.dimension) y = Quantity(y_value, y0.dimension) res_raw = func(y, x, *args) raw = quantify(res_raw) return raw.value dblquad_value, prec = scipy.integrate.dblquad(func_value, x0.value, x1.value, y0.value, y1.value, *oargs, **kwargs) return Quantity(dblquad_value, res_dim * x0.dimension * y0.dimension).rm_dim_if_dimless(), prec
def __init__(self, *args, min=None, max=None, cb_for_init=None, **kwargs): self._callbacks = [] if cb_for_init is not None: self._callbacks.append(cb_for_init) dim = args[1] if min is None: min_v = 0 min = Quantity(min_v, dim) else: min = quantify(min) if max is None: max_v = 100 max = Quantity(max_v, dim) else: max = quantify(max) if not min.dimension == max.dimension: raise DimensionError(min.dimension, max.dimension) if not dim == max.dimension: raise DimensionError(min.dimension, max.dimension) self.min_value = min.value self.max_value = max.value #self.value = args[0] super().__init__(*args, **kwargs)
def uniform(low=0.0, high=1.0, size=None): low = quantify(low) high = quantify(high) if not low.dimension == high.dimension: raise DimensionError(low.dimension, high.dimension) samples = np.random.normal(low=low.value, high=high.value, size=size) return Quantity(samples, low.dimension)
def normal(loc=0.0, scale=1.0, size=None): loc = quantify(loc) scale = quantify(scale) if not loc.dimension == scale.dimension: raise DimensionError(loc.dimension, scale.dimension) samples = np.random.normal(loc=loc.value, scale=scale.value, size=size) return Quantity(samples, loc.dimension)
def list_of_Q_to_Q_array(Q_list): """Convert list of Quantity's object to a Quantity with array value. All Quantity must have the same dimension.""" first = quantify(Q_list[0]) dim = first.dimension val_list = [] for q in Q_list: q = quantify(q) if q.dimension == dim: val_list.append(q.value) else: raise ValueError return Quantity(np.array(val_list), dim)
def parse_qlineedit(self): text = self.qlineedit.text() # Retrieves text in the field try: expression = text.replace(" ", "*") # to parse "5 m" into "5*m" old_favunit = self.favunit # TODO : use a Lexer/Parser to allow # only valid mathematical text res = eval(expression, self.context) res = quantify(res) # update quantity value self.value = res self.favunit = old_favunit # see above, TODO find a way to link those 2 self.value.favunit = self.favunit # update display_value # done by slider signal # update slider value self.qtslider.setValue(self.public_to_raw(res)) except: # if anything fails, do nothing #self.text.value = str(self.value) # self.value.favunit is used here pass
def func_value(z_value, y_value, x_value, *args): x = Quantity(x_value, x0.dimension) y = Quantity(y_value, y0.dimension) z = Quantity(z_value, z0.dimension) res_raw = func(z, y, x, *args) raw = quantify(res_raw) return raw.value
def text_update_values(wdgt): # get expression entered expression = wdgt.value expression = expression.replace(" ", "*") # to parse "5 m" into "5*m" # eval expression with unit context try: old_favunit = self.favunit # TODO : use a Lexer/Parser to allow # only valid mathematical text res = eval(expression, self.context) res = quantify(res) # update quantity value self.value = res self.favunit = old_favunit # see above, TODO find a way to link those 2 self.value.favunit = self.favunit # update display_value self.text.value = str( self.value) # self.value.favunit is used here except: # if anything fails, do nothing self.text.value = str( self.value) # self.value.favunit is used here
def brentq(func_cal, start, stop, *oargs, args=(), **kwargs): start = quantify(start) stop = quantify(stop) if not start.dimension == stop.dimension: raise DimensionError(start.dimension, stop.dimension) start_val = start.value start_dim = start.dimension stop_val = stop.value def func_float(x): res = func_cal(Quantity(x, start_dim), *args) return quantify(res).value res = scipy.optimize.brentq(func_float, start_val, stop.value, *oargs) return Quantity(res, start_dim)
def func_value(x_value, *oargs): # cast back in Quantity x = Quantity(x_value, x0.dimension) # compute Quantity result res_raw = func(x, *args) raw = quantify(res_raw) # return float-value return raw.value
def func_value(t_value, Y_value): # add back the units t = Quantity(t_value, t_span[0].dimension) if not_scalar: Y = np.array([ Quantity(y_value, y0.dimension) for y_value, y0 in zip(Y_value, Y0) ], dtype=object) else: Y = Quantity(Y_value, Y0[0].dimension) # compute with units res_raw = fun(t, Y) # extract the numerical value if not_scalar: raw = np.array([quantify(r) for r in res_raw], dtype=object) raw_value = np.array([r.value for r in raw]) else: raw_value = quantify(res_raw).value return raw_value
def root(func_cal, start, args=(), **kwargs): start = quantify(start) start_val = start.value start_dim = start.dimension def func_cal_float(x_float): q = Quantity(x_float, start_dim) return func_cal(q, *args) res = scipy.optimize.root(func_cal_float, start_val, **kwargs).x[0] return Quantity(res, start_dim)
def tplquad(func, x0, x1, y0, y1, z0, z1, *args): x0 = quantify(x0) x1 = quantify(x1) y0 = quantify(y0) y1 = quantify(y1) z0 = quantify(z0) z1 = quantify(z1) if not x0.dimension == x1.dimension: raise DimensionError(x0.dimension, x1.dimension) if not y0.dimension == y1.dimension: raise DimensionError(y0.dimension, y1.dimension) if not z0.dimension == z1.dimension: raise DimensionError(z0.dimension, z1.dimension) res = func(z0, y0, x0, *args) res = quantify(res) res_dim = res.dimension def func_value(z_value, y_value, x_value, *args): x = Quantity(x_value, x0.dimension) y = Quantity(y_value, y0.dimension) z = Quantity(z_value, z0.dimension) res_raw = func(z, y, x, *args) raw = quantify(res_raw) return raw.value tplquad_value, prec = scipy.integrate.tplquad(func_value, x0.value, x1.value, y0.value, y1.value, z0.value, z1.value, args=args) return Quantity(tplquad_value, res_dim * x0.dimension * y0.dimension * z0.dimension).rm_dim_if_dimless(), prec
def __init__( self, min=None, max=None, step=None, disabled=False, continuous_update=True, description="Quantity:", fixed_dimension=False, label=True, #placeholder="Type python expr", favunit=None, **kwargs): """ kwargs are passed to Box. """ super().__init__(**kwargs) # quantity work # set dimension value = quantify(min) self.favunit = value.favunit or favunit self.dimension = value.dimension # if true, any change in value must have same dimension as initial dimension self.fixed_dimension = fixed_dimension qmin = quantify(min) qmax = quantify(max) qstep = Quantity(0.1, qmin.dimension) # set quantity self.value_left = qmin self.value_right = qmax self.qstep = qstep self.qmin = qmin self.qmax = qmax self.value = self.qmin, self.qmax # set text widget self.rslider = ipyw.FloatRangeSlider( value=[self.value_left.value, self.value_right.value], min=self.qmin.value, max=self.qmax.value, step=self.qstep.value, description=description, disabled=disabled, continuous_update=continuous_update, #orientation=orientation, readout=False, # to disable displaying readout value #readout_format=readout_format, #layout=Layout(width="50%", # margin="0px", # border="solid red"), ) def update_label_on_slider_change(change): new_left, new_right = change.new self.value_left = Quantity(new_left, self.dimension, favunit=self.favunit) self.value_right = Quantity(new_right, self.dimension, favunit=self.favunit) self.value = self.value_left, self.value_right self.label.value = str(self.value_left) + "-" + str( self.value_right) self.rslider.observe(update_label_on_slider_change, names="value") #def update_slider_value(change): # self.slider.value = change.new.value #self.observe(update_slider_value, names="value") # display the quantity value of the slider in label self.label = ipyw.Label(value=str(self.value_left) + "-" + str(self.value_right)) # todo : add callback to update frontend on value change def update_slider_value(change): self.rslider.value = change.new[0].value, change.new[1].value self.observe(update_slider_value, names="value") if label: self.children = [ self.rslider, self.label, ] else: self.children = [ self.rslider, ]
def func_float(x): res = func_cal(Quantity(x, start_dim), *args) return quantify(res).value
def solve_ivp(fun, t_span, Y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, args=None, **options): not_scalar = len(Y0) > 1 # first, quantify everything that could be quantity tstart, tstop = t_span t_span = quantify(tstart), quantify(tstop) if not t_span[0].dimension == t_span[1].dimension: print("error of dimension") if not_scalar: Y0 = np.array([quantify(y) for y in Y0], dtype=object) else: Y0 = [quantify(y) for y in Y0] if t_eval is not None: t_eval = quantify(t_eval) t_span_value = t_span[0].value, t_span[1].value Y0_value = [y.value for y in Y0] if t_eval is not None: t_eval_value = t_eval.value else: t_eval_value = None # second : rewrite everything without units def func_value(t_value, Y_value): # add back the units t = Quantity(t_value, t_span[0].dimension) if not_scalar: Y = np.array([ Quantity(y_value, y0.dimension) for y_value, y0 in zip(Y_value, Y0) ], dtype=object) else: Y = Quantity(Y_value, Y0[0].dimension) # compute with units res_raw = fun(t, Y) # extract the numerical value if not_scalar: raw = np.array([quantify(r) for r in res_raw], dtype=object) raw_value = np.array([r.value for r in raw]) else: raw_value = quantify(res_raw).value return raw_value # compute numerical solution sol = scipy.integrate.solve_ivp(func_value, t_span_value, Y0_value, method=method, t_eval=t_eval_value, dense_output=dense_output, events=events, vectorized=vectorized, args=args, **options) # "decorate" the solution with units sol.t = Quantity(sol.t, t_span[0].dimension) if not_scalar: soly_q = [] for y_value, y0 in zip(sol.y, Y0): soly_q.append(Quantity(y_value, y0.dimension)) arr_q = soly_q #np.array(soly_q, dtype=object) sol.y = arr_q else: sol.y = Quantity(sol.y, Y0[0].dimension) func_sol = sol.sol # for some reason the solution accepts 0*s as well as 0 @check_dimension(t_span[0].dimension) def sol_q(t): return Quantity(func_sol(t), Y0[0].dimension) #/t_span[0].dimension) sol.sol = sol_q return sol
def decorated(x): x = quantify(x) return math_func(x.value)
def decorated(x): x = quantify(x) if not x.dimension == Dimension(None): raise DimensionError(x.dimension, Dimension(None)) return math_func(x.value)
def __init__( self, value=None, min=None, max=None, step=None, disabled=False, continuous_update=True, description="Quantity:", fixed_dimension=False, label=True, favunit=None, #placeholder="Type python expr", **kwargs): super().__init__(**kwargs) # quantity work # set dimension if value is not None: value = quantify(value) elif min is not None: value = min * 1 # to reset favunit else: value = 0.0 self.dimension = value.dimension # if true, any change in value must have same dimension as initial dimension self.fixed_dimension = fixed_dimension # set quantity self.value = value if favunit is None: self.favunit = value._pick_smart_favunit() else: self.favunit = favunit self.value.favunit = self.favunit # validate min if min is not None: qmin = quantify(min) if not qmin.dimension == self.value.dimension: raise DimensionError(qmin.dimension, self.value.dimension) else: qmin = Quantity(0.0, self.value.dimension) # validate max value if max is not None: qmax = quantify(max) if not qmax.dimension == self.value.dimension: raise DimensionError(qmax.dimension, self.value.dimension) else: qmax = Quantity(100.0, self.value.dimension) # validate step value if step is not None: qstep = quantify(step) if not qstep.dimension == self.value.dimension: raise DimensionError(qstep.dimension, self.value.dimension) else: qstep = Quantity(0.1, self.value.dimension) self.qstep = qstep self.qmin = qmin self.qmax = qmax # set slider widget self.slider = ipyw.FloatSlider( value=self.value.value, min=self.qmin.value, max=self.qmax.value, step=self.qstep.value, description=description, disabled=disabled, continuous_update=continuous_update, #orientation=orientation, readout=False, # to disable displaying readout value #readout_format=readout_format, #layout=Layout(width="50%", # margin="0px", # border="solid red"), ) # observe slider value : for interaction with the widget def update_label_on_slider_change(change): self.value = Quantity(change.new, self.value.dimension, favunit=self.favunit) self.label.value = str(self.value) self.slider.observe(update_label_on_slider_change, names="value") # observe self.value : when using the OOP interaction def update_slider_value(change): self.slider.value = change.new.value self.observe(update_slider_value, names="value") # display the quantity value of the slider in label self.label = ipyw.Label(value=str(self.value)) if label: self.children = [ self.slider, self.label, ] else: self.children = [ self.slider, ]
def __init__(self, value=0.0, disabled=False, continuous_update=True, description="Quantity:", fixed_dimension=False, placeholder="Type python expr", favunit=None, add_context={}, **kwargs): # context for parsing self.context = {**units, "pi": pi, **add_context} # set text widget self.text = ipyw.Text( value="", placeholder=placeholder, description=description, disabled=disabled, continuous_update=continuous_update, layout=Layout(width='auto', margin="0px 0px 0px 0px", padding="0px 0px 0px 0px", border="solid gray"), style={'description_width': '130px'}, ) # quantity work # set dimension value = quantify(value) self.dimension = value.dimension # if true, any change in value must have same dimension as initial dimension self.fixed_dimension = fixed_dimension # set quantity self.value = value # favunit if favunit is None: # we fall back on the passed quantity's favunit # (that could be None also) self.favunit = value._pick_smart_favunit() else: self.favunit = favunit # TODO : link those 2 self.value.favunit = self.favunit #link = ipyw.link( # (self.value, "favunit"), # (self, "favunit") #) # set text value after setting the favunit self.text.value = str(self.value) # Actually a Box widget that wraps a Text widget super().__init__(**kwargs) self.children = [self.text] # on_submit observe : what to do when text is entered def text_update_values(wdgt): # get expression entered expression = wdgt.value expression = expression.replace(" ", "*") # to parse "5 m" into "5*m" # eval expression with unit context try: old_favunit = self.favunit # TODO : use a Lexer/Parser to allow # only valid mathematical text res = eval(expression, self.context) res = quantify(res) # update quantity value self.value = res self.favunit = old_favunit # see above, TODO find a way to link those 2 self.value.favunit = self.favunit # update display_value self.text.value = str( self.value) # self.value.favunit is used here except: # if anything fails, do nothing self.text.value = str( self.value) # self.value.favunit is used here # create the callback self.text.on_submit(text_update_values)
def __init__(self, qminimum, qmaximum, value=None, descr="Quantity", favunit=None, parent=None): super(QuantityQtSlider, self).__init__(parent=parent) self.setAutoFillBackground(True) #p = self.palette() #p.setColor(self.backgroundRole(), Qt.Color("#6d6875")) # 6d6875 #self.setPalette(p) self.setStyleSheet('background-color: #e36414;') self.descr = descr from physipy import units from numpy import pi self.units = units self.context = {**units, "pi": pi} # Horizontal Box self.horizontalLayout = QHBoxLayout(self) self.horizontalLayout.setSpacing(0) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) # Label for value self.numlabel = QLabel(self) self.numlabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.numlabel.setMinimumWidth(100) self.numlabel.setStyleSheet("background-color: #fb8b24") #self.numlabel.setMargin(0) # Label for description self.desclabel = QLabel(self) self.desclabel.setText(descr) self.desclabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.desclabel.setMinimumWidth(20) self.desclabel.setStyleSheet( "background-color: #9a031e") #;margin:0px") # QLineEdit self.qlineedit = QLineEdit() self.qlineedit.setMinimumWidth(20) # ComboBox self.cb = QComboBox() units_strings = [k for k in units.keys()] self.cb.addItems([ u_str for u_str, u_q in self.units.items() if qminimum.dimension == u_q.dimension ]) self.cb.currentIndexChanged.connect(self.selectionchange) # Raw slider self.qtslider = QSlider(self) # Add widgets self.horizontalLayout.addWidget(self.desclabel) self.horizontalLayout.addWidget(self.qtslider) self.horizontalLayout.addWidget(self.numlabel) self.horizontalLayout.addWidget(self.qlineedit) self.horizontalLayout.addWidget(self.cb) # Customize slider self.N = 1000000 self.qtslider.setMaximum(self.N) self.qtslider.setOrientation(Qt.Horizontal) self.qtslider.setFixedWidth(200) self.qtslider.valueChanged.connect(self.setLabelValue) self.qtslider.setStyleSheet("background-color: #5f0f40") self.resize(self.sizeHint()) # Init qminimum = quantify(qminimum) qmaximum = quantify(qmaximum) if not qminimum.dimension == qmaximum.dimension: raise ValueError if value is not None: value = quantify(value) if not qminimum.dimension == value.dimension: raise ValueError else: value = qminimum # Save min and max quantity self.qminimum = qminimum self.qmaximum = qmaximum self.dimension = qminimum.dimension # favunit if favunit is None: # we fall back on the passed quantity's favunit # (that could be None also) self.favunit = value._pick_smart_favunit() else: self.favunit = favunit self.value = value self.value.favunit = self.favunit self.qlineedit.setText( self.text_value) # Programmatically sets the text self.qtslider.setValue(self.public_to_raw(value)) #self.setLabelValue(self.qtslider.value()) self.qlineedit.returnPressed.connect(self.parse_qlineedit)
def decorated(y, x): y = quantify(y) x = quantify(x) return math_func(y.value, x.value)
def decorated(x, y): x = quantify(x) y = quantify(y) if not x.dimension == y.dimension: raise DimensionError(x.dimension, y.dimension) return Quantity(math_func(x.value, y.value), x.dimension)
def decorated(x): x = quantify(x) return Quantity(math_func(x.value), x.dimension)
def sqrt(x): x = quantify(x) return Quantity(math.sqrt(x.value), x.dimension**0.5)
def poisson(lam=1.0, size=None): lam = quantify(lam) samples = np.random.poisson(lam.value, size=size) return Quantity(samples, lam.dimension)
def copysign(x, y): x = quantify(x) y = quantify(y) return Quantity(math.copysign(x.value, y.value), x.dimension)