0

This was my previous question about Maxwell's distribution where you can find the source code.

The following code is intended to obtain a histogram from Maxwell's distribution which works on top of that aforementioned code.

using ZedGraph;

public static class Normalization
{
    public static int Normalize(double n_bins, double mu, double sigma, double gaussian)
    {
        var z = (gaussian - mu) / sigma;

        if (z > 3 || z < -3)
        {
            return -1;
        }
        else
        {
            return (int)((z + 3) * n_bins / 6d);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        const double N = 1000000;
        int time = (int)N;
        int binsCount = 51;

        Random rand = new Random();
        int[] bins = new int[binsCount];

        double mass = 14 * 1.67e-27;
        double T = 300;

        for (int i = 0; i < time; i++)
        {
            double gauss = MaxwellBolzman.Next(rand, mass, T);

            int index = Normalization.Normalize(binsCount, mass, T, gauss);

            if (index >= 0)
            {
                bins[index]++;
            }
        }

        PointPairList list = new PointPairList();
        for (int i = 0; i < bins.Length; i++)
        {
            list.Add(i, bins[i]);
        }

        PlotForm form = new PlotForm("Maxwell-Bolzman");
        form.AddBar(list, "Actual", Color.Blue);
        form.AxisChange();
        form.ShowDialog();
    }
}

Output:

According to this link, the graph should look like the following:

enter image description here

user366312
  • 16,949
  • 65
  • 235
  • 452
  • Your question is how to draw a histogram, but it seems like you *have* drawn a histogram; do you have a more specific question that would help you get unblocked? – Eric Lippert Apr 15 '20 at 20:15
  • @EricLippert, the shape of the histogram is not what I expected. There must be some issue with the `Normalize()`. The histogram looks like an incomplete Normal distribution, not a Maxwell's distribution. – user366312 Apr 15 '20 at 20:17
  • That's correct; if you want to show the right hand side of the histogram, your implementation of Normalize is not correct. – Eric Lippert Apr 15 '20 at 20:18
  • Well, no, that's not quite it. Can you say a bit about why you are passing the mass of a nitrogen atom to a method that takes the mean of a distribution of speeds? Remember what I said in your last question: **do unit analysis to find your errors**. – Eric Lippert Apr 15 '20 at 20:19
  • @EricLippert, actually, the problem is, I am not from Chemistry background. But, I have taken a programming course from the Faculty of chemistry. – user366312 Apr 15 '20 at 20:20

1 Answers1

1

As I said in your last question, use unit analysis to find your errors. It was good advice then and it is good advice now.

Let's examine your method:

public static int Normalize(
  double n_bins, 
  double mu,  
  double sigma, 
  double gaussian)

It returns a bin index, so that should be an integer.

It takes a bin count; that should be an integer, not a double. It's not a physical quantity.

What is mu? It's a mean of the distribution. What is the distribution of? Speeds. So mu has units of meters per second.

What is sigma? It's the standard deviation of the distribution of speeds, so it also has units of meters per second.

What is gaussian? It is a sample from the distribution, so it also has units of meters per second.

But in your call:

Normalization.Normalize(binsCount, mass, T, gauss);

You've passed a bin count -- that's correct.

You've passed a mass -- we are expecting meters per second and you've passed kilograms, so that can't possibly be correct.

You've passed a temperature -- we are expecting meters per second and you've passed Kelvin, so that cannot possibly be correct.

And you've passed a sample, so that's correct.

What you should be passing is the mean speed, which you calculated in your last answer, and the standard deviation of speed, which you have an estimate of because you have a known standard deviation of one component of the velocity, and that's a good enough guess.

Again: unit analysis is a powerful tool to find mistakes. I wish C# made it easier to assign units to doubles; these sorts of problems would then be caught by the compiler. F# has this feature and it is quite nice.


UPDATE: It has come to my attention that the original poster does not understand what I mean by unit analysis.

Unit analysis is the technique of associating a "type" with every quantity in a physics problem, and then tracking that type through the problem. If at any point you discover that you have "mixed up" types, you know that there is a problem.

The basic rules of unit analysis are that units only sum with identical units, and units multiply and divide using the standard rules for multiplication and division.

For example, suppose we have some quantities: 10 kilograms, 5 meters, 2 seconds. Suppose we multiply kilograms by meters and divide by seconds; the momentum of an object that masses 10kg moving at 5 meters in 2 seconds is 25 kilogram meters per second.

If later on in our problem we have a quantity that is, say, energy, and we add the momentum to the energy by mistake, our unit analysis tells us that is wrong. 25 kg*m/s cannot be added to anything that has units of energy because energy has units kg*m*m/(s*s), and so we know we've made a mistake somewhere.

Similarly, in the previous question I noted that we can use unit analysis to determine when we are doing a computation in grams, but we expect a value in kilograms. In that case at least we have two things that are both mass, but it is a serious error to use grams when kilograms are expected, and unit analysis can detect this problem.

This is particularly useful in programming because as we've just seen, it is very easy to make a mistake where you have a method that takes a speed and you pass it a temperature, which is meaningless. It was just sheer luck that 300K, the value you passed in for the speed, happened to be in the right ballpark, since 300m/s is also a reasonable speed for a nitrogen molecule. But that was luck. The correct thing to do is to figure out what the right speed to pass in is.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • What do you exactly mean by *Unit Analysis*? Do you mean *Unit Testing*? – user366312 Apr 15 '20 at 20:31
  • Ah, I figured you would understand this term as a science student. I will explain. – Eric Lippert Apr 15 '20 at 20:34
  • 2
    @Eric: Another closely related concept is *Dimensional Analysis*. In general I should think that *Dimensional Analysis* catches attempts to add momentum to energy (not sensible), while *Unit Analysis* catches attempts to add meters to inches (sensible but requires conversion to a common unit first) – Ben Voigt Apr 15 '20 at 21:28
  • 1
    @BenVoigt: That's a good point; it's true that I am somewhat conflating these techniques, which are closely related as you say. But no matter what we call it, it's an error to pass a temperature to a method that is expecting a speed! :) – Eric Lippert Apr 15 '20 at 21:32
  • I am sorry, but, I couldn't solve the problem. I wrote something like the following: `for (int i = 0; i < time; i++) { double gauss = MaxwellBolzman.MaxwellSpeed(rand, mass, T); double mu = MaxwellBolzman.MaxwellComponent(rand, mass, T); double sigma = MaxwellBolzman.MaxwellVariance(mass, T); int index = Normalization.Normalize(binsCount, mu, sigma, gauss); if (index >= 0) { bins[index]++; } }` But, the result is not coming as expected. – user366312 Apr 16 '20 at 13:14
  • 1
    Do the entire calculation on paper, writing out each step. Since that step is not in this website's scope, I'll assume it succeeds. Next, for each line within your program, write out what all the variables will be equal to. I encourage you to do this by hand, without running the application. If any step does not match your paper solution, you've found a bug. If every step matches your paper solution, run the program in the debugger, stepping through one line at a time with a `watch` on each variable. If any step fails to match your human-powered execution, you've found a bug.. – Brian Apr 16 '20 at 13:57
  • As an aside: If you find yourself making dimensional errors, you may wish to make use of named arguments. E.g., instead of calling `Normalization.Normalize(binsCount, ...` , call `Normalization.Normalize(n_bins: binsCount, ...` . – Brian Apr 16 '20 at 14:11
  • @user366312: I concur strongly with Brian's advice and would add one more. Obtain a rubber duck or graduate student or similar object and explain to the duck *why every line of your program is correct*. Out loud, in full sentences. If you find a statement you cannot explain why it is correct, *it probably isn't*. For instance: why is it correct that mu, a *mean*, is assigned not the mean speed, but a single sample of one velocity component? – Eric Lippert Apr 16 '20 at 14:50
  • @user366312: And another piece of advice that I already gave you, that works exceedingly well with Brian's suggestion is *write a test suite that tests each function independently*. That will give you confidence that your subsystems are working correctly, and then you can check whether you have created a program where the subsystems work together correctly. – Eric Lippert Apr 16 '20 at 14:52
  • I am sorry. It is out of topic. I am interested in hearing from you about my question [here](https://stackoverflow.com/q/62383332/5482465). Why did the c# designers provide us with such many options? There must be underlying philosophy about the given options from c# designers' point of view. – Second Person Shooter Jun 15 '20 at 08:30