+sys order of calculation

I’m struggling with the order in which sofistik is reading teddy files when I use python to generate dat files automatically.

I have made this tiny example file to show the issue:

Sofistik file:

+prog template urs:1 $ TASK 1
    <TEXT,FILE=from_sofi.dat>
    10
    </TEXT>
END

! TASK 2
+sys python test.py


+prog template urs:2 $ TASK3
    #include from_py.dat
    prt#from_py
END

The python file multiplies the output from sofistik and writes it to a dat file from_py.dat which I then want Sofistik to read again

Python file:

sofi = float(open('from_sofi.dat').read())*5
with open('from_py.dat','w') as f:
    f.write(f'let#from_py {sofi}')

The idea is that the Sofistik file should perform the tasks line by line, i.e.:

  1. Write output file from_sofi.dat
  2. Run python file test.py
  3. Read input file from_py.dat

However, as I have come to understand Sofistik starts by scanning for #include tags and attempts to include these files which haven’t been generated yet.

As such, I have to manually run each of the three tasks in order to force sofistik to read the file in a proper order.

Is there a way to force sofistik to read the file line by line?

PS:
If there already is a from_py.dat file present in the working directory, it does run, but as it reads the #include before it runs task1, any changes I make in task1 is not included in task3 unless I run everything manually.

Think of it as compiling.

#Include works like a preprocessor instruction, i.e.

  • wps (the calculation window or sps in batch mode) scans through your file
  • copy/pastes all #includes
  • Checks for obvious mistakes (missing ends, #enddef, Endif, endloop, etc)
  • The result is a parsed file, that the program actually runs

If you look at the “input data” in your report, you see the parsed code (no #includes present).

Therefore you can not #include anything that is generated during calculation.
There are two workarounds for this:

  1. Sofistiks own variant that is used in CSM:
    +Apply something.dat
    With this a file generated at run time can be included in the calculation.
    Drawback: It has to be a “complete program”
    Your python file would have to write something like this:
    f.write('+prog template')
    f.write(f'let#from_py {sofi}') # original
    f.write('prt#from_py')
    f.write('end')
    You can have several programs in an applied file.
    Check out the csm examples in your installation folder and how sofistik applies the *_csm.dat files
  2. The cmd way:
    Put whatever you want to run in separate teddy files that calculate towards the same cdb (with #define project)
    Run the files via wps/sps from a batch script consecutively (each file starts its own calculation process)

For a simple “include at runtime” go with apply.
For more complicated processes the batch script approach lets you do almost anything.

1 Like

EDIT:
I now realise that doing this actually doesn’t change the fact the sofistik still scans through the file for #include, etc. so it shouldn’t actually work as it should still try to find the #include first?

But then… why does it work? :face_with_raised_eyebrow:

Original post

Ah that does make sense, thank you very much for that explanation, I’ll keep that in mind for future projects.

For the +apply method, I do, as you also point out, see possible issues in larger projects.
Specifically, I’ve previously used python to generate large files with if functions as a workaround for sofistiks missing matrix functionality. As such I have I have made slight changes to the code you provided where I generate a +prog template with python containing a #Define. Thereby I can include the definition after generation, and force sofistik to read it line by line, while I’m still able to include it when I actually need it.

Please find both the main file and the python generated file below:
main.dat:

+prog template urs:1 $ from_sofi
    <TEXT,FILE=from_sofi.dat>
    10
    </TEXT>
END

+sys python test.py
+apply from_py.dat

+prog template urs:2 $ back to sofi
    loop#row 2
        loop#i 2
            #include test
            prt#from_py(#i)
        endloop
    endloop
END

from_py.dat:

+prog template $ python generated files
  #define test
    if #row == 0
        sto#from_py(0) 50.0
        sto#from_py(1) 100.0
    else #row == 1
        sto#from_py(0) 200.0
        sto#from_py(1) 400.0
    endif
  #ENDDEF
END

Output from main.dat report:

---- CADINT VARIABLE FROM_PY         (     0) =       50.00
---- CADINT VARIABLE FROM_PY         (     1) =       100.0
---- CADINT VARIABLE FROM_PY         (     0) =       200.0
---- CADINT VARIABLE FROM_PY         (     1) =       400.0

I have used the CMD method before as well, but I agree, this should be used for larger projects.

Well sometimes things in sofistik works even when they shouldn’t.
See this as a bug or a unintended feature. :grin:

It could also be reading an old version of test. You should check that.

I try to make sure that everything that is run time generated is within the +apply file.
You never know when developers discover “unintended features” and eliminate them. :cry:

One thing that works and can be used, is to:

  • #define in your main file
  • #include within the +apply file
1 Like