Amigo54
Amigo54

Reputation: 5

Code yields different results when iterating through for loops versus running once

I wrote a script which edits a .txt file of a simulation program (LTspice) and then runs the simulation using the modified .txt file.

There are eight values (with three possible states) which I want to change independently for each iteration. Therefore I used eight for loops to iterate through all the combinations by searching and replacing the strings in the .txt file. This looks like this:

Txt_original = 'SIM_COM_Automated_Copy.txt' #LTSpice output file has to be copied manually first

rawDataFile = 'SIM_COM_Automated_Copy.raw'

list1 =[]
list2 = []

with open(Txt_original, 'rb') as file:
        Data_backup = file.read()

resistorValues = [['Res1=1980', 'Res1=2000', 'Res1=2020'],['Res2=1980', 'Res2=2000', 'Res2=2020'], ['Res3=1980', 'Res3=2000', 'Res3=2020'], ['Res4=1980', 'Res4=2000', 'Res4=2020'], ['Res7=19800', 'Res7=20000', 'Res7=20200'], ['Res8=9900', 'Res8=10000', 'Res8=10100'], ['Res16=19800', 'Res16=20000', 'Res16=20200'], ['Res17=9900', 'Res17=10000', 'Res17=10100']] 

count = 0

for a in range(1,3):
    editSimParameters(Txt_original, resistorValues[0][0], resistorValues[0][a] ) #Res1
    for b in range(1,3):
        editSimParameters(Txt_original, resistorValues[1][0], resistorValues[1][b] ) #Res2
        for c in range(1,3):
            editSimParameters(Txt_original, resistorValues[2][0], resistorValues[2][c] ) #Res3
            for d in range(1,3):
                editSimParameters(Txt_original, resistorValues[3][0], resistorValues[3][d] ) #Res4
                for e in range(1,2):
                    editSimParameters(Txt_original, resistorValues[4][0], resistorValues[4][e] ) #Res7
                    for f in range(1,2):
                        editSimParameters(Txt_original, resistorValues[5][0], resistorValues[5][f] ) #Res8
                        for g in range(1,2):
                            editSimParameters(Txt_original, resistorValues[6][0], resistorValues[6][g] ) #Res16
                            for h in range(1,2):
                                editSimParameters(Txt_original, resistorValues[7][0], resistorValues[7][h] ) #Res17
                                runSimulation(Txt_original)
                                #time.sleep(10)
                                result = evaluateResults(rawDataFile)
                                valueSet = [a, b, c, d, e, f, g, h]
                                
                                if valueSet == [2,2,2,2,1,1,1,1]:
                                    print('Res1= '+resistorValues[0][a])
                                    print('Res2= '+resistorValues[1][b])
                                    print('Res3= '+resistorValues[2][c])
                                    print('Res4= '+resistorValues[3][d])
                                    print('Res7= '+resistorValues[4][e])
                                    print('Res8= '+resistorValues[5][f])
                                    print('Res16= '+resistorValues[6][g])
                                    print('Res17= '+resistorValues[7][h])
                                    print('The result of the combination ' + str(valueSet) + ' is ' + str(result))
                                
                                list1.append(result)
                                list2.append(valueSet)

                                    
                                with open(Txt_original, 'wb') as file:  #Reset the working file
                                    file.write(Data_backup)
                                
                                #Progress Tracking
                                count = count +1        

                                if count%25 == 0:
                                    print(count)

The editSimParameters() function looks like this:

def editSimParameters(workingFile, oldParam, newParam):
    with open(workingFile, 'rb') as file:
        Data_original = file.read() 
        Data_temp = Data_original.replace(oldParam.encode('utf-8'), newParam.encode('utf-8'))
    
    with open(workingFile, 'wb') as file:
        file.write(Data_temp)

I have reduced the number of loop iteration in this example, so that the code terminates faster. Nonetheless when running this code the result for the combination [2,2,2,2,1,1,1,1] is different to the result of the same combination which I obtained by altering the for loops, so that only this combination is executed:

Result after the iteration (16 simulations in total): The result of the combination [2, 2, 2, 2, 1, 1, 1, 1] is 16.347881

Result with altered for loops (1 simulation): The result of the combination [2, 2, 2, 2, 1, 1, 1, 1] is 16.327114

The result with just one simulation is correct which I verified by doing the simulation manually.

Am I overseeing a problem when iterating over and changing the .txt file or is there anything else?

Upvotes: 0

Views: 71

Answers (1)

AKX
AKX

Reputation: 169398

Here's a much simplified (and more powerful) version of what you seem to be trying to do, using itertools.product and a regular expression to replace the resistor values.

The idea is that we

  • read your original LTSpice file (which I don't have at hand, hence a string constant in the source)
  • set up a dictionary matching resistor names to the values those resistors should be attempted with
  • use some gentle zip magic to massage that dictionary into a form itertools.product accepts
  • use itertools.product to generate the cartesian product of the values, then zip them back with the keys to get a combo dict
  • loop over the combo and use re.sub to substitute those values into (a copy of) the template.
  • Instead of print()ing the data like we do here, you'd write that out to the file you feed to the simulator, and do what you must there. I would recommend not overwriting the original template file.

You can add as many keys and values to the resistor_combos dict as you like, and they'll all be exhaustively checked.

import itertools
import re

# Would be read from the original SIM_COM_Automated_Copy file
template = """
Res1=100
Res2=100
Res8=1000
""".strip()

resistor_combos = {
    "Res1": [123, 456],
    "Res2": [789, 126],
}

resistor_keys, resistor_values = zip(*resistor_combos.items())

for value_combo in itertools.product(*resistor_values):
    combo = dict(zip(resistor_keys, value_combo))
    data = template  # "Copy" the template for modification
    for key, value in combo.items():
        data = re.sub(f"^{key}=(\d+)", f"{key}={value}", data, flags=re.MULTILINE)
    print(combo)
    print(data)
    print("====")

This prints out

{'Res1': 123, 'Res2': 789}
Res1=123
Res2=789
Res8=1000
====
{'Res1': 123, 'Res2': 126}
Res1=123
Res2=126
Res8=1000
====
{'Res1': 456, 'Res2': 789}
Res1=456
Res2=789
Res8=1000
====
{'Res1': 456, 'Res2': 126}
Res1=456
Res2=126
Res8=1000
====

Upvotes: 4

Related Questions