.. _jython-impl: # Jython By default, RiskScape will execute your Python function using the Java-based implementation, called [Jython](https://www.jython.org). Alternatively, you can setup RiskScape to use :ref:`cpython-impl`. You can also mix and match, and use CPython for some functions and Jython for other functions. This page describes some of the behaviour specific to Jython in more detail. ## Calling other RiskScape functions You can call other user-defined Jython functions from your function, as well as some built-in RiskScape functions. For example, we could call our `hello` function from the :ref:`hello world example ` from _another_ different function: ```python # basic syntax is: functions.get().call() greeting = functions.get('hello').call('Kia ora', 'Ronnie') ``` Note that currently this has the following limitations: - The types of the arguments must match exactly, e.g. you cannot pass an integer to something that expects a floating argument. - You must not omit any optional arguments. - Built-in RiskScape functions that support a wide range of argument-types (i.e. functions that accept or return the type `Anything`) are not supported. ## Jython packages If you have used Python (or more specifically, CPython) in the past, you may notice that Jython is a little different, in particular when importing and using packages. For example, generating a random number between zero and one would usually look like the following in CPython. ```python import random num = random.uniform(0, 1.0) ``` Whereas in Jython, it would look like this: ```python from java.util import Random random = Random() num = random.nextDouble() ``` .. note:: We recommend you call the built-in RiskScape functions where possible, rather than importing Jython packages. For example, to achieve the same thing using the built-in RiskScape function: ```python num = functions.get('random_uniform').call(0.0, 1.0) ``` .. tip:: In general, once you start needing to import Python packages, it will be simpler to switch from using Jython to using :ref:`cpython-impl`. ## Basic loss function Now let's look at a more complicated example. The below Python code (`quake.py`) is an example of a basic loss function. ```python def function(building, hazard): loss = {} loss['replacement'] = building['replace'] loss['hazard'] = hazard construction = building['construct'] if hazard is None: loss['dr'] = 0 loss['loss'] = 0 else: loss['dr'] = damage_function(construction, hazard) loss['loss'] = loss['replacement'] * loss['dr'] return loss CONSTRUCT_WOOD = 1 def damage_function(construction, hazard): if construction == CONSTRUCT_WOOD: mean = 0.22 stddev = 0.74 else: mean = 0.92 stddev = 0.64 # call the built-in 'lognorm_cdf' riskscape function return functions.get('lognorm_cdf').call(hazard, mean, stddev) ``` This function demonstrates many points we have already covered, such as: * The `building` argument is a `struct`, and contains two attributes that we are interested in: construction type and replacement value. Note that the actual building input data file might contain many more attributes, but our function only cares about two of them. * The `hazard` argument is _nullable_, i.e. it may be `None`. * We call the builtin RiskScape function `lognorm_cdf` to calculate the cumulative log normal distribution. * The return value is a `struct`, which we build up as a Python dictionary. The INI file definition for this function might look like this: ```ini [function quake] description = Example loss function location = quake.py argument-types = [ building, hazard: nullable(floating) ] return-type = shaking_result [type building] type.replace = integer type.construct = integer [type shaking_result] type.hazard = nullable(floating) type.loss = floating type.dr = floating type.replacement = integer ``` We have defined the `building` argument and `return-value` as separate types here, for clarity. ## Older behaviour If you have used older RiskScape releases, this next section covers some of the differences you might notice with Jython functions. ### Function parameters In previous releases, RiskScape used to support a special `PARAMETERS` keyword for Jython functions. These parameters were helpful if your function made certain assumptions when determining the consequence for a given exposure and hazard - you could then vary these assumptions between model runs. The function parameters applied across _all_ exposure and hazard input data. The `PARAMETERS` keyword is no longer supported for Jython. Instead, you can use :ref:`model parameters ` to pass assumptions to your function, and to vary these assumptions between model runs. ### Defining argument/return types inline An older approach used to define the function `ID`, `ARGUMENT_TYPES`, and `RETURN_TYPE` inline in the Python code, rather than in the INI file. This is still supported in the meantime for backwards compatibility. If you are using this approach, :ref:`jython-type-usage` has more examples of using types within a Python function.