Hey I want each and every formulea of atomic structure class 11 chemistry. No exceptions,if possible pdf form
mkdir -p /home/daytona/workspace/atomic-structure && ls /home/daytona/workspace/
~/atomic-structure/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.pdfbase import pdfmetrics
OUTPUT = "/home/daytona/workspace/atomic-structure/Atomic_Structure_Formulas_Class11.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=1.8*cm,
leftMargin=1.8*cm,
topMargin=2*cm,
bottomMargin=2*cm
)
styles = getSampleStyleSheet()
# Custom styles
title_style = ParagraphStyle(
"TitleStyle",
parent=styles["Title"],
fontSize=22,
textColor=colors.HexColor("#1a237e"),
spaceAfter=6,
alignment=TA_CENTER,
fontName="Helvetica-Bold"
)
subtitle_style = ParagraphStyle(
"SubtitleStyle",
parent=styles["Normal"],
fontSize=11,
textColor=colors.HexColor("#37474f"),
spaceAfter=14,
alignment=TA_CENTER,
fontName="Helvetica"
)
section_style = ParagraphStyle(
"SectionStyle",
parent=styles["Heading2"],
fontSize=13,
textColor=colors.white,
spaceBefore=14,
spaceAfter=6,
fontName="Helvetica-Bold",
backColor=colors.HexColor("#1565c0"),
leftIndent=-4,
rightIndent=-4,
borderPad=5,
leading=18
)
formula_name_style = ParagraphStyle(
"FormulaName",
parent=styles["Normal"],
fontSize=10,
textColor=colors.HexColor("#1a237e"),
fontName="Helvetica-Bold",
spaceAfter=2
)
formula_style = ParagraphStyle(
"FormulaStyle",
parent=styles["Normal"],
fontSize=11,
textColor=colors.HexColor("#b71c1c"),
fontName="Helvetica-Bold",
spaceAfter=2,
leftIndent=10
)
note_style = ParagraphStyle(
"NoteStyle",
parent=styles["Normal"],
fontSize=9,
textColor=colors.HexColor("#546e7a"),
fontName="Helvetica-Oblique",
spaceAfter=6,
leftIndent=10
)
body_style = ParagraphStyle(
"BodyStyle",
parent=styles["Normal"],
fontSize=10,
textColor=colors.HexColor("#212121"),
fontName="Helvetica",
spaceAfter=4
)
# ─── Data ───────────────────────────────────────────────────────────────────
sections = [
{
"title": "1. Subatomic Particles",
"formulas": [
{
"name": "Number of Protons (Atomic Number)",
"formula": "Z = Number of protons in nucleus",
"note": "Z also equals number of electrons in a neutral atom."
},
{
"name": "Mass Number",
"formula": "A = Z + N",
"note": "A = mass number, Z = atomic number (protons), N = number of neutrons"
},
{
"name": "Number of Neutrons",
"formula": "N = A - Z",
"note": ""
},
{
"name": "Charge of Electron",
"formula": "e = -1.602 x 10^-19 C",
"note": ""
},
{
"name": "Mass of Electron",
"formula": "m_e = 9.109 x 10^-31 kg",
"note": ""
},
{
"name": "Mass of Proton",
"formula": "m_p = 1.673 x 10^-27 kg",
"note": ""
},
{
"name": "Mass of Neutron",
"formula": "m_n = 1.675 x 10^-27 kg",
"note": ""
},
]
},
{
"title": "2. Electromagnetic Radiation",
"formulas": [
{
"name": "Speed of Light (Wave equation)",
"formula": "c = nu x lambda",
"note": "c = 3 x 10^8 m/s (speed of light), nu = frequency (Hz), lambda = wavelength (m)"
},
{
"name": "Wavenumber",
"formula": "nu_bar = 1 / lambda",
"note": "nu_bar = wavenumber (m^-1 or cm^-1), lambda = wavelength"
},
{
"name": "Frequency from Wavenumber",
"formula": "nu = c x nu_bar",
"note": ""
},
]
},
{
"title": "3. Planck's Quantum Theory",
"formulas": [
{
"name": "Energy of a Photon",
"formula": "E = h * nu",
"note": "h = Planck's constant = 6.626 x 10^-34 J.s, nu = frequency"
},
{
"name": "Energy in terms of wavelength",
"formula": "E = hc / lambda",
"note": ""
},
{
"name": "Energy in terms of wavenumber",
"formula": "E = hc * nu_bar",
"note": ""
},
{
"name": "Total energy of n quanta",
"formula": "E = n * h * nu",
"note": "n = positive integer (number of photons/quanta)"
},
]
},
{
"title": "4. Photoelectric Effect (Einstein)",
"formulas": [
{
"name": "Photoelectric Equation",
"formula": "h*nu = h*nu_0 + (1/2)*m*v^2",
"note": "nu_0 = threshold frequency, m = mass of electron, v = velocity of ejected electron"
},
{
"name": "Work Function (W)",
"formula": "W = h * nu_0",
"note": "Minimum energy needed to eject an electron from the metal surface"
},
{
"name": "Kinetic Energy of Ejected Electron",
"formula": "KE = (1/2)*m*v^2 = h*(nu - nu_0)",
"note": ""
},
]
},
{
"title": "5. Bohr's Atomic Model",
"formulas": [
{
"name": "Radius of nth Orbit",
"formula": "r_n = 0.529 * n^2 / Z Angstrom",
"note": "n = principal quantum number, Z = atomic number; valid for hydrogen-like atoms"
},
{
"name": "Radius (in SI units)",
"formula": "r_n = (n^2 * a_0) / Z where a_0 = 0.529 x 10^-10 m",
"note": "a_0 = Bohr radius"
},
{
"name": "Velocity of Electron in nth Orbit",
"formula": "v_n = 2.18 x 10^6 * Z / n m/s",
"note": ""
},
{
"name": "Total Energy of Electron in nth Orbit",
"formula": "E_n = -13.6 * Z^2 / n^2 eV",
"note": "Negative sign indicates bound state (electron is attracted to nucleus)"
},
{
"name": "Total Energy (in Joules)",
"formula": "E_n = -2.18 x 10^-18 * Z^2 / n^2 J",
"note": ""
},
{
"name": "Kinetic Energy of Electron",
"formula": "KE = +2.18 x 10^-18 * Z^2 / n^2 J = -E_n",
"note": "KE = |E_n| (magnitude of total energy)"
},
{
"name": "Potential Energy of Electron",
"formula": "PE = 2 * E_n = -4.36 x 10^-18 * Z^2 / n^2 J",
"note": ""
},
{
"name": "Angular Momentum (Bohr's Quantization)",
"formula": "mvr = n * h / (2*pi) = n * (h-bar)",
"note": "h-bar = h/(2*pi) = 1.055 x 10^-34 J.s; n = 1, 2, 3, ..."
},
{
"name": "Frequency of Revolution in nth Orbit",
"formula": "f_n = v_n / (2*pi*r_n)",
"note": ""
},
{
"name": "Time Period of Revolution",
"formula": "T_n = 2*pi*r_n / v_n",
"note": "T_n is proportional to n^3 / Z^2"
},
{
"name": "Number of Revolutions per Second",
"formula": "Revolutions/sec = v_n / (2*pi*r_n) = 6.65 x 10^15 * Z^2 / n^3",
"note": ""
},
]
},
{
"title": "6. Spectral Lines (Hydrogen Spectrum)",
"formulas": [
{
"name": "Rydberg Formula (Wavenumber)",
"formula": "nu_bar = R_H * Z^2 * (1/n1^2 - 1/n2^2)",
"note": "R_H = Rydberg constant = 1.097 x 10^7 m^-1; n2 > n1"
},
{
"name": "Energy of Emitted Photon",
"formula": "Delta_E = E_n2 - E_n1 = h*nu = hc/lambda",
"note": "Positive when electron moves from higher to lower orbit (emission)"
},
{
"name": "Lyman Series",
"formula": "n1 = 1, n2 = 2, 3, 4, ... (UV region)",
"note": ""
},
{
"name": "Balmer Series",
"formula": "n1 = 2, n2 = 3, 4, 5, ... (Visible region)",
"note": ""
},
{
"name": "Paschen Series",
"formula": "n1 = 3, n2 = 4, 5, 6, ... (IR region)",
"note": ""
},
{
"name": "Brackett Series",
"formula": "n1 = 4, n2 = 5, 6, 7, ... (IR region)",
"note": ""
},
{
"name": "Pfund Series",
"formula": "n1 = 5, n2 = 6, 7, 8, ... (Far IR region)",
"note": ""
},
{
"name": "Maximum Number of Spectral Lines",
"formula": "Lines = n*(n-1) / 2",
"note": "When electron falls from nth orbit to ground state; n = higher orbit number"
},
]
},
{
"title": "7. de Broglie's Wave-Particle Duality",
"formulas": [
{
"name": "de Broglie Wavelength",
"formula": "lambda = h / (m*v) = h / p",
"note": "m = mass, v = velocity, p = momentum"
},
{
"name": "de Broglie Wavelength (KE form)",
"formula": "lambda = h / sqrt(2*m*KE)",
"note": "KE = kinetic energy = (1/2)*m*v^2"
},
{
"name": "de Broglie Wavelength (Voltage form)",
"formula": "lambda = h / sqrt(2*m*e*V)",
"note": "V = accelerating voltage, e = charge of electron"
},
{
"name": "de Broglie Wavelength for Electron",
"formula": "lambda = 0.328 / sqrt(V) nm (approx.)",
"note": "Valid when electron is accelerated through potential V (in volts)"
},
]
},
{
"title": "8. Heisenberg's Uncertainty Principle",
"formulas": [
{
"name": "Position-Momentum Uncertainty",
"formula": "Delta_x * Delta_p >= h / (4*pi)",
"note": "Delta_x = uncertainty in position, Delta_p = uncertainty in momentum"
},
{
"name": "Expanded form",
"formula": "Delta_x * m * Delta_v >= h / (4*pi)",
"note": "Delta_v = uncertainty in velocity"
},
{
"name": "Energy-Time Uncertainty",
"formula": "Delta_E * Delta_t >= h / (4*pi)",
"note": ""
},
{
"name": "Minimum Uncertainty Product",
"formula": "Delta_x * Delta_p = h-bar / 2 = h / (4*pi) (minimum)",
"note": "h-bar = h/(2*pi)"
},
]
},
{
"title": "9. Quantum Numbers",
"formulas": [
{
"name": "Principal Quantum Number (n)",
"formula": "n = 1, 2, 3, 4, ... (K, L, M, N shells)",
"note": "Determines shell and size of orbital; max electrons = 2n^2"
},
{
"name": "Maximum Electrons in nth Shell",
"formula": "Max electrons = 2 * n^2",
"note": ""
},
{
"name": "Azimuthal (Angular Momentum) Quantum Number (l)",
"formula": "l = 0, 1, 2, ..., (n-1)",
"note": "l=0 -> s, l=1 -> p, l=2 -> d, l=3 -> f"
},
{
"name": "Magnetic Quantum Number (m_l)",
"formula": "m_l = -l, ..., 0, ..., +l (total 2l+1 values)",
"note": "Gives orientation of orbital in space"
},
{
"name": "Number of Orbitals in a Subshell",
"formula": "Orbitals = 2l + 1",
"note": ""
},
{
"name": "Number of Orbitals in nth Shell",
"formula": "Total orbitals = n^2",
"note": ""
},
{
"name": "Spin Quantum Number (m_s)",
"formula": "m_s = +1/2 or -1/2",
"note": "+1/2 = spin up (alpha), -1/2 = spin down (beta)"
},
{
"name": "Orbital Angular Momentum",
"formula": "L = sqrt(l*(l+1)) * h-bar = sqrt(l*(l+1)) * h/(2*pi)",
"note": ""
},
{
"name": "Spin Angular Momentum",
"formula": "S = sqrt(s*(s+1)) * h-bar where s = 1/2",
"note": "S = (sqrt(3)/2) * h-bar"
},
]
},
{
"title": "10. Electronic Configuration Rules",
"formulas": [
{
"name": "Aufbau Principle - Orbital Energy Order",
"formula": "1s < 2s < 2p < 3s < 3p < 4s < 3d < 4p < 5s < 4d < 5p < 6s < 4f < 5d ...",
"note": "Electrons fill lower energy orbitals first"
},
{
"name": "Pauli Exclusion Principle",
"formula": "No two electrons in an atom can have all four quantum numbers identical",
"note": "Max 2 electrons per orbital (with opposite spins)"
},
{
"name": "Hund's Rule of Maximum Multiplicity",
"formula": "Electrons occupy degenerate orbitals singly before pairing",
"note": "Singly occupied orbitals have parallel spins"
},
{
"name": "(n + l) Rule (Madelung's Rule)",
"formula": "Orbital with lower (n + l) fills first; if equal, lower n fills first",
"note": "e.g., 4s (n+l=4) fills before 3d (n+l=5)"
},
]
},
{
"title": "11. Important Constants",
"formulas": [
{
"name": "Planck's Constant",
"formula": "h = 6.626 x 10^-34 J.s",
"note": ""
},
{
"name": "Speed of Light",
"formula": "c = 3 x 10^8 m/s",
"note": ""
},
{
"name": "Rydberg Constant",
"formula": "R_H = 1.097 x 10^7 m^-1 = 109677 cm^-1",
"note": ""
},
{
"name": "Avogadro's Number",
"formula": "N_A = 6.022 x 10^23 mol^-1",
"note": ""
},
{
"name": "Bohr Radius",
"formula": "a_0 = 0.529 x 10^-10 m = 0.529 Angstrom",
"note": ""
},
{
"name": "1 eV",
"formula": "1 eV = 1.602 x 10^-19 J",
"note": ""
},
{
"name": "1 Angstrom",
"formula": "1 A = 10^-10 m = 10^-8 cm",
"note": ""
},
]
},
{
"title": "12. Additional / Derived Formulas",
"formulas": [
{
"name": "Ionisation Energy from Bohr's Model",
"formula": "IE = 13.6 * Z^2 / n^2 eV",
"note": "For H atom (Z=1, n=1): IE = 13.6 eV"
},
{
"name": "Excitation Energy",
"formula": "E_excitation = E_n2 - E_n1",
"note": "Energy required to move electron from n1 to n2 (n2 > n1)"
},
{
"name": "Wavelength of Emitted Radiation",
"formula": "1/lambda = R_H * Z^2 * (1/n1^2 - 1/n2^2)",
"note": ""
},
{
"name": "Moles of Photons",
"formula": "E_molar = N_A * h * nu",
"note": "Total energy per mole of photons"
},
{
"name": "Number Density (Electrons per Shell)",
"formula": "Electrons in subshell = 2*(2l+1)",
"note": "s: 2, p: 6, d: 10, f: 14"
},
{
"name": "Current due to revolving electron",
"formula": "I = e * v_n / (2*pi*r_n)",
"note": "e = charge of electron, v_n = velocity, r_n = radius of nth orbit"
},
{
"name": "Magnetic Moment of Electron",
"formula": "mu = n_BM * (e*h)/(4*pi*m) = sqrt(n*(n+2)) Bohr Magneton",
"note": "n = number of unpaired electrons; 1 BM = 9.274 x 10^-24 J/T"
},
]
}
]
# ─── Build flowable elements ─────────────────────────────────────────────────
elements = []
# Cover heading
elements.append(Spacer(1, 0.3*cm))
elements.append(Paragraph("ATOMIC STRUCTURE", title_style))
elements.append(Paragraph("Complete Formula Sheet | Class 11 Chemistry | NCERT + JEE / NEET", subtitle_style))
elements.append(HRFlowable(width="100%", thickness=2, color=colors.HexColor("#1565c0")))
elements.append(Spacer(1, 0.4*cm))
total = sum(len(s["formulas"]) for s in sections)
elements.append(Paragraph(
f"<b>Total Formulas Covered: {total}</b> Topics: {len(sections)}",
body_style
))
elements.append(Spacer(1, 0.3*cm))
for sec in sections:
# Section header
elements.append(Spacer(1, 0.2*cm))
# Colored section banner using a single-cell table
sec_table = Table([[Paragraph(f" {sec['title']}", ParagraphStyle(
"sh", parent=styles["Normal"], fontSize=12,
textColor=colors.white, fontName="Helvetica-Bold", leading=16
))]], colWidths=[doc.width])
sec_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#1565c0")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
elements.append(sec_table)
elements.append(Spacer(1, 0.15*cm))
for i, f in enumerate(sec["formulas"]):
bg = colors.HexColor("#e8eaf6") if i % 2 == 0 else colors.HexColor("#f3f4ff")
name_para = Paragraph(f["name"], formula_name_style)
formula_para = Paragraph(f["formula"], formula_style)
cell_content = [name_para, formula_para]
if f["note"]:
cell_content.append(Paragraph(f"Note: {f['note']}", note_style))
row_table = Table([[cell_content]], colWidths=[doc.width])
row_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.5, colors.HexColor("#c5cae9")),
]))
elements.append(KeepTogether(row_table))
elements.append(Spacer(1, 0.05*cm))
elements.append(Spacer(1, 0.2*cm))
# Footer note
elements.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#1565c0")))
elements.append(Spacer(1, 0.2*cm))
elements.append(Paragraph(
"Prepared for Class 11 Chemistry | Covers NCERT, JEE Main, JEE Advanced & NEET syllabus",
subtitle_style
))
# ─── Build PDF ───────────────────────────────────────────────────────────────
doc.build(elements)
print(f"PDF generated: {OUTPUT}")
python3 /home/daytona/workspace/atomic-structure/generate_pdf.py
ls -lh /home/daytona/workspace/atomic-structure/Atomic_Structure_Formulas_Class11.pdf
Atomic Structure Formulas Class11
PDF Document · PDF
| Constant | Value |
|---|---|
| h (Planck) | 6.626 × 10⁻³⁴ J·s |
| c | 3 × 10⁸ m/s |
| R_H | 1.097 × 10⁷ m⁻¹ |
| N_A | 6.022 × 10²³ mol⁻¹ |
| a₀ (Bohr radius) | 0.529 Å |
| 1 eV | 1.602 × 10⁻¹⁹ J |
Hey actually in the pdf the formulas are not in a way to read them so if they are in fraction form let them be and also now add the important points and and values in it like for the revision
python3 -c "import matplotlib; import matplotlib.mathtext; print('matplotlib ok', matplotlib.__version__)"
~/atomic-structure/generate_pdf_v2.py
"""
Atomic Structure – Class 11 Chemistry
Complete Formula + Revision PDF (v2)
Formulas rendered as proper typeset images via matplotlib mathtext.
"""
import os, io, textwrap
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib import rcParams
rcParams["mathtext.fontset"] = "cm" # Computer Modern (LaTeX-like)
rcParams["font.family"] = "serif"
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
W, H = A4
LMARGIN = 1.8*cm
RMARGIN = 1.8*cm
CONTENT_W = W - LMARGIN - RMARGIN
OUTPUT = "/home/daytona/workspace/atomic-structure/Atomic_Structure_Formulas_Class11_v2.pdf"
# ── colour palette ────────────────────────────────────────────────────────────
C_DARK = colors.HexColor("#0d1b5e") # deep navy
C_MED = colors.HexColor("#1565c0") # medium blue (section headers)
C_LIGHT = colors.HexColor("#e8eaf6") # lavender row
C_ALT = colors.HexColor("#f0f4ff") # alternate row
C_POINT = colors.HexColor("#1b5e20") # dark green for key-points
C_PTBG = colors.HexColor("#e8f5e9") # key-point background
C_WARNBG = colors.HexColor("#fff8e1") # amber warning / tip background
C_WARN = colors.HexColor("#e65100") # orange
C_RED = colors.HexColor("#b71c1c") # formula text
C_GREY = colors.HexColor("#37474f")
# ── styles ────────────────────────────────────────────────────────────────────
SS = getSampleStyleSheet()
def ps(name, **kw):
p = ParagraphStyle(name, parent=SS["Normal"], **kw)
return p
title_s = ps("T", fontSize=24, textColor=C_DARK, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=4)
sub_s = ps("S", fontSize=10, textColor=C_GREY, fontName="Helvetica",
alignment=TA_CENTER, spaceAfter=12)
fname_s = ps("FN", fontSize=10, textColor=C_DARK, fontName="Helvetica-Bold",
spaceAfter=1, leftIndent=4)
note_s = ps("NO", fontSize=8.5, textColor=C_GREY, fontName="Helvetica-Oblique",
spaceAfter=2, leftIndent=4)
kp_head_s = ps("KH", fontSize=10, textColor=C_POINT, fontName="Helvetica-Bold",
spaceAfter=2)
kp_s = ps("KP", fontSize=9, textColor=colors.HexColor("#1b5e20"),
fontName="Helvetica", spaceAfter=1, leftIndent=8)
tip_s = ps("TIP", fontSize=9, textColor=C_WARN, fontName="Helvetica-Bold",
spaceAfter=0)
body_s = ps("BD", fontSize=10, fontName="Helvetica",
textColor=colors.HexColor("#212121"), spaceAfter=3)
# ── helpers ───────────────────────────────────────────────────────────────────
def render_formula(latex_str, font_size=14, dpi=180):
"""Return a ReportLab Image of a typeset math formula."""
fig = plt.figure(figsize=(0.01, 0.01))
try:
t = fig.text(0, 0, f"${latex_str}$", fontsize=font_size,
color="#b71c1c", ha="left", va="bottom")
fig.canvas.draw()
bb = t.get_window_extent(renderer=fig.canvas.get_renderer())
pad = 6
fig_w = (bb.width + pad*2) / dpi
fig_h = (bb.height + pad*2) / dpi
plt.close(fig)
fig2, ax = plt.subplots(figsize=(max(fig_w, 0.5), max(fig_h, 0.3)))
ax.set_axis_off()
fig2.patch.set_alpha(0)
fig2.text(pad/dpi/max(fig_w,0.5), pad/dpi/max(fig_h,0.3),
f"${latex_str}$", fontsize=font_size,
color="#b71c1c", ha="left", va="bottom", transform=fig2.transFigure)
buf = io.BytesIO()
fig2.savefig(buf, format="png", dpi=dpi, transparent=True,
bbox_inches="tight", pad_inches=0.04)
plt.close(fig2)
buf.seek(0)
# calc display size (cap at content width)
img_w_pt = fig_w * 72
img_h_pt = fig_h * 72
scale = min(1.0, (CONTENT_W - 16) / img_w_pt)
return RLImage(buf, width=img_w_pt*scale, height=img_h_pt*scale)
except Exception as e:
plt.close("all")
return Paragraph(f"<font color='red'>[formula error: {e}]</font>", note_s)
def section_banner(title):
p = Paragraph(f" {title}",
ps("SB", fontSize=12, textColor=colors.white,
fontName="Helvetica-Bold", leading=16))
t = Table([[p]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_MED),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
return t
def formula_row(name, latex, note="", idx=0):
bg = C_LIGHT if idx % 2 == 0 else C_ALT
img = render_formula(latex)
cell = [Paragraph(name, fname_s), img]
if note:
cell.append(Paragraph(f"▸ {note}", note_s))
t = Table([[cell]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("BOX", (0,0), (-1,-1), 0.4, colors.HexColor("#c5cae9")),
]))
return KeepTogether(t)
def key_points_box(points, tip=None):
"""Green box with bullet key-points and optional amber tip."""
content = [Paragraph("★ Key Points / Quick Revision", kp_head_s)]
for pt in points:
content.append(Paragraph(f"• {pt}", kp_s))
if tip:
content.append(Spacer(1, 3))
content.append(Paragraph(f"💡 Tip: {tip}", tip_s))
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_PTBG),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("BOX", (0,0), (-1,-1), 0.8, C_POINT),
]))
return KeepTogether(t)
def values_table(rows):
"""Compact 2-col table: Quantity | Value."""
header = [Paragraph("<b>Quantity</b>", ps("VH", fontSize=9, fontName="Helvetica-Bold", textColor=colors.white)),
Paragraph("<b>Value</b>", ps("VH2", fontSize=9, fontName="Helvetica-Bold", textColor=colors.white))]
data = [header]
for q, v in rows:
data.append([Paragraph(q, ps("VC", fontSize=9, fontName="Helvetica")),
Paragraph(v, ps("VV", fontSize=9, fontName="Helvetica-Bold", textColor=C_RED))])
t = Table(data, colWidths=[CONTENT_W*0.52, CONTENT_W*0.48])
style = [
("BACKGROUND", (0,0), (-1,0), C_MED),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LIGHT, C_ALT]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#b0bec5")),
("BOX", (0,0), (-1,-1), 0.6, C_MED),
]
t.setStyle(TableStyle(style))
return t
# ═══════════════════════════════════════════════════════════════════════════════
# CONTENT DATA
# ═══════════════════════════════════════════════════════════════════════════════
sections = [
# ── 1 ──────────────────────────────────────────────────────────────────────
{
"title": "1. Subatomic Particles",
"formulas": [
("Atomic Number (Z)",
r"Z = \text{No. of protons} = \text{No. of electrons (neutral atom)}",
""),
("Mass Number (A)",
r"A = Z + N",
"N = number of neutrons"),
("Number of Neutrons",
r"N = A - Z",
""),
("Charge of Electron",
r"e^{-} = -1.602 \times 10^{-19} \text{ C}",
""),
("Mass of Electron",
r"m_e = 9.109 \times 10^{-31} \text{ kg}",
""),
("Mass of Proton",
r"m_p = 1.673 \times 10^{-27} \text{ kg}",
""),
("Mass of Neutron",
r"m_n = 1.675 \times 10^{-27} \text{ kg}",
""),
],
"key_points": [
"Isotopes: same Z, different A (e.g., ¹H, ²H, ³H)",
"Isobars: same A, different Z (e.g., ⁴⁰Ar and ⁴⁰Ca)",
"Isotones: same N, different Z",
"Isoelectronic species: same number of electrons (e.g., N³⁻, O²⁻, F⁻, Ne)",
"Proton and neutron masses are ~1836× and ~1839× the electron mass respectively",
"Cathode rays proved existence of electrons (J.J. Thomson, 1897)",
"Gold foil experiment (Rutherford, 1911) proved nucleus is small, dense, positive",
"e/m ratio of electron = 1.758 × 10¹¹ C/kg",
],
"tip": "For any neutral atom: protons = electrons. For ions: electrons = Z ± charge.",
"values": None,
},
# ── 2 ──────────────────────────────────────────────────────────────────────
{
"title": "2. Electromagnetic Radiation",
"formulas": [
("Wave Equation",
r"c = \nu \times \lambda",
"c = speed of light (3×10⁸ m/s), ν = frequency (Hz), λ = wavelength (m)"),
("Wavenumber",
r"\bar{\nu} = \frac{1}{\lambda}",
"Unit: m⁻¹ or cm⁻¹"),
("Frequency from wavenumber",
r"\nu = c \cdot \bar{\nu}",
""),
],
"key_points": [
"EM spectrum (increasing wavelength): γ-rays < X-rays < UV < Visible < IR < Microwaves < Radio",
"Visible light: 400 nm (violet) to 700 nm (red)",
"VIBGYOR: Violet(~400nm), Indigo, Blue, Green, Yellow, Orange, Red(~700nm)",
"Frequency and wavelength are inversely proportional",
"All EM radiation travels at c = 3×10⁸ m/s in vacuum",
],
"tip": "Higher frequency = higher energy = shorter wavelength. γ-rays are most energetic.",
"values": [
("Speed of light (c)", "3 × 10⁸ m/s"),
("Visible range", "400 – 700 nm"),
("UV range", "10 – 400 nm"),
("IR range", "700 nm – 1 mm"),
],
},
# ── 3 ──────────────────────────────────────────────────────────────────────
{
"title": "3. Planck's Quantum Theory",
"formulas": [
("Energy of one photon",
r"E = h\nu",
"h = 6.626×10⁻³⁴ J·s"),
("Energy in terms of wavelength",
r"E = \frac{hc}{\lambda}",
""),
("Energy in terms of wavenumber",
r"E = hc\bar{\nu}",
""),
("Energy of n quanta",
r"E = nh\nu",
"n = number of photons (positive integer)"),
],
"key_points": [
"Energy is quantised – emitted/absorbed in discrete packets called quanta (photons)",
"Higher frequency ⟹ more energetic photons",
"1 eV = 1.602×10⁻¹⁹ J",
"Energy of photon in eV: E = hc/λ (use λ in metres); divide by 1.6×10⁻¹⁹",
"Planck's constant h = 6.626×10⁻³⁴ J·s",
"Black body radiation and photoelectric effect could NOT be explained by classical wave theory – Planck's theory solved it",
],
"tip": "To convert nm to m: multiply by 10⁻⁹. To find E in eV: E(J) / 1.6×10⁻¹⁹.",
"values": [
("Planck's constant (h)", "6.626 × 10⁻³⁴ J·s"),
("1 eV", "1.602 × 10⁻¹⁹ J"),
("1 nm", "10⁻⁹ m"),
("1 Å (Angstrom)", "10⁻¹⁰ m"),
],
},
# ── 4 ──────────────────────────────────────────────────────────────────────
{
"title": "4. Photoelectric Effect",
"formulas": [
("Einstein's Photoelectric Equation",
r"h\nu = h\nu_0 + \frac{1}{2}mv^2",
"ν₀ = threshold frequency, v = velocity of ejected electron"),
("Work Function (Φ)",
r"\Phi = h\nu_0",
"Minimum energy to eject electron from surface"),
("Kinetic Energy of ejected electron",
r"KE = \frac{1}{2}mv^2 = h(\nu - \nu_0)",
"Only possible when ν > ν₀"),
("Threshold wavelength",
r"\lambda_0 = \frac{hc}{\Phi} = \frac{c}{\nu_0}",
"Longest wavelength that can cause photoelectric effect"),
],
"key_points": [
"Photoelectric effect: emission of electrons when light hits a metal surface",
"Effect depends on FREQUENCY, not intensity of light",
"No electrons emitted if ν < ν₀ (regardless of intensity)",
"Increasing intensity increases number of electrons, NOT their KE",
"Increasing frequency increases KE of electrons",
"Stopping potential (V₀): eV₀ = ½mv²_max",
"Different metals have different work functions (threshold frequencies)",
"Proved particle nature of light (Einstein, 1905 – Nobel Prize 1921)",
],
"tip": "Work function in eV = hν₀ / 1.6×10⁻¹⁹. If ν < ν₀, no photoelectric effect.",
"values": None,
},
# ── 5 ──────────────────────────────────────────────────────────────────────
{
"title": "5. Bohr's Atomic Model",
"formulas": [
("Radius of nth orbit",
r"r_n = \frac{0.529\, n^2}{Z} \text{ Å}",
"For H (Z=1): r₁ = 0.529 Å, r₂ = 2.116 Å, r₃ = 4.761 Å"),
("Velocity of electron in nth orbit",
r"v_n = \frac{2.18 \times 10^6\, Z}{n} \text{ m/s}",
""),
("Total Energy of electron",
r"E_n = -\frac{13.6\, Z^2}{n^2} \text{ eV}",
"Negative sign = bound state (electron held by nucleus)"),
("Total Energy (in Joules)",
r"E_n = -\frac{2.18 \times 10^{-18}\, Z^2}{n^2} \text{ J}",
""),
("Kinetic Energy",
r"KE = -E_n = +\frac{13.6\, Z^2}{n^2} \text{ eV}",
"KE is always positive"),
("Potential Energy",
r"PE = 2E_n = -\frac{27.2\, Z^2}{n^2} \text{ eV}",
"PE is always negative (attractive force)"),
("Angular Momentum Quantisation",
r"L = mvr = \frac{nh}{2\pi} = n\hbar",
"ħ = h/2π = 1.055×10⁻³⁴ J·s; n = 1,2,3,..."),
("Time Period of revolution",
r"T_n = \frac{2\pi r_n}{v_n} \propto \frac{n^3}{Z^2}",
""),
("Frequency of revolution",
r"f_n = \frac{v_n}{2\pi r_n} = \frac{6.65\times10^{15}\,Z^2}{n^3} \text{ Hz}",
""),
("Bohr Radius (a₀)",
r"a_0 = 0.529 \text{ Å} = 0.529\times10^{-10} \text{ m}",
""),
],
"key_points": [
"Bohr's postulates: (1) electrons move in fixed circular orbits, (2) angular momentum is quantised, (3) electrons don't radiate while in orbit, (4) radiation emitted/absorbed when electron changes orbit",
"As n increases: radius increases (∝n²), energy increases (less negative), velocity decreases (∝1/n)",
"Ground state of H: n=1, E = -13.6 eV, r = 0.529 Å",
"Ionisation energy of H = 13.6 eV",
"For He⁺ (Z=2): E₁ = -54.4 eV; for Li²⁺ (Z=3): E₁ = -122.4 eV",
"Total energy = KE + PE = E_n; PE = 2E_n; KE = -E_n",
"rₙ ∝ n²/Z | vₙ ∝ Z/n | Eₙ ∝ Z²/n² | Tₙ ∝ n³/Z²",
"Bohr model FAILS for multi-electron atoms; doesn't explain fine/hyperfine structure",
],
"tip": "Remember: PE = 2E (total), KE = −E (total). For H at n=1: E=−13.6 eV, KE=+13.6 eV, PE=−27.2 eV.",
"values": [
("E₁ (H, n=1)", "−13.6 eV"),
("E₂ (H, n=2)", "−3.4 eV"),
("E₃ (H, n=3)", "−1.51 eV"),
("E₄ (H, n=4)", "−0.85 eV"),
("r₁ (H)", "0.529 Å"),
("r₂ (H)", "2.116 Å"),
("r₃ (H)", "4.761 Å"),
("v₁ (H)", "2.18×10⁶ m/s"),
("IE of H", "13.6 eV"),
],
},
# ── 6 ──────────────────────────────────────────────────────────────────────
{
"title": "6. Hydrogen Spectrum & Spectral Series",
"formulas": [
("Rydberg Formula (wavenumber)",
r"\bar{\nu} = R_H Z^2 \left(\frac{1}{n_1^2} - \frac{1}{n_2^2}\right)",
"n₂ > n₁; R_H = 1.097×10⁷ m⁻¹ = 109677 cm⁻¹"),
("Wavelength form",
r"\frac{1}{\lambda} = R_H Z^2 \left(\frac{1}{n_1^2} - \frac{1}{n_2^2}\right)",
""),
("Energy of emitted photon",
r"\Delta E = E_{n_2} - E_{n_1} = h\nu = \frac{hc}{\lambda}",
""),
("Maximum spectral lines (from nth orbit)",
r"\text{Lines} = \frac{n(n-1)}{2}",
"e.g., n=4 → 6 lines"),
("Lyman Series (UV)",
r"n_1=1,\; n_2=2,3,4,\ldots",
"Series limit: n₂=∞, λ_min = 912 Å"),
("Balmer Series (Visible)",
r"n_1=2,\; n_2=3,4,5,\ldots",
"First line (Hα): 656 nm (red), Series limit: 364.6 nm"),
("Paschen Series (Near IR)",
r"n_1=3,\; n_2=4,5,6,\ldots",
""),
("Brackett Series (IR)",
r"n_1=4,\; n_2=5,6,7,\ldots",
""),
("Pfund Series (Far IR)",
r"n_1=5,\; n_2=6,7,8,\ldots",
""),
],
"key_points": [
"Only Balmer series lies in visible region (n₁=2)",
"Lyman series (n₁=1) is in UV – highest energy transitions",
"Series limit = transition from n₂=∞ to n₁ (convergence limit)",
"First line of each series = smallest energy transition (n₂ = n₁+1)",
"Last line (series limit) of each series = largest energy transition (n₂ = ∞)",
"Balmer series first 4 lines: Hα(656nm), Hβ(486nm), Hγ(434nm), Hδ(410nm)",
"Rydberg constant R_H = 1.097×10⁷ m⁻¹",
"Number of lines from n=1 to N shell when electron falls to ground: N(N-1)/2",
],
"tip": "If electron falls from nth orbit to 1st: total lines = n(n−1)/2. Balmer visible: n₁=2, n₂=3,4,5,6.",
"values": [
("R_H (Rydberg constant)", "1.097×10⁷ m⁻¹"),
("R_H (in cm⁻¹)", "109677 cm⁻¹"),
("Hα (Balmer, n=3→2)", "656.3 nm (red)"),
("Hβ (Balmer, n=4→2)", "486.1 nm (blue-green)"),
("Balmer series limit", "364.6 nm"),
("Lyman series limit", "91.2 nm"),
("Paschen series limit", "820.4 nm"),
],
},
# ── 7 ──────────────────────────────────────────────────────────────────────
{
"title": "7. de Broglie's Wave-Particle Duality",
"formulas": [
("de Broglie Wavelength",
r"\lambda = \frac{h}{mv} = \frac{h}{p}",
"m = mass, v = velocity, p = momentum"),
("de Broglie (using KE)",
r"\lambda = \frac{h}{\sqrt{2m \cdot KE}}",
""),
("de Broglie (accelerated electron through voltage V)",
r"\lambda = \frac{h}{\sqrt{2meV}}",
"e = 1.6×10⁻¹⁹ C; for electron: λ ≈ 1.228/√V nm"),
("Bohr orbit condition via de Broglie",
r"2\pi r = n\lambda",
"Circumference = whole number of wavelengths"),
],
"key_points": [
"Proposed by Louis de Broglie (1924): matter has wave properties",
"Wave nature is significant only for very small particles (electrons, protons)",
"For macroscopic objects (e.g., cricket ball), λ is negligibly small – wave nature undetectable",
"Davisson-Germer experiment (1927) confirmed electron diffraction – proved wave nature",
"de Broglie's relation connects particle (p=mv) and wave (λ) properties",
"Heavier the particle or faster it moves → shorter wavelength",
"For electrons at n=1 in H: λ = 2πr₁ (one complete wavelength per orbit)",
],
"tip": "For electrons accelerated through V volts: λ (in nm) = 1.228/√V. For V=100V: λ ≈ 0.123 nm.",
"values": [
("λ for electron at 100V", "0.123 nm"),
("λ for electron at 10000V", "0.0123 nm"),
("de Broglie λ of H atom at 25°C", "~1 Å (order)"),
],
},
# ── 8 ──────────────────────────────────────────────────────────────────────
{
"title": "8. Heisenberg's Uncertainty Principle",
"formulas": [
("Position-Momentum Uncertainty",
r"\Delta x \cdot \Delta p \geq \frac{h}{4\pi}",
"Δx = uncertainty in position, Δp = uncertainty in momentum"),
("Position-Velocity Uncertainty",
r"\Delta x \cdot m\Delta v \geq \frac{h}{4\pi}",
""),
("Energy-Time Uncertainty",
r"\Delta E \cdot \Delta t \geq \frac{h}{4\pi}",
""),
("Compact form using ħ",
r"\Delta x \cdot \Delta p \geq \frac{\hbar}{2}, \quad \hbar = \frac{h}{2\pi}",
"ħ = 1.055×10⁻³⁴ J·s"),
],
"key_points": [
"Statement: It is impossible to simultaneously determine the exact position AND momentum of a microscopic particle",
"This is a FUNDAMENTAL limitation of nature, NOT a measurement error",
"More precisely we know position → less precisely we know velocity (and vice versa)",
"Why electrons can't be inside nucleus: if Δx ≈ 10⁻¹⁵ m (nuclear size), Δp is enormous → electron KE >> nuclear binding energy",
"Heisenberg uncertainty disproves Bohr's fixed circular orbits",
"h/4π = 0.527×10⁻³⁴ J·s (minimum product of uncertainties)",
"Concept leads to probability distribution (orbitals) instead of fixed paths",
],
"tip": "Δx·Δp ≥ h/4π. If Δx = 0 (exact position), Δp = ∞ (completely unknown momentum). This is why 'orbit' is replaced by 'orbital'.",
"values": [
("h/4π (min uncertainty)", "0.527 × 10⁻³⁴ J·s"),
("ħ = h/2π", "1.055 × 10⁻³⁴ J·s"),
],
},
# ── 9 ──────────────────────────────────────────────────────────────────────
{
"title": "9. Quantum Numbers",
"formulas": [
("Principal Quantum Number (n)",
r"n = 1,2,3,\ldots \quad \text{Max electrons} = 2n^2",
"Determines shell (K,L,M,N...) and size/energy of orbital"),
("Azimuthal Q.N. (l)",
r"l = 0,1,2,\ldots,(n-1) \quad \text{Orbitals} = 2l+1",
"l=0(s), l=1(p), l=2(d), l=3(f)"),
("Magnetic Q.N. (mₗ)",
r"m_l = -l, \ldots, 0, \ldots, +l \quad \text{Total values} = 2l+1",
"Gives orientation of orbital in space"),
("Spin Q.N. (mₛ)",
r"m_s = +\tfrac{1}{2} \text{ or } -\tfrac{1}{2}",
"+½ = spin-up (↑), −½ = spin-down (↓)"),
("Orbital Angular Momentum",
r"L = \sqrt{l(l+1)}\,\hbar",
""),
("Spin Angular Momentum",
r"S = \sqrt{s(s+1)}\,\hbar = \frac{\sqrt{3}}{2}\hbar",
"s = ½ for an electron"),
("Total orbitals in nth shell",
r"\text{Orbitals} = n^2",
""),
("Max electrons in subshell",
r"e^- = 2(2l+1)",
"s:2, p:6, d:10, f:14"),
],
"key_points": [
"n = principal: energy + size | l = azimuthal: shape | mₗ = magnetic: orientation | mₛ = spin: spin direction",
"For n=1: only 1s (1 orbital, 2 electrons)",
"For n=2: 2s + 2p (4 orbitals, 8 electrons)",
"For n=3: 3s + 3p + 3d (9 orbitals, 18 electrons)",
"For n=4: 4s + 4p + 4d + 4f (16 orbitals, 32 electrons)",
"Degenerate orbitals: same energy (e.g., 2px, 2py, 2pz)",
"Shape of orbitals: s=sphere, p=dumbbell, d=double dumbbell/cloverleaf",
"Pauli Exclusion Principle: no two electrons in same atom can have identical set of all 4 quantum numbers",
"Number of radial nodes = n - l - 1 | Number of angular nodes = l | Total nodes = n - 1",
],
"tip": "Nodes formula: radial nodes = n−l−1, angular nodes = l, total nodes = n−1. For 2p: radial=0, angular=1, total=1.",
"values": [
("Max e⁻ in s-subshell", "2"),
("Max e⁻ in p-subshell", "6"),
("Max e⁻ in d-subshell", "10"),
("Max e⁻ in f-subshell", "14"),
("Orbitals in n=1", "1"),
("Orbitals in n=2", "4"),
("Orbitals in n=3", "9"),
("Orbitals in n=4", "16"),
],
},
# ── 10 ─────────────────────────────────────────────────────────────────────
{
"title": "10. Electronic Configuration Rules",
"formulas": [
("Aufbau – Filling Order",
r"1s \to 2s \to 2p \to 3s \to 3p \to 4s \to 3d \to 4p \to 5s \to 4d \to 5p \to 6s \to 4f \to 5d \to \ldots",
"Fill lowest energy orbitals first"),
("(n+l) Rule",
r"\text{Lower }(n+l) \text{ fills first; if equal, lower } n \text{ fills first}",
"e.g., 4s (n+l=4) fills before 3d (n+l=5)"),
("Max electrons in nth shell",
r"e^-_{\max} = 2n^2",
""),
],
"key_points": [
"Aufbau Principle: electrons fill orbitals of lowest energy first",
"Pauli Exclusion Principle: max 2 electrons per orbital, with opposite spins",
"Hund's Rule: electrons fill degenerate orbitals singly first, then pair up; singly-filled orbitals have parallel spins (↑↑)",
"Half-filled and fully-filled subshells are extra stable (symmetry + exchange energy)",
"Exceptions: Cr = [Ar] 3d⁵ 4s¹ (not 3d⁴ 4s²) and Cu = [Ar] 3d¹⁰ 4s¹ (not 3d⁹ 4s²)",
"Similarly: Mo(42), Ag(47), Au(79), Pd(46) have exceptions",
"d-orbitals are filled AFTER the next s-orbital (e.g., 4s before 3d)",
"When ions form, 4s electrons are removed before 3d (e.g., Fe²⁺: remove both 4s electrons)",
],
"tip": "Cr and Cu are the most important exceptions: both prefer half-filled/fully-filled d for stability. In Fe²⁺, 4s is lost first → [Ar]3d⁶.",
"values": [
("Cr (Z=24)", "[Ar] 3d⁵ 4s¹ (exception)"),
("Cu (Z=29)", "[Ar] 3d¹⁰ 4s¹ (exception)"),
("Fe (Z=26)", "[Ar] 3d⁶ 4s²"),
("Fe²⁺", "[Ar] 3d⁶"),
("Fe³⁺", "[Ar] 3d⁵"),
],
},
# ── 11 ─────────────────────────────────────────────────────────────────────
{
"title": "11. Important Constants (Quick Reference)",
"formulas": [],
"key_points": [],
"tip": None,
"values": [
("Planck's constant (h)", "6.626 × 10⁻³⁴ J·s"),
("Speed of light (c)", "3 × 10⁸ m/s"),
("Rydberg constant (R_H)", "1.097 × 10⁷ m⁻¹"),
("Avogadro's number (Nₐ)", "6.022 × 10²³ mol⁻¹"),
("Bohr radius (a₀)", "0.529 Å = 0.529×10⁻¹⁰ m"),
("Electron charge (e)", "1.602 × 10⁻¹⁹ C"),
("Electron mass (mₑ)", "9.109 × 10⁻³¹ kg"),
("Proton mass (mₚ)", "1.673 × 10⁻²⁷ kg"),
("Neutron mass (mₙ)", "1.675 × 10⁻²⁷ kg"),
("ħ = h/2π", "1.055 × 10⁻³⁴ J·s"),
("1 eV", "1.602 × 10⁻¹⁹ J"),
("1 Å", "10⁻¹⁰ m = 10⁻⁸ cm"),
("1 nm", "10⁻⁹ m"),
("Boltzmann constant (k)", "1.381 × 10⁻²³ J/K"),
("IE of H atom (eV)", "13.6 eV"),
("IE of He⁺", "54.4 eV"),
("IE of Li²⁺", "122.4 eV"),
],
},
# ── 12 ─────────────────────────────────────────────────────────────────────
{
"title": "12. Additional & Derived Formulas",
"formulas": [
("Ionisation Energy (Bohr)",
r"IE = \frac{13.6\,Z^2}{n^2} \text{ eV}",
"For H (Z=1, n=1): IE = 13.6 eV"),
("Excitation Energy",
r"E_{exc} = E_{n_2} - E_{n_1} = 13.6\,Z^2\!\left(\frac{1}{n_1^2}-\frac{1}{n_2^2}\right)\text{ eV}",
"Energy to move e⁻ from n₁ to n₂"),
("Molar Energy of Photons",
r"E_{mol} = N_A \cdot h\nu",
"Total energy per mole of photons"),
("Current due to revolving electron",
r"I = \frac{ev_n}{2\pi r_n} = \frac{e}{T_n}",
"e = electron charge"),
("Magnetic Moment (unpaired electrons)",
r"\mu = \sqrt{n(n+2)} \text{ B.M.}",
"n = number of unpaired electrons; 1 BM = 9.274×10⁻²⁴ J/T"),
("Stopping Potential",
r"eV_0 = \frac{1}{2}mv_{max}^2 = h(\nu - \nu_0)",
"V₀ = stopping potential in volts"),
("Number of nodes (orbital)",
r"\text{Radial nodes} = n-l-1, \quad \text{Angular nodes} = l",
"Total nodes = n−1"),
],
"key_points": [
"For n=4 → n=1 in H: total spectral lines = 4×3/2 = 6",
"Magnetic moment: Fe²⁺ has 4 unpaired e⁻ → μ = √24 = 4.90 BM",
"Mn²⁺ has 5 unpaired e⁻ → μ = √35 = 5.92 BM (maximum for 3d series)",
"Nodes in 1s: 0 | 2s: 1 (radial) | 2p: 1 (angular) | 3d: 2 (total)",
"d_z² and d_x²-y² point along axes; d_xy, d_xz, d_yz point between axes",
"Threshold frequency ν₀ varies by metal: Na ~5.5×10¹⁴ Hz, Cs ~4.6×10¹⁴ Hz",
],
"tip": "For magnetic moment: count unpaired electrons in the electronic configuration. μ = √n(n+2) BM.",
"values": [
("μ for 1 unpaired e⁻", "1.73 BM"),
("μ for 2 unpaired e⁻", "2.83 BM"),
("μ for 3 unpaired e⁻", "3.87 BM"),
("μ for 4 unpaired e⁻", "4.90 BM"),
("μ for 5 unpaired e⁻", "5.92 BM"),
],
},
]
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ═══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
rightMargin=RMARGIN, leftMargin=LMARGIN,
topMargin=2*cm, bottomMargin=2*cm
)
elements = []
# ── cover heading ─────────────────────────────────────────────────────────────
elements.append(Spacer(1, 0.2*cm))
elements.append(Paragraph("ATOMIC STRUCTURE", title_s))
elements.append(Paragraph(
"Complete Formula Sheet + Revision Notes | Class 11 Chemistry | NCERT / JEE / NEET",
sub_s
))
elements.append(HRFlowable(width="100%", thickness=2.5, color=C_DARK))
elements.append(Spacer(1, 0.25*cm))
total_f = sum(len(s["formulas"]) for s in sections)
elements.append(Paragraph(
f"<b>Formulas: {total_f} | Topics: {len(sections)} | "
f"Includes: Key Points, Revision Notes & Important Values</b>",
body_s
))
elements.append(Spacer(1, 0.3*cm))
# ── sections ──────────────────────────────────────────────────────────────────
for sec in sections:
elements.append(Spacer(1, 0.25*cm))
elements.append(section_banner(sec["title"]))
elements.append(Spacer(1, 0.12*cm))
for i, f in enumerate(sec["formulas"]):
name, latex, note = f
elements.append(formula_row(name, latex, note, i))
elements.append(Spacer(1, 0.04*cm))
# key points box
if sec.get("key_points"):
elements.append(Spacer(1, 0.15*cm))
elements.append(key_points_box(sec["key_points"], sec.get("tip")))
# values table
if sec.get("values"):
elements.append(Spacer(1, 0.15*cm))
elements.append(Paragraph("<b>Important Values</b>",
ps("IVH", fontSize=10, fontName="Helvetica-Bold",
textColor=C_DARK, spaceAfter=3)))
elements.append(values_table(sec["values"]))
elements.append(Spacer(1, 0.2*cm))
# ── footer ────────────────────────────────────────────────────────────────────
elements.append(HRFlowable(width="100%", thickness=1.5, color=C_DARK))
elements.append(Spacer(1, 0.15*cm))
elements.append(Paragraph(
"Class 11 Chemistry | Atomic Structure | NCERT + JEE Main + JEE Advanced + NEET",
sub_s
))
doc.build(elements)
print(f"PDF generated: {OUTPUT}")
python3 /home/daytona/workspace/atomic-structure/generate_pdf_v2.py 2>&1
ls -lh /home/daytona/workspace/atomic-structure/Atomic_Structure_Formulas_Class11_v2.pdf
Atomic Structure Formulas Class11 v2
PDF Document · PDF
Wow
Chemical bonding notes on each and every topic and important topics and mostly or frequently asked questions plssss
~/chemical-bonding/generate_cb_pdf.py
"""
Chemical Bonding & Molecular Structure – Class 11 Chemistry
Complete Notes + Key Points + Frequently Asked Questions PDF
"""
import os, io
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["mathtext.fontset"] = "cm"
rcParams["font.family"] = "serif"
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage, PageBreak
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
W, H = A4
LMARGIN = 1.7 * cm
RMARGIN = 1.7 * cm
CONTENT_W = W - LMARGIN - RMARGIN
OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11.pdf"
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
# ── Colours ───────────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0d1b5e")
C_BLUE = colors.HexColor("#1565c0")
C_LBLUE = colors.HexColor("#e3f2fd")
C_ALT = colors.HexColor("#f0f4ff")
C_GREEN = colors.HexColor("#1b5e20")
C_GBKG = colors.HexColor("#e8f5e9")
C_RED = colors.HexColor("#b71c1c")
C_RBKG = colors.HexColor("#ffebee")
C_AMBER = colors.HexColor("#e65100")
C_ABKG = colors.HexColor("#fff8e1")
C_TEAL = colors.HexColor("#004d40")
C_TBKG = colors.HexColor("#e0f2f1")
C_GREY = colors.HexColor("#37474f")
C_PURPLE = colors.HexColor("#4a148c")
C_PBKG = colors.HexColor("#f3e5f5")
SS = getSampleStyleSheet()
def ps(name, **kw):
return ParagraphStyle(name, parent=SS["Normal"], **kw)
title_s = ps("T", fontSize=22, textColor=C_NAVY, fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=4)
sub_s = ps("S", fontSize=10, textColor=C_GREY, fontName="Helvetica", alignment=TA_CENTER, spaceAfter=10)
sec_txt_s = ps("SB", fontSize=12, textColor=colors.white, fontName="Helvetica-Bold", leading=16)
h2_s = ps("H2", fontSize=11, textColor=C_NAVY, fontName="Helvetica-Bold", spaceAfter=3, spaceBefore=6)
body_s = ps("BD", fontSize=9.5, fontName="Helvetica", textColor=colors.HexColor("#212121"), spaceAfter=3, leading=14)
note_s = ps("NO", fontSize=8.5, textColor=C_GREY, fontName="Helvetica-Oblique", spaceAfter=2, leftIndent=6)
kp_s = ps("KP", fontSize=9, textColor=C_GREEN, fontName="Helvetica", spaceAfter=2, leftIndent=8, leading=13)
kph_s = ps("KH", fontSize=10, textColor=C_GREEN, fontName="Helvetica-Bold", spaceAfter=3)
faq_q_s = ps("FQ", fontSize=9.5, textColor=C_PURPLE, fontName="Helvetica-Bold", spaceAfter=2, leftIndent=4)
faq_a_s = ps("FA", fontSize=9, textColor=colors.HexColor("#212121"), fontName="Helvetica", spaceAfter=4, leftIndent=12, leading=13)
imp_s = ps("IM", fontSize=9, textColor=C_RED, fontName="Helvetica-Bold", spaceAfter=2, leftIndent=8)
tip_s = ps("TP", fontSize=9, textColor=C_AMBER, fontName="Helvetica-Bold", spaceAfter=0)
# ── Render math formula ───────────────────────────────────────────────────────
def render_formula(latex_str, font_size=13, dpi=180):
try:
fig = plt.figure(figsize=(0.01, 0.01))
t = fig.text(0, 0, f"${latex_str}$", fontsize=font_size, color="#b71c1c", ha="left", va="bottom")
fig.canvas.draw()
bb = t.get_window_extent(renderer=fig.canvas.get_renderer())
plt.close(fig)
pad = 6
fw = max((bb.width + pad*2) / dpi, 0.5)
fh = max((bb.height + pad*2) / dpi, 0.3)
fig2, ax = plt.subplots(figsize=(fw, fh))
ax.set_axis_off(); fig2.patch.set_alpha(0)
fig2.text(pad/dpi/fw, pad/dpi/fh, f"${latex_str}$", fontsize=font_size,
color="#b71c1c", ha="left", va="bottom", transform=fig2.transFigure)
buf = io.BytesIO()
fig2.savefig(buf, format="png", dpi=dpi, transparent=True,
bbox_inches="tight", pad_inches=0.04)
plt.close(fig2)
buf.seek(0)
iw = fw * 72
ih = fh * 72
sc = min(1.0, (CONTENT_W - 20) / iw)
return RLImage(buf, width=iw*sc, height=ih*sc)
except Exception as e:
plt.close("all")
return Paragraph(f"[{latex_str}]", note_s)
# ── Layout helpers ────────────────────────────────────────────────────────────
def section_banner(title):
t = Table([[Paragraph(f" {title}", sec_txt_s)]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_BLUE),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 8),
]))
return t
def formula_block(label, latex, note=""):
img = render_formula(latex)
cell = [Paragraph(f"<b>{label}</b>", ps("FL", fontSize=9.5, fontName="Helvetica-Bold",
textColor=C_NAVY, spaceAfter=2)), img]
if note:
cell.append(Paragraph(f"▸ {note}", note_s))
t = Table([[cell]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_LBLUE),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.5, C_BLUE),
]))
return KeepTogether(t)
def key_points_box(points, tip=None):
content = [Paragraph("★ Key Points", kph_s)]
for p in points:
content.append(Paragraph(f"• {p}", kp_s))
if tip:
content.append(Spacer(1,3))
content.append(Paragraph(f"💡 Tip: {tip}", tip_s))
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_GBKG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, C_GREEN),
]))
return KeepTogether(t)
def important_box(points, heading="⚠ Important Points"):
content = [Paragraph(f"<b>{heading}</b>",
ps("IH", fontSize=10, fontName="Helvetica-Bold",
textColor=C_RED, spaceAfter=3))]
for p in points:
content.append(Paragraph(f"★ {p}", imp_s))
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RBKG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, C_RED),
]))
return KeepTogether(t)
def faq_box(qas):
content = [Paragraph("❓ Frequently Asked Questions (Exam Focus)",
ps("FH", fontSize=10, fontName="Helvetica-Bold",
textColor=C_PURPLE, spaceAfter=4))]
for q, a in qas:
content.append(Paragraph(f"Q: {q}", faq_q_s))
content.append(Paragraph(f"Ans: {a}", faq_a_s))
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_PBKG),
("TOPPADDING", (0,0),(-1,-1), 6),
("BOTTOMPADDING", (0,0),(-1,-1), 6),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, C_PURPLE),
]))
return KeepTogether(t)
def values_table(rows):
hdr = [Paragraph("<b>Quantity / Species</b>",
ps("VH", fontSize=9, fontName="Helvetica-Bold", textColor=colors.white)),
Paragraph("<b>Value / Answer</b>",
ps("VH2", fontSize=9, fontName="Helvetica-Bold", textColor=colors.white))]
data = [hdr]
for q, v in rows:
data.append([Paragraph(q, ps("VC", fontSize=9, fontName="Helvetica")),
Paragraph(v, ps("VV", fontSize=9, fontName="Helvetica-Bold", textColor=C_NAVY))])
t = Table(data, colWidths=[CONTENT_W*0.52, CONTENT_W*0.48])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_BLUE),
("TEXTCOLOR", (0,0),(-1,0), colors.white),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
("INNERGRID", (0,0),(-1,-1), 0.3, colors.HexColor("#b0bec5")),
("BOX", (0,0),(-1,-1), 0.6, C_BLUE),
]))
return t
def note_box(text, heading="📝 Note"):
content = [Paragraph(f"<b>{heading}</b>",
ps("NH", fontSize=9.5, fontName="Helvetica-Bold",
textColor=C_TEAL, spaceAfter=2)),
Paragraph(text, ps("NB", fontSize=9, fontName="Helvetica",
textColor=C_TEAL, leading=13))]
t = Table([[content]], colWidths=[CONTENT_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_TBKG),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.7, C_TEAL),
]))
return KeepTogether(t)
def add_section(elements, title, content_fn):
elements.append(Spacer(1, 0.2*cm))
elements.append(section_banner(title))
elements.append(Spacer(1, 0.1*cm))
content_fn(elements)
elements.append(Spacer(1, 0.15*cm))
# ═══════════════════════════════════════════════════════════════════════════════
# CONTENT
# ═══════════════════════════════════════════════════════════════════════════════
def s1(el): # Kossel-Lewis / Octet Rule
el.append(Paragraph(
"Chemical bonds form because atoms attain stability by achieving noble gas configuration "
"(8 electrons in outermost shell = octet; 2 for H/Li = duplet).",
body_s))
el.append(Spacer(1,4))
el.append(Paragraph("<b>Types of Chemical Bonds:</b>", h2_s))
rows = [
("Bond Type", "How Formed", "Example"),
("Ionic (Electrovalent)", "Transfer of electrons (metal→non-metal)", "NaCl, MgO, CaF₂"),
("Covalent", "Sharing of electrons (non-metal + non-metal)", "H₂, Cl₂, H₂O, CO₂"),
("Coordinate (Dative)", "One atom donates BOTH electrons (lone pair)", "NH₄⁺, H₃O⁺, BF₃·NH₃"),
("Metallic", "Sea of delocalised electrons", "Na, Fe, Cu"),
("Hydrogen Bond", "Electrostatic attraction X-H···Y", "H₂O, HF, NH₃"),
]
data = []
for i, r in enumerate(rows):
style_ps = ps(f"TC{i}", fontSize=8.5,
fontName="Helvetica-Bold" if i==0 else "Helvetica",
textColor=colors.white if i==0 else colors.HexColor("#212121"))
data.append([Paragraph(c, style_ps) for c in r])
t = Table(data, colWidths=[CONTENT_W*0.27, CONTENT_W*0.42, CONTENT_W*0.31])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("INNERGRID", (0,0),(-1,-1), 0.3, C_BLUE),
("BOX", (0,0),(-1,-1), 0.6, C_NAVY),
]))
el.append(t)
el.append(Spacer(1,6))
el.append(key_points_box([
"Lewis proposed: bonding electrons are shared pairs; non-bonding = lone pairs",
"Kossel pointed out: atoms close to noble gases tend to form bonds to complete octet",
"Octet rule: atoms react to have 8 electrons in valence shell",
"Exceptions to octet rule: (1) Incomplete octet – BeCl₂ (4e), BCl₃ (6e); (2) Expanded octet – PCl₅, SF₆, IF₇; (3) Odd-electron molecules – NO, NO₂",
"Formal charge = Valence electrons – (lone pair e⁻) – ½(bond pair e⁻)",
"Structure with lowest formal charges and negative charge on more electronegative atom is most stable",
], tip="Remember BeCl₂ (4), BCl₃ (6), PCl₅ (10), SF₆ (12) for exceptions."))
el.append(Spacer(1,6))
el.append(formula_block("Formal Charge",
r"FC = V - L - \frac{B}{2}",
"V=valence electrons, L=lone pair electrons, B=bonding electrons"))
el.append(Spacer(1,6))
el.append(faq_box([
("What is the octet rule? Name exceptions.",
"Atoms bond to achieve 8 electrons in their outermost shell. Exceptions: (1) Incomplete octet: Be (4e in BeCl₂), B (6e in BCl₃); (2) Expanded octet: P (10e in PCl₅), S (12e in SF₆); (3) Odd-electron: NO, NO₂."),
("What is a coordinate/dative bond? Give 2 examples.",
"A bond where BOTH electrons are donated by ONE atom (donor). Examples: NH₄⁺ (N donates to H⁺), H₃O⁺ (O donates to H⁺), BF₃·NH₃ (N→B)."),
("Calculate formal charge of N in NO₃⁻.",
"N in NO₃⁻: V=5, one double bond + two single bonds. Formal charge = 5 − 0 − 8/2 = +1."),
]))
def s2(el): # Ionic Bonding
el.append(Paragraph(
"Ionic bonds form by complete transfer of electrons from a metal (low IE) to a non-metal "
"(high EA), forming oppositely charged ions held by electrostatic attraction.",
body_s))
el.append(Spacer(1,4))
el.append(formula_block("Lattice Enthalpy (Born-Haber cycle related)",
r"\Delta H_{lattice} \propto \frac{z^+ \cdot z^-}{r^+ + r^-}",
"z⁺, z⁻ = charges on ions; r = ionic radii; Higher charge and smaller size → stronger lattice"))
el.append(Spacer(1,5))
el.append(key_points_box([
"Ionic bond favoured by: low ionisation energy (cation), high electron affinity (anion), high lattice energy",
"Lattice energy: energy released when gaseous ions combine to form 1 mole of ionic solid",
"Born-Haber cycle is used to calculate lattice energy indirectly (Hess's law)",
"Greater the lattice energy → higher melting point, higher solubility in polar solvents",
"Ionic compounds: high MP/BP, conduct electricity in molten/aqueous state, brittle, soluble in polar solvents",
"Fajan's Rules: covalent character in ionic bonds increases with (1) small cation, (2) large anion, (3) high charge on ions",
"Fajan's: LiI > LiCl > LiBr > LiF in covalent character",
"Polarisation power of cation ∝ charge/radius² (ionic potential)",
"Order of lattice energy: MgO > NaF > MgCl₂ > NaCl (higher charge = higher lattice energy)",
], tip="For Fajan's Rules: smaller cation + larger anion + higher charge = more covalent character."))
el.append(Spacer(1,6))
el.append(important_box([
"NaF has higher lattice energy than NaCl because F⁻ is smaller → ions closer → stronger attraction",
"MgO has much higher lattice energy than NaCl due to 2+ and 2− charges (4× electrostatic force)",
"LiI has more covalent character than CsI (Li⁺ is smaller, polarises I⁻ more)",
"Born-Haber cycle: ΔHf = ΔHsub + IE + ½ΔHdiss + EA + ΔHlattice",
]))
el.append(Spacer(1,6))
el.append(faq_box([
("What are Fajan's rules?",
"Covalent character increases in ionic compounds when: (1) cation is small and highly charged, (2) anion is large and highly charged. Smaller cation has higher polarising power; larger anion is more polarisable."),
("Arrange in order of increasing lattice energy: NaCl, MgO, CaO, NaF.",
"NaCl < NaF < CaO < MgO. MgO and CaO have 2+/2− charges → much higher lattice energy. MgO > CaO because Mg²⁺ < Ca²⁺ (smaller → closer → stronger attraction)."),
("Why is NaCl a good conductor in molten state but not in solid state?",
"In solid state, ions are fixed in lattice. On melting, ions become free to move → conduct electricity."),
]))
def s3(el): # Covalent Bonding & Lewis Structures
el.append(Paragraph(
"Covalent bonds form by sharing of electron pairs between non-metal atoms. "
"Each shared pair = one bond. Unshared pairs = lone pairs.",
body_s))
el.append(Spacer(1,4))
el.append(Paragraph("<b>Bond Order, Length & Strength:</b>", h2_s))
el.append(values_table([
("Bond order", "No. of shared electron pairs between atoms"),
("Single bond (bond order 1)", "Longest, Weakest"),
("Double bond (bond order 2)", "Shorter, Stronger than single"),
("Triple bond (bond order 3)", "Shortest, Strongest"),
("C−C bond length", "154 pm"),
("C=C bond length", "134 pm"),
("C≡C bond length", "120 pm"),
("N≡N bond length", "110 pm (strongest N bond)"),
("H−H bond length", "74 pm"),
("O=O bond length", "121 pm"),
]))
el.append(Spacer(1,6))
el.append(key_points_box([
"Lewis structure: dots represent electrons; lines represent bonds",
"Lone pairs on central atom cause more repulsion than bond pairs",
"Multiple bonds: double bond = 1σ + 1π; triple bond = 1σ + 2π",
"Resonance: when one Lewis structure is insufficient (e.g., O₃, SO₂, CO₃²⁻, NO₃⁻, C₆H₆)",
"Resonance hybrid is more stable than any single resonance structure (resonance energy)",
"Resonance energy of benzene ≈ 150 kJ/mol (extra stability)",
"In O₃: O−O bond length is intermediate (127.8 pm) between single (148 pm) and double (121 pm)",
"Steps for Lewis structure: (1) count total valence e⁻, (2) connect with single bonds, (3) complete octets with lone pairs, (4) form multiple bonds if needed",
], tip="For resonance: if you can draw 2+ valid Lewis structures with different bond positions (not atom positions), the molecule shows resonance."))
el.append(Spacer(1,6))
el.append(faq_box([
("What is resonance? Give two examples.",
"When a molecule cannot be represented by a single Lewis structure and two or more structures (differing only in electron arrangement) contribute to the actual structure. Examples: O₃ (two O=O/O-O resonance structures), CO₃²⁻ (three equivalent structures), C₆H₆ (Kekulé structures)."),
("How many sigma and pi bonds are in CH₂=CH−C≡CH?",
"CH₂=CH−C≡CH: Single bonds=3σ, C=C gives 1σ+1π, C≡C gives 1σ+2π, C-H bonds=4σ. Total: σ=8, π=3."),
("What is bond order of O₂ and O₂⁻?",
"O₂: bond order = 2. O₂⁻: one extra electron goes into antibonding π* → bond order = 1.5."),
]))
def s4(el): # VSEPR Theory
el.append(Paragraph(
"VSEPR (Valence Shell Electron Pair Repulsion) theory predicts molecular geometry based on "
"repulsion between electron pairs (bond pairs + lone pairs) around the central atom.",
body_s))
el.append(Spacer(1,4))
el.append(Paragraph("<b>Repulsion Order:</b>", h2_s))
el.append(note_box("lp–lp > lp–bp > bp–bp (lone pair repulsion is greatest)",
"Repulsion Hierarchy"))
el.append(Spacer(1,5))
el.append(Paragraph("<b>Shapes (AXₙEₘ notation – A=central, X=bond pair, E=lone pair):</b>", h2_s))
rows = [
("BP", "LP", "Shape", "Bond Angle", "Example"),
("2", "0", "Linear", "180°", "BeCl₂, CO₂, C₂H₂"),
("3", "0", "Trigonal Planar", "120°", "BF₃, SO₃, NO₃⁻"),
("2", "1", "Bent/V-shaped", "< 120°", "SO₂ (~119°), O₃"),
("4", "0", "Tetrahedral", "109.5°", "CH₄, CCl₄, NH₄⁺"),
("3", "1", "Trigonal Pyramidal","107°", "NH₃, PCl₃"),
("2", "2", "Bent/V-shaped", "104.5°", "H₂O, H₂S"),
("5", "0", "Trigonal Bipyramidal","90°,120°","PCl₅"),
("4", "1", "See-saw", "< 90°,120°", "SF₄"),
("3", "2", "T-shaped", "< 90°", "ClF₃, BrF₃"),
("2", "3", "Linear", "180°", "XeF₂, I₃⁻"),
("6", "0", "Octahedral", "90°", "SF₆, PCl₆⁻"),
("5", "1", "Square Pyramidal","< 90°", "BrF₅, IF₅"),
("4", "2", "Square Planar", "90°", "XeF₄, ICl₄⁻"),
]
hdr_ps = ps("VH3", fontSize=8, fontName="Helvetica-Bold", textColor=colors.white)
body_ps = ps("VB3", fontSize=8, fontName="Helvetica")
data = [[Paragraph(c, hdr_ps if i==0 else body_ps) for c in r] for i,r in enumerate(rows)]
t = Table(data, colWidths=[CONTENT_W*0.09, CONTENT_W*0.09, CONTENT_W*0.26,
CONTENT_W*0.22, CONTENT_W*0.34])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("INNERGRID", (0,0),(-1,-1), 0.3, C_BLUE),
("BOX", (0,0),(-1,-1), 0.6, C_NAVY),
]))
el.append(t)
el.append(Spacer(1,6))
el.append(key_points_box([
"Bond angle decreases as lone pairs increase: CH₄(109.5°) > NH₃(107°) > H₂O(104.5°)",
"All three molecules above have 4 electron pairs (tetrahedral electron geometry)",
"PCl₅ has two types of bonds: axial (90°) and equatorial (120°) – axial bonds are longer and weaker",
"In SF₄ (see-saw): lone pair occupies equatorial position (less repulsion with axial bonds)",
"XeF₄ (square planar): 2 lone pairs in axial positions, trans to each other",
"Double bonds cause slightly more repulsion than single bonds but less than lone pairs",
"VSEPR ONLY predicts geometry; hybridisation explains bonding",
], tip="Count total electron pairs = BP + LP. Lone pairs reduce bond angles by ~2-2.5° each."))
el.append(Spacer(1,6))
el.append(important_box([
"H₂O bond angle is 104.5° (NOT 109.5°) due to 2 lone pairs compressing the angle",
"NH₃ is trigonal pyramidal (NOT planar) due to 1 lone pair",
"CO₂ is linear (no lone pairs on C), but H₂O is bent (2 lone pairs on O)",
"SO₂ is bent (~119°) and is polar; SO₃ is trigonal planar and non-polar",
"PCl₅ lone pairs prefer equatorial positions in derivatives",
]))
el.append(Spacer(1,6))
el.append(faq_box([
("Why is bond angle of H₂O (104.5°) less than NH₃ (107°)?",
"H₂O has 2 lone pairs and NH₃ has 1 lone pair around the central atom. Lone pair-lone pair repulsion is greater in H₂O, compressing the bond angle more."),
("What is the shape of XeF₄? Is it polar or non-polar?",
"Square planar (4 BP, 2 LP). The two lone pairs are trans (opposite sides) → dipole moments cancel → XeF₄ is NON-POLAR."),
("Arrange in increasing bond angle: H₂O, NH₃, CH₄, BF₃.",
"H₂O (104.5°) < NH₃ (107°) < CH₄ (109.5°) < BF₃ (120°)."),
("What is the geometry of PCl₅? Why is it unusual?",
"Trigonal bipyramidal. Unusual because it has 5 bond pairs, expanded octet on P (using 3d orbitals). Axial bonds (90°) are longer/weaker than equatorial (120°)."),
]))
def s5(el): # Valence Bond Theory & Hybridisation
el.append(Paragraph(
"Valence Bond Theory: a bond forms when half-filled orbitals of two atoms overlap. "
"Hybridisation: mixing of atomic orbitals to form new equivalent hybrid orbitals.",
body_s))
el.append(Spacer(1,4))
el.append(Paragraph("<b>Hybridisation Table:</b>", h2_s))
rows2 = [
("Hybridisation", "Orbitals Mixed", "Shape", "Bond Angle", "Examples"),
("sp", "1s + 1p", "Linear", "180°", "BeCl₂, C₂H₂, HCN, CO₂"),
("sp²", "1s + 2p", "Trigonal Planar", "120°", "BF₃, C₂H₄, SO₃, NO₃⁻"),
("sp³", "1s + 3p", "Tetrahedral", "109.5°", "CH₄, CCl₄, H₂O, NH₃"),
("sp³d", "1s + 3p + 1d", "Trigonal Bipyramidal","90°,120°","PCl₅"),
("sp³d²", "1s + 3p + 2d", "Octahedral", "90°", "SF₆, [Co(NH₃)₆]³⁺"),
("sp³d³", "1s + 3p + 3d", "Pentagonal Bipyramidal","72°,90°","IF₇"),
]
hdr_p = ps("HT", fontSize=8, fontName="Helvetica-Bold", textColor=colors.white)
body_p = ps("HB", fontSize=8, fontName="Helvetica")
data2 = [[Paragraph(c, hdr_p if i==0 else body_p) for c in r] for i,r in enumerate(rows2)]
t = Table(data2, colWidths=[CONTENT_W*0.15, CONTENT_W*0.17, CONTENT_W*0.24,
CONTENT_W*0.16, CONTENT_W*0.28])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("INNERGRID", (0,0),(-1,-1), 0.3, C_BLUE),
("BOX", (0,0),(-1,-1), 0.6, C_NAVY),
]))
el.append(t)
el.append(Spacer(1,6))
el.append(formula_block("Hybridisation Number Formula",
r"\text{Hyb. No.} = \frac{1}{2}\left[V + M - C + A\right]",
"V=valence e⁻ of central atom, M=monovalent atoms, C=cationic charge, A=anionic charge"))
el.append(Spacer(1,5))
el.append(key_points_box([
"σ (sigma) bond: head-on overlap, along internuclear axis, stronger, free rotation possible",
"π (pi) bond: lateral/sideways overlap, above and below axis, weaker, NO free rotation",
"Single bond = 1σ; Double bond = 1σ+1π; Triple bond = 1σ+2π",
"sp hybridisation: 2 hybrid orbitals, 2 unhybridised p orbitals (for π bonds)",
"sp² hybridisation: 3 hybrid orbitals, 1 unhybridised p orbital",
"sp³ hybridisation: 4 hybrid orbitals, 0 unhybridised p orbitals (pure single bonds)",
"More s-character → shorter bond, stronger bond, more electronegative",
"s-character: sp=50%, sp²=33%, sp³=25%",
"C in diamond = sp³; C in graphite = sp²; C in C₂H₂ = sp",
"Bond angle order: sp(180°) > sp²(120°) > sp³(109.5°) – matches s-character",
], tip="Hybridisation number = ½(V+M−C+A). For CH₄: ½(4+4)=4 → sp³. For BF₃: ½(3+3)=3 → sp²."))
el.append(Spacer(1,6))
el.append(important_box([
"In C₂H₄: each C is sp² hybridised; double bond = 1σ(sp²-sp²) + 1π(p-p)",
"In C₂H₂: each C is sp hybridised; triple bond = 1σ + 2π",
"NH₃ is sp³ but with bond angle 107° (one lone pair distorts tetrahedral)",
"H₂O is sp³ but with bond angle 104.5° (two lone pairs distort more)",
"In C₂H₄ the π bond restricts rotation → cis/trans isomerism is possible",
"PCl₅: P uses sp³d hybridisation with 3d orbitals (period 3 element)",
"SF₆: S uses sp³d² hybridisation",
]))
el.append(Spacer(1,6))
el.append(faq_box([
("What is the hybridisation of N in NO₂, NO₂⁺, NO₂⁻?",
"NO₂: sp² (bent, 134°, odd electron). NO₂⁺: sp (linear, 180°, no lone pair). NO₂⁻: sp² (bent, ~115°, one lone pair)."),
("What is the hybridisation of carbon in: CH₄, C₂H₄, C₂H₂, C₆H₆?",
"CH₄: sp³; C₂H₄: sp²; C₂H₂: sp; C₆H₆: sp² (all 6 carbons)."),
("Why can't rotation occur around a double bond?",
"A π bond is formed by lateral overlap of p orbitals above and below the plane. Rotation would break this overlap, requiring ~250 kJ/mol energy → rotation is restricted at room temperature."),
("What is s-character and why does it matter?",
"s-character = % of s orbital in the hybrid. sp=50%, sp²=33%, sp³=25%. Higher s-character → more penetration → shorter bond length → greater bond strength → more electronegative carbon."),
]))
def s6(el): # MO Theory
el.append(Paragraph(
"Molecular Orbital (MO) Theory: atomic orbitals combine to form molecular orbitals "
"that belong to the entire molecule. Bonding MOs are lower in energy; anti-bonding MOs are higher.",
body_s))
el.append(Spacer(1,4))
el.append(formula_block("Bond Order (MO Theory)",
r"\text{Bond Order} = \frac{N_b - N_a}{2}",
"Nb = electrons in bonding MOs, Na = electrons in anti-bonding MOs"))
el.append(Spacer(1,5))
el.append(Paragraph("<b>MO Electronic Configurations & Properties:</b>", h2_s))
rows3 = [
("Species", "Total e⁻", "Bond Order", "Magnetic Nature", "Stability"),
("H₂", "2", "1", "Diamagnetic", "Stable"),
("H₂⁺", "1", "0.5", "Paramagnetic", "Stable"),
("H₂⁻", "3", "0.5", "Paramagnetic", "Stable"),
("He₂", "4", "0", "–", "Does NOT exist"),
("He₂⁺", "3", "0.5", "Paramagnetic", "Exists"),
("Li₂", "6", "1", "Diamagnetic", "Stable"),
("B₂", "10", "1", "Paramagnetic", "Stable"),
("C₂", "12", "2", "Diamagnetic", "Stable"),
("N₂", "14", "3", "Diamagnetic", "Most stable diatomic"),
("N₂⁺", "13", "2.5", "Paramagnetic", "Stable"),
("O₂", "16", "2", "Paramagnetic", "Stable"),
("O₂⁺", "15", "2.5", "Paramagnetic", "More stable than O₂"),
("O₂⁻", "17", "1.5", "Paramagnetic", "Less stable"),
("O₂²⁻", "18", "1", "Diamagnetic", "Peroxide ion"),
("F₂", "18", "1", "Diamagnetic", "Stable"),
("Ne₂", "20", "0", "–", "Does NOT exist"),
("NO", "15", "2.5", "Paramagnetic", "Stable"),
("CO", "14", "3", "Diamagnetic", "Isoelectronic with N₂"),
]
hdr_p2 = ps("MT", fontSize=7.5, fontName="Helvetica-Bold", textColor=colors.white)
body_p2 = ps("MB", fontSize=7.5, fontName="Helvetica")
data3 = [[Paragraph(c, hdr_p2 if i==0 else body_p2) for c in r] for i,r in enumerate(rows3)]
t = Table(data3, colWidths=[CONTENT_W*0.14, CONTENT_W*0.12, CONTENT_W*0.16,
CONTENT_W*0.24, CONTENT_W*0.34])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("INNERGRID", (0,0),(-1,-1), 0.3, C_BLUE),
("BOX", (0,0),(-1,-1), 0.6, C_NAVY),
]))
el.append(t)
el.append(Spacer(1,6))
el.append(key_points_box([
"MO = Bonding MO (BMO) + Anti-bonding MO (ABMO); ABMO denoted with * (e.g., σ*)",
"Energy order for O₂, F₂: σ1s < σ*1s < σ2s < σ*2s < σ2p < π2p = π2p < π*2p = π*2p < σ*2p",
"Energy order for B₂, C₂, N₂: σ1s < σ*1s < σ2s < σ*2s < π2p = π2p < σ2p < π*2p = π*2p < σ*2p",
"(Note: π2p fills BEFORE σ2p in B₂, C₂, N₂ due to s-p mixing)",
"Bond order > 0 → molecule exists; Bond order = 0 → does not exist",
"Higher bond order = shorter bond length, higher bond energy, more stable",
"Paramagnetic: unpaired electrons present (e.g., O₂, NO, B₂)",
"Diamagnetic: all electrons paired (e.g., N₂, F₂, H₂, CO)",
"O₂ is paramagnetic – proved by MO theory (liquid O₂ attracted to magnets)",
"N₂ has bond order 3 – highest among diatomics listed; very stable (ΔH dissoc = 945 kJ/mol)",
], tip="For O₂: 16 electrons, last 2 go into degenerate π*2p MOs (one each by Hund's rule) → paramagnetic. VBT wrongly predicted diamagnetic."))
el.append(Spacer(1,6))
el.append(faq_box([
("Why is O₂ paramagnetic? How does MO theory explain this?",
"O₂ has 16 electrons. After filling all MOs up to π2p, the last 2 electrons occupy the two degenerate π*2p orbitals singly (Hund's rule) → 2 unpaired electrons → paramagnetic. VBT predicted all paired (diamagnetic) which was wrong."),
("What is the bond order of NO⁺, NO, NO⁻?",
"NO: BO=2.5 (paramagnetic). NO⁺: BO=3 (diamagnetic, isoelectronic with N₂). NO⁻: BO=2 (paramagnetic)."),
("Does He₂ exist? Explain with MO theory.",
"He₂ has 4 electrons: σ1s²(σ*1s)². Nb=2, Na=2 → BO=(2−2)/2=0. Bond order is zero → He₂ does NOT exist."),
("Arrange in increasing bond length: N₂, O₂, F₂, N₂⁺.",
"Higher bond order = shorter length. N₂(BO=3) < N₂⁺(BO=2.5) < O₂(BO=2) < F₂(BO=1). So: F₂ > O₂ > N₂⁺ > N₂ in bond length."),
]))
def s7(el): # Polarity & Dipole Moment
el.append(Paragraph(
"A bond is polar if the two bonded atoms have different electronegativities. "
"Dipole moment (μ) measures the extent of polarity of a bond or molecule.",
body_s))
el.append(Spacer(1,4))
el.append(formula_block("Dipole Moment",
r"\mu = q \times d",
"q = charge (esu), d = bond length; Unit: Debye (D); 1 D = 3.336×10⁻³⁰ C·m"))
el.append(Spacer(1,5))
el.append(key_points_box([
"Electronegativity order: F > O > Cl > N > Br > I > S > C > H",
"Polar bond: δ+ on less electronegative, δ− on more electronegative atom",
"Molecule is non-polar if: (1) all bonds identical + symmetric geometry, OR (2) dipoles cancel",
"Non-polar molecules (μ=0): CCl₄, CO₂, BF₃, BCl₃, CS₂, SF₆, XeF₄, PCl₅, C₆H₆",
"Polar molecules (μ≠0): H₂O (1.85D), NH₃ (1.47D), HCl (1.07D), SO₂ (1.60D), CHCl₃",
"μ increases with: greater EN difference, greater bond length",
"For H₂O > H₂S: μ(H₂O)=1.85D > μ(H₂S)=0.97D (O more electronegative, angle matters)",
"CO₂ is linear → bond dipoles cancel → μ=0 (non-polar)",
"SO₂ is bent → dipoles do NOT cancel → μ≠0 (polar)",
"cis isomer has higher μ than trans isomer (dipoles add in cis, cancel in trans)",
], tip="Symmetric + all same bonds = non-polar. Asymmetric or lone pairs = usually polar. CO₂(linear)=0D but H₂O(bent)=1.85D."))
el.append(Spacer(1,6))
el.append(values_table([
("H₂O", "1.85 D (highly polar)"),
("NH₃", "1.47 D"),
("SO₂", "1.60 D"),
("HF", "1.91 D (highest for HX)"),
("HCl", "1.07 D"),
("HBr", "0.79 D"),
("HI", "0.38 D"),
("CO", "0.12 D (slight, C→O)"),
("CO₂", "0 D (linear, symmetric)"),
("CCl₄", "0 D (tetrahedral, symmetric)"),
("CHCl₃", "1.87 D (polar)"),
("BF₃", "0 D (trigonal planar)"),
]))
el.append(Spacer(1,6))
el.append(faq_box([
("Why is CO₂ non-polar but SO₂ is polar?",
"CO₂ is linear (sp, no lone pair on C) → two C=O dipoles point in exactly opposite directions → net μ=0. SO₂ is bent (sp², 1 lone pair on S) → the two S=O dipoles do NOT cancel → net μ≠0 (~1.60 D)."),
("Which has higher dipole moment: o-dichlorobenzene or p-dichlorobenzene?",
"o-dichlorobenzene (ortho) has μ≈2.50D; p-dichlorobenzene (para) has μ=0 (dipoles cancel). ortho > meta > para in dipole moment for disubstituted benzenes with identical groups."),
("Arrange HF, HCl, HBr, HI in decreasing dipole moment.",
"HF(1.91D) > HCl(1.07D) > HBr(0.79D) > HI(0.38D). EN difference decreases down the group, so dipole moment decreases."),
("NF₃ has lower μ than NH₃. Why?",
"In NH₃ (μ=1.47D), the N−H bond dipoles and lone pair dipole reinforce each other (same direction). In NF₃ (μ=0.24D), N−F bond dipoles (F is more EN than N) point AWAY from lone pair → they partially cancel each other."),
]))
def s8(el): # Hydrogen Bonding
el.append(Paragraph(
"Hydrogen bond: electrostatic attraction between a hydrogen atom covalently bonded to a "
"highly electronegative atom (F, O, N) and another electronegative atom with lone pairs.",
body_s))
el.append(Spacer(1,4))
el.append(key_points_box([
"Condition for H-bond: H must be bonded to F, O, or N (highly EN, small size)",
"Intermolecular H-bond: between different molecules (e.g., H₂O, HF, NH₃, alcohols, carboxylic acids)",
"Intramolecular H-bond: within the SAME molecule (e.g., o-nitrophenol, salicylaldehyde, o-chlorophenol)",
"Intramolecular H-bond → LOWER BP than intermolecular (less intermolecular attraction)",
"H-bond strength: F−H···F > O−H···O > N−H···N",
"H₂O has 4 H-bonds per molecule (tetrahedral arrangement) → unusually high BP (100°C)",
"HF has stronger H-bond than H₂O per bond, but H₂O makes MORE bonds per molecule → H₂O has higher BP",
"Anomalous properties of water due to H-bonding: high BP, high surface tension, expansion on freezing, high specific heat",
"Ice is less dense than water (open cage structure due to H-bonds) → ice floats on water",
"H-bond energy: ~10–40 kJ/mol (weaker than covalent ~400 kJ/mol, stronger than van der Waals ~1–5 kJ/mol)",
"DNA double helix held together by H-bonds (A=T: 2 H-bonds; G≡C: 3 H-bonds)",
], tip="BP order of hydrides: H₂O > HF > NH₃ > H₂S (all others follow MW trend). H₂O is highest due to 2 H-bonds per molecule and extra lone pair."))
el.append(Spacer(1,6))
el.append(important_box([
"o-nitrophenol has LOWER BP than p-nitrophenol (intramolecular H-bond in ortho form)",
"Acetic acid exists as dimer in vapour/benzene due to intermolecular H-bonds",
"NH₃ > PH₃ in BP due to H-bonding in NH₃",
"H-bonding makes proteins, DNA, and cellulose structurally stable",
"CH₃OH (methanol) has higher BP than CH₃F even though F is more EN (O forms H-bonds, F doesn't act as H-bond donor in CH₃F)",
]))
el.append(Spacer(1,6))
el.append(faq_box([
("Why does ice float on water?",
"In ice, each water molecule forms 4 H-bonds in a tetrahedral open-cage lattice, making it less dense than liquid water (where H-bonds are partially broken and molecules are closer). Since ice is less dense, it floats."),
("Arrange in decreasing BP: H₂O, H₂S, H₂Se, H₂Te.",
"H₂O (100°C) > H₂Te (−2°C) > H₂Se (−41°C) > H₂S (−60°C). H₂O is highest due to H-bonding. For H₂S, H₂Se, H₂Te – no H-bonding, BP increases with molar mass."),
("Why is o-nitrophenol more volatile than p-nitrophenol?",
"o-nitrophenol forms intramolecular H-bond (within the molecule) → intermolecular H-bonding is reduced → lower BP → more volatile. p-nitrophenol forms intermolecular H-bonds → higher BP → less volatile."),
("What type of H-bond exists in HF? Why does HF have lower BP than H₂O despite stronger H-bond?",
"HF forms zigzag intermolecular H-bonds (F−H···F). The H-bond in HF is stronger per bond, but each HF molecule can form only 1 H-bond as donor (1 H) and 1 as acceptor (though F has 3 lone pairs), giving a chain structure. H₂O forms a 3D network with 2 H-bonds as donor + 2 as acceptor → stronger network → higher BP."),
]))
def s9(el): # Intermolecular Forces
el.append(Paragraph(
"Van der Waals forces are weak intermolecular attractions that exist between all molecules. "
"They increase with molecular size/molar mass.",
body_s))
el.append(Spacer(1,4))
rows_vdw = [
("Type", "Also Called", "Origin", "Example"),
("Dispersion / London", "London forces", "Temporary induced dipoles in non-polar mol.", "Noble gases, CH₄, Cl₂, I₂"),
("Dipole-Dipole", "Keesom interactions", "Permanent dipoles attract", "HCl, SO₂, acetone"),
("Dipole-Induced Dipole", "Debye interactions", "Permanent dipole induces dipole in neighbour","HCl + Ar"),
("Hydrogen Bond", "(special case)", "X−H···Y (X,Y = F,O,N)", "H₂O, HF, NH₃"),
]
hdr_ps3 = ps("VH4", fontSize=8, fontName="Helvetica-Bold", textColor=colors.white)
body_ps3 = ps("VB4", fontSize=8, fontName="Helvetica")
data_vdw = [[Paragraph(c, hdr_ps3 if i==0 else body_ps3) for c in r] for i,r in enumerate(rows_vdw)]
t = Table(data_vdw, colWidths=[CONTENT_W*0.25, CONTENT_W*0.21, CONTENT_W*0.30, CONTENT_W*0.24])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_NAVY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [C_LBLUE, C_ALT]),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("INNERGRID", (0,0),(-1,-1), 0.3, C_BLUE),
("BOX", (0,0),(-1,-1), 0.6, C_NAVY),
]))
el.append(t)
el.append(Spacer(1,6))
el.append(key_points_box([
"Strength order: Hydrogen Bond > Dipole-Dipole > London forces",
"London forces present in ALL molecules (polar + non-polar)",
"London forces increase with: larger molecule, more electrons, greater polarisability",
"BP of noble gases: He < Ne < Ar < Kr < Xe (London forces increase with size)",
"Branched alkanes have lower BP than straight chain (less surface area → weaker London forces)",
"n-pentane > isopentane > neopentane in BP (decreasing surface area)",
], tip="London forces: all molecules. Dipole-dipole: polar molecules. H-bond: only F,O,N with H. Strength: H-bond > dipole-dipole > London."))
el.append(Spacer(1,6))
el.append(faq_box([
("Why do noble gases exist as monoatomic gases at room temperature?",
"Noble gases have only London (dispersion) forces between atoms – these are very weak. The forces are too weak to hold atoms together as liquids/solids at room temperature."),
("Why does boiling point increase: CH₄ < C₂H₆ < C₃H₈ < C₄H₁₀?",
"All are non-polar, so only London forces act. Molar mass increases → more electrons → greater polarisability → stronger temporary dipoles → stronger London forces → higher BP."),
]))
def s10(el): # Quick Revision & Mega FAQ
el.append(Paragraph("<b>Master Comparison Table</b>", h2_s))
el.append(values_table([
("Bond type / property", "Key fact"),
("Ionic bond", "Transfer of e⁻; NaCl, MgO; high MP/BP"),
("Covalent bond", "Sharing of e⁻; H₂, CO₂; can be non-polar"),
("Coordinate bond", "One atom donates both e⁻; NH₄⁺, H₃O⁺"),
("σ bond", "Head-on overlap; rotation allowed; stronger"),
("π bond", "Lateral overlap; NO rotation; part of double/triple bond"),
("Hybridisation sp", "Linear, 180°, 50% s-char; BeCl₂, C₂H₂"),
("Hybridisation sp²", "Trigonal planar, 120°, 33% s-char; BF₃, C₂H₄"),
("Hybridisation sp³", "Tetrahedral, 109.5°, 25% s-char; CH₄"),
("Bond order (MO)", "(Nb−Na)/2; higher = shorter + stronger bond"),
("O₂ magnetic nature", "PARAMAGNETIC (2 unpaired e⁻ in π*2p)"),
("N₂ bond order", "3 (most stable diatomic)"),
("H₂O dipole moment", "1.85 D (bent shape, polar)"),
("CO₂ dipole moment", "0 D (linear, non-polar)"),
("H-bond strongest", "F−H···F > O−H···O > N−H···N"),
("Fajan's rule", "Small cation + large anion = more covalent"),
("Octet exception (less)", "Be (4), B (6) – incomplete octet"),
("Octet exception (more)", "P,S,Cl (10,12,14) – expanded octet"),
]))
el.append(Spacer(1,8))
el.append(faq_box([
("Which of the following has maximum bond angle: H₂O, H₂S, H₂Se?",
"H₂O (104.5°) > H₂S (92°) > H₂Se (91°). As we go down group 16, central atom is larger, p-orbital used for bonding with less hybridisation, so bond angle decreases toward 90°."),
("Why does BF₃ not satisfy the octet rule yet is stable?",
"B has only 6 electrons in BF₃ (incomplete octet). It is stabilised by back-donation of lone pairs from F into empty p orbital of B (pπ–pπ back bonding), making B−F bonds shorter than expected."),
("Which is more stable: O₂ or O₂⁺?",
"O₂⁺ has bond order 2.5 vs O₂ bond order 2. O₂⁺ is more stable (higher bond order = shorter, stronger bond)."),
("Explain why H₂O has a higher boiling point than H₂S.",
"H₂O forms strong intermolecular H-bonds (O is small and highly EN, so strong X-H···O bonds). H₂S cannot form H-bonds (S is not small/EN enough) → only weak van der Waals forces → much lower BP."),
("What is the structure of PCl₅ in solid state?",
"In solid state, PCl₅ exists as ionic [PCl₄]⁺[PCl₆]⁻. PCl₄⁺ is tetrahedral and PCl₆⁻ is octahedral."),
("Why is NH₃ a better Lewis base than NF₃?",
"In NH₃, the lone pair on N is readily available for donation (H is less EN than N → doesn't withdraw electron density). In NF₃, F (highly EN) withdraws electron density from N, reducing availability of lone pair → NF₃ is a weaker Lewis base."),
("Arrange CCl₄, CHCl₃, CH₂Cl₂, CH₃Cl in order of increasing dipole moment.",
"CCl₄(0D) < CH₃Cl(1.87D): actually order is CCl₄(0) < CHCl₃ < CH₂Cl₂ < CH₃Cl. Wait – correct order: CCl₄=0 < CH₃Cl≈1.87D > CH₂Cl₂≈1.60D > CHCl₃≈1.15D. So: CCl₄(0) < CHCl₃(1.15) < CH₂Cl₂(1.60) < CH₃Cl(1.87)."),
("What are isoelectronic species? Give examples.",
"Species with same number of electrons and same structure. Examples: N₂ and CO (14e); NO⁺ and N₂ and CO; CO₃²⁻, NO₃⁻, SO₃ (all trigonal planar, 24e); NH₄⁺ and CH₄ (10e, tetrahedral); H₂O and F⁻...OH⁻."),
]))
# ═══════════════════════════════════════════════════════════════════════════════
# ASSEMBLE PDF
# ═══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
rightMargin=RMARGIN, leftMargin=LMARGIN,
topMargin=2*cm, bottomMargin=2*cm
)
elements = []
# Cover
elements.append(Spacer(1, 0.2*cm))
elements.append(Paragraph("CHEMICAL BONDING", title_s))
elements.append(Paragraph("& MOLECULAR STRUCTURE", title_s))
elements.append(Spacer(1,4))
elements.append(Paragraph(
"Complete Notes + Key Points + Important Topics + Frequently Asked Questions",
sub_s))
elements.append(Paragraph("Class 11 Chemistry | NCERT + JEE Main + JEE Advanced + NEET", sub_s))
elements.append(HRFlowable(width="100%", thickness=2.5, color=C_NAVY))
elements.append(Spacer(1, 0.2*cm))
elements.append(Paragraph(
"<b>Topics Covered:</b> Kossel-Lewis / Octet Rule • Ionic Bonding • Covalent Bonding & Lewis Structures "
"• VSEPR Theory • Hybridisation (VBT) • MO Theory • Polarity & Dipole Moment "
"• Hydrogen Bonding • Intermolecular Forces • Mega Revision & FAQs",
ps("COV", fontSize=9, fontName="Helvetica", textColor=C_GREY, leading=14, spaceAfter=4)))
elements.append(Spacer(1, 0.2*cm))
sec_defs = [
("1. Kossel-Lewis Approach & Octet Rule", s1),
("2. Ionic Bonding & Lattice Energy", s2),
("3. Covalent Bonding, Lewis Structures & Resonance", s3),
("4. VSEPR Theory – Molecular Shapes", s4),
("5. Valence Bond Theory & Hybridisation", s5),
("6. Molecular Orbital (MO) Theory", s6),
("7. Polarity & Dipole Moment", s7),
("8. Hydrogen Bonding", s8),
("9. Intermolecular Forces (Van der Waals)", s9),
("10. Mega Revision Table & Master FAQs", s10),
]
for title, fn in sec_defs:
add_section(elements, title, fn)
# Footer
elements.append(HRFlowable(width="100%", thickness=1.5, color=C_NAVY))
elements.append(Spacer(1, 0.1*cm))
elements.append(Paragraph(
"Class 11 Chemistry | Chemical Bonding & Molecular Structure | NCERT + JEE + NEET",
ps("FT", fontSize=9, textColor=C_GREY, fontName="Helvetica", alignment=TA_CENTER)))
doc.build(elements)
print(f"✅ PDF generated: {OUTPUT}")
Failed to create session: bad request: failed to resolve container IP after 3 attempts: no IP address found. Is the Sandbox started?
We encountered an error while processing your request. Please try again or reach out to us for help.
Chemical bonding notes on each and every topic and important topics and mostly or frequently asked questions plssss
mkdir -p /home/daytona/workspace/chemical-bonding && echo "dir ready"
~/chemical-bonding/generate_cb_pdf.py
"""
Chemical Bonding & Molecular Structure – Class 11 Chemistry
Complete Notes + Key Points + Important Topics + FAQs PDF
"""
import os, io
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["mathtext.fontset"] = "cm"
rcParams["font.family"] = "serif"
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
W, H = A4
LM = 1.7*cm; RM = 1.7*cm
CW = W - LM - RM
OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11.pdf"
# colours
CN = colors.HexColor("#0d1b5e") # navy
CB = colors.HexColor("#1565c0") # blue
CLB = colors.HexColor("#e3f2fd") # light blue
CAL = colors.HexColor("#f0f4ff") # alternate
CGN = colors.HexColor("#1b5e20") # green
CGB = colors.HexColor("#e8f5e9") # green bg
CRD = colors.HexColor("#b71c1c") # red
CRB = colors.HexColor("#ffebee") # red bg
CAM = colors.HexColor("#e65100") # amber
CAB = colors.HexColor("#fff8e1") # amber bg
CTL = colors.HexColor("#004d40") # teal
CTB = colors.HexColor("#e0f2f1") # teal bg
CPU = colors.HexColor("#4a148c") # purple
CPB = colors.HexColor("#f3e5f5") # purple bg
CGR = colors.HexColor("#37474f") # grey
SS = getSampleStyleSheet()
def ps(name, **kw):
return ParagraphStyle(name, parent=SS["Normal"], **kw)
ttl_s = ps("T", fontSize=22, textColor=CN, fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=3)
sub_s = ps("S", fontSize=10, textColor=CGR, fontName="Helvetica", alignment=TA_CENTER, spaceAfter=8)
h2_s = ps("H2", fontSize=11, textColor=CN, fontName="Helvetica-Bold", spaceAfter=3, spaceBefore=5)
bd_s = ps("BD", fontSize=9.5, fontName="Helvetica", textColor=colors.HexColor("#212121"), spaceAfter=3, leading=14)
nt_s = ps("NT", fontSize=8.5, textColor=CGR, fontName="Helvetica-Oblique", spaceAfter=2, leftIndent=5)
kp_s = ps("KP", fontSize=9, textColor=CGN, fontName="Helvetica", spaceAfter=2, leftIndent=8, leading=13)
kph_s = ps("KH", fontSize=10, textColor=CGN, fontName="Helvetica-Bold", spaceAfter=3)
im_s = ps("IM", fontSize=9, textColor=CRD, fontName="Helvetica-Bold", spaceAfter=2, leftIndent=8)
imh_s = ps("IH", fontSize=10, textColor=CRD, fontName="Helvetica-Bold", spaceAfter=3)
fq_s = ps("FQ", fontSize=9.5, textColor=CPU, fontName="Helvetica-Bold", spaceAfter=2, leftIndent=4)
fa_s = ps("FA", fontSize=9, textColor=colors.HexColor("#212121"), fontName="Helvetica", spaceAfter=5, leftIndent=12, leading=13)
fh_s = ps("FH", fontSize=10, textColor=CPU, fontName="Helvetica-Bold", spaceAfter=4)
tp_s = ps("TP", fontSize=9, textColor=CAM, fontName="Helvetica-Bold", spaceAfter=0)
fn_s = ps("FL", fontSize=9.5, textColor=CN, fontName="Helvetica-Bold", spaceAfter=2)
# ── math formula renderer ────────────────────────────────────────────────────
def render(latex, fs=13, dpi=180):
try:
fig = plt.figure(figsize=(0.01,0.01))
t = fig.text(0,0,f"${latex}$",fontsize=fs,color="#b71c1c",ha="left",va="bottom")
fig.canvas.draw()
bb = t.get_window_extent(renderer=fig.canvas.get_renderer())
plt.close(fig)
pad=6
fw=max((bb.width+pad*2)/dpi,0.5); fh=max((bb.height+pad*2)/dpi,0.3)
fig2,ax=plt.subplots(figsize=(fw,fh)); ax.set_axis_off(); fig2.patch.set_alpha(0)
fig2.text(pad/dpi/fw,pad/dpi/fh,f"${latex}$",fontsize=fs,color="#b71c1c",
ha="left",va="bottom",transform=fig2.transFigure)
buf=io.BytesIO()
fig2.savefig(buf,format="png",dpi=dpi,transparent=True,bbox_inches="tight",pad_inches=0.04)
plt.close(fig2); buf.seek(0)
iw=fw*72; ih=fh*72; sc=min(1.0,(CW-20)/iw)
return RLImage(buf,width=iw*sc,height=ih*sc)
except:
plt.close("all"); return Paragraph(f"[formula]",nt_s)
# ── layout helpers ────────────────────────────────────────────────────────────
def banner(title):
t=Table([[Paragraph(f" {title}",ps("SB",fontSize=12,textColor=colors.white,
fontName="Helvetica-Bold",leading=16))]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CB),
("TOPPADDING",(0,0),(-1,-1),7),("BOTTOMPADDING",(0,0),(-1,-1),7),
("LEFTPADDING",(0,0),(-1,-1),8)]))
return t
def fblock(label,latex,note=""):
img=render(latex)
cell=[Paragraph(f"<b>{label}</b>",fn_s),img]
if note: cell.append(Paragraph(f"▸ {note}",nt_s))
t=Table([[cell]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CLB),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.5,CB)]))
return KeepTogether(t)
def kbox(points,tip=None):
c=[Paragraph("★ Key Points",kph_s)]
for p in points: c.append(Paragraph(f"• {p}",kp_s))
if tip: c.append(Spacer(1,3)); c.append(Paragraph(f"💡 Tip: {tip}",tp_s))
t=Table([[c]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CGB),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CGN)]))
return KeepTogether(t)
def ibox(points,heading="⚠ Important / Exam Points"):
c=[Paragraph(f"<b>{heading}</b>",imh_s)]
for p in points: c.append(Paragraph(f"★ {p}",im_s))
t=Table([[c]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CRB),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CRD)]))
return KeepTogether(t)
def faqbox(qas):
c=[Paragraph("❓ Frequently Asked Questions",fh_s)]
for q,a in qas:
c.append(Paragraph(f"Q: {q}",fq_s))
c.append(Paragraph(f"Ans: {a}",fa_s))
t=Table([[c]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CPB),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CPU)]))
return KeepTogether(t)
def notebox(text,hd="📝 Note"):
c=[Paragraph(f"<b>{hd}</b>",ps("NH",fontSize=9.5,fontName="Helvetica-Bold",
textColor=CTL,spaceAfter=2)),
Paragraph(text,ps("NB",fontSize=9,fontName="Helvetica",textColor=CTL,leading=13))]
t=Table([[c]],colWidths=[CW])
t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),CTB),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.7,CTL)]))
return KeepTogether(t)
def vtable(rows):
hdr=[Paragraph(f"<b>{c}</b>",ps(f"VH{i}",fontSize=8.5,fontName="Helvetica-Bold",
textColor=colors.white)) for i,c in enumerate(rows[0])]
data=[hdr]
for r in rows[1:]:
data.append([Paragraph(str(x),ps(f"VC{i}",fontSize=8.5,fontName="Helvetica"))
for i,x in enumerate(r)])
cws=[CW/len(rows[0])]*len(rows[0])
t=Table(data,colWidths=cws)
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),CN),("ROWBACKGROUNDS",(0,1),(-1,-1),[CLB,CAL]),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("INNERGRID",(0,0),(-1,-1),0.3,CB),
("BOX",(0,0),(-1,-1),0.6,CN)]))
return t
def vtable2(rows): # 2-col key-value
hdr=[Paragraph("<b>Item</b>",ps("VH2a",fontSize=8.5,fontName="Helvetica-Bold",textColor=colors.white)),
Paragraph("<b>Value / Detail</b>",ps("VH2b",fontSize=8.5,fontName="Helvetica-Bold",textColor=colors.white))]
data=[hdr]
for k,v in rows:
data.append([Paragraph(k,ps("VK",fontSize=8.5,fontName="Helvetica")),
Paragraph(v,ps("VV",fontSize=8.5,fontName="Helvetica-Bold",textColor=CN))])
t=Table(data,colWidths=[CW*0.46,CW*0.54])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),CN),("ROWBACKGROUNDS",(0,1),(-1,-1),[CLB,CAL]),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),5),("INNERGRID",(0,0),(-1,-1),0.3,CB),
("BOX",(0,0),(-1,-1),0.6,CN)]))
return t
sp = lambda h=0.12: Spacer(1,h*cm)
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION CONTENT FUNCTIONS
# ═══════════════════════════════════════════════════════════════════════════════
def sec1(el):
el.append(Paragraph("Chemical bonds form to achieve stability (noble gas configuration). Lewis proposed shared electron pairs; Kossel linked bond formation to noble gas shells.",bd_s))
el.append(sp(0.3))
el.append(Paragraph("<b>Types of Bonds:</b>",h2_s))
el.append(vtable([
("Bond Type","How Formed","Example"),
("Ionic","Transfer of e⁻ (metal→non-metal)","NaCl, MgO, CaF₂, K₂O"),
("Covalent","Sharing of e⁻ (non-metal + non-metal)","H₂, Cl₂, H₂O, CO₂, CH₄"),
("Coordinate/Dative","Both e⁻ donated by ONE atom (lone pair)","NH₄⁺, H₃O⁺, BF₃·NH₃"),
("Hydrogen Bond","Electrostatic: X−H···Y (X,Y = F,O,N)","H₂O, HF, NH₃, DNA"),
]))
el.append(sp(0.3))
el.append(fblock("Formal Charge",
r"FC = V - L - \frac{B}{2}",
"V=valence e⁻, L=lone pair e⁻, B=bond pair e⁻; most stable structure has lowest FC"))
el.append(sp(0.2))
el.append(kbox([
"Octet rule: atoms react to have 8 electrons in valence shell (2 for H, Li = duplet)",
"Exceptions – Incomplete octet: BeCl₂ (Be has 4e), BCl₃ / BF₃ (B has 6e)",
"Exceptions – Expanded octet: PCl₅ (P=10e), SF₆ (S=12e), IF₇ (I=14e) using 3d orbitals",
"Exceptions – Odd electron molecules: NO, NO₂, ClO₂ (unpaired electron present)",
"Best Lewis structure = lowest formal charges + negative FC on more electronegative atom",
"Electronegativity order: F > O > Cl > N > Br > I > S > C > H",
], tip="BCl₃ has 6e on B (incomplete octet), PCl₅ has 10e on P (expanded octet). These are the top exam picks."))
el.append(sp(0.2))
el.append(faqbox([
("What is the octet rule? Give 3 exceptions with examples.",
"Atoms bond to achieve 8e in outermost shell. Exceptions: (1) Incomplete octet – BeCl₂ (4e on Be), BCl₃ (6e on B); (2) Expanded octet – PCl₅ (10e on P), SF₆ (12e on S); (3) Odd-electron – NO, NO₂."),
("What is a coordinate bond? Give 2 examples.",
"A bond where BOTH electrons are donated by one atom (the donor/Lewis base). Examples: NH₄⁺ (N donates lone pair to H⁺), H₃O⁺ (O donates to H⁺), BF₃·NH₃ (N→B)."),
("Calculate FC of N in NH₃ and NO₃⁻.",
"NH₃: N has V=5, L=2 (one lone pair), B=6 (3 bonds×2). FC = 5−2−3 = 0. In NO₃⁻: N has V=5, L=0, B=8. FC = 5−0−4 = +1."),
]))
def sec2(el):
el.append(Paragraph("Ionic bonds form by complete e⁻ transfer from metal (low IE) to non-metal (high EA), creating oppositely charged ions held by electrostatic attraction.",bd_s))
el.append(sp(0.2))
el.append(fblock("Lattice Energy Proportionality",
r"\Delta H_{lattice} \propto \frac{z^{+} \cdot z^{-}}{r^{+}+r^{-}}",
"z = ionic charges; r = ionic radii; higher charge & smaller size → stronger lattice"))
el.append(sp(0.2))
el.append(kbox([
"Lattice energy = energy released when 1 mole of ionic solid forms from gaseous ions",
"Born-Haber cycle (Hess's law): ΔHf = ΔHsub + IE + ½ΔHdiss(X₂) + EA + ΔHlattice",
"Ionic bond favoured by: low IE (metal), high EA (non-metal), high lattice energy",
"Properties of ionic compounds: high MP/BP, brittle, conduct in molten/aqueous state, soluble in polar solvents",
"Fajan's Rules: covalent character ↑ when (1) cation is SMALL & HIGHLY charged, (2) anion is LARGE & HIGHLY charged",
"Fajan's polarising power of cation ∝ charge/radius² (ionic potential)",
"Covalent character order: LiI > LiBr > LiCl > LiF (I⁻ largest → most polarisable)",
"AgCl, AgBr, AgI show more covalent character than NaCl (Ag⁺ is more polarising than Na⁺)",
"Lattice energy order: MgO > CaO > MgCl₂ > NaCl > KCl (higher charge + smaller size wins)",
], tip="Fajan's: small cation + large anion + high charge = more covalent. LiI is most covalent among lithium halides."))
el.append(sp(0.2))
el.append(ibox([
"MgO has much higher lattice energy than NaCl (2+/2− vs 1+/1− charges → 4× electrostatic force)",
"NaF > NaCl > NaBr > NaI in lattice energy (F⁻ is smallest → closer to Na⁺)",
"KF has ionic character but KI has significant covalent character (Fajan's)",
"Higher lattice energy → higher melting point (MgO MP ~2852°C vs NaCl MP ~801°C)",
]))
el.append(sp(0.2))
el.append(faqbox([
("What are Fajan's rules? How do they explain covalent character in ionic compounds?",
"Fajan's rules state that covalent character in an ionic bond increases when: (1) the cation is small and/or highly charged → high polarising power; (2) the anion is large and/or highly charged → high polarisability. A small, highly charged cation distorts (polarises) the electron cloud of the anion, creating partial covalent character."),
("Arrange in increasing order of lattice energy: NaCl, MgO, NaF, CaO.",
"NaCl < NaF < CaO < MgO. NaF > NaCl because F⁻ < Cl⁻ (smaller → closer). CaO and MgO have 2+/2− charges (much stronger). MgO > CaO because Mg²⁺ < Ca²⁺."),
("Why does NaCl conduct electricity in molten state but not in solid state?",
"In solid NaCl, Na⁺ and Cl⁻ are fixed in a rigid crystal lattice → cannot move → no conduction. On melting, ions become mobile → can carry charge → conducts electricity."),
]))
def sec3(el):
el.append(Paragraph("Covalent bonds form by sharing of electron pairs. Each shared pair = one bond. Lewis structures show all bonding and lone pairs.",bd_s))
el.append(sp(0.2))
el.append(Paragraph("<b>Bond Order, Length & Strength Comparison:</b>",h2_s))
el.append(vtable2([
("Bond", "Length / Strength"),
("C−C (single)", "154 pm | Weakest C−C"),
("C=C (double)", "134 pm | Stronger"),
("C≡C (triple)", "120 pm | Strongest, shortest"),
("N−N", "145 pm"),
("N=N", "125 pm"),
("N≡N", "110 pm (highest bond dissoc. energy ~945 kJ/mol)"),
("H−H", "74 pm"),
("O=O", "121 pm"),
("O−O (single)", "148 pm"),
("Bond order ↑", "Bond length ↓, Bond energy ↑"),
]))
el.append(sp(0.25))
el.append(kbox([
"Multiple bonds: double = 1σ+1π; triple = 1σ+2π",
"Resonance: when one Lewis structure cannot fully represent a molecule",
"Resonance structures differ only in position of electrons, NOT atoms",
"The actual structure (resonance hybrid) is more stable than any single resonance form",
"Resonance energy = extra stability of hybrid over best single structure",
"Resonance energy of benzene ≈ 150 kJ/mol",
"O₃: O−O bond length = 127.8 pm (intermediate between single 148 pm and double 121 pm)",
"Bond order in O₃ = 1.5 (1 single + 1 double → average = 1.5)",
"CO₃²⁻, NO₃⁻, SO₃ all have 3 equivalent resonance structures (trigonal planar)",
"Steps for Lewis structure: count total valence e⁻ → connect with single bonds → complete octets → form multiple bonds if needed",
], tip="Count σ bonds = all single bonds + 1 per multiple bond. Count π = 1 per double bond + 2 per triple bond."))
el.append(sp(0.2))
el.append(ibox([
"O₃ shows resonance – bond length is 127.8 pm (between single and double)",
"C₆H₆ (benzene) resonance: all C−C bonds are equal (139 pm, between single 154 and double 134)",
"Resonance does NOT mean the molecule flips between structures – the hybrid exists ALL the time",
"In CO₂: 2 σ + 2 π bonds; no lone pairs on C, two lone pairs on each O",
]))
el.append(sp(0.2))
el.append(faqbox([
("What is resonance? Give two examples.",
"When a molecule/ion cannot be represented by a single Lewis structure and two or more structures (differing only in electron arrangement) contribute equally to the true structure. Examples: O₃ (O=O−O ↔ O−O=O), CO₃²⁻ (three equivalent structures), benzene C₆H₆ (Kekulé structures)."),
("How many σ and π bonds in CH₂=CH−C≡CH?",
"C−H bonds: 4σ. C−C single bond: 1σ. C=C: 1σ+1π. C≡C: 1σ+2π. Total: σ = 4+1+1+1 = 7 (wait, count again: 3 CH₂ H's=2, 1 CH, 1 C≡CH). Let's count systematically: CH₂(2H)=2σ, CH(1H)=1σ, C≡C-H(1H)=1σ, total C-H=4σ; C-C single=1σ; C=C: 1σ+1π; C≡C: 1σ+2π. Grand total: σ=8, π=3."),
("What is the bond order of O₃ and why?",
"O₃ has two resonance structures with one O=O and one O−O. The actual bond order = (1+2)/2 = 1.5. Both O−O bonds are equivalent and intermediate in length (127.8 pm) and strength."),
]))
def sec4(el):
el.append(Paragraph("VSEPR theory predicts molecular shape based on repulsion between electron pairs (BP + LP) around the central atom. Lone pairs cause more repulsion than bond pairs.",bd_s))
el.append(sp(0.2))
el.append(notebox("Repulsion order: lp−lp > lp−bp > bp−bp","⚡ Repulsion Hierarchy (Must Remember)"))
el.append(sp(0.2))
el.append(Paragraph("<b>Molecular Shapes (BP=Bond Pairs, LP=Lone Pairs):</b>",h2_s))
rows=[
("BP","LP","Geometry","Bond Angle","Examples"),
("2","0","Linear","180°","BeCl₂, CO₂, CS₂, HCN"),
("3","0","Trigonal Planar","120°","BF₃, BCl₃, SO₃, NO₃⁻"),
("2","1","Bent / V-shape","<120°","SO₂(~119°), O₃, NO₂⁻"),
("4","0","Tetrahedral","109.5°","CH₄, CCl₄, SiCl₄, NH₄⁺"),
("3","1","Trigonal Pyramidal","107°","NH₃, PH₃, PCl₃"),
("2","2","Bent / V-shape","104.5°","H₂O, H₂S, OF₂"),
("5","0","Trigonal Bipyramidal","90°/120°","PCl₅, PF₅"),
("4","1","See-saw","<90°/<120°","SF₄, XeO₂F₂"),
("3","2","T-shaped","<90°","ClF₃, BrF₃"),
("2","3","Linear","180°","XeF₂, I₃⁻, IF₂⁻"),
("6","0","Octahedral","90°","SF₆, PCl₆⁻, [Co(NH₃)₆]³⁺"),
("5","1","Square Pyramidal","<90°","BrF₅, IF₅, XeOF₄"),
("4","2","Square Planar","90°","XeF₄, ICl₄⁻, [PtCl₄]²⁻"),
]
hp=ps("VS",fontSize=8,fontName="Helvetica-Bold",textColor=colors.white)
bp=ps("VB",fontSize=8,fontName="Helvetica")
data=[[Paragraph(c,hp if i==0 else bp) for c in r] for i,r in enumerate(rows)]
t=Table(data,colWidths=[CW*0.08,CW*0.07,CW*0.24,CW*0.19,CW*0.42])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),CN),("ROWBACKGROUNDS",(0,1),(-1,-1),[CLB,CAL]),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("INNERGRID",(0,0),(-1,-1),0.3,CB),
("BOX",(0,0),(-1,-1),0.6,CN)]))
el.append(t)
el.append(sp(0.2))
el.append(kbox([
"Bond angle order (for group 15 hydrides): NH₃(107°) > PH₃(93.5°) > AsH₃(91.8°) > SbH₃(91.3°)",
"Bond angle order (for group 16 hydrides): H₂O(104.5°) > H₂S(92°) > H₂Se(91°) > H₂Te(90°)",
"As we go down a group: central atom is larger → more p-character in bonding → angle approaches 90°",
"PCl₅ (trigonal bipyramidal): axial bonds (90°) are longer and weaker than equatorial bonds (120°)",
"In SF₄ (see-saw): lone pair occupies equatorial position (less repulsion)",
"XeF₄ (square planar): 2 lone pairs both axial (trans to each other) → dipoles cancel → non-polar",
"XeF₂ (linear): 3 lone pairs in equatorial positions, 2 F axial",
"Double bonds take more space than single bonds in VSEPR (count as one BP but repel more)",
"NO₂ (117°) > NO₂⁻ (115°): more bonding electrons in NO₂ expand angle vs lone pair in NO₂⁻",
], tip="For VSEPR: Total electron pairs = BP + LP. Lone pairs always occupy equatorial positions in TBP geometry to minimise 90° repulsions."))
el.append(sp(0.2))
el.append(ibox([
"H₂O = bent (104.5°), NOT linear; NH₃ = trigonal pyramidal, NOT planar",
"CO₂ linear (no LP on C); SO₂ bent (1 LP on S) — very common exam trap!",
"XeF₄ is square planar and NON-POLAR (symmetric, lone pairs cancel)",
"PCl₅ in solid state exists as [PCl₄]⁺[PCl₆]⁻ (tetrahedral cation + octahedral anion)",
"I₃⁻ is linear (3 LP + 2 BP on central I) — don't confuse with trigonal",
]))
el.append(sp(0.2))
el.append(faqbox([
("Why is bond angle of H₂O (104.5°) less than NH₃ (107°)?",
"H₂O has 2 lone pairs and NH₃ has 1 lone pair on the central atom. Lone pair repulsion is greater in H₂O → compresses bond angle more. lp−lp repulsion (in H₂O) > lp−bp repulsion (in NH₃)."),
("Arrange in increasing bond angle: H₂O, NH₃, CH₄, BF₃.",
"H₂O(104.5°) < NH₃(107°) < CH₄(109.5°) < BF₃(120°)."),
("What is the shape and polarity of XeF₄?",
"XeF₄: 4 BP + 2 LP → octahedral electron geometry → square planar molecular shape. The 2 lone pairs are trans (axial) to each other. All 4 Xe−F dipoles cancel symmetrically → XeF₄ is NON-POLAR."),
("Predict the shape of ClF₃ and explain why it is T-shaped.",
"Cl in ClF₃: 3 BP + 2 LP → 5 electron pairs → trigonal bipyramidal base. The 2 lone pairs occupy equatorial positions (less 90° repulsions with bond pairs). So 3 F atoms: 2 axial + 1 equatorial → T-shape. Bond angles slightly less than 90°."),
]))
def sec5(el):
el.append(Paragraph("VBT: a bond forms when half-filled orbitals overlap. Hybridisation mixes atomic orbitals to form equivalent hybrid orbitals with specific geometry.",bd_s))
el.append(sp(0.2))
el.append(fblock("Hybridisation Number",
r"\text{Hyb. No.} = \frac{1}{2}(V + M - C + A)",
"V=valence e⁻ of central atom, M=monovalent atoms bonded, C=cationic charge, A=anionic charge"))
el.append(sp(0.2))
el.append(Paragraph("<b>Hybridisation Reference Table:</b>",h2_s))
rows=[
("Hybridisation","Orbitals","Shape","Bond Angle","s-char%","Examples"),
("sp","s + p","Linear","180°","50%","BeCl₂, C₂H₂, HCN, CO₂, NO₂⁺"),
("sp²","s + 2p","Trig. Planar","120°","33%","BF₃, C₂H₄, SO₃, NO₂, C₆H₆, graphite"),
("sp³","s + 3p","Tetrahedral","109.5°","25%","CH₄, NH₃, H₂O, CCl₄, diamond"),
("sp³d","s+3p+d","Trig. Bipyramidal","90°/120°","20%","PCl₅, SF₄, ClF₃, XeF₂"),
("sp³d²","s+3p+2d","Octahedral","90°","16.7%","SF₆, XeF₄, PCl₆⁻, IF₅"),
("sp³d³","s+3p+3d","Pent. Bipyramidal","72°/90°","14.3%","IF₇"),
]
hp2=ps("HS",fontSize=7.5,fontName="Helvetica-Bold",textColor=colors.white)
bp2=ps("HB",fontSize=7.5,fontName="Helvetica")
data2=[[Paragraph(c,hp2 if i==0 else bp2) for c in r] for i,r in enumerate(rows)]
t=Table(data2,colWidths=[CW*0.14,CW*0.14,CW*0.18,CW*0.15,CW*0.1,CW*0.29])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),CN),("ROWBACKGROUNDS",(0,1),(-1,-1),[CLB,CAL]),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),4),("INNERGRID",(0,0),(-1,-1),0.3,CB),
("BOX",(0,0),(-1,-1),0.6,CN)]))
el.append(t)
el.append(sp(0.2))
el.append(kbox([
"σ (sigma) bond: head-on overlap along internuclear axis; stronger; free rotation possible",
"π (pi) bond: lateral (sideways) overlap of p orbitals; weaker; NO free rotation",
"Single bond = 1σ only. Double bond = 1σ + 1π. Triple bond = 1σ + 2π",
"More s-character → shorter & stronger bond → more electronegative carbon",
"s-character: sp=50% > sp²=33% > sp³=25% → bond angle & strength follow same order",
"Carbon hybridisations: diamond=sp³, graphite=sp², fullerene C₆₀=sp²",
"NH₃ = sp³ (107°, 1 LP); H₂O = sp³ (104.5°, 2 LP) — hybridisation same but angles differ",
"In C₂H₄: each C is sp², double bond = 1σ(sp²−sp²) + 1π(p−p)",
"In C₂H₂: each C is sp, triple bond = 1σ(sp−sp) + 2π(p−p)",
"Back bonding in BF₃: F lone pair → empty p of B (pπ−pπ) → B−F shorter than expected",
"Hybridisation not applicable to molecules explained by MO theory (like O₂)",
], tip="Hyb. No. formula: for CH₄ = ½(4+4)=4 → sp³. For BF₃ = ½(3+3)=3 → sp². For PCl₅ = ½(5+5)=5 → sp³d."))
el.append(sp(0.2))
el.append(ibox([
"C₂H₄ has restricted rotation due to π bond → cis/trans isomerism possible",
"Allene (CH₂=C=CH₂): central C is sp (linear), end C atoms are sp² — interesting geometry",
"NO₂ (sp², 117°), NO₂⁺ (sp, 180°, no LP), NO₂⁻ (sp², 115°, 1 LP) — very important series",
"H₂O and NH₃ both sp³ but bond angles differ due to different number of lone pairs",
"In PCl₅: equatorial bonds (sp²-like) shorter than axial bonds (p-like)",
]))
el.append(sp(0.2))
el.append(faqbox([
("What is the hybridisation of N in NO₂, NO₂⁺, and NO₂⁻?",
"NO₂: sp² (bent, ~117°, 1 odd electron in hybrid orbital). NO₂⁺: sp (linear, 180°, no lone pair/odd electron). NO₂⁻: sp² (bent, ~115°, 1 lone pair on N)."),
("Hybridisation of C in: CH₄, C₂H₄, C₂H₂, C₆H₆, CO₂.",
"CH₄: sp³ | C₂H₄: sp² | C₂H₂: sp | C₆H₆: sp² | CO₂: sp (central C, linear)."),
("Why can't free rotation occur around a C=C double bond?",
"The π bond in C=C is formed by lateral overlap of p orbitals above and below the σ bond axis. Rotation would break this sideways overlap → requires ~250 kJ/mol energy (the π bond energy). At room temp, this energy is unavailable → rotation is restricted → cis/trans isomers are stable."),
("What is the hybridisation of S in SO₂ and SO₃?",
"SO₂: S is sp² hybridised (2 S=O bonds + 1 lone pair on S → bent shape). SO₃: S is sp² hybridised (3 S=O bonds, no lone pair → trigonal planar, non-polar)."),
]))
def sec6(el):
el.append(Paragraph("MO Theory: atomic orbitals combine to form molecular orbitals (MOs) that belong to the whole molecule. Bonding MOs (BMO) are lower energy; antibonding MOs (ABMO) are higher energy.",bd_s))
el.append(sp(0.2))
el.append(fblock("Bond Order (MO Theory)",
r"\text{Bond Order} = \frac{N_b - N_a}{2}",
"Nb = electrons in bonding MOs, Na = electrons in antibonding MOs; BO > 0 → molecule exists"))
el.append(sp(0.2))
el.append(notebox(
"For B₂, C₂, N₂: σ1s < σ*1s < σ2s < σ*2s < π2p = π2p < σ2p < π*2p = π*2p < σ*2p\n"
"For O₂, F₂: σ1s < σ*1s < σ2s < σ*2s < σ2p < π2p = π2p < π*2p = π*2p < σ*2p\n"
"(Key difference: π2p fills BEFORE σ2p in B₂, C₂, N₂ due to s-p orbital mixing)",
"⚡ MO Energy Order (Critical!)"))
el.append(sp(0.2))
el.append(Paragraph("<b>MO Data Table for Common Diatomic Species:</b>",h2_s))
rows=[
("Species","e⁻","BMO config (simplified)","Bond Order","Magnetic","Notes"),
("H₂","2","σ1s²","1","Diamagnetic","Stable"),
("H₂⁺","1","σ1s¹","0.5","Paramagnetic","Stable"),
("H₂⁻","3","σ1s² σ*1s¹","0.5","Paramagnetic","Stable"),
("He₂","4","σ1s² σ*1s²","0","–","Does NOT exist"),
("He₂⁺","3","σ1s² σ*1s¹","0.5","Paramagnetic","Exists"),
("Li₂","6","...σ2s²","1","Diamagnetic","Stable"),
("B₂","10","...π2p¹π2p¹","1","Paramagnetic","Hund's rule in π"),
("C₂","12","...π2p²π2p²","2","Diamagnetic","Stable"),
("N₂","14","...σ2p²","3","Diamagnetic","Most stable, BO=3"),
("N₂⁺","13","...σ2p¹","2.5","Paramagnetic","Less stable than N₂"),
("O₂","16","...π*2p¹π*2p¹","2","Paramagnetic","2 unpaired e⁻ in π*"),
("O₂⁺","15","...π2p⁴ π*2p¹","2.5","Paramagnetic","More stable than O₂"),
("O₂⁻","17","...π*2p² π*2p¹","1.5","Paramagnetic","Superoxide ion"),
("O₂²⁻","18","...π*2p² π*2p²","1","Diamagnetic","Peroxide ion"),
("F₂","18","...σ*2p²","1","Diamagnetic","Stable"),
("Ne₂","20","...σ*2p²","0","–","Does NOT exist"),
("NO","15","...π*2p¹","2.5","Paramagnetic","Stable, odd e⁻"),
("NO⁺","14","...σ2p²","3","Diamagnetic","Isoelectronic with N₂"),
("CO","14","...σ2p²","3","Diamagnetic","Isoelectronic with N₂"),
]
hp3=ps("MS",fontSize=7,fontName="Helvetica-Bold",textColor=colors.white)
bp3=ps("MB",fontSize=7,fontName="Helvetica")
data3=[[Paragraph(c,hp3 if i==0 else bp3) for c in r] for i,r in enumerate(rows)]
t=Table(data3,colWidths=[CW*0.11,CW*0.07,CW*0.32,CW*0.14,CW*0.15,CW*0.21])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),CN),("ROWBACKGROUNDS",(0,1),(-1,-1),[CLB,CAL]),
("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2),
("LEFTPADDING",(0,0),(-1,-1),3),("INNERGRID",(0,0),(-1,-1),0.3,CB),
("BOX",(0,0),(-1,-1),0.6,CN)]))
el.append(t)
el.append(sp(0.2))
el.append(kbox([
"Bond order > 0 → molecule/ion is stable and exists",
"Higher bond order = shorter bond length, higher bond dissociation energy, more stable",
"Paramagnetic = unpaired electrons; Diamagnetic = all paired",
"O₂ is PARAMAGNETIC — proved by MO theory; VBT wrongly predicted diamagnetic (big failure of VBT)",
"B₂ is paramagnetic (2 electrons in degenerate π2p orbitals, one each by Hund's rule)",
"N₂ has bond order 3 — strongest diatomic bond (ΔH_diss ≈ 945 kJ/mol)",
"CO is isoelectronic with N₂ (both 14e, BO=3) but CO has a small dipole moment (0.12D)",
"Isoelectronic pairs: N₂/CO/NO⁺; O₂/S₂; F₂/Cl₂ (same BO); N₂/CO (both diamagnetic, BO=3)",
"Adding electron to bonding MO → increases BO (e.g., O₂ + e⁻ = O₂⁻ has lower BO → less stable)",
"Removing electron from antibonding MO → increases BO (e.g., O₂ → O₂⁺ has higher BO → more stable)",
], tip="For O₂: 16e → last 2 go into degenerate π*2p (one each, Hund's rule) → 2 unpaired e⁻ → paramagnetic. This is the MOST ASKED MO theory question."))
el.append(sp(0.2))
el.append(faqbox([
("Why is O₂ paramagnetic? Explain using MO theory.",
"O₂ has 16 electrons. The MO configuration is: σ1s² σ*1s² σ2s² σ*2s² σ2p² π2p⁴ π*2p¹ π*2p¹. The last two electrons go into the two degenerate π*2p orbitals – one in each (Hund's rule) → 2 unpaired electrons → O₂ is PARAMAGNETIC. VBT failed to predict this because it shows all electrons paired in O=O."),
("Calculate bond order and predict stability: He₂, He₂⁺, H₂⁻.",
"He₂: σ1s²(σ*1s)² → BO=(2−2)/2=0 → does NOT exist. He₂⁺: σ1s²(σ*1s)¹ → BO=(2−1)/2=0.5 → exists. H₂⁻: σ1s²(σ*1s)¹ → BO=(2−1)/2=0.5 → exists."),
("Arrange in increasing bond length: N₂, O₂, F₂, N₂⁺, NO.",
"Higher BO = shorter bond. BO: N₂(3) > NO(2.5) = N₂⁺(2.5) > O₂(2) > F₂(1). Bond length order: N₂ < NO = N₂⁺ < O₂ < F₂."),
("Is CO diamagnetic or paramagnetic? What is its bond order?",
"CO has 14 electrons, same as N₂. MO config: ...σ2p² (all paired). BO = 3. CO is DIAMAGNETIC. It has a very small dipole moment (0.12 D) despite the polar C=O bond (due to lone pair direction balancing the EN dipole)."),
]))
def sec7(el):
el.append(Paragraph("Dipole moment measures the polarity of a bond or molecule. A molecule is non-polar if all bond dipoles cancel due to symmetric geometry.",bd_s))
el.append(sp(0.2))
el.append(fblock("Dipole Moment",
r"\mu = q \times d",
"q = magnitude of charge, d = distance; Unit: Debye (D); 1 D = 3.336×10⁻³⁰ C·m"))
el.append(sp(0.2))
el.append(kbox([
"Electronegativity order: F > O > Cl > N > Br > I > S > C > H",
"Bond polarity: δ+ on less EN atom, δ− on more EN atom",
"Non-polar (μ=0): symmetric + all same bonds — CO₂, BF₃, CCl₄, SF₆, XeF₄, PCl₅, CS₂, C₆H₆",
"Polar (μ≠0): H₂O(1.85D), NH₃(1.47D), HF(1.91D), SO₂(1.60D), CHCl₃(1.87D)",
"μ increases with greater EN difference AND greater bond length",
"HX dipole moment order: HF(1.91) > HCl(1.07) > HBr(0.79) > HI(0.38) D — EN diff decreases",
"For disubstituted benzene: ortho > meta > para in dipole moment (same groups)",
"para-disubstituted benzene (same groups) has μ=0 (dipoles cancel)",
"cis isomer has higher μ than trans isomer (dipoles add vs cancel)",
"CO has small μ=0.12D (C→O direction, lone pair partially cancels EN dipole)",
], tip="CO₂=linear=0D; SO₂=bent=1.60D. NF₃ has LOWER μ than NH₃ because F withdraws e⁻ from N, reducing lone pair donation. Exam favourite!"))
el.append(sp(0.2))
el.append(Paragraph("<b>Important Dipole Moment Values:</b>",h2_s))
el.append(vtable2([
("Molecule","Dipole Moment (D)"),
("HF","1.91 D (highest among hydrogen halides)"),
("H₂O","1.85 D"),
("CHCl₃","1.87 D (polar, 3 Cl on one side)"),
("NH₃","1.47 D"),
("SO₂","1.60 D"),
("HCl","1.07 D"),
("HBr","0.79 D"),
("HI","0.38 D"),
("CO","0.12 D (slight, C→O)"),
("CO₂","0 D (linear, symmetric)"),
("CCl₄","0 D (tetrahedral, symmetric)"),
("BF₃","0 D (trigonal planar, symmetric)"),
("NF₃","0.24 D (low, F withdraws from N)"),
("H₂S","0.97 D"),
("CS₂","0 D (linear, symmetric)"),
]))
el.append(sp(0.2))
el.append(faqbox([
("Why is CO₂ non-polar but SO₂ is polar?",
"CO₂ is LINEAR (sp hybridised C, no lone pair) → two C=O dipoles point in exactly opposite directions → cancel → μ=0. SO₂ is BENT (sp² S, 1 lone pair) → two S=O dipoles point in same general direction → do NOT cancel → μ=1.60D."),
("Why does NF₃ have lower dipole moment than NH₃?",
"NH₃ (μ=1.47D): N−H bond dipoles and lone pair dipole all point in the SAME direction (N is more EN than H, lone pair points away from H) → they reinforce. NF₃ (μ=0.24D): N−F bond dipoles point away from N (F more EN), but lone pair points toward F side → bond dipoles OPPOSE lone pair direction → net dipole nearly cancels."),
("Arrange in decreasing μ: ortho-, meta-, para-dichlorobenzene.",
"o-DCB (~2.50D) > m-DCB (~1.72D) > p-DCB (0D). In para, the two C−Cl dipoles are exactly opposite → cancel. In ortho, they partially add. In meta, intermediate."),
("Which has higher boiling point: cis-2-butene or trans-2-butene?",
"cis-2-butene has higher μ (dipoles of two CH₃ groups add) than trans-2-butene (μ≈0, dipoles cancel). Higher μ → stronger dipole-dipole interactions → higher BP."),
]))
def sec8(el):
el.append(Paragraph("Hydrogen bond: electrostatic attraction between H (bonded to F/O/N) and an electronegative atom (F/O/N) with lone pairs on another molecule or same molecule.",bd_s))
el.append(sp(0.2))
el.append(kbox([
"Condition for H-bond: H must be covalently bonded to F, O, or N (small, highly EN atoms)",
"H-bond strength: F−H···F > O−H···O > N−H···N (F is most EN and smallest)",
"Intermolecular H-bond: between DIFFERENT molecules → higher BP, MP (H₂O, HF, NH₃, alcohols)",
"Intramolecular H-bond: within SAME molecule → LOWER BP (o-nitrophenol, salicylaldehyde)",
"H₂O: each molecule forms 4 H-bonds (2 donor + 2 acceptor) → 3D network → very high BP",
"HF: stronger individual H-bond than H₂O, but only 1 donor H per molecule → lower BP than H₂O",
"BP order (group 16): H₂O(100°C) >> H₂Te(−2°C) > H₂Se(−41°C) > H₂S(−60°C)",
"BP order (group 17): HF(19.5°C) > HI(−35°C) > HBr(−67°C) > HCl(−85°C)",
"H-bond energy: ~10–40 kJ/mol (weaker than covalent ~200–900 kJ/mol, stronger than van der Waals)",
"DNA double helix: A=T (2 H-bonds), G≡C (3 H-bonds) → G≡C more stable",
"Ice is LESS dense than water: H-bonds form open tetrahedral cage → larger volume → lower density",
"Proteins: secondary structure (α-helix, β-sheet) stabilised by H-bonds (N−H···O=C)",
], tip="Anomalous BP of H₂O, HF, NH₃ compared to heavier hydrides is ALWAYS due to H-bonding. Water has most H-bonds per molecule → highest BP in group."))
el.append(sp(0.2))
el.append(ibox([
"o-nitrophenol: intramolecular H-bond → lower BP, more volatile, less soluble in H₂O vs p-nitrophenol",
"Acetic acid (CH₃COOH) forms dimer in vapour/benzene due to intermolecular H-bonds (MW appears 120)",
"H-bonding explains: high surface tension, high specific heat, capillary action of water",
"Ethanol (C₂H₅OH) is infinitely miscible with water due to H-bonding with H₂O",
"Nylon, cellulose, silk — strength comes from H-bonding between polymer chains",
]))
el.append(sp(0.2))
el.append(faqbox([
("Why does ice float on water? Explain with H-bonding.",
"In ice, every H₂O molecule forms 4 H-bonds in a tetrahedral open-cage lattice. This arrangement has more empty space than liquid water (where H-bonds are partially broken and molecules are closer together). Ice is less dense (0.917 g/mL) than liquid water (1.000 g/mL) → ice floats."),
("Arrange in decreasing boiling point: H₂O, H₂S, H₂Se, H₂Te.",
"H₂O(100°C) > H₂Te(−2°C) > H₂Se(−41°C) > H₂S(−60°C). H₂O is anomalously high due to strong H-bonding. H₂S, H₂Se, H₂Te follow MW order (no H-bonding, only van der Waals forces)."),
("Why is o-nitrophenol more volatile than p-nitrophenol?",
"o-nitrophenol forms intramolecular H-bond (−OH···O−N in ortho position) → intermolecular H-bonding reduced → weaker intermolecular forces → lower BP → more volatile. p-nitrophenol forms intermolecular H-bonds (−OH of one molecule with −NO₂ of another) → stronger network → higher BP."),
("Why is NH₃ more soluble in water than PH₃?",
"NH₃ forms strong H-bonds with H₂O (N−H···O and O−H···N) because N is small and highly EN. PH₃ cannot form H-bonds (P is not EN/small enough). H-bonding makes NH₃ highly soluble (702 mL/mL water at 20°C) while PH₃ is sparingly soluble."),
]))
def sec9(el):
el.append(Paragraph("Van der Waals forces are weak intermolecular attractions present in ALL molecules. They increase with molar mass and molecular size.",bd_s))
el.append(sp(0.2))
el.append(Paragraph("<b>Types of Intermolecular Forces:</b>",h2_s))
el.append(vtable([
("Type","Molecules Involved","Origin","Example"),
("London / Dispersion","Non-polar (all molecules)","Temporary induced dipoles","Noble gases, CH₄, Cl₂, I₂, n-alkanes"),
("Dipole-Dipole (Keesom)","Polar molecules","Permanent dipoles attract","HCl, SO₂, acetone, H₂S"),
("Dipole-Induced Dipole (Debye)","Polar + non-polar","Permanent dipole induces temporary dipole","HCl + Ar, I₂ in CCl₄"),
("Hydrogen Bond","X−H (X=F,O,N) + lone pair","Electrostatic (special case)","H₂O, HF, NH₃, alcohols"),
]))
el.append(sp(0.2))
el.append(kbox([
"Strength: Hydrogen bond > Dipole-Dipole > London forces (generally)",
"London forces present in EVERY molecule (polar or non-polar)",
"London forces ∝ molar mass, surface area, number of electrons",
"BP of noble gases: He < Ne < Ar < Kr < Xe — London forces increase with atomic size",
"BP of halogens: F₂ < Cl₂ < Br₂ < I₂ — same reason (London forces with molar mass)",
"Branched alkanes have LOWER BP than straight chain (less surface area → weaker London forces)",
"n-pentane(36°C) > isopentane(28°C) > neopentane(9.5°C) in BP",
"Ion-dipole forces: between ions and polar molecules (e.g., NaCl dissolving in water — Na⁺···δ−O)",
], tip="For non-polar molecules: ONLY London forces. The ONLY factor affecting their BP = molar mass / size. More electrons = stronger London forces."))
el.append(sp(0.2))
el.append(faqbox([
("Why do noble gases exist as monoatomic gases at room temperature?",
"Noble gas atoms have only London (dispersion) forces between them — these are extremely weak (especially for He and Ne with very few electrons). These forces are insufficient to hold atoms together as liquid or solid at room temperature."),
("Why does n-pentane have higher boiling point than neopentane?",
"Both have same molecular formula (C₅H₁₂) but n-pentane has straight chain (more surface area for contact) → stronger London forces → higher BP (36°C). Neopentane is spherical/compact (less surface area) → weaker London forces → lower BP (9.5°C)."),
("Explain why the boiling point increases: CH₄ < C₂H₆ < C₃H₈.",
"All three are non-polar. Only London (dispersion) forces operate. As carbon chain length increases, molar mass increases → more electrons → greater polarisability → stronger temporary dipoles → stronger London forces → higher BP."),
]))
def sec10(el):
el.append(Paragraph("<b>Quick Revision Master Table:</b>",h2_s))
el.append(vtable2([
("Topic / Species","Key Fact to Remember"),
("Ionic bond","e⁻ transfer; high MP/BP; brittle; conducts when molten"),
("Covalent bond","e⁻ sharing; can be polar or non-polar"),
("Coordinate bond","Both e⁻ from one atom; NH₄⁺, H₃O⁺, BF₃·NH₃"),
("σ bond","Head-on overlap; rotation allowed; stronger"),
("π bond","Lateral overlap; NO rotation; in double/triple bonds only"),
("sp hybrid","Linear 180°; 50% s-char; BeCl₂, C₂H₂, HCN, CO₂"),
("sp² hybrid","Trigonal planar 120°; 33% s-char; BF₃, C₂H₄"),
("sp³ hybrid","Tetrahedral 109.5°; 25% s-char; CH₄, NH₃, H₂O"),
("VSEPR lp>bp","Each lone pair reduces bond angle by ~2-2.5°"),
("CH₄/NH₃/H₂O angles","109.5° / 107° / 104.5° (all sp³ but different LP)"),
("MO bond order","(Nb−Na)/2; >0 = stable; higher = shorter/stronger bond"),
("O₂ property","PARAMAGNETIC (2 unpaired e⁻ in π*2p) — MO theory proof"),
("N₂ bond order","3; most stable diatomic; ΔH_diss = 945 kJ/mol"),
("CO₂ dipole","0 D (linear); SO₂ = 1.60 D (bent) — classic comparison"),
("H₂O dipole","1.85 D; bent; HF = 1.91 D (highest among HX)"),
("H-bond strength","F−H···F > O−H···O > N−H···N"),
("Ice vs water density","Ice less dense (open H-bond cage) → floats"),
("Fajan's rules","Small cation + large anion = more covalent character"),
("Octet incomplete","Be(4e), B(6e) in their simple halides"),
("Octet expanded","P(10e in PCl₅), S(12e in SF₆), I(14e in IF₇)"),
("Resonance","O₃, CO₃²⁻, NO₃⁻, SO₃, C₆H₆ (benzene)"),
("Bond order in O₃","1.5 (intermediate between single and double)"),
("Lattice energy order","MgO > CaO >> NaCl > KCl (charge dominates)"),
("para-disubstituted benzene","μ = 0 (dipoles cancel symmetrically)"),
("Isoelectronic species","N₂, CO, NO⁺ (14e, BO=3); CO₃²⁻, NO₃⁻, SO₃"),
]))
el.append(sp(0.3))
el.append(faqbox([
("Arrange in decreasing bond angle: ClF₃, IF₃, BrF₃.",
"All are T-shaped (3 BP + 2 LP). Bond angle depends on size of central atom: larger atom → lone pairs farther apart → less compression. IF₃ > BrF₃ > ClF₃ in bond angle (I > Br > Cl in size)."),
("Why is the H−O−H angle in H₂O (104.5°) less than tetrahedral (109.5°)?",
"H₂O has 2 lone pairs and 2 bond pairs in a tetrahedral arrangement. Lone pair−lone pair repulsion > lone pair−bond pair repulsion > bond pair−bond pair repulsion. The 2 lone pairs push the 2 O−H bonds closer together, compressing the bond angle from 109.5° to 104.5°."),
("What is the hybridisation and shape of XeF₂, XeF₄, XeF₆?",
"XeF₂: sp³d, linear (3 LP equatorial + 2 BP axial). XeF₄: sp³d², square planar (2 LP axial, 4 BP equatorial). XeF₆: sp³d³, distorted octahedral (1 LP, 6 BP)."),
("Which is stronger: ionic bond in NaF or NaCl? Why?",
"NaF has stronger ionic bond (higher lattice energy) because F⁻ is much smaller than Cl⁻. Smaller F⁻ allows Na⁺ and F⁻ to get closer → stronger electrostatic attraction → higher lattice energy (~923 kJ/mol vs ~787 kJ/mol for NaCl)."),
("Why does diamond have higher melting point than graphite?",
"Diamond: each C is sp³ bonded to 4 other C in a 3D covalent network → extremely rigid, all strong σ bonds → very high MP (~3550°C). Graphite: sp² bonded layers with π electrons; layers held by weak van der Waals forces → layers slide easily → lower MP and lubricant."),
("NO has bond order 2.5. Is it diamagnetic or paramagnetic?",
"NO has 15 electrons. MO config ends with ...π*2p¹ (1 electron in antibonding π*). Nb=9, Na=6 → BO=(9−6)/2=1.5... Actually standard result: BO=2.5, 1 unpaired electron → PARAMAGNETIC."),
("Why is NH₃ a better Lewis base than NF₃?",
"In NH₃, H is less electronegative than N, so the lone pair on N is fully available for donation → good Lewis base. In NF₃, F is much more electronegative than N → F withdraws electron density from N → lone pair on N is less available for donation → NF₃ is a much weaker Lewis base."),
]))
# ═══════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ═══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(OUTPUT, pagesize=A4,
rightMargin=RM, leftMargin=LM, topMargin=2*cm, bottomMargin=2*cm)
el = []
el.append(sp(0.15))
el.append(Paragraph("CHEMICAL BONDING",ttl_s))
el.append(Paragraph("& MOLECULAR STRUCTURE",ttl_s))
el.append(sp(0.1))
el.append(Paragraph("Complete Notes + Key Points + Important Topics + Frequently Asked Questions",sub_s))
el.append(Paragraph("Class 11 Chemistry | NCERT + JEE Main + JEE Advanced + NEET",sub_s))
el.append(HRFlowable(width="100%",thickness=2.5,color=CN))
el.append(sp(0.15))
el.append(Paragraph(
"<b>Topics:</b> 1. Kossel-Lewis & Octet Rule • 2. Ionic Bonding • 3. Covalent Bonding & Resonance "
"• 4. VSEPR Theory • 5. VBT & Hybridisation • 6. MO Theory • 7. Polarity & Dipole Moment "
"• 8. Hydrogen Bonding • 9. Intermolecular Forces • 10. Mega Revision & Master FAQs",
ps("COV",fontSize=9,fontName="Helvetica",textColor=CGR,leading=14,spaceAfter=4)))
el.append(sp(0.2))
sections_list = [
("1. Kossel-Lewis Approach & Octet Rule", sec1),
("2. Ionic Bonding & Lattice Energy", sec2),
("3. Covalent Bonding, Lewis Structures & Resonance",sec3),
("4. VSEPR Theory – Molecular Shapes", sec4),
("5. Valence Bond Theory (VBT) & Hybridisation", sec5),
("6. Molecular Orbital (MO) Theory", sec6),
("7. Polarity & Dipole Moment", sec7),
("8. Hydrogen Bonding", sec8),
("9. Intermolecular Forces (Van der Waals)", sec9),
("10. Mega Revision Table & Master FAQs", sec10),
]
for title, fn in sections_list:
el.append(sp(0.2))
el.append(banner(title))
el.append(sp(0.1))
fn(el)
el.append(sp(0.1))
el.append(HRFlowable(width="100%",thickness=1.5,color=CN))
el.append(sp(0.1))
el.append(Paragraph("Class 11 Chemistry | Chemical Bonding & Molecular Structure | NCERT + JEE + NEET",
ps("FT",fontSize=9,textColor=CGR,fontName="Helvetica",alignment=TA_CENTER)))
doc.build(el)
print(f"PDF generated: {OUTPUT}")
python3 /home/daytona/workspace/chemical-bonding/generate_cb_pdf.py 2>&1
ls -lh /home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11.pdf
Chemical Bonding Notes Class11
PDF Document · PDF
| Topic | What's Inside |
|---|---|
| 1. Kossel-Lewis & Octet Rule | Types of bonds table, formal charge formula, octet exceptions (Be, B, P, S), FAQs |
| 2. Ionic Bonding | Lattice energy formula, Born-Haber cycle, Fajan's rules, lattice energy order, FAQs |
| 3. Covalent Bonding & Resonance | Bond order/length/strength table, resonance (O₃, CO₃²⁻, C₆H₆), σ/π bonds, FAQs |
| 4. VSEPR Theory | Full shapes table (13 shapes from linear to square planar), repulsion order, bond angle comparisons, FAQs |
| 5. VBT & Hybridisation | Hybridisation formula, full table (sp to sp³d³), σ/π explanation, back bonding, FAQs |
| 6. MO Theory | MO energy order (both versions), full 19-species data table (bond order, magnetic nature), FAQs |
| 7. Polarity & Dipole Moment | Formula, 16 dipole moment values, NF₃ vs NH₃ explanation, ortho/meta/para comparison, FAQs |
| 8. Hydrogen Bonding | Conditions, types, H-bond strength order, anomalous BP, ice density, DNA, FAQs |
| 9. Intermolecular Forces | All 4 types table, London forces, BP trends in noble gases and alkanes, FAQs |
| 10. Mega Revision + FAQs | 26-row master comparison table + 7 high-frequency exam questions with detailed answers |
They nice but make them spacious and they are unable to read due to some square like sh apes in the notes so please remove them
No not the renders but some kind of wierd square shaped things. Not renders and they are not problamatic
grep -n "★\|❓\|💡\|⚠\|📝\|•\|►\|▸\|→\|≡\|≠\|≤\|≥\|←\|↑\|↓\|⟹\|∝\|∞\|Δ\|α\|β\|π\|σ\|λ\|μ\|ν\|δ\|γ" /home/daytona/workspace/chemical-bonding/generate_cb_pdf.py | head -50
cd /home/daytona/workspace/chemical-bonding && cp generate_cb_pdf.py generate_cb_pdf_v3.py && python3 - << 'PYEOF' import re with open("generate_cb_pdf_v3.py", "r") as f: txt = f.read() # ── 1. Replace emoji/unicode box-causers in Python string literals ──────────── replacements = [ # Emoji used as bullet/icon markers in box headings and tips ("★ Key Points", ">> Key Points"), ("★ Key Points", ">> Key Points"), ('"★ {p}"', '"- " + p'), # handled below differently ("❓ Frequently Asked Questions", "FAQ -- Frequently Asked Questions"), ("⚠ Important / Exam Points", "!! Important / Exam Points"), ('heading="⚠ Important / Exam Points"', 'heading="!! Important / Exam Points"'), ("📝 Note", "[ Note ]"), ('hd="📝 Note"', 'hd="[ Note ]"'), # Tip prefix ('f"💡 Tip: {tip}"', 'f"TIP: {tip}"'), # bullet inside f-strings ('f"• {p}"', 'f"- {p}"'), ('f"★ {p}"', 'f"- {p}"'), ('f"▸ {note}"', 'f"-> {note}"'), # unicode arrows and symbols INSIDE regular Python strings (not LaTeX) # We only want to fix these in non-LaTeX contexts (paragraph text strings) # Do a broad replace of the unicode chars that appear in plain text ] for old, new in replacements: txt = txt.replace(old, new) # ── 2. Replace unicode symbols that appear in plain paragraph text ───────────── # These appear inside quoted strings that go into Paragraph() calls # Use targeted replace - only in non-latex contexts # The LaTeX strings are inside r"..." raw strings, so we must be careful. # Safe approach: replace these only when NOT inside a raw string. # Unicode symbols in plain text (not LaTeX) plain_replacements = [ ("→", "->"), ("↑", "(up)"), ("↓", "(down)"), ("∝", "proportional to"), ("≡", "="), # triple bond context already handled ("≠", "!="), ("≤", "<="), ("≥", ">="), ("←", "<-"), ("⟹", "=>"), # Greek letters in plain text (not in r"..." LaTeX strings) # These appear in paragraph strings like "1sigma+1pi" # We'll leave sigma/pi as written words since they're in plain text # The ones that cause boxes: ("★", "-"), ("❓", "Q&A"), ("💡", "TIP"), ("⚠", "!!"), ("📝", "Note"), ("•", "-"), ("▸", "->"), ("►", "->"), ("≡", " triple bond "), ] # Apply only to non-raw-string portions # Simple approach: replace globally (LaTeX raw strings use \equiv not ≡) for old, new in plain_replacements: txt = txt.replace(old, new) # ── 3. Increase spacing throughout ──────────────────────────────────────────── # Increase leading and font sizes txt = txt.replace("fontSize=9.5, fontName=\"Helvetica\", textColor=colors.HexColor(\"#212121\"), spaceAfter=3, leading=14", "fontSize=10, fontName=\"Helvetica\", textColor=colors.HexColor(\"#212121\"), spaceAfter=6, leading=16") txt = txt.replace("fontSize=9, textColor=CGN, fontName=\"Helvetica\", spaceAfter=2, leftIndent=8, leading=13", "fontSize=10, textColor=CGN, fontName=\"Helvetica\", spaceAfter=4, leftIndent=10, leading=16") txt = txt.replace("fontSize=8.5, textColor=CGR, fontName=\"Helvetica-Oblique\", spaceAfter=2, leftIndent=5", "fontSize=9, textColor=CGR, fontName=\"Helvetica-Oblique\", spaceAfter=4, leftIndent=8") txt = txt.replace("fontSize=9, textColor=CRD, fontName=\"Helvetica-Bold\", spaceAfter=2, leftIndent=8", "fontSize=10, textColor=CRD, fontName=\"Helvetica-Bold\", spaceAfter=4, leftIndent=10") txt = txt.replace("fontSize=9, textColor=colors.HexColor(\"#212121\"), fontName=\"Helvetica\", spaceAfter=5, leftIndent=12, leading=13", "fontSize=10, textColor=colors.HexColor(\"#212121\"), fontName=\"Helvetica\", spaceAfter=6, leftIndent=14, leading=16") txt = txt.replace("fontSize=9.5, textColor=CPU, fontName=\"Helvetica-Bold\", spaceAfter=2, leftIndent=4", "fontSize=10.5, textColor=CPU, fontName=\"Helvetica-Bold\", spaceAfter=3, leftIndent=6") txt = txt.replace("fontSize=9, textColor=CAM, fontName=\"Helvetica-Bold\", spaceAfter=0", "fontSize=10, textColor=CAM, fontName=\"Helvetica-Bold\", spaceAfter=2") # Increase padding in boxes txt = txt.replace('("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),\n ("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CGN)', '("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10),\n ("LEFTPADDING",(0,0),(-1,-1),14),("RIGHTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CGN)') txt = txt.replace('("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),\n ("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CRD)', '("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10),\n ("LEFTPADDING",(0,0),(-1,-1),14),("RIGHTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CRD)') txt = txt.replace('("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),\n ("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CPU)', '("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10),\n ("LEFTPADDING",(0,0),(-1,-1),14),("RIGHTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.8,CPU)') # formula block padding txt = txt.replace('("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),\n ("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.5,CB)', '("TOPPADDING",(0,0),(-1,-1),10),("BOTTOMPADDING",(0,0),(-1,-1),10),\n ("LEFTPADDING",(0,0),(-1,-1),14),("RIGHTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.5,CB)') # note box padding txt = txt.replace('("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),\n ("LEFTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.7,CTL)', '("TOPPADDING",(0,0),(-1,-1),9),("BOTTOMPADDING",(0,0),(-1,-1),9),\n ("LEFTPADDING",(0,0),(-1,-1),14),("RIGHTPADDING",(0,0),(-1,-1),10),("BOX",(0,0),(-1,-1),0.7,CTL)') # Increase spacer sizes txt = txt.replace("sp = lambda h=0.12: Spacer(1,h*cm)", "sp = lambda h=0.18: Spacer(1,h*cm)") # double all sp() calls that use default txt = txt.replace("el.append(sp(0.1))", "el.append(sp(0.22))") txt = txt.replace("el.append(sp(0.2))", "el.append(sp(0.3))") txt = txt.replace("el.append(sp(0.3))", "el.append(sp(0.4))") txt = txt.replace("el.append(sp(0.15))", "el.append(sp(0.28))") txt = txt.replace("el.append(sp(0.25))", "el.append(sp(0.35))") # Change output filename txt = txt.replace( '"Chemical_Bonding_Notes_Class11.pdf"', '"Chemical_Bonding_Notes_Class11_v3.pdf"' ) with open("generate_cb_pdf_v3.py", "w") as f: f.write(txt) print("Patched successfully") PYEOF
python3 /home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py 2>&1
ls -lh /home/daytona/workspace/chemical-bonding/ && grep "OUTPUT\s*=" /home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py | head -3
# Check for remaining problematic unicode in the v3 script (only in Paragraph/string context, not LaTeX raw strings) python3 - << 'PYEOF' import re, unicodedata with open("/home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py") as f: lines = f.readlines() suspicious = [] for i, line in enumerate(lines, 1): # skip lines that are raw LaTeX strings (r"...") if re.search(r'r"[^"]*"', line): continue for ch in line: cp = ord(ch) if cp > 127: name = unicodedata.name(ch, "UNKNOWN") # Only flag if it's NOT a standard Latin/Greek/math that ReportLab handles if "EMOJI" in name or "SYMBOL" in name or "DINGBAT" in name or \ "ARROW" in name or "SUBSCRIPT" in name or "SUPERSCRIPT" in name or \ cp in range(0x2700, 0x27C0) or cp in range(0x1F300, 0x1FFFF): suspicious.append((i, ch, hex(cp), name)) if suspicious: for ln, ch, cp, nm in suspicious[:30]: print(f"Line {ln}: {repr(ch)} ({cp}) -- {nm}") else: print("No problematic unicode found in paragraph text!") PYEOF
python3 - << 'PYEOF' import re, unicodedata with open("/home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py") as f: txt = f.read() # Map of unicode -> ASCII replacement for paragraph text # Subscripts sub_map = { '₀':'0','₁':'1','₂':'2','₃':'3','₄':'4', '₅':'5','₆':'6','₇':'7','₈':'8','₉':'9', } # Superscripts sup_map = { '⁰':'0','¹':'1','²':'2','³':'3','⁴':'4', '⁵':'5','⁶':'6','⁷':'7','⁸':'8','⁹':'9', '⁺':'+','⁻':'-','⁼':'=','⁽':'(','⁾':')', 'ⁿ':'n','ⁱ':'i', } # Greek letters in plain text greek_map = { 'α':'alpha','β':'beta','γ':'gamma','δ':'delta','ε':'epsilon', 'ζ':'zeta','η':'eta','θ':'theta','ι':'iota','κ':'kappa', 'λ':'lambda','μ':'mu','ν':'nu','ξ':'xi','ο':'o','π':'pi', 'ρ':'rho','σ':'sigma','τ':'tau','υ':'upsilon','φ':'phi', 'χ':'chi','ψ':'psi','ω':'omega', 'Α':'Alpha','Β':'Beta','Γ':'Gamma','Δ':'Delta','Ε':'Epsilon', 'Ζ':'Zeta','Η':'Eta','Θ':'Theta','Ι':'Iota','Κ':'Kappa', 'Λ':'Lambda','Μ':'Mu','Ν':'Nu','Ξ':'Xi','Ο':'O','Π':'Pi', 'Ρ':'Rho','Σ':'Sigma','Τ':'Tau','Υ':'Upsilon','Φ':'Phi', 'Χ':'Chi','Ψ':'Psi','Ω':'Omega', } # Math/other symbols misc_map = { '→':'->','←':'<-','↑':'(^)','↓':'(v)','↔':'<->', '⟹'=>'=>','⟺':'<=>', '∝':'prop. to','∞':'inf','∆':'delta','≡':'=','≈':'~', '≠':'!=','≤':'<=','≥':'>=','±':'+-', '×':'x','÷':'/', '°':'deg', '★':'-','❓':'Q&A','💡':'TIP:','⚠':'(!!)','📝':'Note:', '•':'-','▸':'->','►':'->','✓':'(ok)', '½':'1/2','¼':'1/4','¾':'3/4', '\u00b2':'2', # superscript 2 (²) '\u00b3':'3', # superscript 3 (³) '\u00b9':'1', # superscript 1 (¹) } all_map = {**sub_map, **sup_map, **greek_map, **misc_map} # We need to apply replacements ONLY outside raw LaTeX strings (r"...") # Strategy: split on r"..." blocks, replace only in non-raw parts def replace_outside_raw(text, mapping): # Split into segments: raw-string segments vs normal segments # Pattern for raw strings: r"..." or r'...' pattern = r'''r"[^"\\]*(?:\\.[^"\\]*)*"|r'[^'\\]*(?:\\.[^'\\]*)*' ''' parts = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', text) result = [] for i, part in enumerate(parts): if i % 2 == 1: # This is a raw string - leave it alone result.append(part) else: # Normal text - apply replacements for old, new in mapping.items(): part = part.replace(old, new) result.append(part) return ''.join(result) new_txt = replace_outside_raw(txt, all_map) # Fix the output path to be v3 new_txt = new_txt.replace( 'OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11.pdf"', 'OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11_v3.pdf"' ) with open("/home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py", "w") as f: f.write(new_txt) # Count remaining non-ASCII outside raw strings remaining = [] parts2 = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', new_txt) for i, part in enumerate(parts2): if i % 2 == 0: for ch in part: if ord(ch) > 127: remaining.append(ch) if remaining: print(f"Still {len(remaining)} non-ASCII chars outside raw strings:") from collections import Counter for ch, cnt in Counter(remaining).most_common(20): print(f" {repr(ch)} (U+{ord(ch):04X}) x{cnt}") else: print("All clean! No non-ASCII outside raw strings.") PYEOF
~/chemical-bonding/clean_unicode.py
import re
from collections import Counter
with open("/home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py") as f:
txt = f.read()
all_map = {
# subscripts
'\u2080':'0','\u2081':'1','\u2082':'2','\u2083':'3','\u2084':'4',
'\u2085':'5','\u2086':'6','\u2087':'7','\u2088':'8','\u2089':'9',
# superscripts
'\u2070':'0','\u00b9':'1','\u00b2':'2','\u00b3':'3','\u2074':'4',
'\u2075':'5','\u2076':'6','\u2077':'7','\u2078':'8','\u2079':'9',
'\u207a':'+','\u207b':'-','\u207c':'=','\u207d':'(','\u207e':')',
# arrows / math
'\u2192':'->','\u2190':'<-','\u2191':'(^)','\u2193':'(v)','\u2194':'<->',
'\u27f9':'=>','\u27fa':'<=>',
'\u221d':'prop. to','\u221e':'inf','\u2206':'delta','\u0394':'delta',
'\u2261':'=','\u2248':'~','\u2260':'!=','\u2264':'<=','\u2265':'>=',
'\u00b1':'+-','\u00d7':'x','\u00f7':'/','\u00b0':'deg',
'\u00bd':'1/2','\u00bc':'1/4','\u00be':'3/4',
# Greek (plain text only - LaTeX raw strings are skipped)
'\u03b1':'alpha','\u03b2':'beta','\u03b3':'gamma','\u03b4':'delta',
'\u03b5':'epsilon','\u03b6':'zeta','\u03b7':'eta','\u03b8':'theta',
'\u03b9':'iota','\u03ba':'kappa','\u03bb':'lambda','\u03bc':'mu',
'\u03bd':'nu','\u03be':'xi','\u03bf':'o','\u03c0':'pi',
'\u03c1':'rho','\u03c3':'sigma','\u03c4':'tau','\u03c5':'upsilon',
'\u03c6':'phi','\u03c7':'chi','\u03c8':'psi','\u03c9':'omega',
'\u0391':'Alpha','\u0392':'Beta','\u0393':'Gamma','\u0394':'Delta',
'\u0395':'Epsilon','\u0396':'Zeta','\u0397':'Eta','\u0398':'Theta',
'\u0399':'Iota','\u039a':'Kappa','\u039b':'Lambda','\u039c':'Mu',
'\u039d':'Nu','\u039e':'Xi','\u039f':'O','\u03a0':'Pi',
'\u03a1':'Rho','\u03a3':'Sigma','\u03a4':'Tau','\u03a5':'Upsilon',
'\u03a6':'Phi','\u03a7':'Chi','\u03a8':'Psi','\u03a9':'Omega',
# emoji / special symbols
'\u2605':'>>', # star
'\u2606':'>>', # star outline
'\u2713':'OK', # checkmark
'\u2714':'OK',
'\u274c':'X',
'\u2757':'(!)',
'\u2753':'(?)',
'\u25b8':'->', # small right triangle (bullet)
'\u25ba':'->',
'\u25ba':'->',
'\u2022':'-', # bullet
'\u00b7':'-', # middle dot
# emoji that appear as squares
'\u2764':' ', # heart
'\u2665':' ',
'\u2666':' ',
# Fix any leftover emoji range (1F000+)
}
# Add emoji range catch-all by scanning
def replace_outside_raw(text, mapping):
"""Apply mapping only outside r"..." and r'...' raw strings."""
parts = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', text)
result = []
for i, part in enumerate(parts):
if i % 2 == 1:
result.append(part) # raw string - skip
else:
for old, new in mapping.items():
part = part.replace(old, new)
# Also replace any remaining high-unicode chars that slip through
cleaned = []
for ch in part:
cp = ord(ch)
if cp <= 127:
cleaned.append(ch)
elif 128 <= cp <= 591: # Latin Extended, IPA, etc - keep
cleaned.append(ch)
elif 0x00C0 <= cp <= 0x024F: # Latin Extended A/B - keep
cleaned.append(ch)
else:
# Replace unknown high-unicode with space (safe fallback)
cleaned.append(' ')
result.append(''.join(cleaned))
return ''.join(result)
new_txt = replace_outside_raw(txt, all_map)
# Fix output filename
new_txt = new_txt.replace(
'OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11.pdf"',
'OUTPUT = "/home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11_v3.pdf"'
)
with open("/home/daytona/workspace/chemical-bonding/generate_cb_pdf_v3.py", "w") as f:
f.write(new_txt)
# Verify
parts2 = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', new_txt)
remaining = []
for i, part in enumerate(parts2):
if i % 2 == 0:
for ch in part:
if ord(ch) > 591:
remaining.append((ch, ord(ch)))
if remaining:
print(f"Still {len(remaining)} non-ASCII chars outside raw strings:")
for ch, cp in Counter(remaining).most_common(10):
print(f" {repr(ch[0])} U+{ch[1]:04X} x{cp}")
else:
print("All clean!")
cd /home/daytona/workspace/chemical-bonding && python3 clean_unicode.py && python3 generate_cb_pdf_v3.py 2>&1
ls -lh /home/daytona/workspace/chemical-bonding/Chemical_Bonding_Notes_Class11_v3.pdf
Chemical Bonding Notes Class11 v3
PDF Document · PDF
★ ❓ 💡 ⚠ 📝 • ▸ all replaced with plain text like >>, Q&A, TIP:, (!!), ->, -sigma, pi, deltaCan you do it for physics class 11 Motion In A Straight Plane. Formula and important key points sheet for revision. Without placeholders.
mkdir -p /home/daytona/workspace/motion-plane && echo "ready"
~/motion-plane/generate_motion_pdf.py
"""
Motion in a Plane - Class 11 Physics
Formula Sheet + Key Points for Revision
Clean PDF - no unicode/emoji chars in paragraph text
All formulas rendered as typeset images via matplotlib mathtext
"""
import os, io
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["mathtext.fontset"] = "cm"
rcParams["font.family"] = "serif"
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
W, H = A4
LM = 1.8*cm
RM = 1.8*cm
CW = W - LM - RM
OUTPUT = "/home/daytona/workspace/motion-plane/Motion_In_A_Plane_Class11.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
CN = colors.HexColor("#0d1b5e") # deep navy
CB = colors.HexColor("#1565c0") # medium blue
CLB = colors.HexColor("#e3f2fd") # light blue (alt row)
CAL = colors.HexColor("#f5f8ff") # alternate row
CGN = colors.HexColor("#1b5e20") # dark green
CGB = colors.HexColor("#e8f5e9") # green bg
CRD = colors.HexColor("#b71c1c") # dark red
CRB = colors.HexColor("#ffebee") # red bg
CAM = colors.HexColor("#e65100") # amber (tips)
CAB = colors.HexColor("#fff8e1") # amber bg
CGR = colors.HexColor("#37474f") # dark grey
CPU = colors.HexColor("#4a148c") # purple
CPB = colors.HexColor("#f3e5f5") # purple bg
CTL = colors.HexColor("#004d40") # teal
CTB = colors.HexColor("#e0f2f1") # teal bg
SS = getSampleStyleSheet()
def ps(name, **kw):
return ParagraphStyle(name, parent=SS["Normal"], **kw)
# ── Text styles (ALL ASCII-safe) ─────────────────────────────────────────────
title_s = ps("TT", fontSize=24, textColor=CN, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=4)
sub_s = ps("TS", fontSize=10, textColor=CGR, fontName="Helvetica",
alignment=TA_CENTER, spaceAfter=10)
h2_s = ps("H2", fontSize=11, textColor=CN, fontName="Helvetica-Bold",
spaceAfter=4, spaceBefore=6)
body_s = ps("BD", fontSize=10, fontName="Helvetica",
textColor=colors.HexColor("#212121"), spaceAfter=5, leading=16)
note_s = ps("NT", fontSize=9, textColor=CGR, fontName="Helvetica-Oblique",
spaceAfter=4, leftIndent=8, leading=14)
fl_s = ps("FL", fontSize=10, textColor=CN, fontName="Helvetica-Bold",
spaceAfter=3)
kph_s = ps("KH", fontSize=10, textColor=CGN, fontName="Helvetica-Bold",
spaceAfter=4)
kp_s = ps("KP", fontSize=10, textColor=CGN, fontName="Helvetica",
spaceAfter=4, leftIndent=10, leading=16)
imh_s = ps("IH", fontSize=10, textColor=CRD, fontName="Helvetica-Bold",
spaceAfter=4)
im_s = ps("IM", fontSize=10, textColor=CRD, fontName="Helvetica-Bold",
spaceAfter=4, leftIndent=10, leading=16)
tp_s = ps("TP", fontSize=10, textColor=CAM, fontName="Helvetica-Bold",
spaceAfter=2, leading=15)
fh_s = ps("FH", fontSize=10, textColor=CPU, fontName="Helvetica-Bold",
spaceAfter=4)
fq_s = ps("FQ", fontSize=10, textColor=CPU, fontName="Helvetica-Bold",
spaceAfter=3, leftIndent=6)
fa_s = ps("FA", fontSize=9.5, textColor=colors.HexColor("#212121"),
fontName="Helvetica", spaceAfter=6, leftIndent=14, leading=15)
th_s = ps("TH", fontSize=8.5, textColor=colors.white, fontName="Helvetica-Bold")
tb_s = ps("TB", fontSize=8.5, textColor=colors.HexColor("#212121"), fontName="Helvetica")
# ── Math renderer ────────────────────────────────────────────────────────────
def render(latex, fs=14, dpi=180):
try:
fig = plt.figure(figsize=(0.01, 0.01))
t = fig.text(0, 0, f"${latex}$", fontsize=fs,
color="#b71c1c", ha="left", va="bottom")
fig.canvas.draw()
bb = t.get_window_extent(renderer=fig.canvas.get_renderer())
plt.close(fig)
pad = 6
fw = max((bb.width + pad*2) / dpi, 0.5)
fh = max((bb.height + pad*2) / dpi, 0.3)
fig2, ax = plt.subplots(figsize=(fw, fh))
ax.set_axis_off()
fig2.patch.set_alpha(0)
fig2.text(pad/dpi/fw, pad/dpi/fh, f"${latex}$", fontsize=fs,
color="#b71c1c", ha="left", va="bottom",
transform=fig2.transFigure)
buf = io.BytesIO()
fig2.savefig(buf, format="png", dpi=dpi, transparent=True,
bbox_inches="tight", pad_inches=0.05)
plt.close(fig2)
buf.seek(0)
iw = fw * 72; ih = fh * 72
sc = min(1.0, (CW - 24) / iw)
return RLImage(buf, width=iw*sc, height=ih*sc)
except Exception as e:
plt.close("all")
return Paragraph(f"[formula: {e}]", note_s)
# ── Layout helpers ───────────────────────────────────────────────────────────
def banner(title):
t = Table([[Paragraph(f" {title}",
ps("BN", fontSize=12, textColor=colors.white,
fontName="Helvetica-Bold", leading=16))]],
colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CB),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
return t
def fblock(label, latex, note=""):
img = render(latex)
cell = [Paragraph(label, fl_s), img]
if note:
cell.append(Paragraph("-> " + note, note_s))
t = Table([[cell]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CLB),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.6, CB),
]))
return KeepTogether(t)
def kbox(points, tip=None):
c = [Paragraph("KEY POINTS", kph_s)]
for p in points:
c.append(Paragraph("- " + p, kp_s))
if tip:
c.append(Spacer(1, 4))
c.append(Paragraph("TIP: " + tip, tp_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CGB),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.0, CGN),
]))
return KeepTogether(t)
def ibox(points, heading="IMPORTANT / EXAM POINTS"):
c = [Paragraph(heading, imh_s)]
for p in points:
c.append(Paragraph(">> " + p, im_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CRB),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.0, CRD),
]))
return KeepTogether(t)
def faqbox(qas):
c = [Paragraph("FREQUENTLY ASKED QUESTIONS", fh_s)]
for q, a in qas:
c.append(Paragraph("Q: " + q, fq_s))
c.append(Paragraph("Ans: " + a, fa_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CPB),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.0, CPU),
]))
return KeepTogether(t)
def notebox(text, hd="NOTE"):
c = [Paragraph(hd, ps("NH", fontSize=10, fontName="Helvetica-Bold",
textColor=CTL, spaceAfter=3)),
Paragraph(text, ps("NB", fontSize=9.5, fontName="Helvetica",
textColor=CTL, leading=15))]
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), CTB),
("TOPPADDING", (0,0),(-1,-1), 9),
("BOTTOMPADDING", (0,0),(-1,-1), 9),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 0.8, CTL),
]))
return KeepTogether(t)
def vtable(header, rows, col_fracs=None):
if col_fracs is None:
col_fracs = [1/len(header)] * len(header)
cws = [CW * f for f in col_fracs]
data = [[Paragraph(h, th_s) for h in header]]
for r in rows:
data.append([Paragraph(str(x), tb_s) for x in r])
t = Table(data, colWidths=cws)
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), CN),
("ROWBACKGROUNDS", (0,1),(-1,-1), [CLB, CAL]),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("INNERGRID", (0,0),(-1,-1), 0.3, CB),
("BOX", (0,0),(-1,-1), 0.7, CN),
]))
return t
sp = lambda h=0.25: Spacer(1, h * cm)
# ═══════════════════════════════════════════════════════════════════════════════
# SECTION CONTENT
# ═══════════════════════════════════════════════════════════════════════════════
def s1_scalars_vectors(el):
el.append(Paragraph(
"A scalar has only magnitude (e.g. speed, mass, time). "
"A vector has both magnitude AND direction (e.g. velocity, force, displacement).",
body_s))
el.append(sp(0.2))
el.append(vtable(
["Scalar", "Vector"],
[
("Distance (d)", "Displacement (s or r)"),
("Speed (v)", "Velocity (v with arrow)"),
("Mass (m)", "Force (F)"),
("Time (t)", "Acceleration (a)"),
("Energy (E)", "Momentum (p)"),
("Temperature (T)", "Weight (W)"),
("Power (P)", "Torque (tau)"),
],
[0.5, 0.5]
))
el.append(sp(0.3))
el.append(fblock("Magnitude of Vector A",
r"|\vec{A}| = A = \sqrt{A_x^2 + A_y^2}",
"Ax and Ay are the x and y components of vector A"))
el.append(sp(0.2))
el.append(fblock("Direction of Vector (angle with x-axis)",
r"\theta = \tan^{-1}\!\left(\frac{A_y}{A_x}\right)",
"theta = angle the vector makes with positive x-axis"))
el.append(sp(0.2))
el.append(fblock("Unit Vector",
r"\hat{A} = \frac{\vec{A}}{|\vec{A}|}",
"Unit vector has magnitude = 1; shows only direction"))
el.append(sp(0.3))
el.append(kbox([
"Unit vectors along axes: i-hat (x), j-hat (y), k-hat (z) -- each has magnitude 1",
"A vector in 2D: A = Ax * i-hat + Ay * j-hat",
"A vector in 3D: A = Ax * i-hat + Ay * j-hat + Az * k-hat",
"Null vector (zero vector): magnitude = 0, direction undefined",
"Equal vectors: same magnitude AND same direction",
"Negative of a vector: same magnitude, opposite direction",
"Parallel vectors: same or opposite direction",
"Collinear vectors: lie along the same line",
"Coplanar vectors: lie in the same plane",
"A vector is NOT changed by parallel displacement (free vector)",
], tip="A unit vector is just a direction-pointer with no units. To get it: divide any vector by its own magnitude."))
el.append(sp(0.3))
el.append(ibox([
"Distance is always >= displacement (distance >= |displacement|)",
"Speed is always >= magnitude of velocity",
"A scalar can be negative (e.g. temperature, charge) -- negative does NOT make it a vector",
"Current has magnitude and direction but is a SCALAR (doesn't follow vector addition laws)",
]))
def s2_addition(el):
el.append(Paragraph(
"Vectors cannot be added like ordinary numbers. They must be added using geometric or algebraic methods.",
body_s))
el.append(sp(0.2))
el.append(fblock("Triangle Law of Vector Addition",
r"\vec{R} = \vec{A} + \vec{B}",
"Place vectors head-to-tail; resultant R goes from tail of A to head of B"))
el.append(sp(0.2))
el.append(fblock("Magnitude of Resultant (Parallelogram Law)",
r"R = \sqrt{A^2 + B^2 + 2AB\cos\theta}",
"theta = angle between vectors A and B"))
el.append(sp(0.2))
el.append(fblock("Direction of Resultant (angle with A)",
r"\tan\alpha = \frac{B\sin\theta}{A + B\cos\theta}",
"alpha = angle of resultant R from vector A"))
el.append(sp(0.2))
el.append(fblock("Component Method -- Resultant of Multiple Vectors",
r"R_x = \sum A_x,\quad R_y = \sum A_y,\quad R = \sqrt{R_x^2 + R_y^2}",
"Add all x-components, add all y-components, then find magnitude"))
el.append(sp(0.2))
el.append(fblock("Subtraction of Vectors",
r"\vec{A} - \vec{B} = \vec{A} + (-\vec{B})",
"Reverse direction of B, then add to A"))
el.append(sp(0.3))
el.append(kbox([
"Triangle law: place vectors tip-to-tail; resultant from first tail to last tip",
"Parallelogram law: both vectors from same point; diagonal = resultant",
"When theta = 0 deg: R(max) = A + B (vectors in same direction)",
"When theta = 180 deg: R(min) = |A - B| (vectors in opposite directions)",
"When theta = 90 deg: R = sqrt(A^2 + B^2)",
"Lami's theorem: if 3 vectors in equilibrium, A/sin(a) = B/sin(b) = C/sin(c)",
"Vector addition is commutative: A + B = B + A",
"Vector addition is associative: (A+B)+C = A+(B+C)",
"Polygon law: more than 2 vectors added head-to-tail; resultant closes the polygon",
], tip="For perpendicular vectors (90 deg): R = sqrt(A^2 + B^2). For same direction: R = A+B. For opposite: R = |A-B|. These 3 cases come up in every exam."))
el.append(sp(0.3))
el.append(ibox([
"Maximum resultant = A + B (when angle = 0 deg, same direction)",
"Minimum resultant = |A - B| (when angle = 180 deg, opposite directions)",
"Resultant of equal vectors at angle theta: R = 2A*cos(theta/2)",
"If A = B and R = A, then theta = 120 deg (very common MCQ)",
"Three vectors in equilibrium: they form a closed triangle",
]))
el.append(sp(0.3))
el.append(faqbox([
("Two vectors of magnitude 3 and 4 are perpendicular. Find their resultant.",
"theta = 90 deg. R = sqrt(3^2 + 4^2) = sqrt(9+16) = sqrt(25) = 5 units. Direction: tan(alpha) = 4/3, so alpha = 53.13 deg from the vector of magnitude 3."),
("Two equal vectors have resultant equal to either vector. Find the angle between them.",
"Let each vector = A. R = A. Using parallelogram law: A = sqrt(A^2 + A^2 + 2*A*A*cos(theta)) => A^2 = 2A^2(1 + cos(theta)) => cos(theta) = -1/2 => theta = 120 deg."),
]))
def s3_resolution(el):
el.append(Paragraph(
"Any vector can be split (resolved) into two mutually perpendicular components. "
"This is the reverse of vector addition and is the key technique for solving 2D problems.",
body_s))
el.append(sp(0.2))
el.append(fblock("Resolution of Vector A at angle theta",
r"A_x = A\cos\theta,\quad A_y = A\sin\theta",
"Ax = horizontal component, Ay = vertical component, theta = angle with x-axis"))
el.append(sp(0.2))
el.append(fblock("Reconstructing Vector from Components",
r"A = \sqrt{A_x^2 + A_y^2},\quad \theta = \tan^{-1}\!\left(\frac{A_y}{A_x}\right)",
""))
el.append(sp(0.2))
el.append(fblock("Dot Product (Scalar Product)",
r"\vec{A}\cdot\vec{B} = AB\cos\theta = A_xB_x + A_yB_y + A_zB_z",
"Result is a SCALAR; theta = angle between A and B"))
el.append(sp(0.2))
el.append(fblock("Cross Product (Vector Product) -- Magnitude",
r"|\vec{A}\times\vec{B}| = AB\sin\theta",
"Result is a VECTOR perpendicular to both A and B; direction by right-hand rule"))
el.append(sp(0.3))
el.append(kbox([
"Dot product properties: A.A = A^2; i.i = j.j = k.k = 1; i.j = j.k = k.i = 0",
"If A.B = 0 and A,B are non-zero: vectors are perpendicular (theta = 90 deg)",
"Cross product properties: A x A = 0; i x j = k; j x k = i; k x i = j",
"If A x B = 0 and A,B are non-zero: vectors are parallel (theta = 0 or 180 deg)",
"Dot product is commutative: A.B = B.A",
"Cross product is NOT commutative: A x B = -(B x A)",
"Work = F.d (dot product); Torque = r x F (cross product)",
"Area of parallelogram formed by A and B = |A x B|",
"Area of triangle formed by A and B = (1/2)|A x B|",
], tip="Dot product gives a scalar (used for work, power). Cross product gives a vector (used for torque, angular momentum). Remember: dot = cos, cross = sin."))
el.append(sp(0.3))
el.append(vtable(
["Property", "Dot Product (A.B)", "Cross Product (A x B)"],
[
("Result type", "Scalar", "Vector"),
("Formula", "AB cos(theta)", "AB sin(theta)"),
("When A perpendicular to B", "= 0", "= AB (maximum)"),
("When A parallel to B", "= AB (max)", "= 0"),
("Commutative?", "Yes: A.B = B.A", "No: A x B = -(B x A)"),
("i.i / i x i", "= 1", "= 0"),
("i.j / i x j", "= 0", "= k"),
],
[0.28, 0.36, 0.36]
))
def s4_motion_2d(el):
el.append(Paragraph(
"In 2D motion, position, velocity, and acceleration are all vectors. "
"The x and y motions are independent and can be analysed separately.",
body_s))
el.append(sp(0.2))
el.append(fblock("Position Vector",
r"\vec{r} = x\,\hat{i} + y\,\hat{j}",
"x and y are coordinates of the particle in the plane"))
el.append(sp(0.2))
el.append(fblock("Displacement Vector",
r"\Delta\vec{r} = \vec{r}_2 - \vec{r}_1 = \Delta x\,\hat{i} + \Delta y\,\hat{j}",
"Change in position vector from r1 to r2"))
el.append(sp(0.2))
el.append(fblock("Average Velocity",
r"\vec{v}_{avg} = \frac{\Delta\vec{r}}{\Delta t} = \frac{\Delta x}{\Delta t}\hat{i} + \frac{\Delta y}{\Delta t}\hat{j}",
"Direction: same as displacement vector delta-r"))
el.append(sp(0.2))
el.append(fblock("Instantaneous Velocity",
r"\vec{v} = \frac{d\vec{r}}{dt} = \frac{dx}{dt}\hat{i} + \frac{dy}{dt}\hat{j} = v_x\hat{i} + v_y\hat{j}",
"Tangent to the path at that instant"))
el.append(sp(0.2))
el.append(fblock("Speed (Magnitude of Instantaneous Velocity)",
r"v = |\vec{v}| = \sqrt{v_x^2 + v_y^2}",
""))
el.append(sp(0.2))
el.append(fblock("Average Acceleration",
r"\vec{a}_{avg} = \frac{\Delta\vec{v}}{\Delta t} = \frac{v_2 - v_1}{\Delta t}",
""))
el.append(sp(0.2))
el.append(fblock("Instantaneous Acceleration",
r"\vec{a} = \frac{d\vec{v}}{dt} = a_x\hat{i} + a_y\hat{j}",
"ax = dvx/dt, ay = dvy/dt"))
el.append(sp(0.3))
el.append(kbox([
"In 2D, x-motion and y-motion are COMPLETELY INDEPENDENT of each other",
"Average velocity direction = direction of displacement (NOT path direction)",
"Instantaneous velocity is always tangent to the path of motion",
"If path is curved, instantaneous velocity changes direction even at constant speed",
"Speed is a scalar; velocity is a vector",
"Average speed = total distance / total time (NOT |avg velocity| in general)",
"Average velocity = total displacement / total time",
"Velocity and acceleration need NOT be in the same direction",
], tip="x and y are independent. Solve as two separate 1D problems. Only time t is common to both."))
def s5_projectile(el):
el.append(Paragraph(
"Projectile motion: an object launched with initial velocity and moving under gravity alone. "
"Horizontal: uniform velocity. Vertical: uniformly accelerated (g downward).",
body_s))
el.append(sp(0.15))
el.append(notebox(
"Launch: speed = u, angle = theta with horizontal. "
"Horizontal component: ux = u*cos(theta). "
"Vertical component: uy = u*sin(theta). "
"Acceleration: ax = 0, ay = -g (taking upward as positive).",
"PROJECTILE SETUP"))
el.append(sp(0.2))
# All formulas
formulas = [
("Horizontal Velocity (constant throughout)",
r"v_x = u\cos\theta",
"No acceleration horizontally; vx never changes"),
("Vertical Velocity at time t",
r"v_y = u\sin\theta - gt",
"Decreases going up, increases coming down"),
("Speed at time t",
r"v = \sqrt{v_x^2 + v_y^2} = \sqrt{(u\cos\theta)^2 + (u\sin\theta - gt)^2}",
""),
("Horizontal Displacement at time t",
r"x = (u\cos\theta)\,t",
"Uniform motion horizontally"),
("Vertical Displacement at time t",
r"y = (u\sin\theta)\,t - \frac{1}{2}gt^2",
"Taking launch point as origin, upward positive"),
("Time of Flight (total time in air)",
r"T = \frac{2u\sin\theta}{g}",
"Time for projectile to return to same horizontal level"),
("Maximum Height",
r"H = \frac{u^2\sin^2\theta}{2g}",
"Vertical velocity = 0 at maximum height"),
("Horizontal Range",
r"R = \frac{u^2\sin 2\theta}{g}",
"Horizontal distance from launch to landing (same level)"),
("Maximum Range (theta = 45 deg)",
r"R_{max} = \frac{u^2}{g}",
"Achieved when angle of projection = 45 degrees"),
("Equation of Trajectory (path equation)",
r"y = x\tan\theta - \frac{gx^2}{2u^2\cos^2\theta}",
"This is a PARABOLA (y = ax - bx^2 form); x,y are coordinates of the projectile"),
("Velocity Direction at any point (angle phi with horizontal)",
r"\tan\phi = \frac{v_y}{v_x} = \frac{u\sin\theta - gt}{u\cos\theta}",
"phi = 0 at max height; phi = theta at start; phi = -theta at landing"),
("Height at given horizontal distance x",
r"y = x\tan\theta\left(1 - \frac{x}{R}\right)",
"Alternative form of trajectory equation"),
("Complementary Angles -- Same Range",
r"R(\theta) = R(90^\circ - \theta)",
"Angles theta and (90-theta) give the same range for same initial speed"),
]
for i, (label, latex, note) in enumerate(formulas):
el.append(fblock(label, latex, note))
el.append(sp(0.15))
el.append(sp(0.15))
el.append(kbox([
"Trajectory is a PARABOLA (quadratic in x and y)",
"At maximum height: vy = 0; only vx = u*cos(theta) remains",
"At maximum height: KE = (1/2)*m*(u*cos(theta))^2",
"At maximum height: PE = m*g*H = m*g*(u^2*sin^2(theta))/(2g)",
"Time to reach max height = T/2 = u*sin(theta)/g",
"For same initial speed, complementary angles (theta and 90-theta) give the SAME range",
"Range is maximum at theta = 45 deg: R_max = u^2/g",
"At theta = 30 deg and theta = 60 deg: range is same, but different H and T",
"H_max is max when theta = 90 deg: H_max = u^2/(2g)",
"Projectile has acceleration g throughout (even at top); velocity direction changes, not g",
"Horizontal momentum is conserved (no horizontal force)",
"The path of a projectile from ANY reference frame is a parabola (or straight line)",
"If launched horizontally (theta = 0): T = sqrt(2H/g), R = u*sqrt(2H/g)",
], tip="Memorise: T = 2u*sin(theta)/g, H = u^2*sin^2(theta)/(2g), R = u^2*sin(2*theta)/g. These three are derived from each other: R = u*cos(theta)*T and H = (uy)^2/(2g)."))
el.append(sp(0.3))
el.append(ibox([
"At the highest point: vy = 0, speed = u*cos(theta), direction = horizontal",
"When theta = 45 deg: H = R/4 (height is quarter of range)",
"When theta = 45 deg: R = 4H",
"Relation between R, H, T: R = 4H/tan(theta); T = 2*u*sin(theta)/g",
"For horizontal projection from height h: time = sqrt(2h/g), range = u*sqrt(2h/g)",
"Projectile motion is combination of uniform horizontal + uniformly accelerated vertical motion",
"The speed at a point at height y: v = sqrt(u^2 - 2gy) (from energy conservation too)",
]))
el.append(sp(0.3))
el.append(faqbox([
("A ball is thrown at 45 deg with speed 20 m/s. Find range, max height, and time of flight. (g = 10 m/s^2)",
"R = u^2*sin(2*theta)/g = 400*sin(90)/10 = 400/10 = 40 m. "
"H = u^2*sin^2(theta)/(2g) = 400*(0.5)/(20) = 10 m. "
"T = 2u*sin(theta)/g = 2*20*(1/sqrt(2))/10 = 40/(10*sqrt(2)) = 2*sqrt(2) = 2.83 s."),
("For what angle of projection is the range equal to the maximum height?",
"R = H => u^2*sin(2*theta)/g = u^2*sin^2(theta)/(2g) "
"=> 2*sin(theta)*cos(theta) = sin^2(theta)/2 "
"=> 4*cos(theta) = sin(theta) => tan(theta) = 4 => theta = arctan(4) = 76 deg."),
("A projectile is fired at 30 deg and 60 deg with same speed. Compare their ranges and heights.",
"Same range (complementary angles: 30+60=90). "
"H at 60 deg = u^2*sin^2(60)/(2g) = u^2*(3/4)/(2g). "
"H at 30 deg = u^2*sin^2(30)/(2g) = u^2*(1/4)/(2g). "
"So H(60)/H(30) = 3. Height at 60 deg is 3 times height at 30 deg."),
("A ball is thrown horizontally from a 20 m tall building with speed 10 m/s. Where does it land? (g = 10)",
"Time to fall: 20 = (1/2)*10*t^2 => t^2 = 4 => t = 2 s. "
"Horizontal range: R = u*t = 10*2 = 20 m from the base of building."),
]))
def s6_circular(el):
el.append(Paragraph(
"Uniform Circular Motion (UCM): motion in a circle with constant SPEED but continuously changing velocity direction. "
"There is always centripetal acceleration directed toward the centre.",
body_s))
el.append(sp(0.2))
formulas = [
("Angular Displacement",
r"\theta = \frac{\text{arc length}}{r} = \frac{s}{r}",
"Unit: radians (rad); theta in radians; s = arc length, r = radius"),
("Relationship: Degrees to Radians",
r"\theta(\text{rad}) = \frac{\pi}{180} \times \theta(\text{deg})",
"Full circle: 2*pi rad = 360 deg"),
("Angular Velocity (omega)",
r"\omega = \frac{\Delta\theta}{\Delta t} = \frac{2\pi}{T} = 2\pi f",
"omega = angular velocity; T = time period; f = frequency"),
("Linear Speed from Angular Velocity",
r"v = r\omega",
"v = linear/tangential speed at the rim; r = radius"),
("Period (T) and Frequency (f)",
r"T = \frac{1}{f} = \frac{2\pi r}{v} = \frac{2\pi}{\omega}",
"T = time for one complete revolution"),
("Centripetal Acceleration",
r"a_c = \frac{v^2}{r} = r\omega^2 = \frac{4\pi^2 r}{T^2}",
"Direction: always toward the CENTRE; magnitude is constant"),
("Centripetal Force",
r"F_c = \frac{mv^2}{r} = mr\omega^2",
"This is the NET force needed to maintain circular motion; NOT a new force"),
("Angle swept in time t",
r"\theta = \omega t",
"For uniform circular motion only"),
("Tangential Acceleration (non-uniform circular motion)",
r"a_t = \frac{dv}{dt} = r\alpha",
"alpha = angular acceleration = d(omega)/dt; at changes speed, ac changes direction"),
("Total Acceleration (non-uniform circular motion)",
r"a = \sqrt{a_c^2 + a_t^2}",
"ac = centripetal (v^2/r), at = tangential (r*alpha)"),
]
for label, latex, note in formulas:
el.append(fblock(label, latex, note))
el.append(sp(0.15))
el.append(sp(0.15))
el.append(kbox([
"In UCM: speed is constant, but velocity changes (direction changes) -> acceleration exists",
"Centripetal acceleration is directed toward the centre (centripetal = centre-seeking)",
"Centripetal force is NOT a new type of force -- it is played by gravity, tension, normal force, friction, etc.",
"In UCM: work done by centripetal force = 0 (force is perpendicular to velocity)",
"In UCM: kinetic energy is constant (speed is constant)",
"Angular velocity omega is the same for all points on a rotating rigid body",
"Linear speed v = r*omega is DIFFERENT for different r (outer points move faster)",
"1 revolution = 2*pi radians = 360 degrees",
"RPM (revolutions per minute) to rad/s: omega = 2*pi*n/60 (n = RPM)",
"Centripetal acceleration always points radially inward; tangential acceleration is along the circle",
"For Earth orbiting Sun: centripetal force = gravitational force",
"Banking of roads provides centripetal force using the normal force component",
], tip="Centripetal force is NOT listed in free body diagrams as a separate force! It is the net inward force provided by other forces (gravity, tension, friction, etc.)."))
el.append(sp(0.3))
el.append(ibox([
"In UCM: displacement in one complete revolution = 0; distance = 2*pi*r",
"Average velocity in one full revolution = 0 (displacement = 0)",
"Average speed in one full revolution = 2*pi*r/T = v (not zero)",
"The angle between velocity and acceleration in UCM is always 90 deg",
"Centripetal acceleration = v^2/r (use this form; v is linear speed, r is radius)",
"If frequency doubles: centripetal acceleration becomes 4 times (ac proportional to omega^2)",
]))
el.append(sp(0.3))
el.append(faqbox([
("A particle moves in a circle of radius 2 m with speed 4 m/s. Find centripetal acceleration.",
"ac = v^2/r = 4^2/2 = 16/2 = 8 m/s^2, directed toward the centre."),
("The angular velocity of a fan is 10 rad/s. Find linear speed of a point 0.3 m from axis.",
"v = r*omega = 0.3 * 10 = 3 m/s."),
("A stone tied to a string moves in a circle. What provides centripetal force?",
"The TENSION in the string provides the centripetal force. Tension acts toward the centre (inward). There is no separate 'centrifugal force' in the inertial frame."),
("Why does a car need friction to move in a circle on a flat road?",
"The car needs a centripetal force (= mv^2/r) directed toward the centre of the curve. On a flat road, the only horizontal force available is friction between tyres and road. Friction acts inward and provides the centripetal force."),
("Differentiate between centripetal and centrifugal force.",
"Centripetal force: real force directed toward the centre (inertial frame). Exists in both inertial and non-inertial frames. "
"Centrifugal force: pseudo/fictitious force directed AWAY from centre. Exists ONLY in rotating (non-inertial) reference frame. "
"In an inertial frame, centrifugal force does NOT exist."),
]))
def s7_relative(el):
el.append(Paragraph(
"Relative motion: motion of one object as observed from another moving object.",
body_s))
el.append(sp(0.2))
el.append(fblock("Relative Velocity of A with respect to B",
r"\vec{v}_{AB} = \vec{v}_A - \vec{v}_B",
"vAB = velocity of A as seen by observer at B"))
el.append(sp(0.2))
el.append(fblock("Relative Displacement",
r"\vec{r}_{AB} = \vec{r}_A - \vec{r}_B",
"Position of A as observed from B"))
el.append(sp(0.2))
el.append(fblock("Relative Velocity -- Magnitude (two objects at angle theta)",
r"v_{rel} = \sqrt{v_A^2 + v_B^2 - 2v_Av_B\cos\theta}",
"theta = angle between velocity vectors of A and B"))
el.append(sp(0.2))
el.append(fblock("Rain-Man Problem (Umbrella Angle)",
r"\tan\phi = \frac{v_{man}}{v_{rain}}",
"phi = angle of umbrella with vertical; tilt umbrella in direction of motion by angle phi"))
el.append(sp(0.3))
el.append(kbox([
"v(A relative to B) = vA - vB; v(B relative to A) = vB - vA (opposite sign)",
"If two cars move in the same direction: v_rel = vA - vB (difference)",
"If two cars move in opposite directions: v_rel = vA + vB (sum)",
"For two parallel trains moving same direction: v_rel = |vA - vB|",
"For two parallel trains moving opposite direction: v_rel = vA + vB",
"Rain problem: v_rain_relative_to_man = v_rain - v_man",
"Swimmer crossing river: aim upstream at angle to reach directly opposite bank",
"To cross river in minimum time: swim perpendicular to bank (regardless of current)",
"To cross with minimum drift: swim at angle upstream = arcsin(v_current/v_swimmer)",
"Condition to reach directly opposite: v_swimmer > v_current (must be faster than river)",
], tip="For rain-man or river-crossing: draw a vector triangle. v_resultant = v_self + v_medium. The medium (river, wind) vector adds to your self-velocity."))
el.append(sp(0.3))
el.append(ibox([
"v_AB = -v_BA (relative velocity is antisymmetric)",
"If two objects have same velocity: relative velocity = 0 (appear stationary to each other)",
"Relative velocity of two objects moving at 90 deg: v_rel = sqrt(vA^2 + vB^2)",
"Minimum time to cross river = d/v_swimmer (swim perpendicular, ignoring drift)",
"Minimum distance to cross river = d/cos(alpha) where alpha = tilt angle upstream",
]))
el.append(sp(0.3))
el.append(faqbox([
("A swimmer can swim at 5 m/s in still water. River flows at 3 m/s. Width = 40 m. Find minimum crossing time.",
"For minimum time: swim perpendicular to bank. "
"Time = width / v_swimmer = 40/5 = 8 s. "
"Drift = v_river * t = 3 * 8 = 24 m downstream."),
("Same swimmer wants to reach directly opposite. Find angle and time.",
"For zero drift: sin(alpha) = v_river/v_swimmer = 3/5. alpha = 37 deg (upstream). "
"Resultant speed = sqrt(5^2 - 3^2) = sqrt(16) = 4 m/s (perpendicular to bank). "
"Time = 40/4 = 10 s."),
]))
def s8_quick_ref(el):
el.append(Paragraph("<b>Master Formula Quick Reference Table</b>", h2_s))
el.append(vtable(
["Formula", "Expression", "Used For"],
[
("Resultant (parallelogram)", "R = sqrt(A^2+B^2+2AB*cos(theta))", "Adding 2 vectors"),
("Max/Min resultant", "R_max = A+B; R_min = |A-B|", "Same/opposite direction"),
("Unit vector", "A-hat = A-vec / |A|", "Direction only"),
("Dot product", "A.B = AB*cos(theta)", "Work, power, projection"),
("Cross product magnitude", "|AxB| = AB*sin(theta)", "Torque, area"),
("Projectile: time of flight", "T = 2u*sin(theta)/g", "Total time in air"),
("Projectile: max height", "H = u^2*sin^2(theta)/(2g)", "Highest point"),
("Projectile: range", "R = u^2*sin(2theta)/g", "Horizontal distance"),
("Trajectory equation", "y = x*tan(theta) - gx^2/(2u^2*cos^2(theta))", "Parabola path"),
("Max range condition", "theta = 45 deg; R_max = u^2/g", "Optimum angle"),
("Circular: omega", "omega = 2*pi/T = 2*pi*f", "Angular velocity"),
("Circular: v = r*omega", "v = r*omega", "Linear from angular speed"),
("Centripetal acc.", "ac = v^2/r = r*omega^2", "Centre-directed acc."),
("Centripetal force", "Fc = mv^2/r = m*r*omega^2", "Net inward force"),
("Relative velocity", "v_AB = v_A - v_B", "Motion seen from B"),
("River: min time", "t = d / v_swimmer (perpendicular)", "Fastest crossing"),
("River: zero drift angle", "sin(alpha) = v_river / v_swimmer", "Straight crossing"),
("Complementary angles", "R(theta) = R(90-theta)", "Same range, diff. angle"),
],
[0.32, 0.38, 0.30]
))
el.append(sp(0.35))
el.append(Paragraph("<b>Key Values and Conditions</b>", h2_s))
el.append(vtable(
["Condition", "Result"],
[
("Angle between vectors = 0 deg", "R = A+B (maximum); A.B = AB; AxB = 0"),
("Angle between vectors = 90 deg", "R = sqrt(A^2+B^2); A.B = 0; |AxB| = AB"),
("Angle between vectors = 180 deg", "R = |A-B| (minimum); A.B = -AB; AxB = 0"),
("Theta = 45 deg (projectile)", "Range is MAXIMUM (R = u^2/g)"),
("Theta = 90 deg (projectile)", "Height is MAXIMUM (H = u^2/(2g)); Range = 0"),
("Theta = 30 deg and 60 deg", "Same range; H(60) = 3 * H(30); T(60) = sqrt(3) * T(30)"),
("At max height (projectile)", "vy = 0; v = u*cos(theta); KE = (1/2)m(u*cos(theta))^2"),
("UCM: one revolution", "Displacement = 0; Distance = 2*pi*r; Avg velocity = 0"),
("UCM: angle between v and a", "Always 90 deg"),
("Swimmer: min time direction", "Swim perpendicular to bank"),
("Swimmer: zero drift direction", "Swim at upstream angle alpha = arcsin(v_r/v_s)"),
],
[0.48, 0.52]
))
# ═══════════════════════════════════════════════════════════════════════════════
# ASSEMBLE PDF
# ═══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=LM, rightMargin=RM,
topMargin=2*cm, bottomMargin=2*cm
)
el = []
# Cover
el.append(sp(0.15))
el.append(Paragraph("MOTION IN A PLANE", title_s))
el.append(sp(0.05))
el.append(Paragraph("Class 11 Physics -- Formula Sheet + Key Points for Revision", sub_s))
el.append(Paragraph("Covers: Vectors, Projectile Motion, Circular Motion, Relative Motion", sub_s))
el.append(Paragraph("NCERT | JEE Main | JEE Advanced | NEET", sub_s))
el.append(HRFlowable(width="100%", thickness=2.5, color=CN))
el.append(sp(0.3))
sections = [
("1. Scalars and Vectors", s1_scalars_vectors),
("2. Addition and Subtraction of Vectors", s2_addition),
("3. Resolution, Dot Product and Cross Product",s3_resolution),
("4. Motion in a Plane -- Kinematics", s4_motion_2d),
("5. Projectile Motion", s5_projectile),
("6. Uniform Circular Motion (UCM)", s6_circular),
("7. Relative Motion", s7_relative),
("8. Master Quick Reference", s8_quick_ref),
]
for title, fn in sections:
el.append(sp(0.25))
el.append(banner(title))
el.append(sp(0.2))
fn(el)
el.append(sp(0.15))
el.append(HRFlowable(width="100%", thickness=1.5, color=CN))
el.append(sp(0.1))
el.append(Paragraph(
"Class 11 Physics | Motion in a Plane | NCERT + JEE + NEET",
ps("FT", fontSize=9, textColor=CGR, fontName="Helvetica", alignment=TA_CENTER)))
doc.build(el)
print("PDF generated: " + OUTPUT)
# Verify no unicode > 591 in paragraph text before running python3 - << 'PYEOF' import re with open("/home/daytona/workspace/motion-plane/generate_motion_pdf.py") as f: txt = f.read() parts = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', txt) bad = [] for i, part in enumerate(parts): if i % 2 == 0: for j, ch in enumerate(part): if ord(ch) > 591: bad.append((ch, hex(ord(ch)))) if bad: from collections import Counter for ch, cnt in Counter(bad).most_common(10): print(f" {repr(ch[0])} {ch[1]} x{cnt}") else: print("Clean -- no problematic unicode in paragraph text") PYEOF
sed -i 's/═/=/g; s/─/-/g' /home/daytona/workspace/motion-plane/generate_motion_pdf.py python3 - << 'PYEOF' import re with open("/home/daytona/workspace/motion-plane/generate_motion_pdf.py") as f: txt = f.read() parts = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', txt) bad = [ch for i, p in enumerate(parts) if i%2==0 for ch in p if ord(ch) > 591] print("Clean!" if not bad else f"Still {len(bad)} chars: {set(bad)}") PYEOF
python3 - << 'PYEOF' import re with open("/home/daytona/workspace/motion-plane/generate_motion_pdf.py") as f: txt = f.read() parts = re.split(r'(r"[^"\\]*(?:\\.[^"\\]*)*"|r\'[^\'\\]*(?:\\.[^\'\\]*)*\')', txt) # only check Paragraph( content -- strings in double/single quotes not raw # Also check triple-quoted strings bad_lines = [] for i, part in enumerate(parts): if i % 2 == 0: for line in part.split('\n'): # skip comment lines stripped = line.strip() if stripped.startswith('#'): continue # skip triple-quoted docstring lines for ch in line: if ord(ch) > 591: bad_lines.append((line.strip()[:80], repr(ch))) break if bad_lines: for l, c in bad_lines[:10]: print(f"BAD: {c} in: {l}") else: print("All paragraph/code text is clean ASCII!") PYEOF
python3 /home/daytona/workspace/motion-plane/generate_motion_pdf.py 2>&1
ls -lh /home/daytona/workspace/motion-plane/Motion_In_A_Plane_Class11.pdf
Motion In A Plane Class11
PDF Document · PDF
| Section | Content |
|---|---|
| 1. Scalars & Vectors | Scalar vs vector table, magnitude formula, unit vector, direction angle, key properties |
| 2. Vector Addition | Triangle law, parallelogram law formula, resultant magnitude & direction, max/min resultant, Lami's theorem |
| 3. Resolution, Dot & Cross Product | Component resolution, full dot product & cross product table with all properties |
| 4. Motion in a Plane - Kinematics | Position vector, displacement, avg/instantaneous velocity, acceleration in 2D |
| 5. Projectile Motion | 13 formulas - T, H, R, trajectory (parabola), velocity at any point, complementary angles, horizontal projection, 4 solved FAQs |
| 6. Uniform Circular Motion | 10 formulas - omega, v=r*omega, centripetal acc, centripetal force, tangential acc, total acc, 5 FAQs |
| 7. Relative Motion | Relative velocity formula, rain-man problem, river crossing (min time + zero drift), 2 solved problems |
| 8. Master Quick Reference | 18-row formula table + 11-row key conditions table (all exam-critical values in one place) |
Hey I cannot print black and white print outs due colour and size problem.
~/bw_engine.py
"""
Black-and-White Print-Friendly PDF generator
Shared engine for all three Class 11 sheets.
- White backgrounds everywhere
- Black/dark-grey borders and text
- Bold headings to distinguish sections instead of colour
- Compact but spacious layout
- All formula images render in dark red ink (prints as dark grey / black on B&W)
- Zero emoji / unicode -- pure ASCII paragraph text
"""
import io
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["mathtext.fontset"] = "cm"
rcParams["font.family"] = "serif"
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT
W, H = A4
LM = 1.8 * cm
RM = 1.8 * cm
CW = W - LM - RM
# ── Pure B&W palette ─────────────────────────────────────────────────────────
BLACK = colors.black
DGREY = colors.HexColor("#1a1a1a") # near-black text
MGREY = colors.HexColor("#555555") # medium grey (notes, sub-text)
LGREY = colors.HexColor("#dddddd") # light grey (table alt row)
VLIGHT = colors.HexColor("#f5f5f5") # very light grey (formula block bg)
WHITE = colors.white
FORMULA_INK = "#1a1a1a" # formula image ink colour (dark = prints black)
SS = getSampleStyleSheet()
def ps(name, **kw):
return ParagraphStyle(name, parent=SS["Normal"], **kw)
# ── Text styles ───────────────────────────────────────────────────────────────
title_s = ps("TT", fontSize=22, textColor=BLACK, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=3)
sub_s = ps("TS", fontSize=10, textColor=MGREY, fontName="Helvetica",
alignment=TA_CENTER, spaceAfter=6)
h2_s = ps("H2", fontSize=11, textColor=DGREY, fontName="Helvetica-Bold",
spaceAfter=4, spaceBefore=5)
body_s = ps("BD", fontSize=10, fontName="Helvetica", textColor=DGREY,
spaceAfter=5, leading=16)
note_s = ps("NT", fontSize=9, textColor=MGREY, fontName="Helvetica-Oblique",
spaceAfter=4, leftIndent=8, leading=14)
fl_s = ps("FL", fontSize=10, textColor=DGREY, fontName="Helvetica-Bold",
spaceAfter=3)
kph_s = ps("KH", fontSize=10, textColor=BLACK, fontName="Helvetica-Bold",
spaceAfter=4)
kp_s = ps("KP", fontSize=10, textColor=DGREY, fontName="Helvetica",
spaceAfter=4, leftIndent=10, leading=16)
imh_s = ps("IH", fontSize=10, textColor=BLACK, fontName="Helvetica-Bold",
spaceAfter=4)
im_s = ps("IM", fontSize=10, textColor=DGREY, fontName="Helvetica-Bold",
spaceAfter=4, leftIndent=10, leading=16)
tp_s = ps("TP", fontSize=10, textColor=DGREY, fontName="Helvetica-Bold",
spaceAfter=2, leading=15)
fh_s = ps("FH", fontSize=10, textColor=BLACK, fontName="Helvetica-Bold",
spaceAfter=4)
fq_s = ps("FQ", fontSize=10, textColor=DGREY, fontName="Helvetica-Bold",
spaceAfter=3, leftIndent=6)
fa_s = ps("FA", fontSize=9.5, textColor=DGREY, fontName="Helvetica",
spaceAfter=6, leftIndent=14, leading=15)
th_s = ps("TH", fontSize=8.5, textColor=WHITE, fontName="Helvetica-Bold")
tb_s = ps("TB", fontSize=8.5, textColor=DGREY, fontName="Helvetica")
nb_s = ps("NB", fontSize=9.5, textColor=DGREY, fontName="Helvetica", leading=15)
nh_s = ps("NH", fontSize=10, textColor=BLACK, fontName="Helvetica-Bold", spaceAfter=3)
# ── Math renderer (dark ink = prints black) ──────────────────────────────────
def render(latex, fs=14, dpi=180):
try:
fig = plt.figure(figsize=(0.01, 0.01))
t = fig.text(0, 0, f"${latex}$", fontsize=fs,
color=FORMULA_INK, ha="left", va="bottom")
fig.canvas.draw()
bb = t.get_window_extent(renderer=fig.canvas.get_renderer())
plt.close(fig)
pad = 6
fw = max((bb.width + pad * 2) / dpi, 0.5)
fh = max((bb.height + pad * 2) / dpi, 0.3)
fig2, ax = plt.subplots(figsize=(fw, fh))
ax.set_axis_off()
fig2.patch.set_facecolor("white")
fig2.text(pad/dpi/fw, pad/dpi/fh, f"${latex}$", fontsize=fs,
color=FORMULA_INK, ha="left", va="bottom",
transform=fig2.transFigure)
buf = io.BytesIO()
fig2.savefig(buf, format="png", dpi=dpi,
facecolor="white", bbox_inches="tight", pad_inches=0.05)
plt.close(fig2)
buf.seek(0)
iw = fw * 72; ih = fh * 72
sc = min(1.0, (CW - 24) / iw)
return RLImage(buf, width=iw * sc, height=ih * sc)
except Exception as e:
plt.close("all")
return Paragraph(f"[formula error: {e}]", note_s)
# ── Layout helpers ────────────────────────────────────────────────────────────
def banner(title):
"""Bold black section header -- no colour fill, just thick top border."""
p = Paragraph(title, ps("BN", fontSize=12, textColor=BLACK,
fontName="Helvetica-Bold", leading=16))
t = Table([[p]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), VLIGHT),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 10),
("LINEABOVE", (0,0),(-1,0), 2.0, BLACK),
("LINEBELOW", (0,0),(-1,-1), 0.5, MGREY),
("BOX", (0,0),(-1,-1), 0.8, BLACK),
]))
return t
def fblock(label, latex, note=""):
"""Formula block: white bg, thin black border, left accent line."""
img = render(latex)
cell = [Paragraph(label, fl_s), img]
if note:
cell.append(Paragraph("-> " + note, note_s))
t = Table([[cell]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), WHITE),
("TOPPADDING", (0,0),(-1,-1), 9),
("BOTTOMPADDING", (0,0),(-1,-1), 9),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 10),
("BOX", (0,0),(-1,-1), 0.8, BLACK),
("LINEBEFORE", (0,0),(0,-1), 3.0, DGREY),
]))
return KeepTogether(t)
def kbox(points, tip=None):
"""Key points: very light grey bg, solid black border."""
c = [Paragraph("KEY POINTS", kph_s)]
for p in points:
c.append(Paragraph("- " + p, kp_s))
if tip:
c.append(Spacer(1, 4))
c.append(Paragraph("TIP: " + tip, tp_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), VLIGHT),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.2, BLACK),
]))
return KeepTogether(t)
def ibox(points, heading="IMPORTANT / EXAM POINTS"):
"""Important box: white bg, thick dashed border."""
c = [Paragraph(heading, imh_s)]
for p in points:
c.append(Paragraph(">> " + p, im_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), WHITE),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.5, BLACK),
("LINEABOVE", (0,0),(-1,0), 3.0, BLACK),
]))
return KeepTogether(t)
def faqbox(qas):
"""FAQ box: light grey bg, black border."""
c = [Paragraph("FREQUENTLY ASKED QUESTIONS", fh_s)]
for q, a in qas:
c.append(Paragraph("Q: " + q, fq_s))
c.append(Paragraph("Ans: " + a, fa_s))
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), LGREY),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 1.0, BLACK),
]))
return KeepTogether(t)
def notebox(text, hd="NOTE"):
c = [Paragraph(hd, nh_s),
Paragraph(text, nb_s)]
t = Table([[c]], colWidths=[CW])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), VLIGHT),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 12),
("BOX", (0,0),(-1,-1), 0.8, MGREY),
("LINEBEFORE", (0,0),(0,-1), 3.0, BLACK),
]))
return KeepTogether(t)
def vtable(header, rows, col_fracs=None):
if col_fracs is None:
col_fracs = [1 / len(header)] * len(header)
cws = [CW * f for f in col_fracs]
data = [[Paragraph(h, th_s) for h in header]]
for r in rows:
data.append([Paragraph(str(x), tb_s) for x in r])
t = Table(data, colWidths=cws)
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), DGREY),
("ROWBACKGROUNDS", (0,1),(-1,-1), [WHITE, VLIGHT]),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("INNERGRID", (0,0),(-1,-1), 0.4, MGREY),
("BOX", (0,0),(-1,-1), 0.8, BLACK),
]))
return t
def sp(h=0.25):
return Spacer(1, h * cm)
def make_doc(output_path):
return SimpleDocTemplate(
output_path, pagesize=A4,
leftMargin=LM, rightMargin=RM,
topMargin=2 * cm, bottomMargin=2 * cm
)