|
| 1 | +""" |
| 2 | +Title : Implementation of Boyle's law. |
| 3 | +
|
| 4 | +Description : |
| 5 | + Boyle's law, also referred to as the Boyle-Mariotte law, or Mariotte's law |
| 6 | + (especially in France), is a gas law which states that the pressure exerted |
| 7 | + by a gas of a fixed mass and temperature is inversely proportional to the |
| 8 | + volume occupied by it. |
| 9 | +
|
| 10 | + For a gas, the relationship between volume and pressure (at constant mass and |
| 11 | + temperature) can be expressed mathematically as follows. |
| 12 | +
|
| 13 | + P ∝ (1/V) |
| 14 | +
|
| 15 | + Where P is the pressure exerted by the gas and V is the volume occupied by it. This |
| 16 | + proportionality can be converted into an equation by adding a constant, k. |
| 17 | +
|
| 18 | + P = k*(1/V) ⇒ PV = k |
| 19 | +
|
| 20 | + Boyle's law states that when the temperature of a given mass of confined gas is |
| 21 | + constant,the product of its pressure and volume is also constant. When comparing the |
| 22 | + same substance under two different sets of conditions, the law can be expressed as: |
| 23 | +
|
| 24 | + P1V1 = P2V2 |
| 25 | +
|
| 26 | + Where, |
| 27 | +
|
| 28 | + P1 is the initial pressure exerted by the gas in Pascals (P) |
| 29 | + V1 is the initial volume occupied by the gas Litres (L) |
| 30 | + P2 is the final pressure exerted by the gas Pascals (P) |
| 31 | + V2 is the final volume occupied by the gas Litres (L) |
| 32 | +
|
| 33 | + This equation can be used to predict the increase in the pressure exerted by a gas |
| 34 | + on the walls of its container when the volume of its container is decreased |
| 35 | + (and its quantity and absolute temperature remain unchanged). |
| 36 | +
|
| 37 | +Sources : |
| 38 | + https://en.wikipedia.org/wiki/Boyle%27s_law |
| 39 | + https://byjus.com/chemistry/boyles-law/ |
| 40 | +""" |
| 41 | + |
| 42 | +valid_variables: list[str] = ["v1", "v2", "p1", "p2"] |
| 43 | + |
| 44 | + |
| 45 | +def check_validity(values: dict[str, float]) -> None: |
| 46 | + """ |
| 47 | +
|
| 48 | + Function takes dictionary as an input and returns nothing if the input |
| 49 | + is valid |
| 50 | +
|
| 51 | + >>> check_validity({}) |
| 52 | + Traceback (most recent call last): |
| 53 | + ... |
| 54 | + ValueError: Invalid input expected 3 items, got 0 |
| 55 | +
|
| 56 | + >>> check_validity({'v1':2,'v2':4,'k':6}) |
| 57 | + Traceback (most recent call last): |
| 58 | + ... |
| 59 | + ValueError: Invalid input k is not a valid variable |
| 60 | +
|
| 61 | + >>> check_validity({'v1':2,'v2':4,'p1':-6}) |
| 62 | + Traceback (most recent call last): |
| 63 | + ... |
| 64 | + ValueError: Invalid input p1 must be greater than 0 |
| 65 | +
|
| 66 | + >>> check_validity({'v1':2,'v2':4,'p1':6}) |
| 67 | +
|
| 68 | + """ |
| 69 | + if len(values) != 3: |
| 70 | + msg = f"Invalid input expected {3} items, got {len(values)}" |
| 71 | + raise ValueError(msg) |
| 72 | + for value, val in values.items(): |
| 73 | + if value not in valid_variables: |
| 74 | + msg = f"Invalid input {value} is not a valid variable" |
| 75 | + raise ValueError(msg) |
| 76 | + if val <= 0: |
| 77 | + msg = f"Invalid input {value} must be greater than 0" |
| 78 | + raise ValueError(msg) |
| 79 | + |
| 80 | + |
| 81 | +def find_target_variable(values: dict[str, float]) -> str: |
| 82 | + """ |
| 83 | +
|
| 84 | + Function is used to get the valid target variable whose value needs to be found |
| 85 | + using Boyle's Law. |
| 86 | + Function takes a dictionary as an input and returns a string |
| 87 | +
|
| 88 | + >>> find_target_variable({}) |
| 89 | + Traceback (most recent call last): |
| 90 | + ... |
| 91 | + ValueError: Invalid input expected 3 items, got 0 |
| 92 | +
|
| 93 | + >>> find_target_variable({'v1':1,'v2':2,'p2':4}) |
| 94 | + 'p1' |
| 95 | +
|
| 96 | + >>> find_target_variable({'v1':1,'v2':2,'k':4}) |
| 97 | + Traceback (most recent call last): |
| 98 | + ... |
| 99 | + ValueError: Invalid input k is not a valid variable |
| 100 | +
|
| 101 | + >>> find_target_variable({'v1':1,'v2':-2,'p2':4}) |
| 102 | + Traceback (most recent call last): |
| 103 | + ... |
| 104 | + ValueError: Invalid input v2 must be greater than 0 |
| 105 | +
|
| 106 | + """ |
| 107 | + check_validity(values) |
| 108 | + for variable in valid_variables: |
| 109 | + if variable not in values: |
| 110 | + return variable |
| 111 | + raise ValueError("Input is invalid") |
| 112 | + |
| 113 | + |
| 114 | +def boyles_law(values: dict[str, float]) -> dict[str, str]: |
| 115 | + """ |
| 116 | +
|
| 117 | + Function calculates the the unknown pressure or volume using Boyle's law. |
| 118 | + Function takes a dictionary as an input. It contains values for respective |
| 119 | + pressure and volumes and computes the required value and returns it as |
| 120 | + output |
| 121 | +
|
| 122 | + >>> boyles_law({'p1':2,'v2':1}) |
| 123 | + Traceback (most recent call last): |
| 124 | + ... |
| 125 | + ValueError: Invalid input expected 3 items, got 2 |
| 126 | +
|
| 127 | + >>> boyles_law({}) |
| 128 | + Traceback (most recent call last): |
| 129 | + ... |
| 130 | + ValueError: Invalid input expected 3 items, got 0 |
| 131 | +
|
| 132 | + >>> boyles_law({'p1':2,'v2':1, 'k':6}) |
| 133 | + Traceback (most recent call last): |
| 134 | + ... |
| 135 | + ValueError: Invalid input k is not a valid variable |
| 136 | +
|
| 137 | + >>> boyles_law({'p1':2,'v2':1, 'v1':-6}) |
| 138 | + Traceback (most recent call last): |
| 139 | + ... |
| 140 | + ValueError: Invalid input v1 must be greater than 0 |
| 141 | +
|
| 142 | + >>> boyles_law({'p1':100,'v2':150, 'v1':120}) |
| 143 | + {'p2': '80.0 Pa'} |
| 144 | +
|
| 145 | + >>> boyles_law({'p1':10,'v1':20, 'p2':20}) |
| 146 | + {'v2': '10.0 L'} |
| 147 | +
|
| 148 | + >>> boyles_law({'v1':13,'p2':17, 'v2':19}) |
| 149 | + {'p1': '24.846 Pa'} |
| 150 | +
|
| 151 | + >>> boyles_law({'v2':27,'p1':25, 'p2':29}) |
| 152 | + {'v1': '31.32 L'} |
| 153 | +
|
| 154 | + """ |
| 155 | + check_validity(values) |
| 156 | + target = find_target_variable(values) |
| 157 | + float_precision = ".3f" |
| 158 | + if target == "p1": |
| 159 | + p1 = float( |
| 160 | + format((values["p2"] * values["v2"]) / values["v1"], float_precision) |
| 161 | + ) |
| 162 | + return {"p1": f"{p1} Pa"} |
| 163 | + elif target == "v1": |
| 164 | + v1 = float( |
| 165 | + format((values["p2"] * values["v2"]) / values["p1"], float_precision) |
| 166 | + ) |
| 167 | + return {"v1": f"{v1} L"} |
| 168 | + elif target == "p2": |
| 169 | + p2 = float( |
| 170 | + format((values["p1"] * values["v1"]) / values["v2"], float_precision) |
| 171 | + ) |
| 172 | + return {"p2": f"{p2} Pa"} |
| 173 | + else: |
| 174 | + v2 = float( |
| 175 | + format((values["p1"] * values["v1"]) / values["p2"], float_precision) |
| 176 | + ) |
| 177 | + return {"v2": f"{v2} L"} |
| 178 | + |
| 179 | + |
| 180 | +if __name__ == "__main__": |
| 181 | + import doctest |
| 182 | + |
| 183 | + doctest.testmod() |
0 commit comments