示例#1
0
    def _form_upload_post(self, send_status):
        """Process the request and create new Lattice resource.

        :param send_status: callback method to signal completion
        """
        data = self.application.data
        ctx = yield self._create_upload_context()

        content_type = self.handler.request.headers["Content-Type"]
        if not content_type.startswith("multipart/form-data;"):
            send_status(415)
            return

        ctx.lattice.particle_type = self.handler.get_argument("particle_type", "")
        if len(ctx.lattice.particle_type) == 0:
            ctx.errors.particle_type = "Particle Type is required"
        else:
            for p in ctx.particle_types:
                if p["type"] == ctx.lattice.particle_type:
                    particle_type = ObjectDict(p)
                    break
            else:
                ctx.errors.particle_type = "Particle Type '{}' is invalid" \
                                             .format(ctx.lattice.particle_type)

        ctx.lattice.name = self.handler.get_argument("name", "")
        if len(ctx.lattice.name) == 0:
            ctx.errors.name = "Name is required"

        ctx.lattice.branch = self.handler.get_argument("branch", "")
        if len(ctx.lattice.branch) == 0:
            ctx.errors.branch = "Branch is required"

        if self.handler.get_argument("autoversion", "off") == "on":
            ctx.lattice_autoversion = True
        else:
            ctx.lattice_autoversion = False

        ctx.lattice.version = self.handler.get_argument("version", "")
        if not ctx.lattice_autoversion:
            if len(ctx.lattice.version) == 0:
                ctx.errors.version = "Version is required"
            else:
                try:
                    ctx.lattice.version = int(ctx.lattice.version)
                except ValueError:
                    ctx.lattice.version = self._INITIAL_VERSION
                    ctx.errors.version = "Version must be an integer"
                if ctx.lattice.version <= 0:
                    ctx.errors.version = "Version must be greater than zero"

        ctx.lattice.description = self.handler.get_argument("description", "")

        ctx.lattice.status_type = self.handler.get_argument("status_type", "")

        ctx.lattice.created_by = self.handler.current_user

        ctx.lattice.created_date = datetime.now()

        ctx.lattice._id = ObjectId()

        request_files = self.handler.request.files

        if "lattice_file" not in request_files:
            ctx.errors.lattice_file = "Lattice File is required"

        elif len(request_files["lattice_file"]) == 0:
            ctx.errors.lattice_file = "Lattice File is required"

        if ctx.errors:
            send_status(400, ctx)
            return

        # check for another lattice with name, branch and version
        if ctx.lattice_autoversion:
            lattice = yield data.find_lattice_by_name(ctx.lattice.name,
                                                        ctx.lattice.branch)
        else:
            lattice = yield data.find_lattice_by_name(ctx.lattice.name,
                                    ctx.lattice.branch, ctx.lattice.version)

        if ctx.lattice_autoversion:
            if lattice:
                ctx.lattice.version = lattice.version + 1
            else:
                ctx.lattice.version = self._INITIAL_VERSION
        else:
            if lattice:
                ctx.errors.version = "Version already exists"

        if ctx.errors:
            send_status(400, ctx)
            return

        lattice_file = request_files["lattice_file"][0]

        try:
            lattice = read_lattice(StringIO(lattice_file.body))
        except Exception as e:
            LOGGER.warning("Error reading lattice: %s", e)
            ctx.errors.lattice_file = "Lattice File invalid format"

        if ctx.errors:
            send_status(400, ctx)
            return

        ctx.lattice.properties = []

        ctx.lattice.properties.append(dict(
            name="ParticleMass",
            value=lattice.particleMass,
            unit="MeV/c^2"
        ))

        ctx.lattice.properties.append(dict(
            name="ParticleCount",
            value=lattice.nparticles
        ))

        ctx.lattice.properties.append(dict(
            name="ParticleCurrent",
            value=lattice.current,
            unit="A"
        ))

        ctx.lattice.properties.append(dict(
            name="PositionMismatch",
            value=lattice.mismatch
        ))

        ctx.lattice.properties.append(dict(
            name="EnergyMismatch",
            value=lattice.emismatch
        ))

        ctx.lattice.properties.append(dict(
            name="PositionOffset",
            value=lattice.offset
        ))

        ctx.lattice.properties.append(dict(
            name="EnergyOffset",
            value=lattice.eoffset
        ))

        ctx.lattice.properties.append(dict(
            name="DistSigma",
            value=lattice.distSigma
        ))

        ctx.lattice.properties.append(dict(
            name="DistLambda",
            value=lattice.distLambda
        ))

        ctx.lattice.properties.append(dict(
            name="DistMu",
            value=lattice.distMu
        ))

        ctx.lattice.properties.append(dict(
            name="OutputMode",
            value=lattice.outputMode
        ))

        ctx.lattice.properties.append(dict(
            name="IntegratorType",
            value=lattice.integrator
        ))

        nucleons = particle_type.protons + particle_type.neutrons

        # lattice charge states
        if isinstance(lattice.charge, (tuple, list)):
            lattice_charge = []
            for charge in lattice.charge:
                lattice_charge.append(int(charge * lattice.particleMass * nucleons))
        else:
            lattice_charge = int(lattice.charge * lattice.particleMass * nucleons)

        ctx.lattice.properties.append(dict(
            name="ParticleCharge",
            value=lattice_charge
        ))

        ctx.lattice.files = []
        file_content = {}

        file_id = _create_file_id()
        ctx.lattice.files.append(ObjectDict(
            id=file_id,
            name="LatticeFile",
            size=len(lattice_file.body),
            filename=lattice_file.filename,
            location=_create_file_location(lattice_file)
        ))
        file_content[file_id] = lattice_file.body

        for data_file in request_files.get("data_file", []):
            # find a unique file ID
            while True:
                file_id=_create_file_id()
                if file_id not in file_content:
                    break
            ctx.lattice.files.append(ObjectDict(
                id=file_id,
                name="DataFile",
                size=len(data_file.body),
                filename=data_file.filename,
                location=_create_file_location(data_file)
            ))
            file_content[file_id] = data_file.body

        # check that all the data files specified by the
        # lattice have been submitted as attachments
        for filename in lattice.files:
            for f in ctx.lattice.files:
                if f.filename == filename:
                    break
            else:
                ctx.errors.data_file = "Missing data file: " + filename
                send_status(400, ctx)
                return

        attachment_path = self.settings.get("attachment_path", "")
        if len(attachment_path) == 0:
            LOGGER.warn("setting 'attachment_path' not found")
            ctx.errors._global = "Attachment directory not specified"
            send_status(500, ctx)
            return

        if not os.path.isdir(attachment_path):
            LOGGER.error("attachment path '%s' not found", attachment_path)
            ctx.errors._global = "Attachment directory not found"
            send_status(500, ctx)
            return

        try:
            yield data.validate_lattice(ctx.lattice)
        except Exception as e:
            LOGGER.error("lattice validation error: %s", e)
            ctx.errors._global = "Lattice validation error"
            send_status(500, ctx)
            return

        lattice_elements = []
        for idx, element in enumerate(lattice.elements):
            lattice_element = ObjectDict()
            lattice_element.lattice_id = ctx.lattice._id
            lattice_element.order = idx+1
            lattice_element.name = element.name
            lattice_element.type = element.etype
            lattice_element.length = element.length
            lattice_element.position = element.position
            lattice_element.properties = []
            lattice_element.properties.append(dict(
                name="ITYPE",
                value=element.itype
            ))
            lattice_element.properties.append(dict(
                name="STEPS",
                value=element.steps
            ))
            for field in element.fields:
                lattice_element.properties.append(dict(
                    name = field.name,
                    unit = field.unit,
                    value = element.getfield(field.name)
                ))

            try:
                yield data.validate_lattice_element(lattice_element)
            except Exception as e:
                LOGGER.error("lattice element validation error: %s", e)
                ctx.errors._global = "Lattice element validation error"
                send_status(500, ctx)
                return

            lattice_elements.append(lattice_element)

        try:
            lattice_id = yield data.insert_lattice(ctx.lattice, validate=False)
        except Exception as e:
            LOGGER.error("lattice database insert error: %s", e)
            ctx.errors._global = "Lattice database insert error"
            send_status(500, ctx)
            return

        try:
            for lattice_element in lattice_elements:
                lattice_element.lattice_id = lattice_id
                data.insert_lattice_element(lattice_element, validate=False)
        except Exception as e:
            LOGGER.error("lattice element database insert error: %s", e)
            ctx.errors._global = "Lattice element database insert error"
            # Rollback?
            send_status(500, ctx)
            return

        try:
            for f in ctx.lattice.files:
                _write_file_content(attachment_path, f.location, file_content[f.id])
        except Exception as e:
            LOGGER.exception("lattice file write error: %s", e)
            ctx.errors._global = "Lattice file write error"
            #Rollback?
            send_status(500, ctx)
            return

        send_status(201, ctx)
        return