function cannonball_b(start_velocity, timestep, method, output_file)
//
// Follow the motion of a projectile launched from a big cannon
//   on the surface of the Earth.  Allow for the force of
//   air resistance on the projectile, in a simple way,
//   but do NOT include any changing gravitational force
//
// The "method" argument may be either 
//
//        "euler"             use Euler's method
//  or
//        "heun"              use Heun's method
//
// We compute KE, GPE and total E at each timestep and
//    print values only to screen for debugging 
//
// MWR 4/29/2007

  //
  verbose = 1;

  euler_method = 1;
  heun_method = 2;

  // mass of projectile (kg)
  mass = 10000;
  // radius of projectile (m)
  radius = 2.0;


  // sanity checks
  if (start_velocity <= 0)
    mprintf("cannonball_b: start_velocity %f must be positive \n", start_velocity);
    error("cannonball_b: quitting now \n");
  end
  if (timestep <= 0)
    mprintf("cannonball_b: timestep %f must be positive \n", timestep);
    error("cannonball_b: quitting now \n");
  end

  // parse the method -- allow for initial capital
  if ((method == "Euler") | (method == "euler"))
    use_method = euler_method;
  elseif ((method == "Heun") | (method == "heun")) 
    use_method = heun_method;
  else 
    mprintf("cannonball_b: invalid method %s  \n", method);
    error("cannonball_b: quitting now \n");
  end
  

  // we'll write output to this file
  fid = mopen(output_file, "w");
  if (fid < 0)
    mprintf("cannonball_b: could not open file %s \n", output_file);
    error("cannonball_b: quitting now \n");
  end

  // some physical constants
  dt = timestep;

  // initial properties
  time = 0;
  cur_v = start_velocity;
  cur_height = 0;
  iter = 0;
  

  // main loop, in which we update position and velocity
  //   of the cannonball
  while ((iter == 0) | (cur_height > 0))

    // compute energy of projectile
    [ke, gpe, tot_e] = compute_energy(mass, cur_height, cur_v);

    if (verbose > 0)
      mprintf(" iter %6d  time %9.2f  height %9.2f  vel %9.2f  %9.4e %9.4e %9.4e \n", ...
               iter, time, cur_height, cur_v, ke, gpe, tot_e);
    end
    mfprintf(fid, " %9.2f  %9.2f  %9.2f  %9.4e %9.4e %9.4e \n", ...
             time, cur_height, cur_v, ke, gpe, tot_e);

    // compute current acceleration
    accel = acceleration(mass, radius, cur_height, cur_v)

    if (use_method == euler_method)
      // use Euler's method to compute future vel, height

      // compute the new velocity
      new_v = cur_v + accel*dt;

      // compute the new height 
      new_height = cur_height + cur_v*dt;

    else
      // we are using Heun's method, then

      // first, we predict (poorly) the future
      //   velocity, height, and acceleration
      predict_v = cur_v + accel*dt;
      predict_height = cur_height + predict_v*dt;
      predict_accel = acceleration(mass, radius, predict_height, predict_v);

      // use current and future accel to compute a decent
      //    average acceleration over this timestep
      avg_accel = 0.5*(accel + predict_accel);

      // use average accel to calculate good new velocity
      new_v = cur_v + avg_accel*dt;

      // now compute an average velocity over this timestep,
      //   and use it to get the new height
      avg_v = 0.5*(cur_v + new_v);
      new_height = cur_height + avg_v*dt;

    end


    // prepare for next time through loop
    iter = iter + 1;
    time = time + dt;
    cur_height = new_height;
    cur_v = new_v;

  end

  // print final values, just after the ball strikes
  //    the surface
  [ke, gpe, tot_e] = compute_energy(mass, cur_height, cur_v);

  if (verbose > 0)
    mprintf(" iter %6d  time %9.2f  height %9.2f  vel %9.2f  %9.4e %9.4e %9.4e \n", ...
             iter, time, cur_height, cur_v, ke, gpe, tot_e);
  end
  mfprintf(fid, " %9.2f  %9.2f  %9.2f  %9.4e %9.4e %9.4e \n", ...
             time, cur_height, cur_v, ke, gpe, tot_e);


  
  // close the file
  mclose(fid);



endfunction



/////////////////////////////////////////////////////////////
function accel = acceleration(mass, radius, height, velocity)
//
// Given the mass of a projectile, its height above the
//   surface of the Earth, and its velocity, calculate
//   the acceleration on it.
//
// This could be easy, if assume no air resistance,
//   or complicated, if there's air resistance and
//   perhaps multiple bodies.
//

  // physical constants
  G = 6.67E-11;
  mass_earth = 5.98E24;
  radius_earth = 6.37E6;
  pi = 3.14159265358979312;


  // air resistance will be computed like so:
  //
  //    Force  =  C_air * density * area * velocity^2
  //
  C_air = 0.02;
  area = pi*radius*radius;
  density = air_density(height);
  force_air = C_air * area * density * (velocity*velocity);
  // make sure that the force of air resistance
  //   points opposite to velocity
  if (velocity > 0)
    force_air = 0.0 - force_air;
  end
  
  // this version has a constant gravitational force
  g = 9.8;
  force_grav = 0.0 - (mass * g);

  // acceleration is total force divided by mass
  tot_force = force_air + force_grav;
  accel = tot_force / mass;

endfunction

  

  
/////////////////////////////////////////////////////////////
function [ke, gpe, tot_e] = compute_energy(mass, height, velocity)
//
// Given the mass of a projectile, its height above the
//   surface of the Earth, and its velocity, calculate
//   its current KE, GPE and total energy.

  // physical constants
  G = 6.67E-11;
  mass_earth = 5.98E24;
  radius_earth = 6.37E6;

  // this version has no air resistance, just uses
  //   the Law of Universal Gravitation with Earth
  //   and projectile alone
  tot_rad = radius_earth + height;

  ke = 0.5*mass*(velocity*velocity);
  gpe = 0.0 - ((G*mass_earth*mass)/(tot_rad));
  tot_e = ke + gpe;

endfunction

  

/////////////////////////////////////////////////////////////
function density = air_density(height)
//
// Given the height above the surface of the Earth,
//   compute the current air density (kg/m^2).
//
// If given height is less than zero, use value for height zero.

  // air density at sea level (kg/m^3)
  rho_0 = 1.21;
  // scale height of atmosphere (m)
  scale_height = 8000.0;

  if (height <= 0)
    density = rho_0;
  else
    density = rho_0 * exp(0.0 - (height/scale_height));
  end

endfunction
