↓ Skip to main content

ENEM with Python: The Sucrose Inversion Problem (2020)

 Author
Author
Francisco Bustamante
Chemist, data scientist and Python programmer.
Table of Contents

Is it possible to study for the college entrance exam and still learn Python? Of course!

In this article, we analyze a problem from the 2020 exam. It is a chemistry problem, but one that can be solved more with reasoning than with chemistry itself. The exam is the ENEM (Exame Nacional do Ensino Médio), the national high school exam that Brazilian students take to enter universities.

The problem statement
#

Below is the problem statement, taken from the regular yellow exam booklet given in 2020 (the original is in Portuguese):

Sucrase (or invertase) is an enzyme that acts in the human intestine, hydrolyzing the disaccharide sucrose into the monosaccharides glucose and fructose. In a kinetic study of the hydrolysis reaction of sucrose (C12H22O11), 171 g of sucrose were dissolved in 500 mL of water. It was observed that, every 100 minutes of reaction, the sucrose concentration was reduced by half, regardless of the moment chosen as the initial time. The molar masses of the elements H, C, and O are equal to 1, 12, and 16 g.mol−1, respectively. What is the sucrose concentration 400 minutes after the start of the hydrolysis reaction?

The options are:

  • A. 2.50 × 10−3 mol.L−1
  • B. 6.25 × 10−2 mol.L−1
  • C. 1.25 × 10−1 mol.L−1
  • D. 2.50 × 10−1 mol.L−1
  • E. 4.27 × 10−1 mol.L−1

Let’s recognize a few things in the problem. First, the ENEM pattern of having a story with information that is not needed to solve the problem. In this article, I will assume that the reader has a high school level of education, whether as a student, or someone interested in science but without advanced training in the area, or even a high school teacher. So the beginning of the problem may seem a bit challenging. After all, what the heck is hydrolysis, disaccharide, monosaccharide…? The student is not necessarily used to these words.

Three steps to understand problems
#

The first step, then, is to recognize fundamental concepts that will let us focus on the core of the problem itself. Thus, we recognize that this is a kinetics problem ("… kinetic study…"). At this point, some keywords should come to mind:

  • reaction order (first, second, zero…);
  • rate law;
  • catalyst;
  • half-life.

A good part of the high school level kinetics problems focus on these keywords so, if you are a student and are going to take the ENEM, in kinetics this is what you need to know.

So, the second step is to check which keyword connects with the problem. Note the passage “…every 100 minutes of reaction, the sucrose concentration was reduced by half…”. Well, what is basically being said is that the half-life of the reaction is 100 minutes. Using the Wikipedia article on half-life as a reference, we have the following explanation for the term: if the quantity that decays has a value at the start of the process, at the half-life the quantity will have half of that value.

We already know that this is a kinetics problem, more specifically about half-life. The last step before moving on to the solution is to observe the system of units of the problem and what was provided. Neglecting this step is a significant source of errors. Note that the question is about concentration and the options are in mol.L-1. However, the initial concentration was not given, but rather the initial mass. So, there will be a calculation to find the initial concentration, which will involve the volume. The volume provided is in mL but the options are in liters. So, there will be a unit conversion.

That’s it, we now know everything we need and all that is left is to do the calculations. Note that, after recognizing the context and the topic of the problem, everything else plays a merely decorative role. Rarely, in the ENEM, does the student actually need to understand the scenario that was presented and all the “fluff”. Once the keywords are captured, the problem usually becomes substituting values into simple equations or carrying out simple reasoning.

Let’s go to Python!

Solving the problem
#

Let’s start by importing the libraries we will use. The role of each one will be explained throughout the article:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
from molmass import Formula

Note that, at the end of the statement, the molar masses of the elements that make up sucrose were provided. The goal is to let the student calculate the molar mass of sucrose, needed to calculate the initial concentration of the solution. This calculation is very simple: just multiply each element’s molar mass by the number of times it appears in the formula and add up the values obtained. But…

Think. You have a computer that is dozens of orders of magnitude more powerful than your pocket calculator. Millions of crazy chemists around the world do molar mass calculations all the time. Surely someone has already gone to the trouble of making their routine easier by creating a package that speeds up this calculation. For that, there is molmass. See how simple it is: we pass a string with the compound’s formula to the Formula class of molmass and request the mass attribute:

formula = Formula('C12H22O11')
formula.mass  # g/mol
342.297037

An advantage is that the package uses the molar masses of the elements without any rounding, avoiding the propagation of errors from intermediate roundings.

Note that I put the unit in a comment. It is good practice to make the system of units of the code explicit. I have already written on this site about the pint package that lets you work with units in the code itself, converting them automatically. I could use it in this article too, but I will do the conversions step by step to make the article more didactic, closer to what the student would do on paper.

Now, let’s create variables for each piece of information in the statement. Once again, notice the care in including the units. It is a simple detail that helps other people understand your code and helps you notice problems of unit inconsistency (dimensional analysis). And it also helps another very important person: your own future “self”, who won’t even remember what you were thinking when you wrote the code ;-)

mass = 171  # g
volume = 500  # mL
half_life = 100  # min
time = 400  # min

We have already seen that the volume must be in liters. So, we can redefine the variable volume so that it is its current value times 10-3. After all, the prefix m in mL means exactly 10-3 x L:

volume = volume * 1E-3  # mL to L

The 1E-3 in the code has the same meaning as 1 x 10-3. This E notation is widely used in calculators and computer programs for powers of 10.

Now we have enough to calculate the initial molar concentration of sucrose. From chemistry classes:

$$\begin{aligned} &\text{molar concentration} \\ &\quad = \frac{\text{mass}}{\text{molar mass} \cdot \text{volume}} \\ &\quad = \frac{g}{\frac{g}{mol} \cdot \ell} = \frac{mol}{\ell} \end{aligned}$$

Note that, if you don’t remember the formula, you can figure out from the units alone how to arrange the quantities to give the desired unit. In this case, mol/ℓ. So, let’s do this calculation:

initial_concentration = mass / (formula.mass * volume)
initial_concentration  # mol/l
0.9991322244486738

Now, let’s deal with the half-life and finish solving the problem. The concept of half-life is simple and we can reach the answer with reasoning alone. We have already seen that, after each half-life period, the concentration drops by half. Thus:

$$\begin{aligned} c &\xrightarrow{100\ \text{min}} \frac{c}{2} \\ \frac{c}{2} &\xrightarrow[\text{total: } 200\ \text{min}]{100\ \text{min}} \frac{\frac{c}{2}}{2} = \frac{c}{2^2} = \frac{c}{4} \\ \frac{c}{4} &\xrightarrow[\text{total: } 300\ \text{min}]{100\ \text{min}} \frac{\frac{c}{4}}{2} = \frac{c}{2^3} = \frac{c}{8} \\ \frac{c}{8} &\xrightarrow[\text{total: } 400\ \text{min}]{100\ \text{min}} \frac{\frac{c}{8}}{2} = \frac{c}{2^4} = \frac{c}{16} \end{aligned}$$$$c \equiv \text{initial concentration}$$

So, after 400 min, the initial concentration was divided by 16:

initial_concentration / 16  # mol/l
0.06244576402804211

We have reached our answer! Option B, 6.25 x 10-2 mol L-1. But let’s make the code a bit better and more general.

Generalizing the solution
#

Note, in the diagram above, that there is a relationship involving powers of 2 and the number of half-life periods that have elapsed. So, we can generalize our solution a bit more. The number of half-life periods can be easily calculated:

num_half_lives = time / half_life
num_half_lives
4.0

And, with that, calculate the final concentration:

final_concentration = initial_concentration / 2**num_half_lives
final_concentration  # mol/l
0.06244576402804211

Same result as before, but note that the “magic number” 16 no longer appears. We managed to express the problem based on its fundamentals. And, of course, we can present the result in a friendlier way, without so many numbers that are not actually significant, and with the unit. For that, a bit of string formatting:

print(f'{final_concentration:.2E} mol/L')
6.24E-02 mol/L

Much better.

However… think! It would be very interesting if we could somehow just provide the input data and have the result appear. That is what computers are for: to waste hours watching videos on YouTube and to automate repetitive tasks.

We already know the fundamentals of the problem, so we can write a function that takes the input data (initial concentration, half-life, and time) and returns the final concentration:

def concentration_after_half_lives(initial_concentration, half_life, time):
    num_half_lives = time / half_life
    return initial_concentration / 2**num_half_lives


concentration_after_half_lives(initial_concentration, half_life, time)
0.06244576402804211

Now we have a function that automates all the work we have done. It can be used in any similar exercise. It can even be put in a Python script and reused in other contexts that are, mathematically, similar, as we will see next.

Since we are here, let’s understand a bit more about kinetics.

A bit more about kinetics
#

Several simplifications are made in the study of chemistry at the high school level. One of them is treating the concept of half-life as tied to first-order kinetics reactions.

Conceptually, any order can have an expression for half-life. However, the concept is more important from a practical point of view in first-order kinetics such as, for example, radioactive decay or tracking the concentration of some drugs in the bloodstream. Let’s, then, recall important points of first-order kinetics and relate them to the problem.

Considering any chemical species A, if it undergoes any transformation that obeys first-order kinetics, then the following equations are valid:

$$v = k[A]$$$$[A]_t = [A]_0 e^{-kt}$$$$t_{\frac{1}{2}} = \frac{\ln 2}{k}$$$$\begin{aligned} v &\equiv \text{rate} \\ k &\equiv \text{rate constant} \\ [A]_t &\equiv \text{concentration at time } t \\ [A]_0 &\equiv \text{concentration at the initial time} \\ t_{\frac{1}{2}} &\equiv \text{half-life} \end{aligned}$$

Can you recognize the powers of 2 seen earlier in any of these equations?

So, we can write functions that give the rate constant for the reaction and the concentration of A (in the problem, sucrose) after any time. In the functions, I used the NumPy library for the ln (log) and exponential (exp) functions:

def first_order_rate_constant(half_life):
    return np.log(2) / half_life


def concentration(initial_concentration, half_life, time):
    rate_constant = first_order_rate_constant(half_life)
    return initial_concentration * np.exp(-rate_constant * time)


first_order_rate_constant(half_life)  # unit will be min^-1
0.006931471805599453
concentration(initial_concentration, half_life, time)  # mol/l
0.06244576402804211

Obviously, the result obtained is the same as before. But now we have used a deeper knowledge of the subject. Note that it is perfectly possible to solve the problem without going into reaction order (as we did before). However, knowing that this is a first-order kinetics problem, we can explore a bit more. Let’s visualize graphically what “halving the concentration” means and, with the visualization, understand what exponential decay means, a term widely used in first-order kinetics.

First, let’s obtain the sucrose concentrations after 5 consecutive half-lives to have some reference points on the plot:

times = np.array([time for time in range(0, 501, 100)])
concentrations = concentration(initial_concentration, half_life, times)
concentrations
array([0.99913222, 0.49956611, 0.24978306, 0.12489153, 0.06244576,
       0.03122288])

Can you find a pattern in the values above?

Now, let’s use the Matplotlib library to build a plot. In the plot, I want the points above to stand out and I want a curve that shows the profile of an exponential function. Here is the code:

# configuring Matplotlib so the plot looks more presentable
params = {
    'lines.linewidth': 2.5,
    'axes.labelsize': 16,
    'axes.titlesize': 16,
    'xtick.labelsize': 14,
    'ytick.labelsize': 14,
    'figure.autolayout': True,
    'figure.titlesize': 24,    
    'figure.figsize': (12, 8),
    'legend.shadow': False,    
    'legend.fontsize': 14,
}

plt.rcParams.update(params)



fig, ax = plt.subplots()

# creating points for a theoretical curve
t = np.array([time for time in range(0, 551, 20)])
c = concentration(initial_concentration, half_life, t)
ax.plot(t, c, zorder=1, label='Theoretical curve - 1st-order kinetics')

# the half-life points created earlier
ax.scatter(times, concentrations, color='red', s=60, zorder=2,
           label='Half-life points')

# creating a grid with suitable spacing to make the plot easier to read
loc = lambda x: plticker.MultipleLocator(base=x)
ax.xaxis.set_major_locator(loc(50))
ax.yaxis.set_major_locator(loc(0.25))
ax.yaxis.set_minor_locator(loc(0.125))
ax.grid(b=True, axis='both', which='major',
        linestyle='--', linewidth=1.5)
ax.grid(b=True, which='minor', axis='both', linestyle=':', linewidth=1.0)
ax.set_axisbelow(True)

# properly labeling the plot and its components
ax.set_xlabel('Time / min')
ax.set_ylabel('Concentration / $mol \cdot L^{-1}$')
fig.suptitle('Sucrose inversion')
plt.legend()
plt.show()

png

Follow each red point on the resulting plot. Note that, every 100 min (our half-life in the problem), the concentration drops to half of the value it had before those 100 min had passed. Use the grid lines to make it easier to read. Any 100 min interval could be used; for convenience, we started from the value at 0 min.

As said earlier, the most common example of first-order kinetics is radioactive decay; we see in the plot the reason why this decay is usually called exponential.

So, what is sucrose inversion?
#

To finish, let’s understand what this hydrolysis is and why the enzyme can be called invertase. Yes, it is an enzyme because the ending is “ase” and enzymes are catalysts. Remember the keywords I showed at the beginning as being important in kinetics? There it is, catalysts…

Whenever you study a reaction, write its equation with the structures. Always. No exceptions.

What would you do, then? Well, you would probably google the names of the substances, look at the structures, and copy them to build the equation. Or you would spend your hard-earned money buying programs to draw chemical structures. But time is pressing and laziness reigns. Life would be easier if we could enter the names of the substances and the computer would build the equation. And that is what we will do.

The article would get too long and dense if I detailed how chemistry packages work internally to give the computer all the information present in a chemical structure in order to draw it. If organic chemistry classes have already traumatized you with the naming rules, imagine encoding those names. I will explain briefly, but if you want an article just about that, leave it in the comments of the article or on social media.

In simplified terms, there is a naming specification called SMILES that incorporates in a string all the information needed to reproduce a given chemical structure. And, fortunately, there are huge online databases, such as PubChem, from which such SMILES can be extracted for millions of chemical compounds. The pubchempy package lets us search PubChem programmatically.

So, let’s search for the names of the substances and store each SMILES in a list. The statement says that sucrose is transformed into fructose and glucose. But, of course, the names must be in English for the search to work. Here is the code:

import pubchempy
names = ('sucrose', 'water', 'fructose', 'glucose')
smiles = []

for name in names:
    smiles.append(pubchempy.get_compounds(name,'name')[0].isomeric_smiles)
smiles
['C([C@@H]1[C@H]([C@@H]([C@H]([C@H](O1)O[C@]2([C@H]([C@@H]([C@H](O2)CO)O)O)CO)O)O)O)O',
 'O',
 'C1[C@H]([C@H]([C@@H](C(O1)(CO)O)O)O)O',
 'C([C@@H]1[C@H]([C@@H]([C@H](C(O1)O)O)O)O)O']

Believe it or not, this tangle of symbols is all the information needed to (re)build each structure.

Now, we need a package that can understand these SMILES and turn them into pictures of the structures in the form of an equation. This is where RDKit comes in:

from rdkit.Chem import AllChem
from rdkit.Chem.Draw import IPythonConsole
IPythonConsole.ipython_useSVG=True
IPythonConsole.molSize = 550,200

reaction = AllChem.ReactionFromSmarts(f'{smiles[0]}.{smiles[1]}>>{smiles[2]}.{smiles[3]}', 
                                      useSmiles=True)
reaction

svg

Here is our reaction equation, practically effortlessly.

Translating the statement (with some simplifications of language): it is a hydrolysis because a chemical bond is broken in the presence of water (from the Greek: hydro: water, lysis: breaking). Sucrose is a sugar in everyday language. The more formal name of the class of compounds that sugars belong to is carbohydrates, compounds made of carbon, hydrogen, and oxygen, also called saccharides. Look at the structure of sucrose and see that there are two rings joined by bonds involving an oxygen atom. Each of the linked groups is a monosaccharide. Therefore, sucrose is a disaccharide (two linked monosaccharides). I hope this helped to decipher the statement. Consult your nearest chemistry teacher for more details and more rigorous language.

Why is the enzyme called invertase? If you have studied organic chemistry, you should remember that there is the concept of chirality and should recognize that in the structures shown there are several chiral centers on carbon atoms. When a beam of polarized light, a concept seen in physics, passes through a solution containing chiral species, the polarization angle can change. See the following figure:

polarimeter
Working principle of a polarimeter. 1. Light source; 2. Unpolarized light; 3. Polarizer; 4. Polarized light; 5. Sample solution; 6. Rotation of light due to chiral molecules; 7. Rotating analyzer; 8. Detector. Source: Wikipedia

In the case of the problem, when there is a solution with only sucrose, the polarized light is deflected in one direction. However, as sucrose turns into the mixture of fructose and glucose, the deflection angle decreases because the direction of the deflection changes. Hence the idea of inversion, which refers to the change in the direction of the polarized light. Again, I simplified the language quite a bit to make the text more accessible; consult your nearest physics or chemistry teacher for more details and more rigorous language.

Conclusion
#

Impressive how much information can be extracted from a statement, right? The problem itself is simple but, each time you question something, new knowledge is gained.

So, did you learn more Python or more chemistry? For more ENEM problems solved with Python click here.

Share this article with students and with anyone else you like.

See you next time!

Related

ENEM: The Killer Brick Problem

Is it possible to study for the college entrance exam and still learn Python? Of course! And that is one of the goals of the Brazilian Exam Problems category on this site. In it, we use computational tools to analyze and expand problems from the ENEM, Brazil’s national high school exam. In today’s article, we analyze a problem from the 2019 exam. And, along the way, we learn to make 3D and 4D(?!) plots with Matplotlib. All because of a killer brick.

Plots with SymPy and Matplotlib

·3611 words·18 mins
In this article we will see how to make plots with SymPy and Matplotlib. When people talk about SymPy, we usually focus on solving mathematical problems. But many forget that the library has some basic features for building plots, which we will see in this article.