Hi all, ultimately I’m trying to simulate Chladni patterns (made by vibrating a metal plate with particles on it). I’ve come across this equation that gives Chladni patterns (a, b, m, n are parameters).

```
double ofApp::f(double a, double b, double m, double n, double x, double y){
double zpos = a*glm::sin(3.14*x*n)*glm::sin(3.14*y*m) + b*glm::sin(3.14*x*m)*glm::sin(3.14*y*n);
return zpos;
}
```

(small aside, things break when I try to use the PI constant defined in ofMathConstants.h. It also breaks if I manually include more digits like 3.14159).

I’m trying to take the gradient of this function, and use it to push particles around (into the nodes of the function f(a, b, m, n, x, y) ideally). I do this as below:

```
ofVec2f ofApp::gradCalc(double a, double b, double m, double n, double x, double y){
ofVec2f v;
double eps = 1e-10;
double dx = eps;
double dfdx = (f(a, b, m, n, x+dx, y) - f(a, b, m, n, x, y)) / (dx);
double dy = eps;
double dfdy = (f(a, b, m, n, x, y+dy) - f(a, b, m, n, x, y)) / (dy);
v.set(dfdx, dfdy);
return v;
}
```

I can see that this is working… almost. I can draw the gradient field and it looks how I’d expect. However when I try to use this field to move particles, I run into trouble. To debug I focused on just one particle, and I set it up so that I can click on the screen and it’ll show what the gradient is at that point. Sometimes this will look correct and align with the field, but other times it looks very wrong. The magnitude always looks correct though.

Here it is looking correct:

But at a position very close by I get unexpected behavior:

I was thinking it had to do with numerical precision so I went through and made all floats doubles. I’m not very versed in C++ so I feel like I’m overlooking something silly!

Thanks for reading

Here’s the full myApp.cpp and header:

```
#include "ofApp.h"
vector<ofVec3f> pos;
vector<ofVec3f> origPos;
ofEasyCam cam;
ofNode node;
double a = 5;
double b = 5;
double m = 5;
double n = 5;
ofVec3f mousePos (0,0,0);
bool framestep = false;
//--------------------------------------------------------------
void ofApp::setup(){
node.setPosition(ofGetWidth()/2, ofGetHeight()/2, 0);
cam.setTarget(node);
ofSetFrameRate( 60 );
for(double i = 0; i < 50; i++){
for(double j = 0; j < 50; j++){
ofVec3f v;
double zpos = f(a, b, m, n, i*20, j*20);
//cout << zpos << endl;
v.set(i*20, j*20, zpos);
pos.push_back(v);
}
}
origPos.assign(pos.begin(), pos.end());
}
//--------------------------------------------------------------
void ofApp::update(){
if (framestep == true){
cout << mousePos << endl;
cout << gradCalc(a, b, m, n, mousePos.x, mousePos.y) << endl;
framestep = false;
}
}
//--------------------------------------------------------------
void ofApp::draw(){
//try to draw the gradient vectors to see if that calculation's working
//cam.begin();
//this loop draws the gradient field on the 50x50 grid
for(int i = 0; i < pos.size(); i++){
ofSetColor(0, 0, 0);
ofDrawArrow(origPos[i], origPos[i] + gradCalc(a, b, m, n, origPos[i].x, origPos[i].y), 5);
}
//draw the gradient at the point of mouse click
ofSetColor(255, 255, 255);
ofDrawCircle(mousePos.x, mousePos.y, 5);
ofDrawArrow(mousePos, mousePos + gradCalc(a, b, m, n, mousePos.x, mousePos.y), 5);
//cam.end();
string fpsStr = "frame rate: "+ofToString(ofGetFrameRate(), 2);
ofDrawBitmapString(fpsStr, 100,100);
}
double ofApp::f(double a, double b, double m, double n, double x, double y){
double zpos = a*glm::sin(3.14*x*n)*glm::sin(3.14*y*m) + b*glm::sin(3.14*x*m)*glm::sin(3.14*y*n);
return zpos;
}
ofVec2f ofApp::gradCalc(double a, double b, double m, double n, double x, double y){
ofVec2f v;
double eps = 1e-10;
double dx = eps;
double dfdx = (f(a, b, m, n, x+dx, y) - f(a, b, m, n, x, y)) / (dx);
double dy = eps;
double dfdy = (f(a, b, m, n, x, y+dy) - f(a, b, m, n, x, y)) / (dy);
v.set(dfdx, dfdy);
return v;
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
mousePos.set(ofGetMouseX(), ofGetMouseY());
framestep = true;
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}
```

header:

```
#pragma once
#include "ofMain.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
ofVec2f gradCalc(double a, double b, double m, double n, double x, double y);
double f(double a, double b, double m, double n, double x, double y);
};
```