<commit_before>#!/usr/bin/env python
""" 
    Class to validate a given 2D model by averaging it
    and comparing to 1D prediction.
    
    The equation used for averaging is:
    
        (integral dphi from 0 to 2pi)(integral dtheta from 0 to pi)
             p(theta, phi) I(q) sin(theta) dtheta
             
        = (1/N_phi) (1/N_theta) (pi/2) (sum over N_phi) (sum over N_theta)
             p(theta_i, phi_i) I(q) sin(theta_i)
             
    where p(theta, phi) is the probability distribution normalized to 4pi.
    In the current case, we put p(theta, phi) = 1.
    
    The normalization factor results from:
          2pi/N_phi      for the phi sum
        x pi/N_theta     for the theta sum
        x 1/(4pi)        because p is normalized to 4pi
        --------------
        = (1/N_phi) (1/N_theta) (pi/2)
    
    Note: Ellipsoid
        Averaging the 2D ellipsoid scattering intensity give a slightly
        different output than the 1D function from the IGOR library 
        at hight Q (Q>0.3). This is due to the way the IGOR library 
        averages, taking only 76 points in alpha, the angle between
        the axis of the ellipsoid and the q vector.
        
    Note: Core-shell and sphere models are symmetric around
        all axes and don't need to be tested in the following way.
"""
import sys, math
from sans.models.SphereModel import SphereModel
from sans.models.CylinderModel import CylinderModel
from sans.models.EllipsoidModel import EllipsoidModel
from sans.models.CoreShellCylinderModel import CoreShellCylinderModel


class Validate2D:
    """ 
        Class to validate a given 2D model by averaging it
        and comparing to 1D prediction.
    """
    
    def __init__(self):
        """ Initialization """
        # Precision for the result comparison
        self.precision = 0.000001
        # Flag for end result
        self.passed = True
                
    def __call__(self, model_class=CylinderModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        #model.setParam('scale', 1.0)
        #model.setParam('contrast', 1.0)
        
        theta_label = 'cyl_theta'
        if not model.params.has_key(theta_label):
            theta_label = 'axis_theta'
            
        phi_label = 'cyl_phi'
        if not model.params.has_key(phi_label):
            phi_label = 'axis_phi'
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025*i_q
            sum = 0.0
            for i_theta in range(npts):
                theta = 180.0/npts*i_theta
                
                model.setParam(theta_label, theta)
                
                for j in range(npts):
                    model.setParam(phi_label, 180.0 * 2.0 / npts * j)
                    if str(model.run([q, 0])).count("INF")>0:                        
                        print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                    sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
                    #sum += model.run([q, 0])
            
            value = sum/npts/npts*180.0/2.0
            ana = model.run(q)
            if q<0.3 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)
        
        output_f.close()
        return passed
    
    def average(self, model_class=CylinderModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        model.setParam('scale', 1.0)
        model.setParam('contrast', 1.0)
        
        theta_label = 'cyl_theta'
        if not model.params.has_key(theta_label):
            theta_label = 'axis_theta'
            
        phi_label = 'cyl_phi'
        if not model.params.has_key(phi_label):
            phi_label = 'axis_phi'
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025*i_q
            sum = 0.0
            theta = 90.0
            
            model.setParam(theta_label, theta)
            
            for j in range(npts):
                model.setParam(phi_label, 180.0 / 2.0 / npts * j)
                if str(model.run([q, 0])).count("INF")>0:                        
                    print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                #sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
                sum += math.sin(math.pi / 2.0 / npts * j)*model.run([q, 0])
                #sum += model.run([q, 0])
            
            value = sum/npts
            ana = model.run(q)
            if q<0.3 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)
        
        output_f.close()
        return passed
        
    def test_non_oriented(self, model_class=SphereModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        #model.setParam('scale', 1.0)
        #model.setParam('contrast', 1.0)
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025*i_q
            sum = 0.0
            for i_theta in range(npts):
                theta = 180.0/npts*i_theta
                
                for j in range(npts):
                    if str(model.run([q, 0])).count("INF")>0:                        
                        print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                    sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
            
            value = sum/npts/npts*180.0/2.0
            ana = model.run(q)
            if q<0.3 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)<commit_msg>updated and fixed utest 2d<commit_after>#!/usr/bin/env python
""" 
    Class to validate a given 2D model by averaging it
    and comparing to 1D prediction.
    
    The equation used for averaging is:
    
        (integral dphi from 0 to 2pi)(integral dtheta from 0 to pi)
             p(theta, phi) I(q) sin(theta) dtheta
             
        = (1/N_phi) (1/N_theta) (pi/2) (sum over N_phi) (sum over N_theta)
             p(theta_i, phi_i) I(q) sin(theta_i)
             
    where p(theta, phi) is the probability distribution normalized to 4pi.
    In the current case, we put p(theta, phi) = 1.
    
    The normalization factor results from:
          2pi/N_phi      for the phi sum
        x pi/N_theta     for the theta sum
        x 1/(4pi)        because p is normalized to 4pi
        --------------
        = (1/N_phi) (1/N_theta) (pi/2)
    
    Note: Ellipsoid
        Averaging the 2D ellipsoid scattering intensity give a slightly
        different output than the 1D function from the IGOR library 
        at hight Q (Q>0.3). This is due to the way the IGOR library 
        averages, taking only 76 points in alpha, the angle between
        the axis of the ellipsoid and the q vector.
        
    Note: Core-shell and sphere models are symmetric around
        all axes and don't need to be tested in the following way.
"""
import sys, math
from sans.models.SphereModel import SphereModel
from sans.models.CylinderModel import CylinderModel
from sans.models.EllipsoidModel import EllipsoidModel
from sans.models.CoreShellCylinderModel import CoreShellCylinderModel


class Validate2D:
    """ 
        Class to validate a given 2D model by averaging it
        and comparing to 1D prediction.
    """
    
    def __init__(self):
        """ Initialization """
        # Precision for the result comparison
        self.precision = 0.000001
        # Flag for end result
        self.passed = True
                
    def __call__(self, model_class=CylinderModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        #model.setParam('scale', 1.0)
        #model.setParam('contrast', 1.0)
        
        theta_label = 'cyl_theta'
        if not model.params.has_key(theta_label):
            theta_label = 'axis_theta'
            
        phi_label = 'cyl_phi'
        if not model.params.has_key(phi_label):
            phi_label = 'axis_phi'
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025 *i_q
            sum = 0.0
            for i_theta in range(npts):
                theta = 180.0 / npts * i_theta
                
                model.setParam(theta_label, theta)
                
                for j in range(npts):
                    model.setParam(phi_label, 180.0 * 2.0 / npts * j)
                    if str(model.run([q, 0])).count("INF")>0:                        
                        print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                    sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
                    #sum += model.run([q, 0])
            
            value = sum/npts/npts*math.pi/2.0
            ana = model.run(q)
            if q<0.25 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)
        
        output_f.close()
        return passed
    
    def average(self, model_class=CylinderModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        model.setParam('scale', 1.0)
        model.setParam('contrast', 1.0)
        
        theta_label = 'cyl_theta'
        if not model.params.has_key(theta_label):
            theta_label = 'axis_theta'
            
        phi_label = 'cyl_phi'
        if not model.params.has_key(phi_label):
            phi_label = 'axis_phi'
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025*i_q
            sum = 0.0
            theta = 90.0
            
            model.setParam(theta_label, theta)
            
            for j in range(npts):
                model.setParam(phi_label, 180.0 / 2.0 / npts * j)
                if str(model.run([q, 0])).count("INF")>0:                        
                    print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                #sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
                sum += math.sin(math.pi / 2.0 / npts * j)*model.run([q, 0])
                #sum += model.run([q, 0])
            
            value = sum/npts
            ana = model.run(q)
            if q<0.25 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)
        
        output_f.close()
        return passed
        
    def test_non_oriented(self, model_class=SphereModel, points = 101):
        """ 
            Perform test and produce output file
            @param model_class: python class of the model to test
        """
        print "Averaging %s" % model_class.__name__
        passed = True
        
        npts =points
        model = model_class()
        #model.setParam('scale', 1.0)
        #model.setParam('contrast', 1.0)
        
        output_f = open("%s_avg.txt" % model.__class__.__name__,'w')    
        output_f.write("<q_average> <2d_average> <1d_average>\n")
            
        for i_q in range(1, 30):
            q = 0.025*i_q
            sum = 0.0
            for i_theta in range(npts):
                theta = 180.0/npts*i_theta
                
                for j in range(npts):
                    if str(model.run([q, 0])).count("INF")>0:                        
                        print "ERROR", q, theta, 180.0 * 2.0 / npts * j
                    sum += math.sin(theta*math.pi/180.0)*model.run([q, 0])
            
            value = sum/npts/npts*math.pi/2.0
            ana = model.run(q)
            if q<0.25 and (value-ana)/ana>0.05:
                passed = False
            output_f.write("%10g %10g %10g\n" % (q, value, ana))
            print "Q=%g: %10g %10g %10g %10g" % (q, value, ana, value-ana, value/ana)
{'fraction_non_alphanumeric': 0.11070428602196855, 'fraction_numerical': 0.03173235695311939, 'mean_word_length': 1.5180766449746927, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6883874', 'n_tokens_mistral': 4729, 'n_tokens_neox': 4289, 'n_words': 1164}