diff --git a/physics/first_law_of_thermodynamics.py b/physics/first_law_of_thermodynamics.py new file mode 100644 index 000000000000..0ece2092518d --- /dev/null +++ b/physics/first_law_of_thermodynamics.py @@ -0,0 +1,173 @@ +""" +________________________________________________________________________________________ +The first law of thermodynamics states that, when energy passes into or out of a system +(as work, heat, or matter), the system's internal energy changes in accordance with the +law of conservation of energy. This also results in the observation that, in an +externally isolated system, even with internal changes, the sum of all forms of energy +must remain constant, as energy cannot be created or destroyed. + +Check out the formula used to calculate this flux: + -------------- + | Q = ΔU + W | + -------------- + +Q = heat added or removed from the system. +ΔU = variation of internal energy of the system. +W = work done by the system on its surroundings. + +OBS: All units must be equal to each other. +(Description adapted from https://en.wikipedia.org/wiki/Laws_of_thermodynamics ) +""" + + +def __check_args(argument: float) -> None: + """ + Check that the arguments are valid. + >>> __check_args(50.0) + >>> __check_args(-20) + >>> __check_args("50") + Traceback (most recent call last): + ... + TypeError: Invalid argument. Should be an integer or float. + """ + + # Ensure valid instance + if not isinstance(argument, (int, float)): + raise TypeError("Invalid argument. Should be an integer or float.") + + +def __categorize_system(argument_value: float, argument_name: str) -> None: + """ + Categorizes the system based on the work done, heat added/removed, + and internal energy variation. + >>> __categorize_system(0, "work") + The system is isochoric (constant volume). + >>> __categorize_system(50, "heat") + The system is endothermic (absorbing heat). + >>> __categorize_system(-20, "internal_energy_variation") + The internal energy of the system is decreasing. It cooling down. + >>> __categorize_system(10, "invalid") + Traceback (most recent call last): + ... + ValueError: Should be 'work', 'heat', or 'internal_energy_variation'. + """ + + if argument_name == "work": + if argument_value == 0: + print("The system is isochoric (constant volume).") + elif argument_value > 0: + print("The system is expanding.") + elif argument_value < 0: + print("The system is compressing.") + + elif argument_name == "heat": + if argument_value == 0: + print("The system is adiabatic (no heat exchange).") + elif argument_value > 0: + print("The system is endothermic (absorbing heat).") + elif argument_value < 0: + print("The system is exothermic (releasing heat).") + + elif argument_name == "internal_energy_variation": + if argument_value == 0: + print("The system is isothermic (constant internal energy)") + elif argument_value > 0: + print("The internal energy of the system is increasing. It heating up.") + elif argument_value < 0: + print("The internal energy of the system is decreasing. It cooling down.") + + else: + raise ValueError("Should be 'work', 'heat', or 'internal_energy_variation'.") + + +def work(heat: float, internal_energy_variation: float) -> float: + """ + >>> work(50.0, -20.0) + The system is endothermic (absorbing heat). + The internal energy of the system is decreasing. It cooling down. + The system is expanding. + 70.0 + >>> work(50.0, 50.0) + The system is endothermic (absorbing heat). + The internal energy of the system is increasing. It heating up. + The system is isochoric (constant volume). + 0.0 + >>> work(-50.0, 20.0) + The system is exothermic (releasing heat). + The internal energy of the system is increasing. It heating up. + The system is compressing. + -70.0 + """ + __check_args(heat) + __check_args(internal_energy_variation) + + __categorize_system(heat, "heat") + __categorize_system(internal_energy_variation, "internal_energy_variation") + + work = heat - internal_energy_variation + __categorize_system(work, "work") + return round(work, 1) + + +def heat(internal_energy_variation: float, work: float) -> float: + """ + >>> heat(-20.0, 30.0) + The internal energy of the system is decreasing. It cooling down. + The system is expanding. + The system is endothermic (absorbing heat). + 10.0 + >>> heat(50.0, 0.0) + The internal energy of the system is increasing. It heating up. + The system is isochoric (constant volume). + The system is endothermic (absorbing heat). + 50.0 + >>> heat(20.0, -70.0) + The internal energy of the system is increasing. It heating up. + The system is compressing. + The system is exothermic (releasing heat). + -50.0 + """ + __check_args(internal_energy_variation) + __check_args(work) + + __categorize_system(internal_energy_variation, "internal_energy_variation") + __categorize_system(work, "work") + + heat = round(internal_energy_variation + work, 1) + __categorize_system(heat, "heat") + return heat + + +def internal_energy_variation(heat: float, work: float) -> float: + """ + >>> internal_energy_variation(50.0, 30.0) + The system is endothermic (absorbing heat). + The system is expanding. + The internal energy of the system is increasing. It heating up. + 20.0 + >>> internal_energy_variation(50.0, 0.0) + The system is endothermic (absorbing heat). + The system is isochoric (constant volume). + The internal energy of the system is increasing. It heating up. + 50.0 + >>> internal_energy_variation(-50.0, -70.0) + The system is exothermic (releasing heat). + The system is compressing. + The internal energy of the system is increasing. It heating up. + 20.0 + """ + __check_args(heat) + __check_args(work) + + __categorize_system(heat, "heat") + __categorize_system(work, "work") + + internal_energy_variation = round(heat - work, 1) + __categorize_system(internal_energy_variation, "internal_energy_variation") + return internal_energy_variation + + +if __name__ == "__main__": + from doctest import testmod + + testmod() diff --git a/physics/magnetic_flux.py b/physics/magnetic_flux.py new file mode 100644 index 000000000000..99a7ca215fd5 --- /dev/null +++ b/physics/magnetic_flux.py @@ -0,0 +1,81 @@ +""" +________________________________________________________________________________________ +Magnetic flux (Φ) is a scalar quantity that measures the number of magnetic field +lines (B) that pass through a closed area (A). Furthermore, the magnetic flux depends +on the angle formed between the magnetic field and the normal line (N) in area A. +Check out the formula used to calculate this flux: + ------------ + | Φ = B.A.cos(θ) | + ------------ + +Φ = magnetic flux (weber (Wb) or tesla square meter (T.m²)) +B = magnetic field (tesla (T)) +A = area (square meter (m²)) +θ = angle between magnetic field and normal line (degrees (°)) + +(Description adapted from https://en.wikipedia.org/wiki/Ideal_gas_law ) +""" + +from math import cos, radians + + +def check_args(magnetic_field: float, area: float, angle: float) -> None: + """ + Check that the arguments are valid + """ + + # Ensure valid instance + if not isinstance(magnetic_field, (int, float)): + raise TypeError("Invalid magnetic field. Should be an integer or float.") + + if not isinstance(area, (int, float)): + raise TypeError("Invalid area. Should be an integer or float.") + + if not isinstance(angle, (int, float)): + raise TypeError("Invalid angle. Should be an integer or float.") + + # Ensure valid angle + if angle < 0 or angle > 180: + raise ValueError("Invalid angle. Range is 0-180 degrees.") + + # Ensure valid magnetic field + if magnetic_field < 0: + raise ValueError("Invalid magnetic field. Should be a positive number.") + + # Ensure valid area + if area < 0: + raise ValueError("Invalid area. Should be a positive number.") + + +def magnetic_flux(magnetic_field: float, area: float, angle: float) -> float: + """ + >>> magnetic_flux(50.0, 2, 0.0) + 100.0 + >>> magnetic_flux(50, 2, 60.0) + 50.0 + >>> magnetic_flux(0.5, 4.0, 90.0) + 0.0 + >>> magnetic_flux(1, 2.0, 180.0) + -2.0 + >>> magnetic_flux(-1.0, 2.0, 30.0) + Traceback (most recent call last): + ... + ValueError: Invalid magnetic field. Should be a positive number. + >>> magnetic_flux(1.0, 'a', 30.0) + Traceback (most recent call last): + ... + TypeError: Invalid area. Should be an integer or float. + >>> magnetic_flux(1.0, -2.0, 30.0) + Traceback (most recent call last): + ... + ValueError: Invalid area. Should be a positive number. + """ + check_args(magnetic_field, area, angle) + rad = radians(angle) + return round(magnetic_field * area * cos(rad), 1) + + +if __name__ == "__main__": + from doctest import testmod + + testmod()