Пример #1
0
def main():
    from pprofile import StatisticalProfile, Profile

    parser = argparse.ArgumentParser()
    parser.add_argument('inputs', nargs='*')
    args = parser.parse_args()

    for input in args.inputs:
        with open(input, "rt") as h:
            tree = h5yaml.load(h)
        prefix = os.path.dirname(input).rstrip('/')+'/'
        def thunk():
            return submain(prefix=prefix, tree=tree)

        STATISTICAL_PROFILE = True

        if STATISTICAL_PROFILE:
            prof = StatisticalProfile()
            with_item = prof(period=0.001)
        else:
            prof = Profile()
            with_item = prof()

        with with_item:
            thunk()

        with open(prefix+'cachegrind.out.0', 'wt') as file:
            prof.callgrind(file)
        with open(prefix+'pprofile.txt', 'wt') as file:
            prof.annotate(file)
Пример #2
0
def extract_jv(args):
    out_dir = outdir_path_helper(args.out_dir)

    input_dirs = args.input_dirs

    rows = []
    for input_dir in tqdm.tqdm(input_dirs):
        submit = h5yaml.load(os.path.join(input_dir, 'submit.yaml'))
        spar = submit['parameters']
        for f in os.listdir(input_dir):
            m = voltage_step_re.match(f)
            if not m:
                continue
            V_ext = m.group(1)

            filename = os.path.join(input_dir, f)
            tree = h5yaml.load(filename)

            integrals = tree['integrals']

            d = dict(IB_mobility=float(spar['IB_mobility']),
                     IB_thickness=float(spar['IB_thickness']),
                     IB_sigma_ci=float(spar['IB_sigma_ci']),
                     IB_sigma_iv=float(spar['IB_sigma_iv']),
                     concentration_factor=float(spar['concentration_factor']),
                     V=float(V_ext),
                     j_tot_nc=(integrals['avg_j_CB:n_contact'] +
                               integrals['avg_j_VB:n_contact']))

            for k, v in integrals.items():
                d["integrals:" + k] = v

            d['filename'] = filename

            rows.append(d)

    df = pd.DataFrame(rows)

    to_xcsv(df, out_dir + "JV.csv")
Пример #3
0
def voltage_step_plots(input_dir, usetex=False, pdf=False):
    r = []
    for f in os.listdir(input_dir):
        before, sep, after = f.rpartition('.plot_meta.yaml')
        if sep and not after:
            r.append(os.path.join(input_dir, before))

    submitfile = h5yaml.load(os.path.join(input_dir, 'submit.yaml'))

    for basename in r:
        if 'parameter=1.25' not in basename: continue
        plot_main(basename=basename,
                  usetex=usetex,
                  pdf=pdf,
                  submitfile=submitfile)
Пример #4
0
def fixup_titles(submitfiles):
    for submitfile in submitfiles:
        t = h5yaml.load(submitfile)
        p = t['parameters']
        p.setdefault('IB_sigma_ci', '2e-13')
        p.setdefault('IB_sigma_iv', '2e-13')

        p['title'] = title = submitfile_to_title(t)

        with atomic_write(submitfile, overwrite=True) as f:
            h5yaml.dump(t, f)

        olddir = osp.dirname(submitfile)
        newdir = osp.join(osp.dirname(olddir), title)
        os.rename(olddir, newdir)
Пример #5
0
def voltage_step_plots(input, production=False):
    tree = h5yaml.load(input)

    P = tree['parameters']

    for d in P['voltage_steps']:
        prefix = osp.dirname(input).rstrip('/') + '/'
        fn0 = prefix + 'a parameter={} csvplot'.format(d['Vext_str'])
        fn = fn0 + '.csv.0'
        ttl = "V={} {} ".format(d['Vext_str'], P['title'])
        if not osp.exists(fn): continue
        do_main(input=fn,
                output_prefix=prefix + "xplot " + ttl,
                meta_input=fn0 + '.plot_meta.yaml',
                sentaurus_file=d['filename'],
                title=ttl,
                production=production,
                tree_voltage_step=d)
Пример #6
0
def run(submitfile):
    U = make_unit_registry(("mesh_unit = 1 micrometer",))

    PREFIX = dirname(submitfile)
    submitfile_data = h5yaml.load(submitfile)
    P = submitfile_data['parameters']

    TypicalLoggingSetup(filename_prefix=PREFIX).setup()

    setup_dolfin_parameters()

    layers = [
        dict(name='pfsf', material='pfsf'         ,
             thickness=0.05),
        dict(name='p'   , material='semiconductor',
             thickness=1.0),
        dict(name='I'   , material='IB'           ,
             thickness=float(P['IB_thickness'])),
        dict(name='n'   , material='semiconductor',
             thickness=1.0)]

    # -layer means relative to left endpoint of layer
    # +layer means relative to right endpoint of layer
    simple_overmesh_regions = [
        dict(x0=('-pfsf', -0.15), x1=('-pfsf', +0.15), edge_length=0.001 ),
        dict(x0=('+p'   , -0.05), x1=('+p'   , +0.05), edge_length=0.0005),
        dict(x0=('+I'   , -0.05), x1=('+I'   , +0.05), edge_length=0.0005),
        dict(x0=('+n'   , -0.1 ), x1=('+n'   , +0.1 ), edge_length=0.001 ),
    ]

    ls = ConstructionHelperLayeredStructure()
    ls.params = dict(edge_length=0.01, # default edge length
                     layers=layers,
                     simple_overmesh_regions=simple_overmesh_regions,
                     mesh_unit=U.um)
    ls.run()
    mesh_data = ls.mesh_data

    if True:
        Xs_df = pd.DataFrame({
            'X': list(sorted(set(mesh_data.mesh.coordinates()[:,0])))})
        Xs_df.to_csv(PREFIX+"mesh_Xs.csv")

    if False:
        print("exiting early")
        return

    logging.getLogger('main').info("NUM_MESH_POINTS: {}".format(
        len(ls.interval_1d_tag.coordinates['coordinates'])))

    ## topology
    R = CellRegions()
    F = FacetRegions()

    topology_standard_contacts(R, F)

    R.cell = R.p | R.n | R.I | R.pfsf


    F.p_contact   = F.left_contact
    F.pI_junction = R.p.boundary(R.I)
    F.In_junction = R.I.boundary(R.n)
    F.n_contact   = F.right_contact

    F.IB_junctions = F.pI_junction | F.In_junction
    ## end topology


    def create_problemdata(
            goal='full', V_ext=None, phi_cn=None):
        """
goal in {'full', 'local neutrality', 'thermal equilibrium'}
"""
        root = ProblemData(
            goal=goal,
            mesh_data=mesh_data,
            unit_registry=U)
        pdd = root.pdd

        CB = pdd.easy_add_band('CB')
        IB = pdd.easy_add_band('IB')
        VB = pdd.easy_add_band('VB')

        # material to region mapping
        spatial = pdd.spatial

        spatial.add_value_rule(
            R.domain, 'temperature', U('300 K'))

        spatial.add_value_rule(
            R.p, 'poisson/static_rho', U('-1e17 elementary_charge/cm^3'))
        spatial.add_value_rule(
            R.n, 'poisson/static_rho', U('+1e17 elementary_charge/cm^3'))
        spatial.add_value_rule(
            R.pfsf, 'poisson/static_rho', U('-1e19 elementary_charge/cm^3'))
        spatial.add_value_rule(
            R.I, 'poisson/static_rho', U('+0.5e17 elementary_charge/cm^3'))

        ib_material = IBSemiconductor(problem_data=root)
        ib_material.dict['IB/mobility'] = (
            float(P['IB_mobility'])*U('cm^2/V/s'))
        for k in ['ci', 'iv']:
            ib_material.dict['opt_{}/sigma_opt'.format(k)] = (
                float(P['IB_sigma_{}'.format(k)]) * U('cm^2'))

        PFrontSurfaceField(problem_data=root).register()
        semiconductor_material = Semiconductor(problem_data=root)

        ib_material.register()
        semiconductor_material.register()


        mu = pdd.mesh_util

        zeroE = F.exterior

        if goal == 'full':
            optical = root.optical
            ospatial = optical.spatial

            def _ediff(lower, upper):
                d = semiconductor_material.dict
                return ((d[upper+'/energy_level'] -
                         d[lower+'/energy_level']) +
                        U('1e-10 eV'))

            optical.easy_add_field(
                'forward_ci', photon_energy=_ediff('IB', 'CB'),
                direction=(1.0, 0.0))

            optical.easy_add_field(
                'forward_iv', photon_energy=_ediff('VB', 'IB'),
                direction=(1.0, 0.0))

            optical.easy_add_field(
                'forward_cv', photon_energy=_ediff('VB', 'CB'),
                direction=(1.0, 0.0))

            from simudo.util import Blackbody
            bb = Blackbody(temperature=6000*U.K)

            ofield_E_keys = ('forward_cv', 'forward_ci', 'forward_iv')
            for name, (lower, upper) in bb.non_overlapping_energy_ranges(
                    {name: optical.fields[name].photon_energy
                    for name in ofield_E_keys}).items():
                flux = bb.photon_flux_integral_on_earth(
                    lower, upper) * float(P['concentration_factor'])
                flux = flux.to('1/cm^2/s')
                ospatial.add_BC(name+'/Phi', F.left_contact, flux)
                logging.getLogger('main').info(
                    "Input photon flux for field {!r}: {}"
                    .format(name, flux))

            pdd.easy_add_electro_optical_process(
                NonOverlappingTopHatBeerLambertIB,
                name='opt_ci',
                dst_band=CB, src_band=IB, trap_band=IB)

            pdd.easy_add_electro_optical_process(
                NonOverlappingTopHatBeerLambertIB,
                name='opt_iv',
                dst_band=IB, src_band=VB, trap_band=IB)

            pdd.easy_add_electro_optical_process(
                NonOverlappingTopHatBeerLambert,
                name='opt_cv',
                dst_band=CB, src_band=VB)

            # pdd.easy_add_electro_optical_process(
            #     SRHRecombination, dst_band=CB, src_band=VB, name='SRH')

            # NonRadiativeTrap.easy_add_two_traps_to_pdd( pdd, 'nr',
            #                                             CB, VB, IB)

            spatial.add_BC('CB/j', F.nonconductive,
                           U('A/cm^2') * mu.zerovec)
            spatial.add_BC('VB/j', F.nonconductive,
                           U('A/cm^2') * mu.zerovec)
            spatial.add_BC('IB/j', F.exterior,
                           U('A/cm^2') * mu.zerovec)

            # majority contact
            spatial.add_BC('VB/u', F.p_contact,
                           VB.thermal_equilibrium_u)
            spatial.add_BC('CB/u', F.n_contact,
                           CB.thermal_equilibrium_u)

            # minority contact
            spatial.add_BC('VB/u', F.n_contact,
                           VB.thermal_equilibrium_u)
            spatial.add_BC('CB/u', F.p_contact,
                           CB.thermal_equilibrium_u)

            phi0 = pdd.poisson.thermal_equilibrium_phi
            spatial.add_BC('poisson/phi', F.p_contact,
                           phi0 + V_ext)
            spatial.add_BC('poisson/phi', F.n_contact,
                           phi0)

            zeroE -= (F.p_contact | F.n_contact).both()

        elif goal == 'thermal equilibrium':
            # to match old method, use local charge neutrality phi as
            # the phi boundary condition for Poisson-only thermal
            # equilibrium
            spatial.add_BC('poisson/phi', F.p_contact | F.n_contact,
                           phi_cn)
            zeroE -= (F.p_contact | F.n_contact).both()

        spatial.add_BC('poisson/E', zeroE,
                       U('V/m') * mu.zerovec)

        return root

    problem = create_problemdata(goal='local charge neutrality')

    problem.pdd.easy_auto_pre_solve()

    problem0 = problem
    problem = create_problemdata(goal='thermal equilibrium',
                                 phi_cn=problem0.pdd.poisson.phi)
    problem.pdd.initialize_from(problem0.pdd)

    problem.pdd.easy_auto_pre_solve()

    V_ext = U.V * dolfin.Constant(0.0)
    problem0 = problem
    problem = create_problemdata(goal='full', V_ext=V_ext)
    problem.pdd.initialize_from(problem0.pdd)

    from simudo.physics import (
        VoltageStepper, OpticalIntensityAdaptiveStepper)
    from simudo.io.output_writer import (
        OutputWriter, MetaExtractorBandInfo,
        MetaExtractorIntegrals)

    meta_extractors = (
        MetaExtractorBandInfo,
        partial(MetaExtractorIntegrals,
                facets=F[{'p_contact', 'n_contact'}],
                cells=R[{'pfsf', 'p', 'n', 'I'}]))

    optics = float(P['concentration_factor']) != 0

    if optics:
        optical_rampup_start_logparam = 20
        stepper = OpticalIntensityAdaptiveStepper(
            solution=problem,
            # parameter_target_values=[1e-10, 0.1, 1.0],
            parameter_target_values=[0]+[
                10**-n for n in
                range(0, optical_rampup_start_logparam+1, 4)[::-1]],
            step_size=10**-optical_rampup_start_logparam,
            # step_size=0.5,
            output_writer=OutputWriter(
                filename_prefix=PREFIX+"I", plot_1d=True, plot_iv=False,
                meta_extractors=meta_extractors),
            selfconsistent_optics=True)

        stepper.do_loop()

    V_exts = list(np.linspace(0, 1.5, 75+1))
    V_exts.extend(np.linspace(1.15, 1.30, 75+1))
    V_exts = list(set(V_exts))
    V_exts.sort()

    stepper = VoltageStepper(
        solution=problem, constants=[V_ext],

        # parameter_target_values=[1.0],
        # step_size=0.5,

        parameter_target_values=V_exts,

        # parameter_target_values=np.arange(0, 12)*0.1,

        parameter_unit=U.V,
        output_writer=OutputWriter(
            filename_prefix=PREFIX+"a", plot_1d=True, plot_iv=False,
            meta_extractors=meta_extractors),
        selfconsistent_optics=optics)

    stepper.do_loop()

    return locals()
Пример #7
0
def summary_analysis(basedirs, output_prefix=None, pdf=False, usetex=False):

    matplotlib_configure_CM_font(size=16, usetex=usetex)
    savefig_ = functools.partial(savefig, pdf=pdf)

    if output_prefix is None:
        output_prefix = osp.join(basedirs[0], 'sen_summary ')
    rows = []
    for basedir in basedirs:
        for subdir_ in os.listdir(basedir):
            subdir = osp.join(basedir, subdir_)
            submit_file = osp.join(subdir, 'submit.yaml')
            if not osp.exists(submit_file): continue
            submit = h5yaml.load(submit_file)

            submitp = submit['parameters']
            for analysis_file in glob.iglob(
                    glob.escape(subdir) +
                    '/xplot * sentaurus_plot_analysis.yaml'):
                ana = h5yaml.load(open(analysis_file))
                row = ana.copy()
                del row['voltage_step']
                row['doping_str'] = doping = submitp['doping']
                row['doping'] = float(doping)
                row['Vext_str'] = Vext = ana['voltage_step']['Vext_str']
                row['Vext'] = float(Vext)
                row['meshp'] = float(submitp['mesh_points'])
                row['meth'] = submitp['transport_method']
                row['fta'] = float(submitp['fill_threshold_abs'])
                row['ftr'] = float(submitp['fill_threshold_rel'])
                row['fwz'] = bool(submitp['fill_with_zero_except_bc'])
                for k in ('quaddeg_super', 'quaddeg_g', 'quaddeg_rho',
                          'min_srv'):
                    row[k] = submitp[k]
                rows.append(row)
    df = pd.DataFrame(rows)

    TRIAL_FLOODFILL = 0
    TRIAL_FWZ = 1
    TRIAL_CELLAVG = 2

    df['numtrial'] = TRIAL_FLOODFILL

    def where(c, x, y):
        return c * x + (1 - c) * y

    df['numtrial'] = where(df['numtrial'] != TRIAL_FLOODFILL, df['numtrial'],
                           where(df['fwz'] == True, TRIAL_FWZ, df['numtrial']))

    df['numtrial'] = where(
        df['numtrial'] != TRIAL_FLOODFILL, df['numtrial'],
        where(((df['fta'] == 0.0) & (df['ftr'] == 0.0)), TRIAL_CELLAVG,
              df['numtrial']))

    df.to_csv(output_prefix + 'table.csv')
    with open(output_prefix + 'table.txt', 'wt') as handle:
        print(tabulate(df, headers='keys', tablefmt='psql'), file=handle)

    def jrel_comparison_plot(df0,
                             df1=None,
                             baseline_label='baseline',
                             trial_label=None,
                             filename_prefix=None,
                             total_current=False,
                             contact_suffix0='',
                             contact_suffix1='',
                             is_paper_plot=False):
        for which_carrier, which_contact in itertools.product(
                't' if total_current else 'pn', 'pn'):

            def _make_relvar(contact_suffix):
                return 'jrel__c{}{}_{}'.format(which_contact, contact_suffix,
                                               which_carrier)

            relvar0 = _make_relvar(contact_suffix0)
            relvar1 = _make_relvar(contact_suffix1)

            figkw = dict(figsize=(6.4, 4.8))

            fig, ax = plt.subplots(**figkw)

            # ax.set_prop_cycle(color=['#294171', '#5A1705', '#8E887C'])

            for k in sorted(set(df0['doping'])):
                xdf0 = df0[df0['doping'] == k]

                doping_str = xdf0.iloc[0]['doping_str']
                if is_paper_plot:
                    label = (r"$N_A=N_D={}\;\mathrm{{cm^{{-3}}}}$".format(
                        sci_to_latex(doping_str)))
                else:
                    label = r"c={}".format(doping_str)
                p = ax.plot(xdf0['Vext'],
                            abs(xdf0[relvar0]),
                            label=label,
                            marker='.')

                if df1 is None: continue

                xdf1 = df1[df1['doping'] == k]
                color = p[0].get_color()
                ax.plot(xdf1['Vext'],
                        abs(xdf1[relvar1]),
                        label='_nolegend_',
                        color=color,
                        linestyle='dashed',
                        marker='.')

            ax.set_yscale('log')
            if df1 is not None:
                ax.plot([], [],
                        color='black',
                        linestyle='solid',
                        label=baseline_label)
                ax.plot([], [],
                        color='black',
                        linestyle='dashed',
                        label=trial_label)

            ax.set_xlabel(r"$V_{\mathrm{ext}}$ ($\mathrm{V}$)")

            if is_paper_plot:
                ax.set_ylabel(r"Relative error in $J$")
                legend_kwargs = dict(prop=dict(size=14))
            else:
                ax.set_ylabel(
                    r"$j_{{{},\mathrm{{rel}}}}$ at {} contact".format(
                        which_carrier, which_contact))
                legend_kwargs = {}

            # ax.set_xlim([-2, 2])
            # ax.set_ylim([1e-8, 1e-2])

            ax.legend(**legend_kwargs)
            if False:
                fig.tight_layout()
            else:
                fig.subplots_adjust(hspace=0.,
                                    left=0.15,
                                    right=0.95,
                                    bottom=0.13,
                                    top=0.92)
            savefig_(fig, filename_prefix + ' ' + _make_relvar(''))
            plt.close(fig)

    df, df_orig = df[abs(df['Vext']) > 1e-3], df
    df.sort_values('Vext', inplace=True)

    jrel_comparison_plot(df[df['numtrial'] == TRIAL_CELLAVG],
                         filename_prefix=output_prefix + "baseline_cellavg")

    if True:
        df = df[df['min_srv'] == '0']

    df2 = df[df['numtrial'] == TRIAL_CELLAVG]
    if False:
        jrel_comparison_plot(
            df2[df2['meshp'] > 0],
            df2[df2['meshp'] < 0],
            baseline_label='unif',
            trial_label='non-unif',
            filename_prefix=output_prefix + "mesh_compare",
            total_current=True,
        )

    if False:
        jrel_comparison_plot(
            df2[df2['quaddeg_g'] == 30],
            df2[df2['quaddeg_g'] == 8],
            baseline_label='$d_g=30$',
            trial_label='$d_g=6$',
            filename_prefix=output_prefix + "quaddeg_compare",
            total_current=True,
        )

    # mixed-u-j vs mixedqfl method comparison
    if True:
        jrel_comparison_plot(
            df2[df['meth'] == 'mixed_qfl_j'],
            df2[df['meth'] == 'mixed_u_j'],
            baseline_label='Simudo',
            trial_label='TTCB...CD',
            contact_suffix0='I',
            contact_suffix1='M',
            filename_prefix=output_prefix + "method_compare",
            total_current=True,
            is_paper_plot=True,
        )
        jrel_comparison_plot(
            df2[df['meth'] == 'mixed_u_j'],
            df2[df['meth'] == 'mixed_u_j'],
            baseline_label='TTCB...CD integrated',
            trial_label='TTCB...CD median',
            contact_suffix0='M',
            contact_suffix1='I',
            filename_prefix=output_prefix + "method_compare_extraction",
            total_current=True,
            is_paper_plot=True,
        )

    df4 = df2[df2['quaddeg_g'] == df2['quaddeg_g'].values.max()]
    if True:
        jrel_comparison_plot(
            df4,
            df4,
            baseline_label='line cut',
            trial_label='integrated',
            filename_prefix=output_prefix + "linecut_vs_integrated",
            total_current=True,
            contact_suffix0='',
            contact_suffix1='I',
        )

    df5 = df4[(df4['meshp'] == -1) & (
        (df4['doping_str'] == '1e15') | (df4['doping_str'] == '1e18'))]
    df6 = df4[(df4['meshp'] == -1)]
    if True:
        jrel_comparison_plot(
            df5,
            filename_prefix=output_prefix + "paper_plot",
            total_current=True,
            contact_suffix0='I',
            is_paper_plot=True,
        )
        jrel_comparison_plot(
            df6,
            filename_prefix=output_prefix + "paper_plot_all_curves",
            total_current=True,
            contact_suffix0='I',
        )
Пример #8
0
def do_main(input='out/stupidtest/a parameter=0.4 csvplot.csv.0',
            output_prefix='out/mrs2018_pnbench_',
            meta_input=None,
            sentaurus_file="data/sentaurus/diode_1d c=1e18 V=0.4.csv.xz",
            title=None,
            tree_voltage_step=None,
            production=False,
            reduce_vsize=False):
    df = pd.read_csv(input)

    if production:
        title = None

    if sentaurus_file is not None:
        with lzma.open(sentaurus_file, mode='rb') as handle:
            Sdf, Sdf_units = sentaurus_import.read_df_unitful(handle=handle,
                                                              unit_registry=U)
        #df.sort_values('coord_x', inplace=True)
        #df.reset_index(drop=True, inplace=True)
        Sdf, Sdf_units = sentaurus_import.interpolate_df(
            Sdf, Sdf_units, df['coord_x'].values * U.micrometer)
        make_compatible_sentaurus(Sdf)
    else:
        Sdf, Sdf_units = None, None
        Sdf = df  # to avoid a billion conditionals in the plot

    fig = plot_cmp_density(df, Sdf, title)
    savefig(fig, output_prefix + "u")
    plt.close(fig)

    fig = plot_cmp_current(df, Sdf, title)
    savefig(fig, output_prefix + "j")
    plt.close(fig)

    fig = plot_cmp_current(df, Sdf, title, value_only=True, grid=False)
    savefig(fig, output_prefix + "jv")
    plt.close(fig)

    if input.endswith(
            " c=1e18 Vd=-1 meshp=2000 bchack=0 ffill=1 fta=0 ftr=1e-10 fwz=0/a parameter=-0.2 csvplot.csv.0"
    ) and 0:
        fig = plot_cmp_current(df,
                               Sdf,
                               title,
                               value_only=True,
                               is_inset=True,
                               grid=False,
                               force_lims=[(40, 70), (-1.655e-6, -1.62e-6)])
        savefig(fig, output_prefix + "jv_inset")
        plt.close(fig)

    fig = plot_cmp_current(df, Sdf, title, relative_only=True)
    savefig(fig, output_prefix + "jr")
    plt.close(fig)

    fig = plot_offset_partitioning(df, title)
    savefig(fig, output_prefix + "op")
    plt.close(fig)

    df_add_drift_diffusion_terms(df)
    fig = plot_drift_diffusion_currents(df, title)
    savefig(fig, output_prefix + "jdd")
    plt.close(fig)

    if meta_input:
        meta_input = h5yaml.load(meta_input)

    d = do_single_analysis_summary(df,
                                   Sdf,
                                   title,
                                   meta_input=meta_input,
                                   tree_voltage_step=tree_voltage_step)
    d['voltage_step'] = tree_voltage_step
    h5yaml.dump(d, output_prefix + 'sentaurus_plot_analysis.yaml')