Esempio n. 1
0
def find_cc(lens_model,
            mass_scale,
            model_param_8,
            model_param_9,
            model_param_10,
            galaxy_position=[0, 0],
            e_L=0,
            theta_L=0,
            shear=0,
            theta_shear=0,
            gravlens_params={},
            caustic_CC_file='crit.txt',
            gravlens_input_file='gravlens_CC_input.txt',
            grid_factor=5.,
            grid_factor2=3.,
            max_iter_number=20,
            min_n_lines=200,
            gridhi1_CC_factor=2.,
            accept_res_limit=2E-4):
    """ 
	Determines the caustics and critical curves (CC) for a single component lens model. Uses an iterative
	procedure to determine the grid size and the minimum number of points on the curves.

	The CC size may vary considerably depending on the lens-source configuration. Because of this, 
	we developed an iterative method to find the CC, that involves the size of the grid used by 
	gravlens (gridhi1). The initial value of gridhi1 must be an upper limit for the size of the CC, 
	and find_cc will try to find the CC. Each time gravlens can't find the CC, we lower	gridhi1 
	by a factor of grid_factor (=5), in order to increase precision. This continues on until 
	gravlens finds the CC or the number of iterations, max_iter_number (=20), is reached. After 
	finding the CC, if the file is composed of less than min_n_lines (=200) lines, the code redefines 
	gridhi1 to gridhi1/grid_factor2 (grid_factor2=3), usually increasing the number of points. With this 
	first determination of the CC, the code uses its scale (gridhi1_CC_factor(=2) times the distance
	of the furthest CC point to the lens center) to reobtain the CC with the apropriate value for the 
	grid, ensuring best precision. If the CC were not found after these attempts, this function returns "False" and an 
	error message. If all caustic points have coordinates < accept_res_limit (=2E-4), a warning 
	message will be generated, meaning that the precision of gravlens (limited by the number of 
	digits in the output file) is being reached. 
 
	Example:
	         x_caustic, y_caustic, x_CC, y_CC, gravlens_config = find_cc('nfw',1,1,0,0)

	Input:
	 - lens_model          <str> : lens name (see gravlens manual table 3.1)
	 - mass_scale        <float> : mass scale of the lens - "parameter 1"
	 - model_param_8     <float> : misc. lens parameter - often scale radio (depends on the lens model)
	 - model_param_9     <float> : misc. lens parameter - often scale radio (depends on the lens model)
	 - model_param_10    <float> : misc. lens parameter - often a power law index  (depends on the lens model)
	 - galaxy_position    <list> : [x,y] position of the lens
	 - e_L               <float> : lens ellipticity (default=0)
	 - theta_L           <float> : lens position angle (in degrees) with respect to the vertical 
				       (counterclockwise)
	 - shear             <float> : external shear amplitude
	 - theta_shear       <float> : external shear direction (in degrees)
	 - gravlens_params     <dic> : contains the keys and values of the gravlens configuration (see 
				       default parameters at function set_gravlens_default,inside lens_parameters)
	 - caustic_CC_file     <str> : name of the output file with the caustic and CC positions
	 - gravlens_input_file <str> : name of the input file used to run gravlens
	 - grid_factor       <float> : used in the iteration to find the critical curves. Each time no 
				       curves were found, the grid size is divided by grid_factor
	 - min_n_lines         <int> : minimum number of lines demanded in the CC file to decrease the grid by grid_factor_2 
	 - grid_factor2      <float> : if the CC file is composed of less than min_n_lines, the code divides
				       the grid size by grid_factor2 
	 - max_iter_number     <int> : maximum number of time the grid size will be divided by grid_factor
	 - gridhi1_CC_factor <float> : the final size of the grid will be gridhi1_CC_factor * (the furthest CC point)
	 - accept_res_limit  <float> : if the furthest CC point is closer than accept_res_limit from the lens 
				       center, display a warning about lack of precision in determining the curves

	Output:
	 - <list>     : [x_caustic, ycaustic], with x_caustic and ycaustic being the lists with the 
			caustic coordinates
	 - <list>     : [x_CC, y_CC], with x_CC and y_CC being the lists with the CC coordinates
	 - <dict>     : all configuration variables used for running gravlens (including gridhi1)
	 - <str>      : name of the file with the caustic and CC positions ('caustic_CC_file')
	 - <str>      : name of the input file used to run gravlens (gravlens_input_file)

	"""

    inputlens, setlens, gravlens_params_updated = lens_parameters(
        lens_model, mass_scale, model_param_8, model_param_9, model_param_10,
        galaxy_position, e_L, theta_L, shear, theta_shear, gravlens_params
    )  # inputlens is the gravlens input (sets general parameters and the lens parameters)	# setlens is the gravlens input line that concerns the lens (ex: nfw 1 0 ...)
    logging.debug(
        'Determined the strings that defines the mass model in gravlens through the \'lens_parameters\' function'
    )
    #--------------------------------------

    #-----------------------------
    os.system('rm -f %s' %
              caustic_CC_file)  # if the file previously exists, delete it
    critcurves(inputlens, caustic_CC_file,
               gravlens_input_file)  # gets the critical curves (crit.txt file)
    logging.debug(
        'Got the critical curves (%s file) with function \"critcurves\"' %
        caustic_CC_file)
    #-----------------------------

    # ITERATION ON gridhi1 (TO GET BETTER RESOLUTION ON CC)
    counter = 0
    while os.path.isfile(
            './' + caustic_CC_file
    ) == False and counter < max_iter_number:  # looks for the C.C. file (crit.txt) - if this file does not exist, add a note to arccatalog and quit
        gravlens_params_updated['gridhi1'] = float(
            gravlens_params_updated['gridhi1']) / grid_factor
        # gridhi1 /= 5.

        lens_par_out = lens_parameters(
            lens_model, mass_scale, model_param_8, model_param_9,
            model_param_10, galaxy_position, e_L, theta_L, shear, theta_shear,
            gravlens_params_updated
        )  # inputlens is the gravlens input (sets general parameters and the lens parameters)

        inputlens, setlens, gravlens_params_updated = lens_par_out
        critcurves(
            inputlens, caustic_CC_file,
            gravlens_input_file)  # gets the critical curves (crit.txt file)
        counter += 1
    logging.debug('(Number of iterations on gridhi1 = %d)' % (counter))

    if os.path.isfile(
            './' + caustic_CC_file
    ) == False:  # looks for the C.C. file (crit.txt) - if this file does not exist, returns 'False'
        logging.error(
            'Gravlens could not determine the caustics and critical curves. Try changing the input units (for example, from arcseconds to miliarcsecond), because gravlens outputs the critical curves with only 6 digits. The grid size used was %f and it was obtained through %d iteration.'
            % (float(gravlens_params_updated['gridhi1']), counter))
        return False

    if len(
            open('./' + caustic_CC_file).readlines()
    ) < min_n_lines:  # these correspond to critical cases when the CC have too few points.
        gravlens_params_updated['gridhi1'] = float(
            gravlens_params_updated['gridhi1']) / grid_factor2  # gridhi1 /= 3.

        lens_par_out = lens_parameters(
            lens_model, mass_scale, model_param_8, model_param_9,
            model_param_10, galaxy_position, e_L, theta_L, shear, theta_shear,
            gravlens_params_updated
        )  # inputlens is the gravlens input (sets general parameters and the lens parameters)
        inputlens, setlens, gravlens_params_updated = lens_par_out

        critcurves(
            inputlens, caustic_CC_file,
            gravlens_input_file)  # gets the critical curves (crit.txt file)

    x1, y1, u1, v1 = np.loadtxt(
        caustic_CC_file, usecols=(0, 1, 2, 3),
        unpack=True)  # CC_x, CC_y, caustic_x, caustic_y

    #-----------------------------------------------------------------------------------------------------------
    # redefine gridhi1 according to the CC size

    index_CC = np.argmax(
        x1**2 + y1**2
    )  # it is not necessary to use the lens center since we want the furthest point anyway
    logging.debug(
        'The CC furthest point is at (%s, %s), a distance %s of the origin .' %
        (x1[index_CC], y1[index_CC], (x1[index_CC]**2 + y1[index_CC]**2)**0.5))

    gravlens_params_updated['gridhi1'] = gridhi1_CC_factor * (
        (x1[index_CC]**2 + y1[index_CC]**2)**0.5)

    #-----------------------------------------------------------------------------------------------------------
    # get CC with best value for the grid
    lens_par_out = lens_parameters(
        lens_model, mass_scale, model_param_8, model_param_9, model_param_10,
        galaxy_position, e_L, theta_L, shear, theta_shear,
        gravlens_params_updated
    )  # inputlens is the gravlens input (sets general parameters and the lens parameters)
    inputlens, setlens, gravlens_params_updated = lens_par_out

    logging.debug('gridhi1 = %f and number of iterations on gridhi1 = %d' %
                  (float(gravlens_params_updated['gridhi1']), counter))

    critcurves(inputlens, caustic_CC_file,
               gravlens_input_file)  # gets the critical curves (crit.txt file)

    x1, y1, u1, v1 = np.loadtxt(
        caustic_CC_file, usecols=(0, 1, 2, 3),
        unpack=True)  # CC_x, CC_y, caustic_x, caustic_y

    #	index_CC = np.argmax(x1**2 + y1**2)
    #	logging.debug( 'The CC furthest point is at (%s, %s), a distance %s of the origin .' % (x1[index_CC], y1[index_CC], (x1[index_CC]**2 + y1[index_CC]**2)**0.5 ) )

    # check if the precision is ok (gravlens outputs coordinates with only 6 decimal places)
    if max(max(np.abs(u1)), max(np.abs(v1))) < accept_res_limit:
        logging.warning(
            'The caustics seem to be determined with low resolution')

    return x1, y1, u1, v1, gravlens_params_updated
def lensing(lens_model, mass_scale, model_param_8, model_param_9, model_param_10, galaxy_position, e_L, 
            theta_L, shear, theta_shear, gravlens_params, dimpix, source_centers, source_model, 
            ref_magzpt, reference_band, base_name='sbmap', nover_max=3):
    """
    Lenses sources for the given lens model. 
    
    The lensing is performed with the gravlens software, using command SBmap2.

    Input:
     - lens_model        <str> : Lens name (see gravlens manual table 3.1)
     - mass_scale      <float> : Mass scale of the lens - "parameter 1"
     - model_param_8   <float> : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_9   <float> : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_10  <float> : misc. lens parameter - often a power law index (depends on the lens model)
     - galaxy_position  <list> : [x,y] position of the lens
	 - e_L             <float> : lens ellipticity (ellipticity = 1 - q, where 0<q<=1 is the axial ratio) 
	 - theta_L         <float> : lens position angle (in degrees) with respect to the vertical (counterclockwise)
	 - shear           <float> : external shear amplitude
	 - theta_shear     <float> : external shear direction (in degrees)
     - gravlens_params   <dic> : Contains the keys and values of the gravlens configuration , dimpix, source_centers, source_model, 
     - ref_magzpt      <float> : The zero point magnitude to be used. It only affects the source fluxes.
     - reference_band    <str> :
     - base_name         <str> : 
     - nover_max         <int> :

    Output:
     - image_names <list> :

    """

    inputlens, setlens, same_gravlens_params = lens_parameters(lens_model, mass_scale, model_param_8, 
                                                  model_param_9, model_param_10, galaxy_position, e_L, 
                                                  theta_L, shear, theta_shear, gravlens_params)

    half_frame_size = gravlens_params['gridhi1']
    Npix = int( (2.*half_frame_size) / dimpix )
    image_names = []
    f199 = open('sersicinput.txt', 'w')
    f199.write(inputlens)
    for i in range (0,len(source_centers)):
        source_type = source_model[i]['source_type'] # type of the source (can be 'sersic' or 'uniform')
        f199.write('setsource 1\n')
        # Nover increase resolution if the source is smaller than the pixel
        nover = source_model[i]['nover']
        while source_model[i]['rs'] < dimpix/nover and nover < nover_max:
            nover += 1
        source_model[i]['nover'] = nover
        # -------------------------------------------------------------------
        if source_type == 'sersic':
            # determine 'totalsourceplaneflux', according to the source magnitude
            totalsourceplaneflux = 10**((2./5)*(ref_magzpt - source_model[i]['mag']))
            f199.write('%s %f %.6f %.6f %f %f %.6f 0 %f macro\n' % (source_type, totalsourceplaneflux, source_centers[i][0], source_centers[i][1], source_model[i]['es'], source_model[i]['thetas'], source_model[i]['rs'], source_model[i]['ns']  ) ) # sersic/uniform F x y e PA halflightr nothing nS macro/micro
        if source_type == 'uniform':
            # fix 'totalsourceplaneflux' to 1
            totalsourceplaneflux = 1
            f199.write('%s %f %.6f %.6f %f %f %.6f 0 0 macro\n' % (source_type, totalsourceplaneflux, source_centers[i][0], source_centers[i][1], source_model[i]['es'], source_model[i]['thetas'], source_model[i]['rs'] ) ) # sersic/uniform F x y e PA halflightr nothing macro/micro
        #------------------------------------------------------------------------
        f199.write('0 0 0 0 0 0 0 0\n')
        image_names.append('%s%05d_%s.fits' % (base_name, i, reference_band) )
        f199.write('SBmap2 %0.9f %0.9f %d %0.9f %0.9f %d %d %s 3\n' % (-half_frame_size, half_frame_size, Npix, -half_frame_size, half_frame_size, Npix, nover, image_names[-1]) ) # <x lo> <hi> <# steps> <y lo> <hi> <# steps> <Nover> <file> <outtype>
        logging.debug( "The source %d is centered at %s and its properties are %s" % (i+1, source_centers[i] ,str(source_model) ) )

    f199.close()



    if len(source_centers) > 0:
        logging.info( "gravlens is lensing %d finite source(s) (this may take several minutes depending on the resolution)..." % len(source_centers) )
        status = os.system('gravlens sersicinput.txt > /dev/null')
        logging.debug('Executed gravlens to lens the finite sources and returned status %s' % str(status) )
    else:
        logging.info( "There were no sources to be lensed" )

    return image_names, half_frame_size
def lens_point_sources(x,
                       y,
                       lens_model,
                       mass_scale,
                       model_param_8,
                       model_param_9,
                       model_param_10,
                       galaxy_position=(0, 0),
                       e_L=0,
                       theta_L=0,
                       shear=0,
                       theta_shear=0,
                       gravlens_params={},
                       gravlens_input_file='findimg_input.txt',
                       gravlens_output_file='findimg_out.txt',
                       keep_files=False):
    """
    Computes the positions of point images from a list of point sources.

    
   Input:
     - x                  [float,...] : x coordinates of the point sources
     - y                  [float,...] : y coordinates of the point sources
     - lens_model                 str : Lens name (see gravlens manual table 3.1)
     - mass_scale               float : Mass scale of the lens - "parameter 1"
     - model_param_8            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_9            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_10           float : misc. lens parameter - often a power law index (depends on the lens model)
     - galaxy_position  [float,float] : [x,y] position of the lens
	 - e_L                      float : lens ellipticity (ellipticity = 1 - q, where 0<q<=1 is the axial ratio) 
	 - theta_L                  float : lens position angle (in degrees) with respect to the vertical 
					                    (counterclockwise)
	 - shear                    float : external shear amplitude
	 - theta_shear              float : external shear direction (in degrees)
     - gravlens_params           dict : contains the keys and values of the gravlens configuration (see 
				                        default parameters at function set_gravlens_default,inside lens_parameters)
     - gravlens_input_file        str : name of the input file for gravlens
     - gravlens_output_file       str : name of the output file generated by gravlens (with the point images' info)
     - keep_files                bool : 'True' to keep gravlens input and output files and 'False' to delete them

    Output:
     - x_img          [ [float,...],... ] : x coordinates of the point images. It has the same size of the input 'x', 
                                            but each element of x_img has the n images of the corresponding source (n>=1)
     - y_img          [ [float,...],... ] : y coordinates of the point images. Same shape of x_img
     - magnification  [ [float,...],... ] : magnifications (mu_t*mu_r) of corresponding images. Same shape of x_img
     - time_delay     [ [float,...],... ] : time delay of each image. Same shape of x_img
     - out_file                 [str,...] : list of gravlens output files with the images' parameters

    """

    inputlens, setlens, gravlens_params_updated = lens_parameters(
        lens_model, mass_scale, model_param_8, model_param_9, model_param_10,
        galaxy_position, e_L, theta_L, shear, theta_shear, gravlens_params)

    # run gravlens to get the images ========================================================
    f = open(gravlens_input_file, 'w')
    f.write(inputlens)
    out_file = []
    for i in range(len(x)):
        out_file.append(gravlens_output_file[:-4] + '_' + str(i) +
                        gravlens_output_file[-4:])
        f.write('findimg %0.6f %0.6f %s \n' % (x[i], y[i], out_file[-1]))
    f.close()
    os.system('gravlens %s > /dev/null' % (gravlens_input_file))
    # now we have 'len(x)' files with the images information (pos, magnification, time delay)
    #========================================================================================

    # we now read the files ========================================================
    x_img, y_img, magnification, time_delay = [], [], [], []
    for i in range(len(x)):  # len(x) = len(out_file)
        img_properties = np.loadtxt(out_file[i],
                                    comments='#',
                                    skiprows=1,
                                    unpack=True)  # , ndmin=4
        if len(
                img_properties
        ) == 0:  # in the case no images were found (means that the grid is not big enough)
            x_img.append([])
            y_img.append([])
            magnification.append([])
            time_delay.append([])
        else:
            x_img.append(
                list(np.array(img_properties[0], ndmin=1))
            )  # I transform to list so sum(x_img, []) will flatten this list
            y_img.append(
                list(np.array(img_properties[1], ndmin=1))
            )  # I transform to list so sum(y_img, []) will flatten this list
            magnification.append(img_properties[2])
            time_delay.append(img_properties[3])
    # ==============================================================================

    if keep_files == False:
        os.system('rm -f %s %s' %
                  (gravlens_input_file, gravlens_output_file[:-4] + '*.' +
                   gravlens_output_file[-3:]))

    return x_img, y_img, magnification, time_delay, out_file
def select_source_positions(
        lens_model,
        mass_scale,
        model_param_8,
        model_param_9,
        model_param_10,
        galaxy_position=[0., 0.],
        e_L=0,
        theta_L=0,
        shear=0,
        theta_shear=0,
        gravlens_params={},
        src_density_or_number=10,
        minimum_distortion=0.,
        control_rhombus=2.,
        caustic_CC_file='crit.txt',
        gravlens_input_file='gravlens_CC_input.txt',
        rad_curves_file='lens_curves_rad.dat',
        tan_curves_file='lens_curves_tan.dat',
        curves_plot='crit-caust_curves.png',
        show_plot=0,
        write_to_file=0,
        max_delta_count=20,
        delta_increment=1.1,
        grid_factor=5.,
        grid_factor2=3.,
        max_iter_number=20,
        min_n_lines=200,
        gridhi1_CC_factor=2.,
        accept_res_limit=2E-4,
        gravlens_mag_input_file='gravlens_magtensor_in.txt',
        gravlens_mag_output_file='gravlens_magtensor_out.txt',
        keep_mag_files=False,
        gravlens_img_input_file='findimg_input.txt',
        gravlens_img_output_file='findimg_out.txt',
        keep_img_files=False):
    """ 
    Determines the source centers that are candidates to generate an arc. 

    The sources are sampled in a rectangle near the tangential caustic and lensed. The sorces with at 
    least one image with |mu_t/mu_r| > minimum_distortion are selected, together with its images and properties.

    If src_density_or_number is a float (and therefore a density), the number of sources is given by 
    np.random.poisson(rectangle_area*src_density_or_number )

    Input:
     - lens_model                 str : Lens name (see gravlens manual table 3.1)
     - mass_scale               float : Mass scale of the lens - "parameter 1"
     - model_param_8            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_9            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_10           float : misc. lens parameter - often a power law index (depends on the lens model)
     - galaxy_position  [float,float] : [x,y] position of the lens
	 - e_L                      float : lens ellipticity (ellipticity = 1 - q, where 0<q<=1 is the axial ratio) 
	 - theta_L                  float : lens position angle (in degrees) with respect to the vertical 
					                    (counterclockwise)
	 - shear                    float : external shear amplitude
	 - theta_shear              float : external shear direction (in degrees)
     - gravlens_params           dict : contains the keys and values of the gravlens configuration (see 
				                        default parameters at function set_gravlens_default,inside lens_parameters)
     - src_density_or_number int/float : if int, it is the number of point sources to be sampled. If it 
                                         is a float it is the source density
     - minimum_distortion       float : the minimum ratio |mu_t/mu_r| at least one image of a source must 
                                        have to the source be selected  
     - control_rhombus
	 - caustic_CC_file          str : name of the output file with the caustic and CC positions
	 - gravlens_input_file      str : name of the input file used to run gravlens
	 - rad_curves_file          str : name of the file containing the radial curves (optional - see write_to_file) 
	 - tan_curves_file          str : name of the file containing the radial curves (optional - see write_to_file) 
	 - curves_plot              str : the name of the generated plot file (including the extension, ex. 
					'curves_plot.png'). To see the extensions available see matplotlib.pyplot help 
					(default='crit_curves.png'). If curves_plot=0 means no plots.
	 - show_plot                int : use 0 for 'no screen display' (default) and 1 for display on 
					  the screen.
	 - write_to_file            int : Option to write the curves to a file (see rad_curves_file and 
					  tan_curves_file ). The default is 0, meaning not to write to a file.
     - delta_increment        float : 
	 - grid_factor            float : used in the iteration to find the critical curves. Each time no 
				       curves were found, the grid size is divided by grid_factor
	 - grid_factor2           float : if the CC file is composed of less than min_n_lines, the code divides
				       the grid size by grid_factor2 
	 - max_iter_number          int : maximum number of time the grid size will be divided by grid_factor
	 - min_n_lines              int : minimum number of lines demanded in the CC file to decrease the grid by grid_factor_2 
	 - gridhi1_CC_factor      float : the final size of the grid will be gridhi1_CC_factor * (the furthest CC point)
	 - accept_res_limit       float : if the furthest CC point is closer than accept_res_limit from the lens 
				       center, display a warning about lack of precision in determining the curves
     - gravlens_mag_input_file    str : name of the input file for gravlens (magnification tensor)
     - gravlens_mag_output_file   str : name of the output file generated by gravlens (magnification tensor)
     - keep_mag_files            bool : 'True' to keep gravlens input and output files (magnification tensor files) 
                                        and 'False' to delete them
     - gravlens_img_input_file    str : name of the input file for gravlens (point images)
     - gravlens_img_output_file   str : name of the output file generated by gravlens (point images)
     - keep_img_files            bool : 'True' to keep gravlens input and output files (point images) and 'False' to delete them

    Output:
     - x_src_f                    [float,...] : x coordinates of the selected point sources  
     - y_src_f                    [float,...] : y coordinates of the selected point sources  
     - x_img_f            [ [float,...],... ] : x coordinates of the point images. It has the same size of x_src_f, but
                                                each element of x_img_f has the n images of the corresponding source (n>=1)
     - y_img_f            [ [float,...],... ] : x coordinates of the point images. Same shape of x_img_f
     - image_distortions  [[float,float],...] : each pair has respectively the tangential and radial distortions 
                                                [mu_t,mu_r] of the selected sources 
    
    

    """

    # find and separate critical curves
    out_run_find_cc = run_find_cc(lens_model,
                                  mass_scale,
                                  model_param_8,
                                  model_param_9,
                                  model_param_10,
                                  galaxy_position,
                                  e_L,
                                  theta_L,
                                  shear,
                                  theta_shear,
                                  gravlens_params,
                                  caustic_CC_file,
                                  gravlens_input_file,
                                  rad_curves_file,
                                  tan_curves_file,
                                  curves_plot=0,
                                  show_plot=show_plot,
                                  write_to_file=write_to_file,
                                  max_delta_count=max_delta_count,
                                  delta_increment=delta_increment,
                                  grid_factor=grid_factor,
                                  grid_factor2=grid_factor2,
                                  max_iter_number=max_iter_number,
                                  min_n_lines=min_n_lines,
                                  gridhi1_CC_factor=gridhi1_CC_factor,
                                  accept_res_limit=accept_res_limit)

    logging.info(
        'Ran pipelines.find_cc.run and obtained and separated the caustic and critical curves'
    )

    rad_CC_x, rad_CC_y, tan_CC_x, tan_CC_y, rad_caustic_x, rad_caustic_y, tan_caustic_x, tan_caustic_y = out_run_find_cc
    #----------------------------------------------------------

    #------------ call compute_deformation_rhombus ---------------------------
    xlosango, ylosango = compute_deformation_rhombus(float(theta_L),
                                                     tan_caustic_x,
                                                     tan_caustic_y,
                                                     control_rhombus)
    #---------------------------------------------------------------------------

    #-----------------------------------------------------------------------------------------------------------

    x_vert_1, y_vert_1 = min(xlosango), min(
        ylosango)  # vert_1 : lower left corner
    x_vert_2, y_vert_2 = max(xlosango), max(
        ylosango)  # vert_2 : upper right corner

    logging.debug(
        'The sources will be randomly generated in the range [%s,%s] (x direction) and [%s,%s] (y direction).'
        % (str(x_vert_1), str(x_vert_2), str(y_vert_1), str(y_vert_2)))

    rectangle_area = (x_vert_1 - x_vert_2) * (y_vert_1 - y_vert_2
                                              )  # deltaX*deltaY
    # if src_density_or_number is a float, it is a density, if it is a integer it is the number of sources
    if type(src_density_or_number) == int:
        nsources = src_density_or_number
    if type(src_density_or_number) == float:
        nsources = np.random.poisson(rectangle_area * src_density_or_number)
    logging.debug('Number of point sources generated = %d' % nsources)
    #-----------------------------------------------------------------------------------------------------------
    # redefine gridhi1
    tan_CC_x = np.array(tan_CC_x)
    tan_CC_y = np.array(tan_CC_y)
    index = np.argmax(tan_CC_x**2 + tan_CC_y**2)
    image_plane_factor = float(gridhi1_CC_factor)
    gravlens_params['gridhi1'] = image_plane_factor * (
        (tan_CC_x[index]**2 + tan_CC_y[index]**2)**0.5)
    inputlens, setlens, gravlens_params = lens_parameters(
        lens_model, mass_scale, model_param_8, model_param_9, model_param_10,
        galaxy_position, e_L, theta_L, shear, theta_shear, gravlens_params)
    #-----------------------------------------------------------------------------------------------------------
    source_positions_output = source_positions(
        nsources, [x_vert_1, x_vert_2], [y_vert_1, y_vert_2],
        minimum_distortion, lens_model, mass_scale, model_param_8,
        model_param_9, model_param_10, galaxy_position, e_L, theta_L, shear,
        theta_shear, gravlens_params, gravlens_mag_input_file,
        gravlens_mag_output_file, keep_mag_files, gravlens_img_input_file,
        gravlens_img_output_file, keep_img_files)
    while source_positions_output == False:
        gravlens_params['gridhi1'] = float(gravlens_params['gridhi1']) * 1.15
        logging.debug('loop in source_positions: gridhi1 = %f' %
                      float(gravlens_params['gridhi1']))
        inputlens, setlens, gravlens_params = lens_parameters(
            lens_model, mass_scale, model_param_8, model_param_9,
            model_param_10, galaxy_position, e_L, theta_L, shear, theta_shear,
            gravlens_params)
        source_positions_output = source_positions(
            nsources, [x_vert_1, x_vert_2], [y_vert_1, y_vert_2],
            minimum_distortion, lens_model, mass_scale, model_param_8,
            model_param_9, model_param_10, galaxy_position, e_L, theta_L,
            shear, theta_shear, gravlens_params, gravlens_mag_input_file,
            gravlens_mag_output_file, keep_mag_files, gravlens_img_input_file,
            gravlens_img_output_file, keep_img_files)
    logging.debug('gridhi1 = %s' % float(gravlens_params['gridhi1']))

    x_src_f, y_src_f, x_img_f, y_img_f, image_distortions = source_positions_output

    logging.debug(
        'Selected positions for finite sources. Coordinates x: %s. Coordinates y: %s'
        % (str(x_src_f), str(y_src_f)))
    logging.debug(
        'Images of the point sources. Coordinates x: %s. Coordinates y: %s' %
        (str(x_img_f), str(y_img_f)))
    logging.debug('Corresponding mu_t and mu_r for each image: %s' %
                  str(image_distortions))

    img_x_plot, img_y_plot = sum(x_img_f, []), sum(y_img_f, [])
    plot_cc(tan_caustic_x,
            tan_caustic_y,
            rad_caustic_x,
            rad_caustic_y,
            tan_CC_x,
            tan_CC_y,
            rad_CC_x,
            rad_CC_y,
            curves_plot,
            show_plot=0,
            src_x=x_src_f,
            src_y=y_src_f,
            img_x=img_x_plot,
            img_y=img_y_plot)

    return x_src_f, y_src_f, x_img_f, y_img_f, image_distortions
def get_distortions(x,
                    y,
                    lens_model,
                    mass_scale,
                    model_param_8,
                    model_param_9,
                    model_param_10,
                    galaxy_position=(0, 0),
                    e_L=0,
                    theta_L=0,
                    shear=0,
                    theta_shear=0,
                    gravlens_params={},
                    gravlens_input_file='gravlens_magtensor_in.txt',
                    gravlens_output_file='gravlens_magtensor_out.txt',
                    keep_files=False):
    """
    Computes the tangential and radial local distortions for a list of (image plane) points.

    
   Input:
     - x                  [float,...] : x coordinates of the points the local distortions will be calculated
     - y                  [float,...] : y coordinates of the points the local distortions will be calculated
     - lens_model                 str : Lens name (see gravlens manual table 3.1)
     - mass_scale               float : Mass scale of the lens - "parameter 1"
     - model_param_8            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_9            float : misc. lens parameter - often scale radio (depends on the lens model)
     - model_param_10           float : misc. lens parameter - often a power law index (depends on the lens model)
     - galaxy_position  [float,float] : [x,y] position of the lens
	 - e_L                    <float> : lens ellipticity (ellipticity = 1 - q, where 0<q<=1 is the axial ratio) 
	 - theta_L                <float> : lens position angle (in degrees) with respect to the vertical 
					                    (counterclockwise)
	 - shear                  <float> : external shear amplitude
	 - theta_shear            <float> : external shear direction (in degrees)
     - gravlens_params           dict : contains the keys and values of the gravlens configuration (see 
				                        default parameters at function set_gravlens_default,inside lens_parameters)
     - gravlens_input_file        str : name of the input file for gravlens
     - gravlens_output_file       str : name of the output file generated by gravlens (with the magnification tensor)
     - keep_files                bool : 'True' to keep gravlens input and output files and 'False' to delete them

    Output:
     - distortions  [[float,float],...] : each pair has respectively the tangential and radial 
                                          distortions [mu_t,mu_r] of the corresponding input point (x_i,y_i) 

    """

    inputlens, setlens, gravlens_params_updated = lens_parameters(
        lens_model, mass_scale, model_param_8, model_param_9, model_param_10,
        galaxy_position, e_L, theta_L, shear, theta_shear, gravlens_params)

    f = open(gravlens_input_file, 'w')
    f.write(inputlens)
    for i in range(len(x)):
        f.write('magtensor %0.9f %0.9f \n' % (x[i], y[i]))
    f.close()
    os.system('gravlens %s > %s' % (gravlens_input_file, gravlens_output_file))

    f = open(gravlens_output_file, 'r').readlines()
    nlinha = len(f) - 6 * len(
        x
    )  # I am using this to get the matrix elements without worrying about the number of lines the file has (which depends on the number of parameters of gravlens we modify). 'nlinha' is the number of lines that DON'T contain the output data of magtensor
    distortions = []
    for i in range(len(x)):  # calculates the magnifications at each point
        a11 = float(f[nlinha +
                      i * 6].split()[0])  # element 11 of the mag tensor
        a12 = float(f[nlinha +
                      i * 6].split()[1])  # element 12 (=21) of the mag tensor
        a22 = float(f[nlinha + i * 6 +
                      1].split()[1])  # element 22 of the mag tensor
        mu_t = (((a11 + a22) / 2.) / (a11 * a22 - a12**2) -
                ((((a22 - a11) / 2.)**2 + a12**2)**0.5) /
                (abs(a11 * a22 - a12**2)))**(-1)
        mu_r = (((a11 + a22) / 2.) / (a11 * a22 - a12**2) +
                ((((a22 - a11) / 2.)**2 + a12**2)**0.5) /
                (abs(a11 * a22 - a12**2)))**(-1)
        distortions.append([mu_t, mu_r])
    if keep_files == False:
        os.system('rm -f %s %s' % (gravlens_input_file, gravlens_output_file))

    return distortions