Skip to content

The main goal of this package is to reduce the clutter and simplify the process of analyzing and processing data, and doing simple calculations.

License

Notifications You must be signed in to change notification settings

nicholas12392/nanoscipy

Repository files navigation

nanoscipy

nanoscipy has been made, to ease the data-handling, -processing, and - analysis. Additionally, it also provides a simple way to perform numerical calculations with units. This package is being readily updated at the moment, so be sure to keep up, as new and useful additions and fixes are very likely to be included.

Installation and updating

Use the package manager pip to install nanoscipy like below. Rerun this command to check for and install updates .

pip install nanoscipy

For package updates, use:

pip install --upgrade nanoscipy

Note that if you're using anaconda, you might have to install the module from the anaconda terminal instead (or use conda rather than pip)

Import

Click for details

Currently, the package consists of four distinct modules: ```bash nanoscipy.functions ``` Contains most of the practical functions of nanoscipy.

nanoscipy.modules

Contains all classes of nanoscipy.

nanoscipy.util

Contains all utility functions and lists used within nanoscipy. Different modules use functions from this module. Note that some of these functions may be of practical use, but many are simply throw-away functions to increase readability.

nanoscipy.mathpar

The module with the mathematical parser of nanoscipy. Specifically, this contains the practical function parser(), which is the collective parser itself.

nanoscipy.unitpar

Contains a script that allows for computation with units.

Getting started with unit computations

Click for details

There are two main functions of concern here; `mathpar.parser()` and `unitpar.unit_parser()`, but the focus will be on the module `modules.NumAn` as this is what is meant to be the 'calculator'. This section will serve as an explanation of how it works and how it may be used for different purposes. (Last updated: v3.0.8)

1) The NumAn object

When defining the NumAn object there are a few things to note. The __init__() function takes five different inputs, all of which are optional. The first is cons which is where initial constants can be defined so that they may be used in computations later on (by default no constants are defined), e.g.:

import nanoscipy.modules as nsm
cal1 = nsm.NumAn('A=234 kg, lambda=53 nm')

Will have the constants A and lambda defined with the values 234 kg and 53 nm assigned to them, respectively. Constants may also be defined via the attribute function .add_cns(), which works in much the same way, so that for

import nanoscipy.modules as nsm
cal2 = nsm.NumAn()
cal2.add_cns('A=234 kg, lambda=53 nm')

the same constants are defined as for the cal1 object. The add-constant attribute does, however, work slightly different, allowing for new constants to be defined with previously defined constants, so

cal2.add_cns('A2=4*A')

would make it so that A2=936 kg. Constants may effectively have any desired name with a few exceptions: The constant must be a string, meaning that it cannot be converted to a float or int, so B2=34 is allowed, but 22=34 is not. Be aware that constant-values are substituted before calculations are done, which means that if a constant 2H=4 is defined, and a calculation is done for a string '32H' the result is '3*2H=3*4=12'.

The second parameter is unit_identifier. This defines an identifier for which units can be told apart from defined constants by the different scripts. This can in principle be set to any symbol, but be smart about it. The default value used for this purpose is ' ', which is illustrated in the examples above. Another example is seen below for unit_identifier='~'

import nanoscipy.modules as nsm
cal3 = nsm.NumAn(unit_identifier='~')
cal3.add_cns('A=234~kg, lambda=53~nm')
cal3.add_cns('A2=4*A')

The third parameter is units. This tells the script whether units should be used or not (explicitly). Effectively, this only affects natural constants used (see More about constants). Therefore, the default setting is units=True meaning that the script will act as computations should be done with units. Setting this to False will have the script do calculations without units (effectively). It must although be emphasized that this only affects natural constants and so everything is still fine if no units are used initially, as long as no natural constants are used, unless it is by division or multiplication, in which case it is also fine.

The next parameter is cprint. This affects how the result from a computation is displayed (the console print), and affects all computations if not anything else is set specifically per computation (see Calculations). There are a few options here, but the main difference is between 'num' and 'sym'. If set to 'num' the result will be displayed as the mathpar.parser() reads the expression, i.e. with only numbers and mathematical symbols. If set to 'sym' the expression will be displayed with symbols/constants rather than numbers. A variance is 'symc', which displays the constants used in the expression, along with the result. Subtypes are 'sym_ex' and 'symc_ex', which will display the main expression with explicit multiplication (if any implicit multiplication was used). If set to None or False no console print is done. Examples can be found in Calculations. The default setting is 'symc_ex'.

The last parameter is sf which sets the significant figures for the console print. It is important to note that it does not change the significant figures of the calculation itself nor the result. It only changes the console print. This parameter takes integer values, and can be set to None if no evaluation is desired. The default value is 4. Note that this feature works by using the mpmath.workdps function.

2) More about constants

There has already been presented examples of how constants may be defined, but there are a few additional features to note. A list of all the currently defined constants can be seen by calling the attribute function .constants(). Note that if constants are defined with units, then they are displayed with ' ' as the unit identifier, regardless of the value of unit_identifier in the __init__() call. When adding constants that have already been defined, the new constant value will overwrite the old, and a prompt will be printed in the console. E.g.:

cal1 = nsm.NumAn('A=234 kg, lambda=53 nm')
cal1.add_cns('A=34 g')
>>> Constant 'A = 234 kg' has been changed to '34 g'.

Constants may also be removed with the attribute function .del_cns(). Simply specify which constants should be removed in the call. E.g. from the example above:

cal1.constants()
>>> Currently defined constants:
>>> | lambda = 53 nm
>>> | A = 34 g
cal1.del_cns('A, lambda')
cal1.constants()
>>> Currently defined constants:

Note here that .del_cns() can also be used with multiple arguments, rather than with a single string, e.g.:

cal1.del_cns('A', 'lambda')
cal1.constants()
>>> Currently defined constants:

Constants may also be defined from latest computed result by calling the attribute function .add_res() with the name of the constant, e.g. .add_res('omega') will add the latest result from computation as the constant 'omega'.

Other than the constants that can be defined by the user, there are some pre-defined natural constants, which may be used in all calculations, in which they might be needed. These are constants such as the Boltzmann constant _k, the Planck constant _h or the speed of light in a vacuum _c. Note that all constants are denoted with an underscore. A full list of the supported units can be seen by calling the attribute .supported_physical_constants. Depending on whether units is set to True or False, these natural constants will either have associated units or will simply be the natural constant value with SI units:

test = nsm.NumAn(units=False)
print(test.supported_physical_constants)
>>> ('_hbar=1.0545718176461565e-34', ..., '_mp=1.67262192369e-27')
test = nsm.NumAn(units=True)
print(test.supported_physical_constants)
>>> ('_hbar=(1.0545718176461565e-34 J Hz^-1)', ..., '_mp=(1.67262192369e-27 kg)')

3) Calculations

Calculations are performed via the .calc() attribute function. This effectively utilizes unitpar.unit_parser(), which utilizes mathpar.parser() to compute the numerical part of the expression. An example of basic usage is seen below:

import nanoscipy.modules as nsm
cal = nsm.NumAn()
cal.calc('3*5+2^2')
>>> Result: 3·5+2^2 = 19
19

There are a few things to note here. As seen, the support for mathematical operators is slightly different compared to normal python. Specifically, there is support for the operations; +, -, *, /, ^, ! (currently, there is no support for the usual way of denoting a power as **). There is also a 'prettifier' built-in, which automatically changes constants and specific operations to be more in line with how it would look, when simply writing it out on a piece of paper. An example of this is with the use of constants;

cal.add_cns('omega=34 s^-1, d=4 m')
cal.calc('domega')
>>> Result: d·ω = 136 m s^-1
>>> | ω = 34 s^-1
>>> | d = 4 m
136

This also illustrates a feature regarding implicit multiplication, as this is also read properly by the script (which is why caution must be made, when defining constants). Note also that the units will be in the displayed result from the console, but they are not a part of the returned output (to obtain the unit, the attribute .__ans_unit__ can be called). The result from the calculation can be directly added to the list of constants by calling the attribute function .add_res() in the call with a specified name:

cal.add_res('v')
cal.constants()
>>> Currently defined constants:
>>> | omega = 34 s^-1
>>> | d = 4 m
>>> | v = 136 m s^-1

Note that a result may be directly added as a constant, by specifying the parameter add_res in the .calc() call:

cal.calc('domega', 'v', cprint=None)
cal.constants()
>>> Currently defined constants:
>>> | omega = 34 s^-1
>>> | d = 4 m
>>> | v = 136 m s^-1

This also shows use of the cprint (local) kwarg. As opposed to setting the console print option in the __init__() when defining the function as described in The NumAn object. When set in .calc() it only changes the console print for that single calculation, and all others will follow the default set in __init__():

cal.calc('2d/omega', cprint='num')
>>> Result: 2·(4 m)/(34 s^-1) = 0.2353 m s
0.23529411764705882
cal.calc('2domega')
>>> Result: 2·d·ω = 272 m s^-1
>>> | ω = 34 s^-1
>>> | d = 4 m
272

As seen in the former calculation, the significant figures in the console print differs from the output. This is due to described evaluation feature sf (The NumAn object). This parameter can also be set locally with a kwarg per calculation:

cal.add_cns('m=12.3432 g, a=834.2325 m s^-2')
cal.calc('ma')
>>> Result: m·a = 10.3 N
>>> | m = 12.34 g
>>> | a = 834.2 m
10.297098594
cal.calc('ma', sf=6)
>>> Result: m·a = 10.2971 N
>>> | m = 12.3432 g
>>> | a = 834.233 m
10.297098594

As seen, the parameter also affects the displayed constants. Another example (also illustrating the use of natural constants):

cal.add_cns('T=293.15 K')
cal.calc('T_k')
>>> Result: T·kᴮ = 4.047e-21 J
>>> | T = 293.1 K
4.0473725435e-21

Another thing to note is that there is native support for many mathematical functions such as the trigonometric functions, the natural logarithm, etc. The full list of supported such functions (including the value of pi), can be found by calling the attribute .__exclusions__. Some examples of use:

cal.calc('sin(deg(45))')
>>> Result: sin(deg(45)) = 0.8061
0.8060754911159176
cal.add_cns('E=0.3 eV')
cal.calc('exp(E/_kT)')
>>> Result: exp(-E/(kᴮ·T)) = 6.958e-6 a.u.
>>> | T = 293.1 K
>>> | E = 0.3 eV
6.95757565703751e-06
cal.calc('sin(2pi)')
>>> Result: sin(2·π) = 0
0

Note that the natural logarithm is denoted by 'ln()', whereas log10 is denoted as 'log()'.

4) The units

A note must be made about the functionality of the units. In general, when computing the units, all given units are converted into their respective SI components and then reduced. At last, if they correspond to a directly derived unit the resulting unit will be changed into that derived unit. It is, however, currently quite limited, what the script can recognize as a derived unit. Only the base units e.g. N, K, J and the inverse base units; N^-1, K^-1, J^-1 can be found. If the unit result cannot be recognized as a derived unit, it is simply given as SI units.

There is currently support for the vast majority of the SI unit derivatives, excluding the candela derived units. There is also special support for some other units such as the atomic mass unit (amu or u), Angstrom (Å), atmosphere (atm), etc. The full list of supported units, can be seen by calling the attribute .supported_units.

There is also an important point to be made in regard to denotation of the units in an expression. The working principle of the units is that they are essentially multiplicative factors, and so all units act like they are just that. With one very significant exception. When writing units in fractions, if the unit in the denominator consists of multiple units, only the first of those will be read as being in the denominator. This is best illustrated with an example:

import nanoscipy.modules as nsm
test = nsm.NumAn()
test.calc('23 m/2 s')
>>> Result: 23 m/2 s = 11.5 m s^-1
11.5
test.calc('23 m/2 s g')
>>> Result: 23 m/2 s g = 0.0115 m kg s^-1
0.0115

As seen in the latter, the expression '23 m/2 s g' is being read as '(23* m/2* s)* g' rather than '23* m/(2* s* g)'. Due to this, it is always recommended to write expressions with units in parentheses (this is automatically handled, when defining constants and using them in expressions, as shown above, so that a constant defined as 'A=4 kg' will be used by the script as 'A=(4 kg)), especially as this odd functionality may change in the future, but as of now, the way to go is:

test.calc('23 m/(2 s g)')
>>> Result: 23 m/(2 s g) = 1.15e+4 m s^-1 kg^-1
11500

Note that there is currently no support for doing square-roots as 'sqrt(4 m^2)':

test.calc('sqrt(4 m^2)')
>>> Result: sqrt(4 m^2) = 2 m^2
2
test.calc('(4 m^2)^(1/2)')
>>> Result: (4 m^2)^(1/2) = 2 m
2

5) Tips and tricks

It may be convenient to reduce the amount of code needed to do computations, especially if the script is run in a console environment rather than an IDE. This can be done by defining the attribute functions as short variables as follows:

import nanoscipy.modules as nsm
cal = nsm.NumAn()
a = cal.add_cns
d = cal.del_cns
c = cal.calc

Then, when adding new constants simply run a(), when deleting constants, d() and when doing computations c(). E.g.:

a('theta=rad(74), gamma=3.412')
c('gammacos(theta)')
d('gamma')
cal.constants()
>>> Result: γ·cos(θ) = 0.9405
>>> | θ = 1.292
>>> | γ = 3.412
>>> Currently defined constants:
>>> | theta = 1.2915436464758034

6) Disclaimer

Note importantly that this guide may not be completely up-to-date with the newest version of nanoscipy, as it takes a lot of time to re-write and keep an overview of what is in and what is missing. Therefore, I will always recommend to check out the patch notes. It is noted in the beginning of the guide, which version the guide is currently up-to-date with.

About

The main goal of this package is to reduce the clutter and simplify the process of analyzing and processing data, and doing simple calculations.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages