0

I'm trying to understand how "in memory" works within python. From my understanding it's a variable that is not stored anywhere but just kind of floats in the memory. I'm not exactly sure how to word this correctly.

To clarify I'm using PyKEP module and I'm loading in a SPICE kernel pykep.util.load_spice_kernel('kernel_name.bsp'). Link to the documentation

When I do this I have no new variable in the the global scope. However, it allows me to then access more data (velocity, position, ect) of the asteroid that I would call after as such.

asteroid = pk.planet.spice(spiceID, 'SUN', 'ECLIPJ2000', 'NONE', pk.MU_SUN, mu_self, self_radius, self_radius * 1.05)

I can now use asteroid.eph(epoch) without any errors in the global scope. However, this is not the case if I define it in other places or try to move it.

For example:

example 1: functions

Note pk is the PyKEP module below.

def loadKernel(name = 'de440s_Ryugu.bsp', spiceID = '162173', mu_self = 30.03336, self_radius = 432.5):
    pk.util.load_spice_kernel(name)
    asteroid = pk.planet.spice(spiceID, 'SUN', 'ECLIPJ2000', 'NONE', pk.MU_SUN, mu_self, self_radius, self_radius * 1.05)
    return asteroid

Inside the function's local scope I could use asteroid.eph(epoch) but outside I need to re-execute that first line. Which makes sense. But, why can't I return it to the global scope.

example 2: inside objects/classes

class Trajectory:
    def __init__(
            self,
            seq=[pk.planet.gtoc7(3413), pk.planet.gtoc7(
                234), pk.planet.gtoc7(11432)])
        # We define data members:
        self.__seq = seq

    def velAndPos(self):
        r, v = self.__seq[i + 1].eph(end)
        return r, v

Here I would encounter an error saying that the kernel file is not loaded even if I add pykep.util.load_spice_kernel('kernel_name.bsp') as the first line in the velAndPos method. Why would this be the case? Is it because the __seq is privet?

Further, what is the advantage of using "in memory" variables?

Thank you in advance.

Wojciech
  • 33
  • 5
  • 1
    "Why can't I return it to global scope" -- what do you mean, you "can't return it to global scope"? If there's a specific problem or error you're asking about, that would make it far more clear. (Also, see [mre] guidelines -- the code in your question should be the shortest possible thing we can _run ourselves without any changes_ to see the same problem; code that depends on variables or data files only you have can't be run without changes). – Charles Duffy Apr 18 '22 at 23:45
  • I'm finding it hard to understand what you are asking, note, "I'm trying to understand how "in memory" works within python. From my understanding it's a variable that is not stored anywhere but just kind of floats in the memory." doesn't really make any sense. I've never heard the term "in-memory variable", it certainly isn't a *Python* term, so maybe it is related to the specific library you are using. Futhermore, it is completely unclear what the specific problem or errors are that you are encountering. You really must provide a [mcve] with a clear problem specification – juanpa.arrivillaga Apr 19 '22 at 00:41
  • "Why would this be the case? Is it because the __seq is privet?" Note, it is *very important to understand* that **python doesn't have private variables**. Python doesn't have access modifiers at all. *everything* is public. leading single-underscores inside of class definitions are name-mangled, so `__some_var` will be changed to `_SomeClass__some_var`, this is *merely* to prevent accidental name collisions in subclasses. – juanpa.arrivillaga Apr 19 '22 at 00:42

3 Answers3

0

You can create a variable as a "global variable" in the global scope, prior to utilizing it inside of a function definition, and then declare it as "global" inside of the function. Here is an example that may help you:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

And here is a link to a thread that covers this topic: Using global variables in a function

Chowlett2
  • 128
  • 1
  • 1
  • 8
  • Hi, I tried this before however this does not work. The reason is if I defined `globvar =pykep.util.load_spice_kernel('kernel_name.bsp')` I cannot access the `asteroid.eph(epoch)`. And if I defined it as `global pykep.util.load_spice_kernel('kernel_name.bsp')` I get an syntax error. – Wojciech Apr 18 '22 at 23:17
  • The biggest headache I have is that the `pykep.util.load_spice_kernel('kernel_name.bsp')` cannot be stored in a variable and when it's not there are no new variable in neither the global or local scope. Yet, it allows me to now access extra data in other variables. – Wojciech Apr 18 '22 at 23:22
0

Doing my best to answer your question, but if someone else knows better please correct me in the comments.

How do in memory variable's work? Linked here you'll see that python and other high-level languages use a symbol table to map a variable name to the address it represents. And from the PyKep docs you'll find that your call to that utility loads the kernel into memory. At this point, the page table of the process that is executing your python process is aware of where the kernel has been loaded.

How it applies to your code (best guess) It's hard to say exactly without seeing your project structure, but I'll give it a shot. My guess is that you are not properly sequencing your calls to methods/attributes requiring a loaded kernel. For example, if you load the kernel only at the time of a function call, that kernel won't exist in the process until that function is called.

Michael
  • 21
  • 2
0

I had a quick look at pykep and I suspect some of the confusion is because it's implemented in C++ and bound to Python.

The kernels, it seems, are binary data files that the load function brings into memory, and then the other pykep functions can access them (again, under the hood it's all C++).

So it's not such a surprise that you aren't seeing the data appear as Python variables.

Now, as for your code - managing data with classes is a good practice. You can actually run arbitrary code in the class definition scope, so I think the following has a decent chance of working:

class Trajectory:

    pk.util.load_spice_kernel(name)

    def __init__(self, seq=None, name=None):

        if seq is None:
            # don't use something mutable as your default value,
            # else modifying it also modify the default behaviour
            seq = [
                pk.planet.gtoc7(3413),
                pk.planet.gtoc7(234),
                pk.planet.gtoc7(11432)
            ]
        # We define data members:
        self.__seq = seq

    def velAndPos(self):
        r, v = self.__seq[i + 1].eph(end)
        return r, v

If that doesn't work, you might try having the load call in both methods, but that seems inefficient.

Paddy Alton
  • 1,855
  • 1
  • 7
  • 11
  • Hi, I did the adjustments you mentioned but I still get the `SPICE cannot compute the ephemerides, have you loaded all needed Kernel files?` error I get previously. It looks like the object or instances of the object don't see the kernel. I tried also laoding it in both methods but that did not work. If this helps the type of the `pk.util.load_spice_kernel(name)` is NoneType and no variable shows up for it. what makes me curious is how the `pk.planet.gtoc7` has the kernel preloaded but that's unfortunately hidden in a PYO file. – Wojciech Apr 19 '22 at 10:06
  • Does it work if you make the load call in the top level of the file (i.e. put it outside any functions or classes, preferably just after your module imports, before you define any functions or classes)? If not, then that is rather confusing (you say it works if you do this just in a procedural script?). BTW, you get NoneType because any python function that doesn't return anything *actually* returns `None`. So it's just telling you the load function runs some procedure that modifies programme state without returning anything (on which point: *ugh!* ) – Paddy Alton Apr 19 '22 at 10:21
  • Actually I found out that the reason it did not work was because you have to have another kernel loaded. And as long as it is loaded in the global scope then the object and it's methods can access it. Thank you for your help I'm going to mark your answer as correct. – Wojciech Apr 19 '22 at 23:46