MagickScience
Hello! MagickScience is a scientific library for developing lab machines and scientific inventions. It provides units, molecules, among other features, to allow developers of scientific software to develop their software easily. Enjoy!
MagickScience is under development, but the units are already released. Molecules aren't, but they will by ready soon!
MagickScience includes special units to use, then it's unneeded to care about having the proper dimensions and prefixes when developing scientific software, you can instantiate any value you have on the machine, without performing operations with a calculator first to convert the units to a common prefix. Learn how to use them at the Wiki.
Team
MagickScience is developed by Ismael Correa, a software developer of 32 years old. You can email if you find bugs, request new features, or have any other need, at ismael.correa.castro@gmail.com.
Funding
MagickScience is looking for funding, in order to do some digital marketing and pay some other needs of the project. If you want to support this library, and science will thank you for that, you can donate in this sponsors page.
Installation
To install MagickScience you have to use CMake and Make. The library is called msci_units, the other msci libraries aren't yet published in the web. The commands to install it are the following:
cmake .
make
make install
Introduction
MagickScience is a set of libraries that allows to create the software of scientific inventions, being them scientific machines or just scientific software. This library, MagickScience Units, allows to handle scalar and vectorial units inside the code. They are very lightweight, they size similar to a float, and can be used extensively to do any math calculation necessary for the invention. The prefixes can be changed, in order to display the units in the more proper dimensions. Also, all the conversions known are supported. Then, instead of the meter, a length can be described by a light-year, an astronomical unit (AU), among other units of measure.
The unit classes that MagickScience provides are the following:
- scalar_unit: Handles scalar units. It covers vectors in 1D too.
- vector_unit_2d: Handles vector units in 2D dimensions. It inherits scalar_unit.
- vector_unit_3d: Handles vector units in 3D dimensions. It inherits scalar_unit.
- vector_unit_nd: Handles vector units in ND dimensions. It inherits scalar_unit.
scalar_unit classes can be used both for scalar units and vector units in 1D. In the case of vector units in 1D, a negative value indicates, as on math, that it points to the left on the x axis. Otherwise, if the value is positive, it points to the right.
All the unit classes have fixed dimensions. Once instanciated, they can't change to a different set of dimensions. Besides that, prefixes and abbreviations can be used freely, every unit can change to any other prefix and use any abbreviation that matches the original dimensions (and no other set of dimensions).
Consumption of memory
The scalar_unit and vector unit classes, vector_unid_2d, vector_unid_3d and vector_unit_nd size more than a single float, which uses 4 bytes, but don't size a big amount and so, they can be used in great quantities for any purpose, cause they are very lightweight.
The angle class uses only 4 bytes, and works perfectly fine, very similar to a normal float. Then, you can use it freely every time you need to do calculations that need angles.
Example of use
Angle
An angle object manages angles. It stores angles in grades, rather than in radians. It can be initialized to any grade between 0 and 360 (without including 360, cause this is identical to 0 in meaning), and any initialization that's not inside this range of values gets automatically converted inside it, to his equivalent value between the range.
An example of use of angle is the following:
// Constructors and instantiation
angle y = 54; // Better constructor! Preferred method
angle a = 367; // Gets converted to the value 7, because 7 is the equivalent of 367 inside 0 and 360
angle b = angle(12);
angle c = angle(34_Pa);
angle x = 73_angle; // Not the most optimum constructor, but equally supported
angle z = 23_N; // Angles can be instantiated with units if that is needed, although it's not recommended
// Angles operations with other angles
angle b = a + x;
angle c = a - x;
angle d = a * b;
angle e = a / c;
b += a;
c -= b;
e *= a;
c /= e;
d ^= a;
// Numeric operations
angle x = a + 3;
angle y = x - 6;
angle z = x * 3;
angle g = y / 4;
angle h = z ^ 5;
x += 3;
x -= 6;
x *= 2;
x /= 4;
x ^= 7;
x++;
++x;
x--;
--x;
float a_grade = x.get_grade();
float a_radians = x.get_radian();
x.invert(); // Inverts the angle, the orientation described by this angle points now in the opposite direction
float y = float(x); // Angles can be converted to floatScalar units
Scalar units and vector units are the central objects of MagickScience Units. They store a value and a set of dimensions, as units on science do. Scalar units are just normal values, while vector units have a value and a direction to which the vector points to.
Scalar units can operate with other scalar units, as well as with numeric primitive types. Functions like abs(), sqrt() and to_string() are supported. They have functions to operate with strings, and functions to operate with streams.
An example of use of an scalar unit is the following:
length x = 10_m;
length y = length(8,"mm");
length z = length("10 m");
area xy = area(100,"m2");
x = 2_m;
length a = x + 3.2_dm;
length e = x - 1_mm;
area b = y * 3_m;
length c = b / 2_m;
x += 1_km;
y -= 50_cm;
length f = a + 1.5;
length g = b - 7;
length h = c * 3;
length i = c / 1.5;
area j = c ^ 2;
f += 2;
f -= 1;
g *= 1.5;
h /= 5;
x++;
y--;
x.change_dimensions("mm"); // Dimensions can be set to any prefix
x.change_dimensions("s"); // An scalar_unit can't change to other dimensions different than the dimensions they started
if (x.has_dimensions("km")) // Dimensions are compared without prefixes
{}
x.set_same_prefix(y); // Now x has dimensions "mm" as y
ostringstream out;
out << x; // scalar_unit classes can operate with streams
length w = 100_m;
string d = to_string(w); // Creates the string "100 m"
float a = abs(x); // abs() gives the absolute value of the scalar_unit
scalar_unit b = sqrt(xy); // sqrt() gives the square root of the scalar_unit
scalar_unit c = pow(a,x); // Dimensions would be "m3"
if (equal_dimensions(x,y)) // Evaluates to true if the two scalar_unit objects have the same dimensions, independent of prefixes
{}
if (x == y) // Evaluates to true if the scalar_unit objects have the same value and the same dimensions
{}
if (x == 3) // Compares by value, it's better to only compare scalar_unit. To use 3_m instead would have been better, but numeric primitive types are allow to be used
{}
length a;
cin >> a; // There's support for input streams
string a;
a += x; // Adds the scalar_unit to the string
string b = "x: " + x;
string c = x + " value";Vector units in 2D
Vector units in 2D allow to do calculations for lab machines and simulations of physics and other areas of science in 2 dimensions. They inherit scalar_unit, and additional to his member-variables they include the member-variable theta, of class angle (described above).
An example of use of it is the following:
force_2d x = force_2d(21_N,56_angle); // Creates a force_2d with a value of 21 N and an inclination angle of 56º
force_2d y = force_2d(32,"mN",11); // vector_unid_2d of force with values "32 mN 11º"
vector_unit_2d z = vector_unid_2d(10,"kPa",48); // vector_unit_2d with values "10 kPa 48º"
x.theta += 21_angle; // theta of x can be accessed directed and used as any angle, it's the better way to use it
x += y; // Sum a vector of the same dimensions
y -= z; // Substraction supported. Can't substract vectors of different dimensions
force_2d a = x + y; // Sum of vector_unid_2d
force_2d b = x - y; // Substraction of vector_unid_2d
velocity_2d acc = acceleration_2d("5 m/s") * 100_s; // vector_unid_2d can multiply with scalar_unit
vector_unid_2d p = x / area("10 m2"); // vector_unid_2d can divide with scalar_unit
vector_unid_2d ab = x + 4; // vector_unid_2d can sum with numeric primitive types
vector_unid_2d ac = y - 7; // vector_unid_2d can substract with numeric primitive types
vector_unid_2d ad = x * 3; // vector_unid_2d can multiply with numeric primitive types
vector_unid_2d ae = y / 5; // vector_unid_2d can divide with numeric primitive types
vector_unid_2d xy = x ^ 2; // vector_unid_2d can power with numeric primitive types
x += 3; // vector_unid_2d with operator+= for numeric primitive types
y -= 9; // vector_unid_2d with operator-= for numeric primitive types
x *= 2; // vector_unid_2d with operator*= for numeric primitive types
y /= 6; // vector_unid_2d with operator/= for numeric primitive types
force e = x.x_projection(); // vector_unid_2d projection on the x axis
force f = x.y_projection(); // vector_unid_2d projection on the y axis
x.invert(); // Now x points to the opposite direction
string x_display = to_string(x); // Prints "21N 56º"
energy c = norm(x) * 2_m; // Use of norm() for vector_unit_2d
vector_unid_2d xy = sqrt(x^4); // Gives x ^ 2
vector_unid_2d xy = sqrt_nth(x^4,4); // Gives x
scalar_unit a = dot_product(x,y); // Gives the dot product of x and y, which is an scalar_unit
angle b = angle_between(x,y); // Gives the angle between the two vectors
if (same_direction(x,y)) // Gives true if the vectors point to the same direction
{}
if (parallel(x,y)) // Gives true if the vectors are parallel (point to the same or to the opposite direction)
{}
if (orthogonal(x,y)) // Gives true if the vectors are orthogonal (have 90º of difference in the direction they point to)
{}
if (x == y) // Gives true if the two vector_unit_2d are equal. There's the operator != too
{}
if (x == "21N 56º") // Gives true if the vector is the specified by the string. There's the operator != too
{}
string b;
b =+ x; // Appends x to the string b
string c = "x: " + x; // Creates a new string by inserting x as with to_string(x)
string d = x + " is a vector"; // Both directions are supported for creating strings with vector_unit_2d
cout << x; // Prints x in the output stream, any ostream can be used, not only cout. x is printed with to_string
vector_unit_2d a;
cin >> a; // Initializes a with the string given to cin
Vector units in 3D
Vector units in 3D are the most useful vectorial units. They allow to do all the simulations of physics and any other area of science in 3D, which is the most common scenario. To work, they have, as vector_unit_2d, a value, dimensions, and an angle theta, but they include the angle phi. So, they work as spherical coordinates, having cartesian projections for each axis. The class vector_unit_3d inherits from scalar_unit, as vector_unit_2d, but not from vector_unit_2d, evading math errors that would be derived from that, because 2D and 3D dimensions are not mathematically equivalent in 2D (when projecting the x and y axis there appears the angle phi on the equations for the 3D cases).
An example of use is the following:
force_3d x = force_3d(45_N,12_angle); // Creates a force_3d with a value of 45 N and an inclination angle of 12º
force_3d y = force_3d(78,"kN",67); // vector_unid_3d of force with values "78 mN 67º"
vector_unit_3d z = vector_unid_3d(100,"MPa",60); // vector_unit_3d with values "100 MPa 60º"
x.theta += 16; // theta of x can be accessed directed and used as any angle, it's the better way to use it
x.phi = 90; // phi of x can be accessed directly too
x += y; // Sum a vector of the same dimensions
y -= z; // Substraction supported. Can't substract vectors of different dimensions
force_3d a = x + y; // Sum of vector_unid_3d
force_3d b = x - y; // Substraction of vector_unid_3d
velocity_3d acc = acceleration_3d("25 m/s") * 100_s; // vector_unid_3d can multiply with scalar_unit
vector_unid_3d p = x / area("100 m2"); // vector_unid_3d can divide with scalar_unit
vector_unid_3d ab = x + 16; // vector_unid_3d can sum with numeric primitive types
vector_unid_3d ac = y - 98; // vector_unid_3d can substract with numeric primitive types
vector_unid_3d ad = x * 2; // vector_unid_3d can multiply with numeric primitive types
vector_unid_3d ae = y / 8; // vector_unid_3d can divide with numeric primitive types
vector_unid_3d xy = x ^ 4; // vector_unid_3d can power with numeric primitive types
x += 7; // vector_unid_3d with operator+= for numeric primitive types
y -= 19; // vector_unid_3d with operator-= for numeric primitive types
x *= 4; // vector_unid_3d with operator*= for numeric primitive types
y /= 2; // vector_unid_3d with operator/= for numeric primitive types
force e = x.x_projection(); // vector_unid_3d projection on the x axis
force f = x.y_projection(); // vector_unid_3d projection on the y axis
force f = x.z_projection(); // vector_unid_3d projection on the z axis
x.invert(); // Now x points to the opposite direction
string x_display = to_string(x); // Prints "45N 12º"
energy c = norm(x) * 2_m; // Use of norm() for vector_unit_3d
vector_unid_3d xy = sqrt(x^4); // Gives x ^ 2
vector_unid_3d xy = sqrt_nth(x^4,4); // Gives x
scalar_unit a = dot_product(x,y); // Gives the dot product of x and y, which is an scalar_unit
vector_unit_3d b = cross_product(x,y); // Gives the cross product of x and y, which is a vector_unit_3d
angle b = angle_between(x,y); // Gives the angle between the two vectors
if (same_direction(x,y)) // Gives true if the vectors point to the same direction
{}
if (parallel(x,y)) // Gives true if the vectors are parallel (point to the same or to the opposite direction)
{}
if (orthogonal(x,y)) // Gives true if the vectors are orthogonal (have 90º of difference in the direction they point to)
{}
if (x == y) // Gives true if the two vector_unit_3d are equal. There's the operator != too
{}
if (x == "45N 12º") // Gives true if the vector is the specified by the string. There's the operator != too
{}
string b;
b =+ x; // Appends x to the string b
string c = "x: " + x; // Creates a new string by inserting x as with to_string(x)
string d = x + " is a vector"; // Both directions are supported for creating strings with vector_unit_3d
cout << x; // Prints x in the output stream, any ostream can be used, not only cout. x is printed with to_string
vector_unit_3d a;
cin >> a; // Initializes a with the string given to cin
Vector units in ND
Vector units in ND are very interesting vector units. They allow to operate in ND, which means, inside MagickScience, that the dimensions can be changed. ND allows to operate in 1D, 2D, 3D and more dimensions at the same time. The way they allow that is with a vector member-variable, which allows to control the angles of the n dimensions were the vector operates. For 2D it has one angle, as vector_unit_2d, and for 3D it has two angles, as vector_unit_3d. For 1D it doesn't has any angle.
An example of use is the following:
force_nd x = force_nd(29_N,{8_angle,16_angle,32_angle}); // Creates a force_nd with a value of 29 N and an inclination angle of 8º, another of 16º and another of 32º
force_nd y = force_nd(44,"dN",{55,13,42}); // vector_unid_nd of force with values "44 dN 55º 13º 42º"
vector_unit_nd z = vector_unit_nd(81,"MPa",{32,44,67}); // vector_unit_nd with values "81 MPa 32º 44º 67º"
x.angles[0] += 7; // theta of x can be accessed directed and used as any angle, it's the better way to use it
x.angles[1] = 71; // phi of x can be accessed directly too
x.angles[2] -= 4;
x += y; // Sum a vector of the same dimensions
y -= z; // Substraction supported. Can't substract vectors of different dimensions
force_nd a = x + y; // Sum of vector_unit_nd
force_nd b = x - y; // Substraction of vector_unit_nd
velocity_nd acc = acceleration_nd("19 m/s",{14,52,33}) * 80_s; // vector_unit_nd can multiply with scalar_unit
vector_unit_nd p = x / area("100 m2"); // vector_unit_nd can divide with scalar_unit
vector_unit_nd ab = x + 9; // vector_unit_nd can sum with numeric primitive types
vector_unit_nd ac = y - 78; // vector_unit_nd can substract with numeric primitive types
vector_unit_nd ad = x * 3; // vector_unit_nd can multiply with numeric primitive types
vector_unit_nd ae = y / 5; // vector_unit_nd can divide with numeric primitive types
vector_unit_nd xy = x ^ 3; // vector_unit_nd can power with numeric primitive types
x += 45; // vector_unit_nd with operator+= for numeric primitive types
y -= 15; // vector_unit_nd with operator-= for numeric primitive types
x *= 3; // vector_unit_nd with operator*= for numeric primitive types
y /= 7; // vector_unit_nd with operator/= for numeric primitive types
force e = x.x_projection(); // vector_unit_nd projection on the x axis
force f = x.y_projection(); // vector_unit_nd projection on the y axis
force f = x.z_projection(); // vector_unit_nd projection on the z axis
force f = x.n_projection(2); // vector_unit_nd projection on the y axis, any axis can be specified. x is 1, y is 2, z is 3
x.invert(); // Now x points to the opposite direction
string x_display = to_string(x); // Prints "29N 8º 16º 32º"
energy c = norm(x) * 2_m; // Use of norm() for vector_unit_nd
vector_unid_nd xy = sqrt(x^4); // Gives x ^ 2
vector_unid_nd xy = sqrt_nth(x^4,4); // Gives x
scalar_unit a = dot_product(x,y); // Gives the dot product of x and y, which is an scalar_unit
vector_unit_nd b = cross_product(x,y); // Gives the cross product of x and y, which is a vector_unit_nd
angle b = angle_between(x,y); // Gives the angle between the two vectors
if (same_nd(x,y)) // Gives true if the vector have the same ND, if both are 2D, both are 3D, or both are 1D
{}
if (same_direction(x,y)) // Gives true if the vectors point to the same direction
{}
if (parallel(x,y)) // Gives true if the vectors are parallel (point to the same or to the opposite direction)
{}
if (orthogonal(x,y)) // Gives true if the vectors are orthogonal (have 90º of difference in the direction they point to)
{}
if (x == y) // Gives true if the two vector_unit_nd are equal. There's the operator != too
{}
if (x == "29N 8º 16º 32º") // Gives true if the vector is the specified by the string. There's the operator != too
{}
string b;
b =+ x; // Appends x to the string b
string c = "x: " + x; // Creates a new string by inserting x as with to_string(x)
string d = x + " is a vector"; // Both directions are supported for creating strings with vector_unit_nd
cout << x; // Prints x in the output stream, any ostream can be used, not only cout. x is printed with to_string
vector_unit_nd a;
cin >> a; // Initializes a with the string given to cin
MagickScience Units Internals
Internally, the library has some important mechanisms important to be known by a serious developer. Those important mechanisms are described here, in order to avoid the developer to read the code of the library and learn every detail.
The first important mechanism to describe is the static storage of custom dimensions. This storage is static, meaning that every time a unit of a dimension not registered is created, this storage is the one used, instead of the name being stored inside the instance. With that behavior, when instantiating a big amount of dimensions, a big amount of memory is saved. To refer to the static storage it's used the char symbol[3] of the dimension class, which uses only 3 bytes instead of the bytes the full dimension name would use. Then, each instance of a dimension class, given that static storage, uses only 6 bytes of memory.