Ik probeer een fysisch proces te simuleren met behulp van een heel erg simpel model. Helaas is mijn simpele aanpak net niet snel genoeg, het is prima om een aantal keer als test te draaien, maar het doel is uiteindelijk om de uitkomst van de simulatie te bekijken als functie van een van de parameters, welke ik over een grote range wil veranderen, en dat gaat veel te lang duren. Ik zou dus graag het algoritme verbeteren als dat mogelijk is om het sneller te maken.
Ik ben begonnen in Python maar heb het algoritme uiteindelijk over gezet naar C# wat toch wel VEEL sneller was. Misschien dat ik nog naar C++ ofzo kan overstappen maar ik denk dat die stap me veel minder brengt en dat het algoritme zelf nu de bottleneck is.
Het model is heel simpel: ik heb een grid van 1000x1000 cells wat een bepaald materiaal voorstelt (dit getal staat redelijk vast, ik wil niet veel kleiner en veel groter is niet nodig). Op dit materiaal ga ik één voor één een groot aantal "impacts" simuleren, die allemaal een krater achterlaten van een vaste grootte. Ik genereer dus een groot aantal (x, y) coordinaten, en voor elk van die coordinaten teken ik op de grid een circelvormige impact krater met een straal van bijvoorbeeld 20 cellen.
Uiteindelijk wil ik kijken naar de (oppervlakte) fractie van de krater (aantal cellen die in een krater liggen gedeeld door de rest).
Het meest voor de hand liggende algoritme dat ik kon bedenken was als volgt (pseudo code):
Voor elk (random) impact punt doe ik dus een loop door elke cell binnen de maximale 'bounding box' van de krater cirkel. Voor elke cell check ik de afstand tot het impact punt en als die kleiner of gelijk aan de gewenste straal is dan ligt het punt dus binnen de krater. In deze pseudo code negeer ik even rand condities waarbij de krater half buiten de grid valt (ik gebruik een 'wrap around' om de grid in principe oneindig te laten zijn, alles wat er links buiten valt komt rechts terug).
Helaas is dit dus langzaam, waarschijnlijk door de dubbele loop (voor elk impact punt moet hij weer opnieuw door alle cells loopen die in de buurt van het impact punt liggen). Hoe groter de straal van de kraters, hoe langer het duurt uiteraard, en de straal van de krater is nu juist een van de dingen die ik wil varieren, dat is dus niet optimaal.
Ik zie niet zo snel wat ik hier aan kan verbeteren. Eventueel zou ik de wortel weg kunnen laten bij de afstand check (en gewoon radius^2 vergelijken) maar dat maakt zowat geen verschil.
Ik ging op zoek naar oplossingen maar ik weet niet zo goed hoe ik dit moet verwoorden. Toch kwam ik een aantal tips tegen die wel logisch leken: het probleem nu is dat ik elke keer opnieuw door alle cellen in de buurt van het impact punt moet gaan loopen. Het zou veel sneller zijn als elke cell gewoon weet wat zijn buren zijn en dat ik die allemaal tegelijk op 1 kan zetten in plaats van eerst moet checken of ze wel binnen de straal vallen.
De makkelijkste manier om dat te doen is door na het opbouwen van de grid eerst voor elke cell deze loop uit te voeren en die cell te laten weten welke cellen er binnen de straal liggen. Dat was echter niet zo slim bedacht want het enige wat ik daarmee bereik is dat ik het langste gedeelte van de simulatie nu eerst op ELKE cell ga uitvoeren in plaats van op maar 10,000 cellen. Het opbouwen van de grid duurt dus een eeuwigheid (en hij raakt zelfs out of memory), dus dat werkt ook niet echt. Daarnaast zou ik die hele procedure steeds weer opnieuw moeten doorlopen als ik de gewenste straal van de kraters zou veranderen (wat ik dus van plan ben) en schiet ik er nog niks mee op.
Ten slotte heb ik nog bedacht of het parallel te maken was. Misschien is dat wel zo in het speciale geval wat ik nu omschrijf maar de werkelijke simulatie is net wat ingewikkelder, en volgens mij is het belangrijk dat elke impact achter elkaar gebeurt en niet tegelijk (de uitkomst van de impact hangt af van of er al een krater is op dat punt of niet). Dus ik zoek voornamelijk naar een beter algoritme en niet zozeer een parallel algoritme, maar als iemand daar een tip voor heeft dan kan ik daar misschien ook wel wat mee...
Kent iemand een betere manier om de grid op te bouwen zodat elke cell al meteen weet welke cellen er om zich heen liggen binnen de straal die ik wil? Of een andere manier om dit sneller te maken?
Ik ben begonnen in Python maar heb het algoritme uiteindelijk over gezet naar C# wat toch wel VEEL sneller was. Misschien dat ik nog naar C++ ofzo kan overstappen maar ik denk dat die stap me veel minder brengt en dat het algoritme zelf nu de bottleneck is.
Het model is heel simpel: ik heb een grid van 1000x1000 cells wat een bepaald materiaal voorstelt (dit getal staat redelijk vast, ik wil niet veel kleiner en veel groter is niet nodig). Op dit materiaal ga ik één voor één een groot aantal "impacts" simuleren, die allemaal een krater achterlaten van een vaste grootte. Ik genereer dus een groot aantal (x, y) coordinaten, en voor elk van die coordinaten teken ik op de grid een circelvormige impact krater met een straal van bijvoorbeeld 20 cellen.
Uiteindelijk wil ik kijken naar de (oppervlakte) fractie van de krater (aantal cellen die in een krater liggen gedeeld door de rest).
Het meest voor de hand liggende algoritme dat ik kon bedenken was als volgt (pseudo code):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| // Straal van krater radius = 20 // Grid van 1000x1000 cellen // Cell waarde 0 is geen krater, waarde 1 is krater cells = int[1000, 1000] // Bijvoorbeeld 10000 impacts for i = 0 to 10000 { // Kies random locatie x = random(0, 1000) y = random(0, 1000) // Definieer vierkant rondom impact punt waar binnen de krater moet liggen minX = x - radius maxX = x + radius minY = y - radius maxY = y + radius // Check elk punt of het binnen de krater ligt for xi = minX to maxX { for yi = minY to maxY { // Is de afstand van dit punt tot impact punt < radius? distance = sqrt((x-xi)^2 + (y-yi)^2) if (distance <= radius) { // Dit punt ligt binnen krater cells[xi, yi] = 1 } } } } |
Voor elk (random) impact punt doe ik dus een loop door elke cell binnen de maximale 'bounding box' van de krater cirkel. Voor elke cell check ik de afstand tot het impact punt en als die kleiner of gelijk aan de gewenste straal is dan ligt het punt dus binnen de krater. In deze pseudo code negeer ik even rand condities waarbij de krater half buiten de grid valt (ik gebruik een 'wrap around' om de grid in principe oneindig te laten zijn, alles wat er links buiten valt komt rechts terug).
Helaas is dit dus langzaam, waarschijnlijk door de dubbele loop (voor elk impact punt moet hij weer opnieuw door alle cells loopen die in de buurt van het impact punt liggen). Hoe groter de straal van de kraters, hoe langer het duurt uiteraard, en de straal van de krater is nu juist een van de dingen die ik wil varieren, dat is dus niet optimaal.
Ik zie niet zo snel wat ik hier aan kan verbeteren. Eventueel zou ik de wortel weg kunnen laten bij de afstand check (en gewoon radius^2 vergelijken) maar dat maakt zowat geen verschil.
Ik ging op zoek naar oplossingen maar ik weet niet zo goed hoe ik dit moet verwoorden. Toch kwam ik een aantal tips tegen die wel logisch leken: het probleem nu is dat ik elke keer opnieuw door alle cellen in de buurt van het impact punt moet gaan loopen. Het zou veel sneller zijn als elke cell gewoon weet wat zijn buren zijn en dat ik die allemaal tegelijk op 1 kan zetten in plaats van eerst moet checken of ze wel binnen de straal vallen.
De makkelijkste manier om dat te doen is door na het opbouwen van de grid eerst voor elke cell deze loop uit te voeren en die cell te laten weten welke cellen er binnen de straal liggen. Dat was echter niet zo slim bedacht want het enige wat ik daarmee bereik is dat ik het langste gedeelte van de simulatie nu eerst op ELKE cell ga uitvoeren in plaats van op maar 10,000 cellen. Het opbouwen van de grid duurt dus een eeuwigheid (en hij raakt zelfs out of memory), dus dat werkt ook niet echt. Daarnaast zou ik die hele procedure steeds weer opnieuw moeten doorlopen als ik de gewenste straal van de kraters zou veranderen (wat ik dus van plan ben) en schiet ik er nog niks mee op.
Ten slotte heb ik nog bedacht of het parallel te maken was. Misschien is dat wel zo in het speciale geval wat ik nu omschrijf maar de werkelijke simulatie is net wat ingewikkelder, en volgens mij is het belangrijk dat elke impact achter elkaar gebeurt en niet tegelijk (de uitkomst van de impact hangt af van of er al een krater is op dat punt of niet). Dus ik zoek voornamelijk naar een beter algoritme en niet zozeer een parallel algoritme, maar als iemand daar een tip voor heeft dan kan ik daar misschien ook wel wat mee...
Kent iemand een betere manier om de grid op te bouwen zodat elke cell al meteen weet welke cellen er om zich heen liggen binnen de straal die ik wil? Of een andere manier om dit sneller te maken?