def channelpedia_xml_to_neuroml2(cpd_xml, nml2_file_name, unknowns=""):


    info = 'Automatic conversion of Channelpedia XML file to NeuroML2\n'+\
           'Uses: https://github.com/OpenSourceBrain/BlueBrainProjectShowcase/blob/master/Channelpedia/ChannelpediaToNeuroML2.py'
    print(info)

    root = ET.fromstring(cpd_xml)

    channel_id = 'Channelpedia_%s_%s' % (root.attrib['ModelName'].replace(
        "/", "_").replace(" ", "_").replace(".", "_"), root.attrib['ModelID'])

    doc = neuroml.NeuroMLDocument()

    metadata = osb.metadata.RDF(info)

    ion = root.findall('Ion')[0]
    chan = neuroml.IonChannelHH(
        id=channel_id,
        conductance='10pS',
        species=ion.attrib['Name'],
        notes=
        "This is an automated conversion to NeuroML 2 of an ion channel model from Channelpedia. "
        +
        "\nThe original channel model file can be found at: http://channelpedia.epfl.ch/ionchannels/%s"
        % root.attrib['ID'] +
        "\n\nConversion scripts at https://github.com/OpenSourceBrain/BlueBrainProjectShowcase"
    )

    chan.annotation = neuroml.Annotation()

    model_url_template = 'http://channelpedia.epfl.ch/ionchannels/%s/hhmodels/%s.xml'
    desc = osb.metadata.Description(channel_id)
    metadata.descriptions.append(desc)
    osb.metadata.add_simple_qualifier(desc, \
                                      'bqmodel', \
                                      'isDerivedFrom', \
                                      model_url_template%(root.attrib['ID'], root.attrib['ModelID']), \
                                      "Channelpedia channel ID: %s, ModelID: %s; direct link to original XML model" % (root.attrib['ID'], root.attrib['ModelID']))

    channel_url_template = 'http://channelpedia.epfl.ch/ionchannels/%s'
    osb.metadata.add_simple_qualifier(desc, \
                                      'bqmodel', \
                                      'isDescribedBy', \
                                      channel_url_template%(root.attrib['ID']), \
                                      "Channelpedia channel ID: %s; link to main page for channel" % (root.attrib['ID']))

    for reference in root.findall('Reference'):
        pmid = reference.attrib['PubmedID']
        #metadata = update_metadata(chan, metadata, channel_id, "http://identifiers.org/pubmed/%s"%pmid)
        ref_info = reference.text
        osb.metadata.add_simple_qualifier(desc, \
                                          'bqmodel', \
                                          'isDescribedBy', \
                                          osb.resources.PUBMED_URL_TEMPLATE % (pmid), \
                                          ("PubMed ID: %s is referenced in original XML\n"+\
                                          "                                 %s") % (pmid, ref_info))

    for environment in root.findall('Environment'):
        for animal in environment.findall('Animal'):

            species = animal.attrib['Name'].lower()

            if species:
                if species in osb.resources.KNOWN_SPECIES:
                    known_id = osb.resources.KNOWN_SPECIES[species]
                    osb.metadata.add_simple_qualifier(desc, \
                                                      'bqbiol', \
                                                      'hasTaxon', \
                                                      osb.resources.NCBI_TAXONOMY_URL_TEMPLATE % known_id, \
                                                      "Known species: %s; taxonomy id: %s" % (species, known_id))
                else:
                    print("Unknown species: %s" % species)
                    unknowns += "Unknown species: %s\n" % species

        for cell_type_el in environment.findall('CellType'):
            cell_type = cell_type_el.text.strip().lower()

            if cell_type:
                if cell_type in osb.resources.KNOWN_CELL_TYPES:
                    known_id = osb.resources.KNOWN_CELL_TYPES[cell_type]
                    osb.metadata.add_simple_qualifier(desc, \
                                                      'bqbiol', \
                                                      'isPartOf', \
                                                      osb.resources.NEUROLEX_URL_TEMPLATE % known_id, \
                                                      "Known cell type: %s; taxonomy id: %s" % (cell_type, known_id))
                else:
                    print("Unknown cell_type: %s" % cell_type)
                    unknowns += "Unknown cell_type: %s\n" % cell_type

    print("Currently unknown: <<<%s>>>" % unknowns)

    comp_types = {}
    for gate in root.findall('Gates'):

        eq_type = gate.attrib['EqType']
        gate_name = gate.attrib['Name']
        target = chan.gates

        if eq_type == '1':
            g = neuroml.GateHHUndetermined(id=gate_name,
                                           type='gateHHtauInf',
                                           instances=int(
                                               float(gate.attrib['Power'])))
        elif eq_type == '2':
            g = neuroml.GateHHUndetermined(id=gate_name,
                                           type='gateHHrates',
                                           instances=int(
                                               float(gate.attrib['Power'])))

        for inf in gate.findall('Inf_Alpha'):
            equation = check_equation(inf.findall('Equation')[0].text)

            if eq_type == '1':
                new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'inf')
                g.steady_state = neuroml.HHVariable(type=new_comp_type)

                comp_type = lems.ComponentType(
                    new_comp_type, extends="baseVoltageDepVariable")

                comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time'))
                comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage'))

                comp_type.dynamics.add(
                    lems.DerivedVariable(name='V',
                                         dimension="none",
                                         value="v / VOLT_SCALE"))
                comp_type.dynamics.add(
                    lems.DerivedVariable(name='x',
                                         dimension="none",
                                         value="%s" % equation,
                                         exposure="x"))

                comp_types[new_comp_type] = comp_type

            elif eq_type == '2':
                new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'alpha')
                g.forward_rate = neuroml.HHRate(type=new_comp_type)

                comp_type = lems.ComponentType(new_comp_type,
                                               extends="baseVoltageDepRate")

                comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time'))
                comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage'))

                comp_type.dynamics.add(
                    lems.DerivedVariable(name='V',
                                         dimension="none",
                                         value="v / VOLT_SCALE"))
                comp_type.dynamics.add(
                    lems.DerivedVariable(name='r',
                                         dimension="per_time",
                                         value="%s / TIME_SCALE" % equation,
                                         exposure="r"))

                comp_types[new_comp_type] = comp_type

        for tau in gate.findall('Tau_Beta'):
            equation = check_equation(tau.findall('Equation')[0].text)

            if eq_type == '1':
                new_comp_type = "%s_%s_tau" % (channel_id, gate_name)
                g.time_course = neuroml.HHTime(type=new_comp_type)

                comp_type = lems.ComponentType(new_comp_type,
                                               extends="baseVoltageDepTime")

                comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time'))
                comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage'))

                comp_type.dynamics.add(
                    lems.DerivedVariable(name='V',
                                         dimension="none",
                                         value="v / VOLT_SCALE"))
                comp_type.dynamics.add(
                    lems.DerivedVariable(name='t',
                                         dimension="time",
                                         value="(%s) * TIME_SCALE" % equation,
                                         exposure="t"))

                comp_types[new_comp_type] = comp_type

            elif eq_type == '2':
                new_comp_type = "%s_%s_%s" % (channel_id, gate_name, 'beta')
                g.reverse_rate = neuroml.HHRate(type=new_comp_type)

                comp_type = lems.ComponentType(new_comp_type,
                                               extends="baseVoltageDepRate")

                comp_type.add(lems.Constant('TIME_SCALE', '1 ms', 'time'))
                comp_type.add(lems.Constant('VOLT_SCALE', '1 mV', 'voltage'))

                comp_type.dynamics.add(
                    lems.DerivedVariable(name='V',
                                         dimension="none",
                                         value="v / VOLT_SCALE"))
                comp_type.dynamics.add(
                    lems.DerivedVariable(name='r',
                                         dimension="per_time",
                                         value="%s  / TIME_SCALE" % equation,
                                         exposure="r"))

                comp_types[new_comp_type] = comp_type

        target.append(g)

    doc.ion_channel_hhs.append(chan)

    doc.id = channel_id

    writers.NeuroMLWriter.write(doc, nml2_file_name)

    print("Written NeuroML 2 channel file to: " + nml2_file_name)

    for comp_type_name in comp_types.keys():
        comp_type = comp_types[comp_type_name]
        ct_xml = comp_type.toxml()

        # Quick & dirty pretty printing..
        ct_xml = ct_xml.replace('<Const', '\n        <Const')
        ct_xml = ct_xml.replace('<Dyna', '\n        <Dyna')
        ct_xml = ct_xml.replace('</Dyna', '\n        </Dyna')
        ct_xml = ct_xml.replace('<Deriv', '\n            <Deriv')
        ct_xml = ct_xml.replace('</Compone', '\n    </Compone')

        # print("Adding definition for %s:\n%s\n"%(comp_type_name, ct_xml))
        nml2_file = open(nml2_file_name, 'r')
        orig = nml2_file.read()
        new_contents = orig.replace("</neuroml>",
                                    "\n    %s\n\n</neuroml>" % ct_xml)
        nml2_file.close()
        nml2_file = open(nml2_file_name, 'w')
        nml2_file.write(new_contents)
        nml2_file.close()

    print("Inserting metadata...")
    nml2_file = open(nml2_file_name, 'r')
    orig = nml2_file.read()
    new_contents = orig.replace(
        "<annotation/>", "\n        <annotation>\n%s        </annotation>\n" %
        metadata.to_xml("            "))
    nml2_file.close()
    nml2_file = open(nml2_file_name, 'w')
    nml2_file.write(new_contents)
    nml2_file.close()

    ###### Validate the NeuroML ######

    from neuroml.utils import validate_neuroml2

    validate_neuroml2(nml2_file_name)

    return unknowns
"""
Generating a Hodgkin-Huxley Ion Channel and writing it to NeuroML
"""

import neuroml
import neuroml.writers as writers

chan = neuroml.IonChannelHH(id='na',
                          conductance='10pS',
                          species='na',
                          notes="This is an example voltage-gated Na channel")

m_gate = neuroml.GateHHRates(id='m',instances='3')
h_gate = neuroml.GateHHRates(id='h',instances='1')

m_gate.forward_rate = neuroml.HHRate(type="HHExpRate",
                                     rate="0.07per_ms",
                                     midpoint="-65mV",
                                     scale="-20mV")

m_gate.reverse_rate = neuroml.HHRate(type="HHSigmoidRate",
                                     rate="1per_ms",
                                     midpoint="-35mV",
                                     scale="10mV")

h_gate.forward_rate = neuroml.HHRate(type="HHExpLinearRate",
                                     rate="0.1per_ms",
                                     midpoint="-55mV",
                                     scale="10mV")

h_gate.reverse_rate = neuroml.HHRate(type="HHExpRate",
    def generate_channel_nml2(self,bio_params,channel_params,model_params):
        """
        Generates NeuroML2 file from ion channel parameters.

        :param bio_params: Biological parameters
        :param channel_params: Channel parameters
        :param model_params: NeuroML2 file parameters
        :return: NeuroML2 file
        """

        unknowns = ''
        info = 'This is an ion channel model NeuroML2 file generated by ChannelWorm: https://github.com/openworm/ChannelWorm'
        channel_id='ChannelWorm_%s_%s_%s'%(model_params['channel_name'],model_params['channel_id'],model_params['model_id'])

        doc = neuroml.NeuroMLDocument()

        metadata = osb.metadata.RDF(info)

        desc = osb.metadata.Description(channel_id)
        metadata.descriptions.append(desc)

        osb.metadata.add_simple_qualifier(desc,
                                          'bqmodel',
                                          'isDerivedFrom',
                                          "ChannelWorm channel Name: %s channel ID: %s, ModelID: %s"
                                          %(model_params['channel_name'],model_params['channel_id'],model_params['model_id']))

        for reference in model_params['references']:
            DOI = reference['doi']
            pmid = reference['PMID']
            ref_info = reference['citation']
            osb.metadata.add_simple_qualifier(desc,
                                              'bqmodel',
                                              'isDescribedBy',
                                              osb.resources.PUBMED_URL_TEMPLATE % (pmid),
                                              ("DOI: %s, PubMed ID: %s \n"+
                                               "                                 %s") % (DOI, pmid, ref_info))

        species = 'caenorhabditis elegans'

        if osb.resources.KNOWN_SPECIES.has_key(species):
            known_id = osb.resources.KNOWN_SPECIES[species]
            osb.metadata.add_simple_qualifier(desc,
                                              'bqbiol',
                                              'hasTaxon',
                                              osb.resources.NCBI_TAXONOMY_URL_TEMPLATE % known_id,
                                              "Known species: %s; taxonomy id: %s" % (species, known_id))
        else:
            print("Unknown species: %s"%species)
            unknowns += "Unknown species: %s\n"%species

        cell_type = bio_params['cell_type']

        if osb.resources.KNOWN_CELL_TYPES.has_key(cell_type):
            known_id = osb.resources.KNOWN_CELL_TYPES[cell_type]
            osb.metadata.add_simple_qualifier(desc,
                                              'bqbiol',
                                              'isPartOf',
                                              osb.resources.NEUROLEX_URL_TEMPLATE % known_id,
                                              "Known cell type: %s; taxonomy id: %s" % (cell_type, known_id))
        else:
            print("Unknown cell_type: %s"%cell_type)
            unknowns += "Unknown cell_type: %s\n"%cell_type

        # for contributor in model_params['contributors']:
        #     metadata.descriptions.append('Curator: %s (%s)'%(contributor['name'],contributor['email']))

        print("Currently unknown: <<<%s>>>"%unknowns)

        ion = bio_params['ion_type']
        unit = dict(zip(bio_params['channel_params'],bio_params['unit_chan_params']))
        chan = neuroml.IonChannelHH(id=channel_id,
                                    conductance='10pS',
                                    species=ion)

        chan.annotation = neuroml.Annotation()
        target = chan.gate_hh_tau_infs

        for gate in bio_params['gate_params']:

            gate_name = gate
            instances = bio_params['gate_params'][gate_name]['power']
            g_type='HHSigmoidVariable'

            if gate_name == 'vda':
                g = neuroml.GateHHTauInf(id=gate_name, instances=instances)
                v_half = str(channel_params['v_half_a']) + ' ' + str(unit['v_half_a'])
                k = str(channel_params['k_a']) + ' ' + str(unit['k_a'])
                g.steady_state = neuroml.HHRate(midpoint=v_half,scale=k,rate=1,type=g_type)
                if 'T_a' in channel_params:
                    T = str(channel_params['T_a']) + ' ' + str(unit['T_a'])
                    t_type="fixedTimeCourse"
                    g.time_course = neuroml.HHTime(tau=T, type=t_type)
                target.append(g)
            elif gate_name == 'vdi':
                g = neuroml.GateHHTauInf(id=gate_name, instances=instances)
                v_half = str(channel_params['v_half_i']) + ' ' + str(unit['v_half_i'])
                k = str(channel_params['k_i']) + ' ' + str(unit['k_i'])
                g.steadyState = neuroml.HHTime(midpoint=v_half,scale=k,rate=1,type=g_type)
                if 'T_i' in channel_params:
                    T = str(channel_params['T_i']) + ' ' + str(unit['T_i'])
                    t_type="fixedTimeCourse"
                    g.timeCourse = neuroml.HHTime(tau=T, type=t_type)
                target.append(g)

            # TODO: Consider ion dependent activation/inactivation

        nml2_file_name = model_params['file_name']
        doc.ion_channel_hhs.append(chan)
        doc.id = channel_id
        writers.NeuroMLWriter.write(doc,nml2_file_name)

        print("Written NeuroML 2 channel file to: "+nml2_file_name)

        nml2_file = open(nml2_file_name, 'r')
        orig = nml2_file.read()
        new_contents = orig.replace("<annotation/>", "\n        <annotation>\n%s        </annotation>\n"%metadata.to_xml("            "))
        nml2_file.close()
        nml2_file = open(nml2_file_name, 'w')
        nml2_file.write(new_contents)
        nml2_file.close()

        myValidator = validators.Validator()
        myValidator.validate_nml2(nml2_file_name)

        return nml2_file