<jupyter_start><jupyter_text>IntroductionSome collisions between particles and the airfoil result in an inward recoil force - a recoil into the airfoil.  Effectively this contributes to a negative pressure on an edge of the airfoil, and that should never happen.The problem is being investigated on branch `debug_particle_inside_foil`, revision `234a5d7fc6f492f8a9ba68dbd4eb63e963c11057`, which was created `Wed Oct 20 10:18:22 2021 -0600`.  The problem manifests in `main` revisions up through this date.<jupyter_code>%matplotlib osx
import matplotlib.pyplot as plt
import math
foil = [
    (21.61566625583794, 30.582579917106106),
    (22.285935920085585, 31.40518764019059),
    (22.86876914734008, 31.675743426771763),
    (23.998393101103794, 31.98929160626099),
    (25.107325989624854, 32.17220154123417),
    (26.205579618665837, 32.28768528548939),
    (28.378058542917618, 32.36694384488441),
    (30.528511494491735, 32.307135885923635),
    (32.662945556845735, 32.14618864088592),
    (34.78403054484963, 31.90095865745075),
    (38.99282783498218, 31.199791844586784),
    (43.16958734667449, 30.296346459568934),
    (47.32498833940664, 29.25804869311516),
    (51.46036572061364, 28.09332681906521),
    (55.57905675888301, 26.823251522018445),
    (59.68172890793227, 25.45203693889474),
    (61.72605671842308, 24.722181209674225),
    (63.765712352891384, 23.9628265220146),
    (63.748358556236255, 23.85325896209791),
    (61.61792921618728, 24.039491028654865),
    (59.48816732985583, 24.22993723213169),
    (55.228643557192896, 24.61082963908534),
    (50.97178959939998, 25.008578593718475),
    (46.71627054904209, 25.41475582219136),
    (42.463421313554214, 25.837789598343736),
    (38.2185815226764, 26.31139301753458),
    (33.98308608384365, 26.843994353603644),
    (31.869343086732307, 27.135579843157412),
    (29.76160717307851, 27.46509256499003),
    (27.663215611469777, 27.853603203700867),
    (25.57950803164616, 28.3348248546489),
    (24.545329959485656, 28.62389825470145),
    (23.521831146805233, 28.980397845471963),
    (22.517688491932457, 29.459107406918783),
    (22.032303507433692, 29.803815610639006),
]
foil.append(foil[0])
x_foil = [p[0] for p in foil]
y_foil = [p[1] for p in foil]
class Record:
    def __init__(self, **kw):
        for k, v in kw.items():
            setattr(self, k, v)

def plot_foil():
    plt.plot(x_foil, y_foil, "k-")

def plot_record(rec):
    norm_x0 = sum(rec.edge_x) / 2.0
    norm_y0 = sum(rec.edge_y) / 2.0

    fig = plt.figure()
    plt.axis("equal")
    plot_foil()

    plt.plot(rec.edge_x, rec.edge_y, "b-", linewidth=3)
    plt.arrow(norm_x0, norm_y0, rec.edge_normal[0], rec.edge_normal[1], width=0.05, color="blue")

    # Recoil force anchored at old particle position:
    plt.arrow(*rec.pos_before, *rec.recoil_force, width=0.2, color="red")
    # Recoil vector anchored at old position:
    plt.arrow(*rec.pos_before, *rec.recoil_vec, width=0.1, color="pink")
    # Recoil unit vector:
    plt.arrow(*rec.pos_before, *rec.recoil_unit, width=0.05, color="orange")

    color_before = "#88ff88"
    color = "#009900"

    # Original particle position and velocity:
    plt.arrow(*rec.pos_before, *rec.vel_before, width=0.1, color=color_before)

    # Particle velocity vector anchored at new particle position:
    plt.arrow(*rec.pos, *rec.vel, width=0.1, color=color)

    # Particle positions:
    plt.plot(*rec.pos_before, marker="D", color=color_before)
    plt.plot(*rec.pos, marker="o", color=color)

    msg = "Negative" if rec.is_negative_force else "Positive"
    plt.title(f"Particle {rec.particle_id} - {msg}")
    plt.show()
plot_record(Record(
    particle_id=129,
    mass=1.0,
    edge_index=13,
    is_negative_force=True,
    recoil_force=(0.5392993141930545, 1.7488783991599564),
    recoil_vec=(0.00923608340988216, 0.02995143205874777),
    recoil_unit=(0.294676227936813, 0.9555971539769944),
    recoil_overlap=0.03134315745300853,
    pos_before=(52.44017413168943, 27.889193305986247),
    vel_before=(2.9852556164223527, 0.037031388844566804),
    pos=(52.44941021509931, 27.919144738044995),
    vel=(2.4459563022292983, -1.7118470103153896),
    edge_x=(51.46036572061364, 55.57905675888301),
    edge_y=(28.09332681906521, 26.823251522018445),
    edge_normal=(0.294676227936813, 0.9555971539769944),
))

plot_record(Record(
    particle_id=19174,
    mass=1.0,
    edge_index=25,
    is_negative_force=False,
    recoil_force=(0.08761850619809214, 0.6967834254761159),
    recoil_vec=(-0.010825856303603679, -0.08609228308324464),
    recoil_unit=(-0.12476457502354961, -0.99218637403423),
    recoil_overlap=0.08677027354567812,
    pos_before=(36.94759769359838, 26.432684776816743),
    vel_before=(3.0023826998695546, -0.023640365531086047),
    pos=(36.93677183729478, 26.3465924937335),
    vel=(2.9147641936714623, -0.720423791007202),
    edge_x=(38.2185815226764, 33.98308608384365),
    edge_y=(26.31139301753458, 26.843994353603644),
    edge_normal=(-0.1247645750235496, -0.9921863740342299),
))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12968811685748124, 'fraction_numerical': 0.38551125148045795, 'mean_word_length': 4.501628664495114, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '18874', 'license': 'MIT', 'n_tokens_mistral': 3296, 'n_tokens_neox': 2148, 'n_words': 319, 'path': 'misc/research/notebooks/debug_inward_collision_force.ipynb', 'repo_name': 'mchapman87501/DMCWingWorks', 'size': '5066'}