Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Calculating Black Body Radiation

00:00 Okay buckle up, here I go. The code here is in a file called black_body.py. It’s a bit of a longer example than you might normally find in a course like this, but most of it’s straightforward procedural coding.

00:13 My first import is the NumPy library. It’s common practice to import the whole module and alias it as np.

00:22 I’m not sure whether I think this is good or bad. It definitely keeps it all together, but if you did it with every module, you’d quickly start to lose track of what all the short forms were for.

00:32 But for NumPy, at least everybody does it so consistency with the community is a good thing.

00:38 Matplotlib is a funny little library. It can be either context-driven or object-driven. What this means is you don’t necessarily have to create a new graph object.

00:48 You can just start calling functions in the pyplot submodule. A library just assumes that all the functions are building up to the same graph.

00:56 This is a horrible design from a purist computer science point of view, but it does make for less code. Like with NumPy, common practice is to alias out the pyplot submodule as plt, often pronounced as “plot.” This can cause some weird stuff if you’re not used to it.

01:13 For example, one of the functions in plt is plot, so reading it out loud, that would be “plot.plot”. Alright, funky alias practices out of the way, let’s move on to the next bit of bad practice.

01:26 The seterr() function configures NumPy’s behavior when a floating point error happens. Using the over argument changes what happens if an overflow gets triggered.

01:37 As you might guess, ignore means to just keep chugging along. The end result will be that you can see your data, but if it overflowed, it will have become negative.

01:47 None of the data I’m playing with is going to cause this kind of overflow, but if you start to play with extreme values, you might blow something up. Instead of falling over, this just keeps working.

01:57 It’s up to you as to how you feel about this. I wouldn’t fault you if you took it out of your code and forced the exception to happen so you could fix it.

02:06 You’ll recall that Planck’s law has a bunch of constants in it. These are those constants. Normally the convention in Python is for them to be capitalized, but as the case of these letters are meaningful in science, I’ve written them as is.

02:21 I’m going to be generating an array of wavelengths and then putting it into a histogram. The bins value here is the number of buckets in the histogram.

02:29 I’ve put it up here at the top so that if I want to play with the value, I can easily.

02:34 The radiance() function takes a temperature and an array of wavelengths. It then applies Planck’s law to each wavelength and returns an array of radiance values.

02:44 Note that since wavelengths is a NumPy array, you can just do math on it like a single value variable, and the math gets applied across all the items in the array.

02:55 This is both powerful and confusing. It can make it hard to tell in the code when you’re dealing with a scalar value and when you’re dealing with an array.

03:02 But on the flip side, it means you don’t have to write any loops and complex formulas like this one don’t care whether it’s one value or many. The a and b variables are just temps in order to make the r calculation shorter and slightly easier to read.

03:17 Let me scroll down a bit.

03:21 Different temperature stars have different ranges of wavelengths where the resulting radiance is a reasonable sized value. This function filled with magic numbers is really just a lookup table for the start and end wavelengths to use in the graph.

03:34 For example, if the star’s temperature is less than 1200 Kelvin, then the first if clause triggers and the graph will be between 10e-6 and 15 * 10e-6.

03:45 These values are arbitrary and chosen simply to make the graph prettier. Let me scroll down some more,

03:54 and here’s another function with magic numbers. To colorize our graph, you need to know what the visible color spectrum is. This function takes a wavelength value and returns a color. Anything below or above the visible spectrum and you get black. Anything inside the visible spectrum gets the appropriate color from the rainbow.

04:15 Interesting side note, there are seven colors in the rainbow because Newton was both a genius and a guy who believed in a lot of mystical hoo-ha. He didn’t see seven colors in the spectrum.

04:26 Depending on whose history you read, it was somewhere between five and six, but there are seven days of the week, seven natural notes in the Western music scale and licks break purple into purple and violet and red into orange and red, and there you have it.

04:41 We’ve got seven colors. Alright, that’s our color mapping and formulas out of the way. Now, for the main body of the code.

04:49 If you haven’t come across this kind of if statement before, the __name__ == '__main__' pattern well, it’s a bit of Python magic.

04:57 It’s a lot of magic in this script. When you import a module, the double underscore name value shortened to __name__ has the name of the module inside it.

05:06 If you run a Python file as a script, instead of getting the module name, __name__ gets __main__ instead. If you have bare runnable code in a file, I mean code that isn’t in a function or class, it gets called when you import it.

05:21 If you only want some code to be called as a script and not on import, then you can’t have bare code.

05:28 Instead, you put it in an if statement that checks the __name__ value. To be honest, for this kind of program, I don’t usually bother with this construct.

05:37 It’s a short enough script that I’ll only ever be running it and not importing it. But this is a Python course and it’s considered best practices, so my fellow Pythonistas might hunt me down and torture me if I didn’t.

05:48 Nobody expects the Spanish Inquisition.

05:52 The first step in the body of the script is to ask the user for a temperature. This gets converted to a float and stored in the temperature variable.

06:01 Next, I call the temperature_range() function that I showed before, which gives reasonable bounding values for our graph based on the input temperature.

06:10 I then create an evenly distributed array of 50 values, or whatever you’ve changed BINS to, between start and stop using NumPy’s linspace().

06:20 These will be all the wavelengths for the calculation,

06:24 and now that I’m set up, I call the radiance() function to invoke Planck’s law. The input will be a temperature, the range of wavelengths, and the output will be the radiance array.

06:36 That’s pretty much it. There’s a lot of code left, but the rest of it is just output.

Avatar image for CarpinchoDelSur

CarpinchoDelSur on Sept. 10, 2024

Why do you use many “if” and not “elif” insted?

Avatar image for Christopher Trudeau

Christopher Trudeau RP Team on Sept. 10, 2024

Hi CarpinchoDelSur,

You could use elif. When you’ve got code like this where you are immediately returning inside the if-block, the elif doesn’t matter as you will never get to the next block.

Also, this form saves you a variable. You could store the answer in a value then return it at the bottom, then you’d want the elif clause, but that means an additional variable. Technically an optimization, but not one that will save you much time/memory, so it pretty much comes down to a style thing.

Become a Member to join the conversation.