Skip to content
  • Search
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse

ZMT zurich med tech

  1. Home
  2. Sim4Life
  3. Python API
  4. Acoustic simulation - phase information needed (using Python)

Acoustic simulation - phase information needed (using Python)

Scheduled Pinned Locked Moved Python API
11 Posts 2 Posters 1.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    montanaro
    wrote on last edited by
    #2

    Hi,

    For a point sensor p(f):

    Under properties you get the option for Complex component and can select Phase (deg).

    from Python:

    
    import numpy
    import s4l_v1.analysis as analysis
    import s4l_v1.document as document
    import s4l_v1.model as model
    import s4l_v1.units as units
    from s4l_v1 import ReleaseVersion
    from s4l_v1 import Unit
    
    # Adding a new SimulationExtractor
    simulation = document.AllSimulations["Single Element Focused Transducer"]
    simulation_extractor = simulation.Results()
    
    # Adding a new AcousticSensorExtractor
    acoustic_sensor_extractor = simulation_extractor["Focus  (SEFT)"]
    
    # Get Point Sensor 
    input = acoustic_sensor_extractor.Outputs["p(f)"]
    # Get Point Sensor data (output is complex pressure)
    output = input.Data.GetComponent(0)
    
    # Post Process: Angle
    output_angle = numpy.angle(output)
    
    1 Reply Last reply
    1
    • M Offline
      M Offline
      montanaro
      wrote on last edited by
      #3

      For Field sensor p(x,y,z,f):

      Easiest is to create a 'Calculator' and calculate it yourself, then right click field and select 'To Python..' to get the corresponding Python code

      Select overall field -> p(x,y,z,f) -> Field Data Tools -> Calculator -> Value Location: Cell Center -> Scalar Variables: F (Re{p}) -> Scalar Variables: G (Im{p}) -> Expression: atan(G/F) (change it to read this or whatever suitable formula you wish)

      Then you can use the viewers (note, careful with division by zero, you'll need to adjust the color bar accordingly, also you'll get 'wrapped' angles)

      (In the next reply I'll show you how you can extract the field, manipulate it, and plot it back ... Very useful to plot arbitrary numpy arrays in S4L)

      Python code:

      import numpy
      import s4l_v1.analysis as analysis
      import s4l_v1.document as document
      import s4l_v1.model as model
      import s4l_v1.units as units
      from s4l_v1 import ReleaseVersion
      from s4l_v1 import Unit
      
      # Creating the analysis pipeline
      # Adding a new SimulationExtractor
      simulation = document.AllSimulations["Single Element Focused Transducer"]
      simulation_extractor = simulation.Results()
      
      # Adding a new AcousticSensorExtractor
      acoustic_sensor_extractor = simulation_extractor["Overall Field"]
      
      # Adding a new FieldCalculator
      inputs = [acoustic_sensor_extractor.Outputs["p(x,y,z,f)"]]
      field_calculator = analysis.field.FieldCalculator(inputs=inputs)
      field_calculator.Expression = u"atan(G/F)"
      field_calculator.ValueLocation = field_calculator.ValueLocation.enum.CellCenter
      field_calculator.UpdateAttributes()
      document.AllAlgorithms.Add(field_calculator)
      
      # Adding a new SliceFieldViewer
      inputs = [field_calculator.Outputs["Result(x,y,z)"]]
      slice_field_viewer = analysis.viewers.SliceFieldViewer(inputs=inputs)
      slice_field_viewer.Data.Mode = slice_field_viewer.Data.Mode.enum.QuantityRealPart
      slice_field_viewer.Slice.Plane = slice_field_viewer.Slice.Plane.enum.XZ
      slice_field_viewer.Slice.Index = 155
      slice_field_viewer.UpdateAttributes()
      document.AllAlgorithms.Add(slice_field_viewer)
      
      1 Reply Last reply
      1
      • M Offline
        M Offline
        montanaro
        wrote on last edited by
        #4

        To get the field as a numpy array:

        import numpy
        import s4l_v1.analysis as analysis
        import s4l_v1.document as document
        import s4l_v1.model as model
        import s4l_v1.units as units
        from s4l_v1 import ReleaseVersion
        from s4l_v1 import Unit
        
        # Creating the analysis pipeline
        # Adding a new SimulationExtractor
        simulation = document.AllSimulations["Single Element Focused Transducer"]
        simulation_extractor = simulation.Results()
        
        # Adding a new AcousticSensorExtractor
        acoustic_sensor_extractor = simulation_extractor["Overall Field"]
        document.AllAlgorithms.Add(acoustic_sensor_extractor)
        
        # Adding a new SliceFieldViewer
        field = acoustic_sensor_extractor.Outputs["p(x,y,z,f)"]
        # Remember to update
        # Otherwise this script will fail unless you have already extracted results in the GUI
        field.Update()
        
        field_np = field.Data.Field(0) # Field as flattened 1D array
        # 3D Field dimensions (which might be different to grid dimensions)
        # Data is often times defined at cell centers, Grid at cell nodes
        dims = numpy.array(field.Data.Grid.Dimensions)
        if numpy.prod(dims) != len(field_np):
        	dims = dims-1
        field_np = field_np.reshape(dims, order='F') # Field as 3D array
        
        xaxis = field.Data.Grid.XAxis
        yaxis = field.Data.Grid.YAxis
        zaxis = field.Data.Grid.ZAxis
        
        # You can now manipulate field_np as you wish
        field_angle = numpy.unwrap(numpy.angle(field_np))
        

        To plot your numpy array back into sim4life you create what is known as a 'Trivial Producer' which holds your numpy array which can be manipulated in the analysis tab:

        data = field_angle
        
        grid = analysis.core.RectilinearGrid()
        grid.XAxis = xaxis
        grid.YAxis = yaxis
        grid.ZAxis = zaxis
        
        # Careful, the new field is a field of Doubles, changes to ComplexFieldData
        # if you need to work with complex numbers
        new_field = analysis.core.DoubleFieldData()  
        new_field.Grid = grid
        if data.size == (len(grid.XAxis) * len(grid.YAxis) * len(grid.ZAxis)):
        	new_field.ValueLocation = analysis.core.eValueLocation.kNode
        elif data.size == (len(grid.XAxis)-1) * (len(grid.YAxis)-1) * (len(grid.ZAxis)-1):
        	new_field.ValueLocation = analysis.core.eValueLocation.kCellCenter
        else:
        	print "ERROR: Grid and Data don't match"
        	assert False
        new_field.NumberOfComponents = 1
        new_field.NumberOfSnapshots = 1
        new_field.Quantity.Name = "My Field"
        
        # Note: memory layout is such that x is fastest, z slowest dimension
        values = data.ravel('F')	
        values = values.astype(numpy.float64) # Change if working with ComplexFieldData
        new_field.SetField( 0, values )
        assert new_field.Check()
        
        producer = analysis.core.TrivialProducer()
        producer.Description = "My Trivial Producer"
        producer.SetDataObject(new_field)
        
        document.AllAlgorithms.Add(producer)
        
        1 Reply Last reply
        1
        • A Offline
          A Offline
          Annalisa
          wrote on last edited by
          #5

          Thank you very much for the detailed instructions.
          I tried the first code you gave me and it works for a single sensor as expected.
          (just need to add input.Update()).
          In my case I have several sensors so I need to use a for loop in order to extract the phase value on each sensor.
          My code is:

          from future import absolute_import
          from future import print_function
          import sys, os, math
          import h5py
          import s4l_v1.model as model
          import s4l_v1.simulation.acoustic as acoustic
          import s4l_v1.analysis as analysis
          import s4l_v1.document as document
          import scipy.io

          import numpy
          import s4l_v1.document as document
          import s4l_v1.materials.database as database
          import s4l_v1.model as model
          import s4l_v1.simulation.acoustic as acoustic
          import s4l_v1.units as units
          from s4l_v1 import ReleaseVersion
          from s4l_v1 import Unit

          try:
          # Define the version to use for default values
          ReleaseVersion.set_active(ReleaseVersion.version5_2)

          # Creating the analysis pipeline
          # Adding a new SimulationExtractor
          simulation = document.AllSimulations["My simulation"]
          simulation_extractor = simulation.Results()
          
          
          for i in range(0,128):
          
          	# Adding a new AcousticSensorExtractor
          	acoustic_sensor_extractor = simulation_extractor["Sensor" + str(i)]
          	document.AllAlgorithms.Add(acoustic_sensor_extractor)
          	input = acoustic_sensor_extractor.Outputs["p(f)"]
          	input.Update()
          
          	# Get Point Sensor data (output is complex pressure)
          	output = input.Data.GetComponent(i)
          	
          	# Post Process: Angle
          	output_angle = numpy.angle(output)
          

          except Exception as exc:
          import traceback
          traceback.print_exc(exc)
          Reset active version to default
          ReleaseVersion.reset()
          raise(exc)

          When I run this code the console gives this message:
          File "C:\Users\PC\Documents\Sim4Life\5.2\Scripts\temp\BP p(f) extractor.py", line 58
          Reset active version to default
          ^
          SyntaxError: invalid syntax

          any idea?

          Thanks

          Annalisa

          1 Reply Last reply
          0
          • M Offline
            M Offline
            montanaro
            wrote on last edited by
            #6

            "input.Update()"

            • you're right. As a general rule, make sure to always have this (if results are extracted and updated in the GUI you might not get this error)

            Not sure why you get this error but this line seems wrong:
            GetComponent(i) ... Should probably be GetComponent(0)

            Components are typically useful when you have vector fields, In which case GetComponent(0) probably corresponds to E_x, GetComponent(1) to E_y, etc.. They should typically be set to 0 since most fields have only 1 'component'. (not to be confused with snapshots which typically refer to time snapshots or frequency snapshots, where 0 is the main harmonic)

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Annalisa
              wrote on last edited by
              #7

              GetComponent(0), yes you are right. That was a typo.
              The problem still persists.
              How can I extract the phase on each sensors using a "for" loop?

              thanks again

              1 Reply Last reply
              0
              • M Offline
                M Offline
                montanaro
                wrote on last edited by montanaro
                #8

                Just tried it on a simple example and seemed to work ... Maybe get rid of

                try:
                # Define the version to use for default values
                ReleaseVersion.set_active(ReleaseVersion.version5_2)
                

                and

                except Exception as exc:
                import traceback
                traceback.print_exc(exc)
                Reset active version to default
                ReleaseVersion.reset()
                raise(exc)
                

                (seems that 'reset active version ...' line should be a comment)

                This is what I tried:

                # -*- coding: utf-8 -*-
                # Creating the analysis pipeline
                # Adding a new SimulationExtractor
                simulation = document.AllSimulations["Single Element Focused Transducer - Copy"]
                simulation_extractor = simulation.Results()
                
                for i in range(1,5):
                
                	# Adding a new AcousticSensorExtractor
                	acoustic_sensor_extractor = simulation_extractor["Focus " + str(i)]
                	document.AllAlgorithms.Add(acoustic_sensor_extractor)
                	input = acoustic_sensor_extractor.Outputs["p(f)"]
                	input.Update()
                
                	# Get Point Sensor data (output is complex pressure)
                	output = input.Data.GetComponent(0)
                	
                	# Post Process: Angle
                	output_angle = numpy.angle(output)
                	print i, output_angle
                

                and this was my output:

                1 [ 1.69136047]
                2 [ 1.69136047]
                3 [ 1.69136047]
                4 [ 1.69136047]
                

                (my point sensors were all at the same location)

                1 Reply Last reply
                1
                • A Offline
                  A Offline
                  Annalisa
                  wrote on last edited by
                  #9
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    Annalisa
                    wrote on last edited by
                    #10

                    Now, I want assign each phase value to an element of my transducer.
                    But using my code:

                    for i in range(0,128):
                    	
                    	source_settings = acoustic.SourceSettings()
                    	source_settings.Name = "Source Settings" + str(i)
                    	source_settings.Amplitude = 100000.0, Unit("Pa")		
                    	source_settings.Phase = -output_angle[i], units.Degrees
                    	simulation.Add(source_settings, components[i])
                    

                    does not work because in output_angle (evaluated with the previous code) I have only the last value (corresponding to sensor#127).
                    I would need to allocate all the phase values in a callable list (?) in order to be able to use the for loop.
                    Thank for further helps

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      montanaro
                      wrote on last edited by montanaro
                      #11

                      You need to make output_angle into an array and append the new values at the end every time (the i-th element will have the i-th phase you want)

                      output_angle = numpy.array([])
                      for i in range(0,128):
                      	# your code
                      	output_angle = numpy.append(output_angle, numpy.angle(output))
                      
                      1 Reply Last reply
                      1
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Search