Search code examples
loopsschemeraytracing

Scheme: How to create a loop that saves data to files with different names?


I am using a program (TracePro) that uses Scheme, which I haven't used all that much. I want to create a code that changes some initial values, runs a simulation, and then saves the resulting data table to a file, then changes the values again, runs the simulation, saves data, etc. for 90 times. The code I've created so far:

(raytrace:set-beam-orientation-euler-degrees (gvector 0 90 -90))
(raytrace:grid)
(edit:select (car (cdr (entity:faces (entity 12)))))
(analysis:incident)
(analysis:incident-save "C:/Users/Admin/Desktop/testdata/incident0.csv" "csv")

Is there a way to create a loop that would run this piece of code with different incident angle, from 0 to 90, and different file name, from incident0.csv all the way to incident90.csv, without having to copy the code 90 times, and change it manually...? I sort of have an idea how to handle the changing incident angle, but no idea about the file name change.

Thanks in advance.


Solution

  • I don't know the specifics of TracePro, but in any Scheme program you can loop by using recursion. First, we must refactor the parts in the code that change and make them parameters, encapsulating the code in a function. I'm not sure which value is supposed to be the incident angle, please adjust as necessary:

    (define (run-simulation angle)
      (raytrace:set-beam-orientation-euler-degrees
       (gvector angle 90 -90)) ; assuming that the first parameter is the angle
      (raytrace:grid)
      (edit:select
       (car (cdr (entity:faces (entity 12)))))
      (analysis:incident)
      (analysis:incident-save
       (string-append          ; this is how we can dynamically create file names
        "C:/Users/Admin/Desktop/testdata/incident"
        (number->string angle)
        ".csv")
       "csv"))
    

    With the above procedure in place, it's easy to loop on it, calling it as many times as needed. Notice how we use the base case of the recursion for stopping, and how at the recursive step we increment the current value:

    (define (loop init end)
      (cond ((> init end) 'done)      ; base case of recursion
            (else                     ; otherwise
             (run-simulation init)    ; call the previous procedure
             (loop (+ init 1) end)))) ; advance recursion
    

    Now we just have to provide appropriate start and stop parameters at the time we call the loop:

    (loop 0 90)
    

    If we're smart about it, we can reuse the same looping procedure for other purposes, notice that the only thing that might change is the procedure that gets called - so we can pass it as a parameter, too!

    (define (loop func init end)
      (cond ((> init end) 'done)
            (else
             (func init)
             (loop func (+ init 1) end))))
    
    (loop run-simulation 0 90)
    

    There are other tricks you can apply to make the program more flexible, but for the time being, the above code should put you on the right track. Happy Scheming!