Uploading .stix file into a DstabilityModel (Geolib)

I tried uploading a .stix to a File and then parsing the data to a DstabilityModel.
I followed the guide in this link: Integrations - GEOLIB | VIKTOR Documentation
but the result is a parsed_file that is None.

How can I upload a .stix to a DstabilityModel?

For more information on how to use the GEOlib, you can refer to Deltares’ documentation: Welcome to GEOLib’s documentation! — geolib 0.1.6 documentation

Hi Jordi,

It might be the case that you need to call seek(0) on the temporary file before parsing it into the DStabilityModel

Thanks for the GEOlib documentation.
Still I can’t get it to work.
Using seek(0) does not fixes this…

Hi Jordi,

I find it difficult to fully understand what your flow is, but i have tried to get this working myself and ran into a similar issue.

The strange thing is that if i use older GeoLib versions, i can’t get it working but i do run into an error that seems to at least try to build a DStabilityModel. From GeoLib 0.1.4 and up i see similar behaviour to yours: no errors but after DStabilityModel.parse(path_to_stix) my result is None. This also happens when i don’t use a NamedTemporaryFile but run it from a python script pointing to an actual file on my actual drive… very strange behaviour. But it does appear to not be related to the flow using NamedTemporaryFile.

Could it be something to do with the version of DStability? I ask because the first item in the geolib 0.1.4 changelog (so the first version that has this behaviour states:

[Feature]: Add support for D-Stability 20.3. :tada: Note that this drops support for older DStability releases, the console release should follow soon.

Which version of DStability are you using?

Of course, if it appears to be an issue not with the flow of reading the file from memory but reading a .stix file into GeoLib’s DStabilityModel, then maybe asking the GeoLib team about this behaviour might be the fastest way to get a clear answer. Obviously we (at least myself) am definately curious about this and i’ll try to figure out what’s going on.

Roeland

I will asked Geolib about this.
I use the version 2021.02 so I believe that is a newer version than the 20.3.

But I also exported a .stix file en tried to upload the same file again.
With the same result…

I tried to find contact details on the website with documentation, but can’t find any.
You know how to contact the team?

geolib@deltares.nl

Hi all,

I am also bumping into a similar issue. Has one of you found a solution yet?

I feel like I almost got it but there is an error I didn’t understand.

In my controller I have the following code:

 def see_how_stix_works_here_in_viktor(self, params, **kwargs):
        stix_file  = params.stix_file_input #FileResource 
        # https://docs.viktor.ai/docs/guides/integrations/geolib/
        temp_file = NamedTemporaryFile(suffix='.stix', delete=False,
                                           mode='wb')
        temp_file.write(stix_file.file.getvalue_binary())
        temp_file.close()
        path = Path(temp_file.name)  
        parsed_file = DStabilityModel().parse(path)
        os.remove(temp_file.name)
        print(parsed_file) 
        return parsed_file 

This resulted in parsed_file = None

However, if I change

  parsed_file = DStabilityModel().parse(path) 

into

  parsed_file = DStabilityModel()
  parsed_file.parse(path) 
  print(parsed_file)

I can see the DStability-data, something like
filename=WindowsPath(‘…/AppData/Local/Temp/tmp2v2_z79z.stix’) datastructure=DStabilityStructure(waternets=[Waternet(Id=‘161’, ContentVersion=‘1’, PhreaticLineId=‘162’, HeadLines=[PersistableHeadLine(Id=‘162’, Label=‘PL1’, Notes=‘’, Points=[PersistablePoint(X=-95.0, Z=1.455), …

To me, this looks quite good. However, this outputis followed by an error, which is this: (this is the part I don’t understand anymore)

2022-06-30 11:56:46.640 ERROR   : Exception is raised
Traceback (most recent call last):
  File "viktor_connector\connector.pyx", line 400, in connector.Job.execute
  File "viktor\core.pyx", line 1799, in viktor.core._handle_job
  File "viktor\core.pyx", line 1783, in viktor.core._handle_job.non_view_result
AttributeError: 'DStabilityModel' object has no attribute '_serialize 

What would be a solution to solve this error? Your help is very much appreciated :slight_smile: btw, I am using GeoLib 0.1.6 and DStability 2020.03

Hi Yida,

Do you invoke see_how_stix_works_here_in_viktor using a button? In this case the method should return the corresponding Result type, for example a DownloadButton should return a DownloadResult (see Topics - Files | VIKTOR Documentation).

Hi Kevin,

Thanks a lot. Indeed, I made a button. I overlooked that part of returning the corresponding button-result. Now I have a new question: is there any best practice how to store the geolib-models?

In my parametrization I have the following fields

class MyParametrization(Parametrization):
   stix_files = FileField('stix file')
   btn_2 = SetParamsButton("Stix test", "see_how_stix_works_here_in_viktor", longpoll=True)
   my_dataset = HiddenField('no UI', name="my_dataset")

In the controller method, I’d like to store the DStabilitymodel()-object including all the class variables. I was trying this but since parsed_file is not a dictionary but an object it gives an error.

def see_how_stix_works_here_in_viktor(self, params, **kwargs):
  ...
  return SetParamsResult({'my_dataset': parsed_file})
2022-06-30 13:48:41.923 ERROR   : Result can not be serialized to JSON: Object of type DStabilityModel is not JSON serializable

So my question is, is there any best practice how to store a DStability()-object including all class variables?

Hi Yida, why would you like to store the object? Does parsing the stix take a lot of time?

Hi Kevin,

Thanks for your question :pray:

Here is a bit of background information. I am trying to build an app and I have some existing code stored on my local computer. The objective of that code is to make a summary/appendix based on many stix-files (say >20) (and maybe also some other types of input data such as Excels). Furthermore, one key variable in my object is a list of DStability()-objects.

First, for the app it would be nice upload the stix files and store them. Then let the user select using buttons/boolean switches which type of output (tables/figures/document) they want, including the level of detail. Lastly, execute the tool using a button and download the result.

When the user hits the ‘execute’ button, I don’t want the data to be parsed every time they make a small change in the button/switches, hence my question. Also, storing a (list of) DStability()object(s) would make a smooth connection to the current code.

Is there a way to store the object? Or would you recommend another way? I thought an alternative might be parsing, executing the tool, and downloading, all in one go.

Thanks for the explanation.

It is not possible to store a DStability object (or any object) since this is not json serializable (e.g. string, int, bytes, etc.). We do offer the following options for storage:

However, these options in turn require the data to be json serializable which means you will need to serialize the DStability object, and subsequently de-serialize (parse) when retrieving. So you will still be left with the parsing step.

I can’t really think of another way, but I am wondering how much time does the parsing take?

Hi Kevin, thanks for your reply.

Parsing 15 stix files takes little more than 4 seconds :slight_smile: to be precise for hitting the parsing 6 times:
— 4.299708843231201 seconds —
— 4.3733580112457275 seconds —
— 4.385324239730835 seconds —
— 4.614434003829956 seconds —
— 4.221465587615967 seconds —
— 4.275190353393555 seconds —

Hi all,

The original problem posted by Jordi (@jdeleau ) is that the parsed_file = DSettlementModel().parse(file_path) is resulting in parsed_file being None. This is actually expected!

What the parse() function is doing is parsing the provided file into the DSettlementModel.
As @yida.tao already discovered in her post.

So the workflow should be as follows:

dsettlement_model= DSettlementModel() # Empty model
dsettlement_model.parse(Input_or_output_file) # parse input or output file into the model

After this, the data is in the model can be used in further calculations.

@bvanderhulst
The snippet in the documentation is kind of misleading:

temp_file = NamedTemporaryFile(suffix='.sld', delete=False, mode='wb')  # create a temporary file with correct suffix; don't delete on close(); remove mode 'b' in case of StringIO/str
temp_file.write(my_bytesio.getvalue())  # write in-memory content (bytes in this case) to file
temp_file.close()  # close (does not delete) the file to ensure the data is actually written to file (instead of kept in buffer)
path = Path(temp_file.name)  # name returns the path in `str`, GEOLIB requires (in most cases) a Path object
parsed_file = DSettlementModel().parse(path)  # obtain the parsed results
os.remove(temp_file.name)  # remove the temporary file to avoid cluttering of files

The second to last line should be replaced by:

dsettlement_model = DSettlementModel() # create empty model
dsettlement_model.parse(path)  # parse file into DSettlementModel() model
1 Like

@mweehuizen. I have implemented you proposed solution as well as a solution using a .sld file in the repository. However I get an error as shown in the image below. Are you familiar with this issue?

Both options I tried are shown below:

        # Viktor file
        d_settlement_model = ff.d_settlement_model()
        results = run_d_settlement_analysis_from_model(d_settlement_model)  # returns as str in results

        # d_settlement_output_path = MODEL_FILE_PATH / "output_dsettlement.sld"  # Path to be used directly in DSettlementModel.parse()
        # 
        # with open(d_settlement_output_path, "w") as f:
        #     for line in results.split(sep="\n"):
        #         f.write(line)
        #     f.close()

        temp_file = NamedTemporaryFile(
            suffix=".sld", delete=False, mode="w"
        )  # create a temporary file with correct suffix; don't delete on close(); remove mode 'b' in case of StringIO/str
        temp_file.write(results)  # write in-memory content (bytes in this case) to file
        temp_file.close()  # close (does not delete) the file to ensure the data is actually written to file (instead of kept in buffer)
        path = Path(temp_file.name)  # name returns the path in `str`, GEOLIB requires (in most cases) a Path object
        output_model = DSettlementParser()
        output_model.parse(path)  # parse file into DSettlementModel() model
        os.remove(temp_file.name)  # remove the temporary file to avoid cluttering of files

        result_table = output_model.table_calculated_settlements()

        return WebResult(html=StringIO(result_table.to_html()))

The parser works locally using the GeoLib, it doesn’t work when implementing it within the Viktor environment. Any idea?

Hi Johan,

I am not sure what is going wrong. What is returned by the run_d_settlement_analysis_from_model function?
Can you print results and post it here?

Hi Maarten,
The output is a string shown in the file below.

output_dsettlement.sld (294.3 KB)

If we run the GeoLib locally it works fine with the same input. However through the Viktor workers loading it into the GeoLib Parser it raises this error.

Hi,

I actually wanted to know what kind of object type results was (bytes, BytesIO, String).

But i think i spotted the problem:

Can you change this line:

output_model = DSettlementParser()

to:

output_model = DSettlementModel()