hunar4321 / particle-life

A simple program to simulate artificial life using attraction/reuplsion forces between many particles
MIT License
2.92k stars 292 forks source link

Simultaneous attractive and repulsive forces in the same particle #85

Open KhadrasWellun opened 1 year ago

KhadrasWellun commented 1 year ago

Hi! I want a particle of a certain colour to attract and repel a particle of another colour simultaneously, on different beams and with different intensities. In the original application, a particle either attracts or repels another particle, depending on the sign of the intensity of the interaction force. I started by defining interactions as follows: void interaction(std::vector Group1, const std::vector Group2, float G, float Gradius, float A, float Aradius, float viscosity, float Gprobability, float Aprobability); "G" would be "powerSlidera" for pull force, "Gradius" would be "vSlidera" for pull force, "A" would be "powerSliderr" for repelling force, "Aradius" would be "vSliderr" for repelling force. Defining interactions would be of the form: if (numberSliderR > 0) interaction(&green, &red, powerSlider_a_GR, vSlider_a_GR, powerSlider_r_GR, vSlider_r_GR, viscosityG, probability_a_GR, probability_r_GR);

However, I have no idea how the calculation of forces and velocities should be defined.

I try to defined:

void ofApp::interaction(std::vector Group1, const std::vector Group2, const float G, const float Gradius, const float A, const float Aradius, const float viscosity, const float Gprobability, const float Aprobability) { const float g = G / -100; //Gravity coefficient const float a = A / 100; //Anti-Gravity coefficient const auto group1size = Group1->size(); const auto group2size = Group2->size(); const bool radius_toggle = radiusToogle;

But I don't know if it's good.

Then I modified this: //Calculate the force in given bounds. if ((r < (Gradius Gradius - Aradius Aradius) || radius_toggle) && r != 0.0F) { fx += (dx / std::sqrt(dx dx + dy dy)); fy += (dy / std::sqrt(dx dx + dy dy)); } }

                //Calculate new velocity
                p1.vx = (p1.vx + (fx * (g + a))) * (1 - viscosity);
                p1.vy = (p1.vx + (fx * (g + a))) * (1 - viscosity) + worldGravity;

But I don't know if it's good.

It must be kept in mind that each type of force has its intensity and range of action and this must be clearly defined in the application.

There would be three situations: when Gradius > Aradius; when Gradius = Aradius; when Gradius < Aradius.

For each of them I think the formulas for force and velocity should be defined.

For example: Blue can attract White with an intensity of 20, on a radius of 100, and at the same time repel White with an intensity of 30 but on a radius of 40. Then White can attract Blue with an intensity of 30 on a radius of 70, but simultaneously repel it with an intensity of 50 on a radius of 60. So White can be caught by the attraction of Blue but cannot approach it at less than 60, because it repels Blue with an intensity of 50 which is greater than the attraction of 30 it has to Blue at a radius of 70. At a distance of 60, there is a neutral force of zero intensity between Blue and White.

Any ideas? Any help?

ker2x commented 1 year ago

A simple patch would be to revert the sign in an else condition.

if(within radius) {
  attract
} else {
  repulse
}

from my experience, any rule that apply to the whole screen (r > radius*radius) lead to uninteresting result.

KhadrasWellun commented 1 year ago

A simple patch would be to revert the sign in an else condition.

if(within radius) {
  attract
} else {
  repulse
}

from my experience, any rule that apply to the whole screen (r > radius*radius) lead to uninteresting result.

But I don't want to apply the rules to the whole screen. I think I misunderstood part of the code.

KhadrasWellun commented 1 year ago

Do you have any idea how to make settings menu with vertical scrollbar? When you have a lot of data in the menu, you need to be able to scroll through it to view it. I'd like to do that but I don't know how.

ker2x commented 1 year ago

I don't know. I made gui group instead.

KhadrasWellun commented 1 year ago

I finished inserting the matrix but i got this: image

Something is very wrong here in what i've done.

KhadrasWellun commented 1 year ago

I don't understand this part of the code. This is where the problem with the strange behaviour of the particles comes from. Please, could you help me? I have defined two intensities (one for attraction and one for repulsion) and two ranges of action. How should this piece of code be modified so that each distance or distance difference corresponds to the appropriate intensity or intensity difference? I have attached a document explaining how I see the two types of forces and what I want to implement in this code. Attraction and Repulsion Explained.pdf Here I have attached my latest version of the code. src.zip And here is the piece of code where I think it is wrongly modified by me:

pragma omp for

    for (auto i = 0; i < group1size; i++)
    {
        if (rd() % 100 < probability) {
            auto& p1 = (*Group1)[i];
            float fx = 0;
            float fy = 0;

            //This inner loop is, of course, where most of the CPU time is spent. Everything else is cheap
            for (auto j = 0; j < group2size; j++)
            {
                const auto& p2 = (*Group2)[j];

                // you don't need sqrt to compare distance. (you need it to compute the actual distance however)
                const auto dx = p1.x - p2.x;
                const auto dy = p1.y - p2.y;
                const auto r = dx * dx + dy * dy;

                //Calculate the force in given bounds. 
                if ((r > (Gradius * Gradius - Aradius * Aradius) || radius_toggle) && r != 0.0F)
                {
                    fx += (dx / std::sqrt(dx * dx + dy * dy));
                    fy += (dy / std::sqrt(dx * dx + dy * dy));
                }
            }

                //Calculate new velocity
                p1.vx = (p1.vx + (fx * (g + a)) * (1 - viscosity));
                p1.vy = (p1.vx + (fx * (g + a))) * (1 - viscosity) + worldGravity;
ker2x commented 1 year ago

Try with this (doing comparison with the distance squared was a dirty optimization trick that may not even worth it). I'm not sure about this part with the if(r> ...) , I need to take time to understand the pdf. But at least the code will be much more clear

        for (auto j = 0; j < group2size; j++)
            {
                const auto& p2 = (*Group2)[j];

                // you don't need sqrt to compare distance. (you need it to compute the actual distance however)
                const auto dx = p1.x - p2.x;
                const auto dy = p1.y - p2.y;
                const auto r = std::sqrt(dx * dx + dy * dy);

                //Calculate the force in given bounds. 
                if ((r > (Gradius - Aradius) || radius_toggle) && r != 0.0F)
                {
                    fx += (dx / r);
                    fy += (dy / r);
                }
            }

                //Calculate new velocity
                p1.vx = (p1.vx + (fx * (g + a)) * (1 - viscosity));
                p1.vy = (p1.vx + (fx * (g + a))) * (1 - viscosity) + worldGravity;
KhadrasWellun commented 1 year ago

No change. image

KhadrasWellun commented 1 year ago

I noticed that changing the parameters of the interaction forces has no effect on what happens on the screen. This means that those parameters are not taken into account. This definition is wrong: void ofApp::interaction(std::vector Group1, const std::vector Group2, const float G, const float Gradius, const float viscosity, const float Gprobability, const float A, const float Aradius, const float Aprobability)

But how should it be correct?

KhadrasWellun commented 1 year ago

I will try another way. I will define 2 types of interactions: interaction1 and interaction2. One is for attraction and the other for repulsion. Then I will use them as follows: image

But no efect.

KhadrasWellun commented 1 year ago

I got stuck. I don't know what to do.

ker2x commented 1 year ago

wait, how old is the code you're using as a base ? I'm pretty sure I removed all the raw pointer.

Also : I'm really getting confused by the ">". you tell it to apply force to particle that are outside the radius. therefore : the whole screen. which lead to result with a single group of particle like you have. why not "<" ?

KhadrasWellun commented 1 year ago

wait, how old is the code you're using as a base ? I'm pretty sure I removed all the raw pointer.

Also : I'm really getting confused by the ">". you tell it to apply force to particle that are outside the radius. therefore : the whole screen. which lead to result with a single group of particle like you have. why not "<" ?

I don't know how old. I downloaded with the last modification.

With r < Gradius, I gain:

image

With r < Gradius * Gradius I gain:

image

ker2x commented 1 year ago

well my bad. I'm so busy playing with my oneapi branch that I forgot to do some merge request here. you have the last code indeed ^^

KhadrasWellun commented 1 year ago

The main problem is this: I made a button to randomize only the interaction parameters and changing them over and over again nothing happens on the screen.

Look:

image

After a cuple of randomization,

image

KhadrasWellun commented 1 year ago

It can be seen that the forces acting on the screen are not those resulting from the parameters. There are other forces on the screen that move and keep the particles aligned that are much stronger than the forces resulting from the parameters defined by those sliders. So, the formulas for calculating forces and velocities do not take into account the powerSlider and vSlider parameters.

ker2x commented 1 year ago

There is something super weird, even in my code. How come power became G. and why did I write "gravity coefficient" when it clearly isn't ...

ker2x commented 1 year ago

ha yes I see... "attraction" is named "gravity"... (which is kind of bad since there is a world gravity parameter)

ker2x commented 1 year ago

random guess.

can you try with std::abs(Gradius - Aradius) ?

KhadrasWellun commented 1 year ago

I have already modified the code defining the 2 interactions and I no longer have how to write the Gradius - Aradius condition in the same sentence.

image

KhadrasWellun commented 1 year ago

Now, two types of interactions occur simultaneously between two particles.

image

KhadrasWellun commented 1 year ago

Now, two types of interactions occur simultaneously between two particles. (or they should...)

image

KhadrasWellun commented 1 year ago

However, I think this code should be rewritten from scratch and rewritten taking into account what is written in this document. Attraction and Repulsion Explained.pdf Because what is written in this document should actually happen in this simulation. Also, there should be a very, very weak gravitational force that brings together all the structures formed by the colored forces and makes them reinteract, always regrouping. At some point, because of the small action radii of the coloured forces, the structures formed by the particles remain outside these action radii and stop moving. That's why you need a gravitational force with an infinite action radius to bring them all together. Or a particle with an infinite radius of action and very weak forces that do the job of universal gravity. In order to prevent all the particles from clumping into a small area of the simulation surface, dark matter should be introduced, which will prevent the matter from collapsing into itself. That is, a very strong repulsive force, but with a very small radius of action. Only then will this simulator generate interesting structures.

Romanian Adrian Ferent from the University of Bucharest has some very interesting findings on dark photons, dark matter, dark energy, Planck's wall and Ferent's wall, gravitons and elementary particle theory. From here I would like to implement some ideas.

https://www.academia.edu/30873188/Dark_Energy_is_Gravitational_Waves_Dark_Energy_is_Gravitons?email_work_card=title

https://independent.academia.edu/ADRIANFERENT

I can say that this Romanian professor is a true genius.