class HighGlucoseScenario(): def __init__(self, hostname, port, projection, output_folder, image_k=4, image_samples_per_pixel=64, log_level=1, shaders=list(['bio_explorer']), magnetic=False): self._log_level = log_level self._hostname = hostname self._url = hostname + ':' + str(port) self._be = BioExplorer(self._url) self._core = self._be.core_api() self._image_size = [1920, 1080] self._image_samples_per_pixel = image_samples_per_pixel self._image_projection = projection self._image_output_folder = output_folder self._shaders = shaders self._magnetic = magnetic self._prepare_movie(projection, image_k) self._log( 1, '================================================================================' ) self._log(1, '- Version : ' + self._be.version()) self._log(1, '- URL : ' + self._url) self._log(1, '- Projection : ' + projection) self._log(1, '- Frame size : ' + str(self._image_size)) self._log(1, '- Export folder : ' + self._image_output_folder) self._log(1, '- Samples per pixel: ' + str(self._image_samples_per_pixel)) self._log( 1, '================================================================================' ) def _log(self, level, message): if level <= self._log_level: print('[' + str(datetime.now()) + '] ' + message) def _get_transformation(self, start_frame, end_frame, frame, data): '''Progress''' progress = (frame - start_frame) * 1.0 / (end_frame - start_frame) progress = max(0.0, progress) progress = min(1.0, progress) '''Position''' start_pos = data[0].to_list() end_pos = data[2].to_list() pos = start_pos for i in range(3): pos[i] += (end_pos[i] - start_pos[i]) * progress '''Rotation''' start_rot = data[1] end_rot = data[3] rot = Quaternion.slerp(start_rot, end_rot, progress) if data[4] == ROTATION_MODE_SINUSOIDAL: rot = Quaternion.slerp(start_rot, end_rot, math.cos((progress - 0.5) * math.pi)) return [Vector3(pos[0], pos[1], pos[2]), rot, progress * 100.0] def _add_viruses(self, frame): virus_sequences = [ [[-1000, 2499], [2500, 2599], [2600, 2799], [2800, 2999], [3000, 3099], [3100, 3750]], # Virus used for the ACE2 close-up [[0, 2100], [2200, 2299], [2300, 2499], [2500, 3049], [3050, 3149], [3150, 3750]], [[-800, 2549], [2550, 2649], [2650, 2849], [2850, 3199], [3200, 3299], [3300, 3750]], [[-1400, 3750], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6]], [[-400, 2599], [2600, 2699], [2700, 2899], [2900, 3119], [3120, 3219], [3220, 3750]], [[0, 2649], [2650, 2749], [2750, 2949], [2950, 3199], [3200, 3299], [3300, 3750]], # new Viruses [[-1, -1], [-1, -1], [-1, -1], [-1, 3212], [3213, 3312], [3313, 3750]], [[-1, -1], [-1, -1], [-1, -1], [-1, 3201], [3202, 3301], [3302, 3750]], [[-1, -1], [-1, -1], [-1, -1], [-1, 3171], [3172, 3271], [3272, 3750]], [[-1, -1], [-1, -1], [-1, -1], [-1, 3152], [3153, 3252], [3253, 3750]], [[-1, -1], [-1, -1], [-1, -1], [-1, 3358], [3359, 3458], [3459, 3750]] ] virus_radii = [ 45.0, 44.0, 45.0, 43.0, 44.0, 43.0, 45.0, 46.0, 44.0, 45.0, 44.0 ] virus_flights_in = [ [ Vector3(-250.0, 100.0, -70.0), Quaternion(0.519, 0.671, 0.528, -0.036), Vector3(-337.3, -92.3, -99.2), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], [ Vector3(-50.0, 300.0, 250.0), Quaternion(0.456, 0.129, -0.185, -0.860), Vector3(-74.9, -99.0, 228.8), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], [ Vector3(150.0, 100.0, 50.0), Quaternion(0.087, 0.971, -0.147, -0.161), Vector3(187.5, -110.4, 51.2), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], [ Vector3(40.0, 250.0, -50), Quaternion(0.0, 0.0, 0.0, 1.0), Vector3(4.5, 100.0, 7.5), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], [ Vector3(60.0, 100.0, -240.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(73.9, -117.1, -190.4), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], [ Vector3(200.0, 100.0, 300.0), Quaternion(-0.866, 0.201, 0.308, -0.336), Vector3(211.5, -104.9, 339.2), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR ], # New viruses (no flying in, only flying out) [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ], [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ], [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ], [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ], [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ] ] virus_flights_out = [[ Vector3(-250.0, -150.0, -70.0), Quaternion(), Vector3(-270.0, 200.0, -99.2), Quaternion(0.519, 0.671, 0.528, -0.036), ROTATION_MODE_LINEAR ], [ Vector3(-50.0, -150.0, 250.0), Quaternion(), Vector3(-75.0, 240.0, 228.8), Quaternion(0.456, 0.129, -0.185, -0.860), ROTATION_MODE_LINEAR ], [ Vector3(150.0, -150.0, 50.0), Quaternion(), Vector3(187.0, 300.0, 51.2), Quaternion(0.087, 0.971, -0.147, -0.161), ROTATION_MODE_LINEAR ], [ Vector3(), Quaternion(), Vector3(), Quaternion(), ROTATION_MODE_LINEAR ], [ Vector3(60.0, -150.0, -240.0), Quaternion(), Vector3(74.0, 195.0, -220.0), Quaternion(-0.095, 0.652, -0.326, 0.677), ROTATION_MODE_LINEAR ], [ Vector3(-200.0, -150.0, 300.0), Quaternion(), Vector3(-210.0, 205.0, 330.0), Quaternion(-0.866, 0.201, 0.308, -0.336), ROTATION_MODE_LINEAR ], [ Vector3(531, -150.0, -34.0), Quaternion(), Vector3(500.0, 215.0, -50.0), Quaternion(0.431, -0.145, -0.700, -0.550), ROTATION_MODE_LINEAR ], [ Vector3(225.0, -150.0, 554.0), Quaternion(), Vector3(200.0, 190.0, 520.0), Quaternion(-0.466, -0.086, -0.616, -0.629), ROTATION_MODE_LINEAR ], [ Vector3(-171, -150.0, -5.0), Quaternion(), Vector3(-160.0, 300.0, 10.0), Quaternion(0.227, 0.834, -0.187, 0.468), ROTATION_MODE_LINEAR ], [ Vector3(-331, -150.0, 343), Quaternion(), Vector3(-310.0, 230.0, 350.0), Quaternion(0.417, 0.849, -0.075, -0.316), ROTATION_MODE_LINEAR ], [ Vector3(159.0, -150.0, -341.0), Quaternion(), Vector3(170.0, 100.0, -360.0), Quaternion(0.483, -0.352, 0.769, -0.226), ROTATION_MODE_LINEAR ]] indices = range(len(virus_sequences)) if self._magnetic: indices = [1] for virus_index in indices: name = 'Coronavirus ' + str(virus_index) current_sequence = 0 sequences = virus_sequences[virus_index] for i in range(len(sequences)): if frame >= sequences[i][0]: current_sequence = i '''Initialize position and rotation to end-of-flight values''' start_frame = sequences[current_sequence][0] end_frame = sequences[current_sequence][1] progress_in_sequence = (frame - start_frame) / (end_frame - start_frame) morphing_step = 0.0 if current_sequence == 0: '''Flying''' pos, rot, progress = self._get_transformation( start_frame, end_frame, frame, virus_flights_in[virus_index]) self._log( 3, '- Virus %d is flying in... (%.01f pct)' % (virus_index, progress)) elif current_sequence == 1: '''Landing''' pos = virus_flights_in[virus_index][2] rot = virus_flights_in[virus_index][3] pos.y -= landing_distance * progress_in_sequence self._log(3, '- Virus %d is landing...' % virus_index) elif current_sequence == 2: '''Merging into cell''' pos = virus_flights_in[virus_index][2] rot = virus_flights_in[virus_index][3] morphing_step = (frame - start_frame) / (end_frame - start_frame) pos.y -= landing_distance self._log( 3, '- Virus %d is merging in (%.01f pct)' % (virus_index, morphing_step * 100.0)) elif current_sequence == 3: '''Inside cell''' self._log(3, '- Virus %d is inside cell' % virus_index) '''Virus is not added to the scene''' self._be.remove_assembly(name=name) continue elif current_sequence == 4: '''Merging out of cell''' pos = virus_flights_out[virus_index][0] rot = virus_flights_out[virus_index][1] morphing_step = 1.0 - (frame - start_frame) / (end_frame - start_frame) self._log( 3, '- Virus %d is merging out (%.01f pct)' % (virus_index, morphing_step * 100.0)) else: '''Flying out''' pos, rot, progress = self._get_transformation( start_frame, end_frame, frame, virus_flights_out[virus_index]) self._log( 3, '- Virus %d is flying out... (%.01f pct)' % (virus_index, progress)) self._be.add_coronavirus(name=name, resource_folder=resource_folder, representation=protein_representation, position=pos, rotation=rot, add_glycans=add_glycans, assembly_params=[ virus_radii[virus_index], 5 * frame + 2 * virus_index, 0.25, frame + 2 * virus_index + 1, 0.1, morphing_step ]) def _add_cell(self, frame): name = 'Cell' nb_receptors = cell_nb_receptors size = scene_size * 2.0 height = scene_size / 10.0 position = Vector3(4.5, -186.0, 7.0) random_seed = 10 nb_lipids = cell_nb_lipids ace2_receptor = Protein(sources=[pdb_folder + '6m18.pdb'], occurences=nb_receptors, position=Vector3(0.0, 6.0, 0.0)) membrane = ParametricMembrane(sources=[ membrane_folder + 'segA.pdb', membrane_folder + 'segB.pdb', membrane_folder + 'segC.pdb', membrane_folder + 'segD.pdb' ], occurences=cell_nb_lipids) cell = Cell(name=name, size=size, extra_parameters=[height], shape=BioExplorer.ASSEMBLY_SHAPE_SINUSOIDAL, membrane=membrane, receptor=ace2_receptor, random_position_seed=frame + 1, random_position_strength=0.025, random_rotation_seed=frame + 2, random_rotation_strength=0.2) self._be.add_cell(cell=cell, position=position, representation=protein_representation, random_seed=random_seed) '''Modify receptor position when attached virus enters the cell''' receptors_instances = [90, 23, 24, 98, 37, 44] receptors_sequences = [[2500, 2599], [2200, 2299], [2550, 2649], [2600, 2699], [2650, 2749], [-1, -1]] for i in range(len(receptors_instances)): instance_index = receptors_instances[i] sequence = receptors_sequences[i] start_frame = sequence[0] end_frame = sequence[1] if frame >= start_frame: if frame > end_frame: '''Send receptor to outter space''' status = self._be.set_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index, position=Vector3(0.0, 1e6, 0.0)) else: '''Current receptor transformation''' transformation = self._be.get_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index) p = transformation['position'].split(',') q = transformation['rotation'].split(',') pos = Vector3(float(p[0]), float(p[1]), float(p[2])) q2 = Quaternion(float(q[0]), float(q[1]), float(q[2]), float(q[3])) '''Bend receptor''' progress = (frame - start_frame) * 1.0 / (end_frame - start_frame) q1 = Quaternion(axis=[0, 1, 0], angle=math.pi * progress) rot = q2 * q1 pos.x += landing_distance * progress * 0.3 pos.y -= landing_distance * progress * 0.3 status = self._be.set_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index, position=pos, rotation=rot) '''Glycans''' if nb_receptors != 0 and add_glycans: self._be.add_multiple_glycans( representation=glycan_representation, assembly_name=name, glycan_type=BioExplorer.NAME_GLYCAN_COMPLEX, protein_name=BioExplorer.NAME_RECEPTOR, paths=complex_paths, indices=[53, 90, 103, 322, 432, 690], assembly_params=[0, 0, 0.0, frame + 3, 0.2]) self._be.add_multiple_glycans( representation=glycan_representation, assembly_name=name, glycan_type=BioExplorer.NAME_GLYCAN_HYBRID, protein_name=BioExplorer.NAME_RECEPTOR, paths=hybrid_paths, indices=[546], assembly_params=[0, 0, 0.0, frame + 4, 0.2]) indices = [[155, Quaternion(0.707, 0.0, 0.707, 0.0)], [730, Quaternion(0.707, 0.0, 0.707, 0.0)]] count = 0 for index in indices: o_glycan_name = name + '_' + BioExplorer.NAME_GLYCAN_O_GLYCAN + '_' + str( index[0]) o_glycan = Sugars( assembly_name=name, name=o_glycan_name, source=o_glycan_paths[0], protein_name=name + '_' + BioExplorer.NAME_RECEPTOR, representation=glycan_representation, chain_ids=[2, 4], site_indices=[index[0]], rotation=index[1], assembly_params=[0, 0, 0.0, frame + count + 5, 0.2]) self._be.add_sugars(o_glycan) count += 1 def _add_surfactant_d(self, name, position, rotation, random_seed): surfactant_d = Surfactant( name=name, surfactant_protein=BioExplorer.SURFACTANT_PROTEIN_D, head_source=surfactant_head_source, branch_source=surfactant_branch_source) self._be.add_surfactant(surfactant=surfactant_d, representation=protein_representation, position=position, rotation=rotation, random_seed=random_seed) def _add_surfactant_a(self, name, position, rotation, random_seed): surfactant_a = Surfactant( name=name, surfactant_protein=BioExplorer.SURFACTANT_PROTEIN_A, head_source=surfactant_head_source, branch_source=surfactant_branch_source) self._be.add_surfactant(surfactant=surfactant_a, representation=protein_representation, position=position, rotation=rotation, random_seed=random_seed) def _add_glucose_to_surfactant_head(self, name): for index in [321, 323]: glucose_name = name + '_' + BioExplorer.NAME_GLUCOSE + '_' + str( index) glucose = Sugars(assembly_name=name, name=glucose_name, source=glucose_path, protein_name=name + '_' + BioExplorer.NAME_SURFACTANT_HEAD, representation=glycan_representation, site_indices=[index]) self._be.add_sugars(glucose) def _add_surfactants_d(self, frame): spd_sequences = [[-1550, 3750], [0, 3750], [0, 3750]] spd_random_seeds = [1, 2, 6] spd_flights = [[ Vector3(-340.0, 0.0, -100.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(74.0 + (74.0 + 340), 24.0 + (24.0 - 0.0), -45.0 + (-45.0 + 100)), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL ], [ Vector3(-200, 0.0, -200.0), Quaternion(0.087, 0.971, -0.147, -0.161), Vector3(304.0, 75.0, -100.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL ], [ Vector3(-460.0, 50.0, 0.0), Quaternion(0.519, 0.671, 0.528, -0.036), Vector3(160.0, -50.0, -50.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL ]] for surfactant_index in range(len(spd_sequences)): name = 'Surfactant-D ' + str(surfactant_index) sequence = spd_sequences[surfactant_index] pos, rot, progress = self._get_transformation( start_frame=sequence[0], end_frame=sequence[1], frame=frame, data=spd_flights[surfactant_index]) self._log(3, '- ' + name + ' (%.01f pct)' % progress) self._add_surfactant_d( name=name, position=pos, rotation=rot, random_seed=spd_random_seeds[surfactant_index]) self._add_glucose_to_surfactant_head(name=name) def _add_surfactants_a(self, frame): spa_sequences = [[0, 3750]] spa_random_seeds = [2] spa_frames = [ [ Vector3(-400.0, -100.0, 100.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(250.0, -50.0, 100.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL ], ] for surfactant_index in range(len(spa_frames)): name = 'Surfactant-A ' + str(surfactant_index) sequence = spa_sequences[surfactant_index] pos, rot, progress = self._get_transformation( start_frame=sequence[0], end_frame=sequence[1], frame=frame, data=spa_frames[surfactant_index]) self._log(3, '- ' + name + ' (%.01f pct)' % progress) self._add_surfactant_a( name=name, position=pos, rotation=rot, random_seed=spa_random_seeds[surfactant_index]) self._add_glucose_to_surfactant_head(name=name) def _add_glucose(self, frame): glucose = Protein(sources=[glucose_path], load_non_polymer_chemicals=True, occurences=nb_glucoses) volume = Volume(name=BioExplorer.NAME_GLUCOSE, size=scene_size, protein=glucose, random_position_seed=frame + 20, random_position_stength=scene_size / 600.0, random_rotation_seed=frame + 21, random_rotation_stength=0.3) status = self._be.add_volume(volume=volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=100) def _add_lactoferrins(self, frame): lactoferrin = Protein(sources=[lactoferrin_path], load_non_polymer_chemicals=True, occurences=nb_lactoferrins) lactoferrins_volume = Volume(name=BioExplorer.NAME_LACTOFERRIN, size=scene_size, protein=lactoferrin, random_position_seed=frame + 30, random_position_stength=scene_size / 400.0, random_rotation_seed=frame + 31, random_rotation_stength=0.3) status = self._be.add_volume(volume=lactoferrins_volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=101) def _add_defensins(self, frame): defensin = Protein(sources=[defensin_path], load_non_polymer_chemicals=True, occurences=nb_defensins) defensins_volume = Volume(name=BioExplorer.NAME_DEFENSIN, size=scene_size, protein=defensin, random_position_seed=frame + 40, random_position_stength=scene_size / 400.0, random_rotation_seed=frame + 41, random_rotation_stength=0.3) status = self._be.add_volume(volume=defensins_volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=102) def _set_materials(self): '''Default materials''' self._be.apply_default_color_scheme( shading_mode=BioExplorer.SHADING_MODE_DIFFUSE, specular_exponent=50.0) def _create_snapshot(self, shader, frame, movie_maker): samples_per_pixel = self._image_samples_per_pixel '''Renderer''' if shader == 'albedo': self._core.set_renderer(current='albedo') elif shader == 'ambient_occlusion': self._core.set_renderer(current='ambient_occlusion', samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = self._core.AmbientOcclusionRendererParams() params.samplesPerFrame = 32 params.rayLength = 5.0 self._core.set_renderer_params(params) samples_per_pixel = 4 elif shader == 'depth': status = self._core.set_renderer(current='depth', samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = status = self._core.DepthRendererParams() params.infinity = 2000.0 status = self._core.set_renderer_params(params) samples_per_pixel = 2 elif shader == 'raycast_Ns': status = self._core.set_renderer(current='raycast_Ns', samples_per_pixel=1, subsampling=1, max_accum_frames=1) samples_per_pixel = 2 else: status = self._core.set_renderer( background_color=[96 / 255, 125 / 255, 139 / 255], current='bio_explorer', head_light=False, samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = self._core.BioExplorerRendererParams() params.exposure = 1.0 params.gi_samples = 1 params.gi_weight = 0.3 params.gi_distance = 5000 params.shadows = 0.8 params.soft_shadows = 0.05 params.fog_start = 1000 params.fog_thickness = 300 params.max_bounces = 1 params.use_hardware_randomizer = True status = self._core.set_renderer_params(params) samples_per_pixel = self._image_samples_per_pixel '''Lights''' status = self._core.clear_lights() status = self._core.add_light_directional( angularDiameter=0.5, color=[1, 1, 1], direction=[-0.7, -0.4, -1], intensity=1.0, is_visible=False) movie_maker.create_snapshot(size=self._image_size, path=self._image_output_folder + '/' + shader, base_name='%05d' % frame, samples_per_pixel=samples_per_pixel) '''Camera''' status = self._core.set_camera(current='bio_explorer_perspective') def _build_frame(self, frame): self._log(2, '- Resetting scene...') self._be.reset() self._log(2, '- Building surfactants...') self._add_surfactants_d(frame) self._add_surfactants_a(frame) self._log(2, '- Building glucose...') self._add_glucose(frame) self._log(2, '- Building lactoferrins...') self._add_lactoferrins(frame) self._log(2, '- Building defensins...') self._add_defensins(frame) self._log(2, '- Building viruses...') self._add_viruses(frame) self._log(2, '- Building cell...') self._add_cell(frame) if self._magnetic: self._log(2, '- Building fields...') self._be.go_magnetic(colormap_filename=colormap_folder + 'high_glucose_v2.1dt', voxel_size=0.5, density=0.1, colormap_range=[0.0, 1.0]) else: self._log(2, '- Setting materials...') self._set_materials() self._log(2, '- Showing models...') status = self._be.set_models_visibility(True) status = self._core.set_renderer() def _make_export_folder(self, folder): import os path = self._image_output_folder + '/' + folder command_line = 'mkdir -p ' + path os.system(command_line) command_line = 'ls ' + path if os.system(command_line) != 0: self._log(3, 'ERROR: Failed to create folder ' + path) def _make_export_folders(self): for folder in self._shaders: self._make_export_folder(folder) def _prepare_movie(self, projection, image_k): if projection == 'perspective': aperture_ratio = 1.0 self._image_size = [image_k * 960, image_k * 540] self._core.set_camera(current='bio_explorer_perspective') elif projection == 'fisheye': self._image_size = [int(image_k * 1024), int(image_k * 1024)] self._core.set_camera(current='fisheye') elif projection == 'panoramic': self._image_size = [int(image_k * 1024), int(image_k * 1024)] self._core.set_camera(current='panoramic') elif projection == 'opendeck': self._image_size = [7 * 2160, 3840] self._core.set_camera(current='cylindric') self._image_output_folder = self._image_output_folder + '/' + \ projection + '/' + str(self._image_size[0]) + 'x' + str(self._image_size[1]) self._make_export_folders() def _set_clipping_planes(self): '''Clipping planes''' clip_planes = list() if self._magnetic: pos = Vector3(-74.9, -99.0, 228.8) size = Vector3(70.0, 100.0, 70.0) clip_planes.append([1.0, 0.0, 0.0, -pos.x + size.x]) clip_planes.append([-1.0, 0.0, 0.0, pos.x + size.x]) clip_planes.append([0.0, 1.0, 0.0, -pos.y + size.y]) clip_planes.append([0.0, -1.0, 0.0, pos.y + size.y]) clip_planes.append([0.0, 0.0, 1.0, -pos.z + size.z]) clip_planes.append([0.0, 0.0, -1.0, pos.z + size.z]) else: clip_planes.append([1.0, 0.0, 0.0, scene_size * 1.5 + 5]) clip_planes.append([-1.0, 0.0, 0.0, scene_size * 1.5 + 5]) clip_planes.append([0.0, 0.0, 1.0, scene_size + 5]) clip_planes.append([0.0, 0.0, -1.0, scene_size + 5]) cps = self._core.get_clip_planes() ids = list() if cps: for cp in cps: ids.append(cp['id']) self._core.remove_clip_planes(ids) for plane in clip_planes: self._core.add_clip_plane(plane) def render_movie(self, start_frame=0, end_frame=0, frame_step=1, frame_list=list()): '''Accelerate loading by not showing models as they are loaded''' status = self._be.set_general_settings( model_visibility_on_creation=False) aperture_ratio = 0.0 cameras_key_frames = [ { # 1. Cell view (frame 0) 'apertureRadius': aperture_ratio * 0.0, 'direction': [0.0, 0.0, -1.0], 'focusDistance': 1.0, 'origin': [150.0, -170.0, 400.0], 'up': [0.0, 1.0, 0.0] }, { # 2. Virus view (frame 500) 'apertureRadius': aperture_ratio * 0.0, 'direction': [0.0, 0.0, -1.0], 'focusDistance': 449.50, 'origin': [-67.501, -17.451, 254.786], 'up': [0.0, 1.0, 0.0] }, { # 3. Surfactant Head (frame 1000) 'apertureRadius': aperture_ratio * 0.02, 'direction': [0.276, -0.049, -0.959], 'focusDistance': 25.54, 'origin': [38.749, 35.228, 5.536], 'up': [0.0, 1.0, 0.0] }, { # 4. Virus overview (frame 1500) 'apertureRadius': aperture_ratio * 0.0, 'direction': [0.009, 0.055, -0.998], 'focusDistance': 109.59, 'origin': [-0.832, 72.134, 387.389], 'up': [0.017, 0.998, 0.055] }, { # 5. ACE2 receptor (frame 2000) 'apertureRadius': aperture_ratio * 0.02, 'direction': [-0.436, 0.035, -0.898], 'focusDistance': 62.17, 'origin': [-33.619, -164.994, 276.296], 'up': [0.011, 0.999, 0.033] }, { # 6. Membrane overview (frame 2500) 'apertureRadius': aperture_ratio * 0.0, 'direction': [0.009, 0.055, -0.998], 'focusDistance': 1.0, 'origin': [0.293, 19.604, 1000], 'up': [0.017, 0.998, 0.055] }, { # 7. (frame 3000) 'apertureRadius': aperture_ratio * 0.0, 'focusDistance': 1.0, 'direction': [0.009, 0.055, -0.998], 'origin': [0.293, 19.604, 1000], 'up': [0.017, 0.998, 0.055] }, { # 8. (frame 3500) 'apertureRadius': aperture_ratio * 0.0, 'focusDistance': 60, 'direction': [0.009, 0.055, -0.998], 'origin': [0.293, 19.604, 1000], 'up': [0.017, 0.998, 0.055] } ] '''Double the frames to make it smoother''' key_frames = list() for cameras_key_frame in cameras_key_frames: key_frames.append(cameras_key_frame) key_frames.append(cameras_key_frame) mm = MovieMaker(self._be) mm.build_camera_path(key_frames, 250, 150) self._log(1, '- Total number of frames: %d' % mm.get_nb_frames()) self._core.set_application_parameters(viewport=self._image_size) self._core.set_application_parameters(image_stream_fps=0) frames_to_render = list() if len(frame_list) != 0: frames_to_render = frame_list else: if end_frame == 0: end_frame = mm.get_nb_frames() for i in range(start_frame, end_frame + 1, frame_step): frames_to_render.append(i) cumulated_rendering_time = 0 nb_frames = len(frames_to_render) frame_count = 1 '''Clipping planes''' self._set_clipping_planes() '''Frames''' for frame in frames_to_render: try: start = time.time() self._log( 1, '- Rendering frame %i (%i/%i)' % (frame, frame_count, nb_frames)) self._log(1, '------------------------------') '''Stop rendering during the loading of the scene''' status = self._core.set_renderer(samples_per_pixel=1, subsampling=1, max_accum_frames=1) '''Frame setup''' self._build_frame(frame) mm.set_current_frame(frame=frame, camera_params=self._core. BioExplorerPerspectiveCameraParams()) self._log(1, '- Frame buffers') for shader in self._shaders: '''Rendering settings''' self._log(2, '- ' + shader) self._create_snapshot(shader, frame, mm) end = time.time() rendering_time = end - start cumulated_rendering_time += rendering_time average_rendering_time = cumulated_rendering_time / frame_count remaining_rendering_time = ( nb_frames - frame_count) * average_rendering_time self._log(1, '------------------------------') self._log( 1, 'Frame %i successfully rendered in %i seconds' % (frame, rendering_time)) hours = math.floor(remaining_rendering_time / 3600) minutes = math.floor( (remaining_rendering_time - hours * 3600) / 60) seconds = math.floor(remaining_rendering_time - hours * 3600 - minutes * 60) expected_end_time = datetime.now() + timedelta( seconds=remaining_rendering_time) self._log( 1, 'Estimated remaining time: %i hours, %i minutes, %i seconds' % (hours, minutes, seconds)) self._log(1, 'Expected end time : %s' % expected_end_time) self._log( 1, '--------------------------------------------------------------------------------' ) frame_count += 1 except Exception as e: self._log(1, 'ERROR: Failed to render frame %i' % frame) self._log(1, str(e)) time.sleep(10) self._be = BioExplorer(self._url) self._core = self._be.core_api() mm = MovieMaker(self._be) self._core.set_application_parameters(image_stream_fps=20) self._log(1, 'Movie rendered, live long and prosper \V/')
def test_virus(): resource_folder = 'tests/test_files/' pdb_folder = resource_folder + 'pdb/' rna_folder = resource_folder + 'rna/' glycan_folder = pdb_folder + 'glycans/' bio_explorer = BioExplorer('localhost:5000') bio_explorer.reset() # Settings virus_radius = 45.0 add_glycans = True protein_radius_multiplier = 1.0 protein_representation = BioExplorer.REPRESENTATION_ATOMS protein_load_hydrogen = False # Virus configuration nb_protein_s = 62 nb_protein_s_indices = [1, 27, 43] nb_protein_e = 42 nb_protein_m = 50 show_rna = True # Virus parameters show_functional_regions = False show_glycosylation_sites = False # Suspend image streaming bio_explorer.core_api().set_application_parameters(image_stream_fps=0) # Protein S open_conformation_indices = nb_protein_s_indices closed_conformation_indices = list() for i in range(nb_protein_s): if i not in open_conformation_indices: closed_conformation_indices.append(i) params = [11.5, 0, 0.0, 0, 0.0, 0.0] virus_protein_s = Protein( sources=[pdb_folder + '6vyb.pdb', pdb_folder + 'sars-cov-2-v1.pdb'], load_hydrogen=protein_load_hydrogen, occurences=nb_protein_s, assembly_params=params, rotation=Quaternion(0.087, 0.0, 0.996, 0.0), instance_indices=[open_conformation_indices, closed_conformation_indices]) # Protein M (QHD43419) params = [2.5, 0, 0.0, 0, 0.0, 0.0] virus_protein_m = Protein( sources=[pdb_folder + 'QHD43419a.pdb'], load_hydrogen=protein_load_hydrogen, occurences=nb_protein_m, assembly_params=params, rotation=Quaternion(0.99, 0.0, 0.0, 0.135)) # Protein E (QHD43418 P0DTC4) params = [2.5, 0, 0.0, 0, 0.0, 0.0] virus_protein_e = Protein( sources=[pdb_folder + 'QHD43418a.pdb'], load_hydrogen=protein_load_hydrogen, occurences=nb_protein_e, assembly_params=params, rotation=Quaternion(0.705, 0.705, -0.04, -0.04)) # Virus membrane virus_membrane = ParametricMembrane( sources=[pdb_folder + 'membrane/popc.pdb'], occurences=15000) # RNA Sequence clip_planes = list() rna_sequence = None if show_rna: clip_planes.append([0.0, 0.0, -1.0, 15.0]) rna_sequence = RNASequence( source=rna_folder + 'sars-cov-2.rna', assembly_params=[11.0, 0.5], t_range=Vector2(0, 30.5 * math.pi), shape=bio_explorer.RNA_SHAPE_TREFOIL_KNOT, shape_params=Vector3(1.51, 1.12, 1.93)) # Coronavirus name = 'Coronavirus' coronavirus = Virus( name=name, protein_s=virus_protein_s, protein_e=virus_protein_e, protein_m=virus_protein_m, membrane=virus_membrane, rna_sequence=rna_sequence, assembly_params=[virus_radius, 1, 0.025, 2, 0.4, 0.0]) bio_explorer.add_virus( virus=coronavirus, position=Vector3(-70.0, -100.0, 230.0), representation=protein_representation, atom_radius_multiplier=protein_radius_multiplier, clipping_planes=clip_planes) # Glycans if add_glycans: complex_paths = [glycan_folder + 'complex/5.pdb', glycan_folder + 'complex/15.pdb', glycan_folder + 'complex/25.pdb', glycan_folder + 'complex/35.pdb'] high_mannose_paths = [ glycan_folder + 'high-mannose/1.pdb', glycan_folder + 'high-mannose/2.pdb', glycan_folder + 'high-mannose/3.pdb', glycan_folder + 'high-mannose/4.pdb'] o_glycan_paths = [glycan_folder + 'o-glycan/12.pdb'] # High-mannose indices_closed = [61, 122, 234, 603, 709, 717, 801, 1074] indices_open = [61, 122, 234, 709, 717, 801, 1074] bio_explorer.add_multiple_glycans( assembly_name=name, glycan_type=bio_explorer.NAME_GLYCAN_HIGH_MANNOSE, protein_name=bio_explorer.NAME_PROTEIN_S_CLOSED, paths=high_mannose_paths, indices=indices_closed, representation=protein_representation, atom_radius_multiplier=protein_radius_multiplier) bio_explorer.add_multiple_glycans( assembly_name=name, glycan_type=bio_explorer.NAME_GLYCAN_HIGH_MANNOSE, protein_name=bio_explorer.NAME_PROTEIN_S_OPEN, paths=high_mannose_paths, indices=indices_open, representation=protein_representation, atom_radius_multiplier=protein_radius_multiplier) # Complex indices1 = [17, 74, 149, 165, 282, 331, 343, 616, 657, 1098, 1134, 1158, 1173, 1194] indices2 = [17, 74, 149, 165, 282, 331, 343, 1098, 657, 1134, 1158, 1173, 1194] bio_explorer.add_multiple_glycans( assembly_name=name, glycan_type=bio_explorer.NAME_GLYCAN_COMPLEX, protein_name=bio_explorer.NAME_PROTEIN_S_CLOSED, paths=complex_paths, indices=indices1, representation=protein_representation, atom_radius_multiplier=protein_radius_multiplier) bio_explorer.add_multiple_glycans( assembly_name=name, glycan_type=bio_explorer.NAME_GLYCAN_COMPLEX, protein_name=bio_explorer.NAME_PROTEIN_S_OPEN, paths=complex_paths, indices=indices2, representation=protein_representation, atom_radius_multiplier=protein_radius_multiplier) # O-Glycans for index in [323, 325]: o_glycan_name = name + '_' + bio_explorer.NAME_GLYCAN_O_GLYCAN + '_' + str(index) o_glycan = Sugars( assembly_name=name, name=o_glycan_name, source=o_glycan_paths[0], protein_name=name + '_' + bio_explorer.NAME_PROTEIN_S_CLOSED, representation=protein_representation, site_indices=[index], atom_radius_multiplier=protein_radius_multiplier) bio_explorer.add_sugars(o_glycan) # High-mannose glycans on Protein M indices = [5] protein_name = name + '_' + bio_explorer.NAME_PROTEIN_M high_mannose_glycans = Sugars( rotation=Quaternion(0.707, 0.0, 0.0, 0.707), assembly_name=name, name=protein_name + '_' + bio_explorer.NAME_GLYCAN_HIGH_MANNOSE, protein_name=protein_name, source=high_mannose_paths[0], site_indices=indices, representation=protein_representation ) bio_explorer.add_glycans(high_mannose_glycans) # Complex glycans on Protein E indices = [48, 66] protein_name = name + '_' + bio_explorer.NAME_PROTEIN_E complex_glycans = Sugars( rotation=Quaternion(0.707, 0.0, 0.0, 0.707), assembly_name=name, name=protein_name + '_' + bio_explorer.NAME_GLYCAN_COMPLEX, protein_name=protein_name, source=complex_paths[0], site_indices=indices, representation=protein_representation ) bio_explorer.add_glycans(complex_glycans) # Apply default materials bio_explorer.apply_default_color_scheme(shading_mode=bio_explorer.SHADING_MODE_BASIC) # Functional regions on open spike if show_functional_regions: indices = [1, 16, 306, 330, 438, 507, 522, 816, 835, 908, 986, 1076, 1274, 2000] region_colors = [ [1.0, 1.0, 1.0], [0.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 0.0], [0.4, 0.1, 0.1], [0.0, 1.0, 0.0], [1.0, 1.0, 1.0], [1.0, 0.0, 0.0], [1.0, 1.0, 1.0], [1.0, 1.0, 0.0], [1.0, 1.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]] palette = list() for index in range(len(indices) - 1): for i in range(0, indices[index + 1] - indices[index]): color = list() for j in range(3): color.append(region_colors[index][j] * 1) palette.append(color) bio_explorer.set_protein_color_scheme( assembly_name=name, name=name + '_' + bio_explorer.NAME_PROTEIN_S_OPEN, color_scheme=bio_explorer.COLOR_SCHEME_REGION, palette=palette) # Display glycosylation sites if show_glycosylation_sites: palette = sns.color_palette('Set2', 2) bio_explorer.set_protein_color_scheme( assembly_name=name, name=name + '_' + bio_explorer.NAME_PROTEIN_S_OPEN, color_scheme=bio_explorer.COLOR_SCHEME_GLYCOSYLATION_SITE, palette=palette) bio_explorer.set_protein_color_scheme( assembly_name=name, name=name + '_' + bio_explorer.NAME_PROTEIN_S_CLOSED, color_scheme=bio_explorer.COLOR_SCHEME_GLYCOSYLATION_SITE, palette=palette) # Set rendering settings bio_explorer.core_api().set_renderer( background_color=[96 / 255, 125 / 255, 139 / 255], current='bio_explorer', samples_per_pixel=1, subsampling=4, max_accum_frames=64) params = bio_explorer.core_api().BioExplorerRendererParams() params.shadows = 0.75 params.soft_shadows = 1.0 bio_explorer.core_api().set_renderer_params(params) # Restore image streaming bio_explorer.core_api().set_application_parameters(image_stream_fps=20)
class LowGlucoseScenario(): def __init__(self, hostname, port, projection, output_folder, image_k=4, image_samples_per_pixel=64, log_level=1, shaders=list(['bio_explorer'])): self._log_level = log_level self._hostname = hostname self._url = hostname + ':' + str(port) self._be = BioExplorer(self._url) self._core = self._be.core_api() self._image_size = [1920, 1080] self._image_samples_per_pixel = image_samples_per_pixel self._image_projection = projection self._image_output_folder = output_folder self._shaders = shaders self._prepare_movie(projection, image_k) self._log(1, '================================================================================') self._log(1, '- Version : ' + self._be.version()) self._log(1, '- URL : ' + self._url) self._log(1, '- Projection : ' + projection) self._log(1, '- Frame size : ' + str(self._image_size)) self._log(1, '- Export folder : ' + self._image_output_folder) self._log(1, '- Samples per pixel: ' + str(self._image_samples_per_pixel)) self._log(1, '================================================================================') def _log(self, level, message): if level <= self._log_level: print('[' + str(datetime.now()) + '] ' + message) def _get_transformation(self, start_frame, end_frame, frame, data): '''Progress''' progress = (frame - start_frame) * 1.0 / (end_frame - start_frame) progress = max(0.0, progress) progress = min(1.0, progress) '''Position''' start_pos = data[0].to_list() end_pos = data[2].to_list() pos = start_pos for i in range(3): pos[i] += (end_pos[i] - start_pos[i]) * progress '''Rotation''' start_rot = data[1] end_rot = data[3] rot = Quaternion.slerp(start_rot, end_rot, progress) if data[4] == ROTATION_MODE_SINUSOIDAL: rot = Quaternion.slerp(start_rot, end_rot, math.cos((progress - 0.5) * math.pi)) return [Vector3(pos[0], pos[1], pos[2]), rot, progress * 100.0] def _add_viruses(self, frame): virus_radii = [45.0, 44.0, 45.0, 43.0, 44.0] virus_sequences = [ [[0, 2599], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6]], [[0, 2599], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6]], [[0, 2599], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6]], [[0, 2999], [3000, 3099], [3100, 3299], [3300, 3750], [1e6, 1e6], [1e6, 1e6]], [[0, 599], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1e6, 1e6], [1600, 3750]], ] virus_flights_in = [ [Vector3(-35.0, 300.0, -70.0), Quaternion(0.519, 0.671, 0.528, -0.036), Vector3(-5.0, 45.0, -33.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], [Vector3(153.0, 300.0, -200.0), Quaternion(0.456, 0.129, -0.185, -0.860), Vector3(73.0, 93.0, -130.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # Virus used for SP-D zoom [Vector3(-100.0, 300.0, 20.0), Quaternion(0.087, 0.971, -0.147, -0.161), Vector3(-79.0, 108.0, 80.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # Virus getting inside cell [Vector3(224.9, 300.0, -220.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(211.5, -104.9, -339.2), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # Virus used for detailed view of the Spike [Vector3(200.0, 20.0, -150.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(200.0, 20.0, -150.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR] ] virus_flights_out = [ # Unused [Vector3(-5.0, 45.0, -33.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(-105.0, 45.0, -33.0), Quaternion(0.0, 1.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # Unused [Vector3(73.0, 93.0, -130.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(-33.0, 93.0, -130.0), Quaternion(0.0, 0.0, 1.0, 0.0), ROTATION_MODE_LINEAR], # Virus used for SP-D zoom [Vector3(-84.0, 110.0, 75.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(-100.0, -100.0, 51.2), Quaternion(0.087, 0.971, -0.147, -0.161), ROTATION_MODE_LINEAR], # Unused [Vector3(0.0, 0.0, 0.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # Virus used for detailed view of the Spike [Vector3(200.0, 20.0, -150.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(300.0, -100.0, -100.0), Quaternion(0.456, 0.129, -0.185, -0.860), ROTATION_MODE_LINEAR] ] for virus_index in range(len(virus_sequences)): name = 'Coronavirus ' + str(virus_index) current_sequence = 0 sequences = virus_sequences[virus_index] for i in range(len(sequences)): if frame >= sequences[i][0]: current_sequence = i '''Initialize position and rotation to end-of-flight values''' start_frame = sequences[current_sequence][0] end_frame = sequences[current_sequence][1] progress_in_sequence = (frame - start_frame) / (end_frame - start_frame) morphing_step = 0.0 if current_sequence == 0: '''Flying''' pos, rot, progress = self._get_transformation(start_frame, end_frame, frame, virus_flights_in[virus_index]) self._log(3, '- Virus %d is flying in... (%.01f pct)' % (virus_index, progress)) elif current_sequence == 1: '''Landing''' pos = virus_flights_in[virus_index][2] rot = virus_flights_in[virus_index][3] pos.y -= landing_distance * progress_in_sequence self._log(3, '- Virus %d is landing...' % virus_index) elif current_sequence == 2: '''Merging into cell''' pos = virus_flights_in[virus_index][2] rot = virus_flights_in[virus_index][3] morphing_step = (frame - start_frame) / (end_frame - start_frame) pos.y -= landing_distance self._log(3, '- Virus %d is merging in (%.01f pct)' % (virus_index, morphing_step * 100.0)) elif current_sequence == 3: '''Inside cell''' self._log(3, '- Virus %d is inside cell' % virus_index) '''Virus is not added to the scene''' self._be.remove_assembly(name=name) continue elif current_sequence == 4: '''Merging out of cell''' pos = virus_flights_out[virus_index][0] rot = virus_flights_out[virus_index][1] morphing_step = 1.0 - (frame - start_frame) / (end_frame - start_frame) self._log(3, '- Virus %d is merging out (%.01f pct)' % (virus_index, morphing_step * 100.0)) else: '''Flying out''' pos, rot, progress = self._get_transformation(start_frame, end_frame, frame, virus_flights_out[virus_index]) self._log(3, '- Virus %d is flying out... (%.01f pct)' % (virus_index, progress)) if False: self._be.add_sphere(name=name, position=pos, radius=virus_radii[virus_index]) else: self._be.add_coronavirus( name=name, resource_folder=resource_folder, representation=protein_representation, position=pos, rotation=rot, add_glycans=add_glycans, assembly_params=[virus_radii[virus_index], 5 * frame + 2 * virus_index, 0.25, frame + 2 * virus_index + 1, 0.1, morphing_step] ) def _add_cell(self, frame): name = 'Cell' nb_receptors = cell_nb_receptors size = scene_size * 2.0 height = scene_size / 10.0 position = Vector3(4.5, -186.0, 7.0) random_seed = 10 nb_lipids = cell_nb_lipids ace2_receptor = Protein( sources=[pdb_folder + '6m18.pdb'], occurences=nb_receptors, position=Vector3(0.0, 6.0, 0.0)) membrane = ParametricMembrane( sources=[ membrane_folder + 'segA.pdb', membrane_folder + 'segB.pdb', membrane_folder + 'segC.pdb', membrane_folder + 'segD.pdb' ], occurences=cell_nb_lipids ) cell = Cell( name=name, size=size, extra_parameters=[height], shape=BioExplorer.ASSEMBLY_SHAPE_SINUSOIDAL, membrane=membrane, receptor=ace2_receptor, random_position_seed=frame + 1, random_position_strength=0.025, random_rotation_seed=frame + 2, random_rotation_strength=0.2 ) self._be.add_cell( cell=cell, position=position, representation=protein_representation, random_seed=random_seed) '''Modify receptor position when attached virus enters the cell''' receptors_instances = [37] receptors_sequences = [[3000, 3099]] for i in range(len(receptors_instances)): instance_index = receptors_instances[i] sequence = receptors_sequences[i] start_frame = sequence[0] end_frame = sequence[1] if frame >= start_frame: if frame > end_frame: '''Send receptor to outter space''' status = self._be.set_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index, position=Vector3(0.0, 1e6, 0.0) ) else: '''Current receptor transformation''' transformation = self._be.get_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index ) p = transformation['position'].split(',') q = transformation['rotation'].split(',') pos = Vector3(float(p[0]), float(p[1]), float(p[2])) q2 = Quaternion(float(q[0]), float(q[1]), float(q[2]), float(q[3])) '''Bend receptor''' progress = (frame - start_frame) * 1.0 / (end_frame - start_frame) q1 = Quaternion(axis=[0, 1, 0], angle=math.pi * progress) rot = q2 * q1 pos.x += landing_distance * progress * 0.3 pos.y -= landing_distance * progress * 0.3 status = self._be.set_protein_instance_transformation( assembly_name=name, name=name + '_' + BioExplorer.NAME_RECEPTOR, instance_index=instance_index, position=pos, rotation=rot ) '''Glycans''' if nb_receptors != 0 and add_glycans: self._be.add_multiple_glycans( representation=glycan_representation, assembly_name=name, glycan_type=BioExplorer.NAME_GLYCAN_COMPLEX, protein_name=BioExplorer.NAME_RECEPTOR, paths=complex_paths, indices=[53, 90, 103, 322, 432, 690], assembly_params=[0, 0, 0.0, frame + 3, 0.2] ) self._be.add_multiple_glycans( representation=glycan_representation, assembly_name=name, glycan_type=BioExplorer.NAME_GLYCAN_HYBRID, protein_name=BioExplorer.NAME_RECEPTOR, paths=hybrid_paths, indices=[546], assembly_params=[0, 0, 0.0, frame + 4, 0.2]) indices = [[155, Quaternion(0.707, 0.0, 0.707, 0.0)], [730, Quaternion(0.707, 0.0, 0.707, 0.0)]] count = 0 for index in indices: o_glycan_name = name + '_' + BioExplorer.NAME_GLYCAN_O_GLYCAN + '_' + str(index[0]) o_glycan = Sugars( assembly_name=name, name=o_glycan_name, source=o_glycan_paths[0], protein_name=name + '_' + BioExplorer.NAME_RECEPTOR, representation=glycan_representation, chain_ids=[2, 4], site_indices=[index[0]], rotation=index[1], assembly_params=[0, 0, 0.0, frame + count + 5, 0.2]) self._be.add_sugars(o_glycan) count += 1 def _add_surfactant_d(self, name, position, rotation, random_seed): surfactant_d = Surfactant( name=name, surfactant_protein=BioExplorer.SURFACTANT_PROTEIN_D, head_source=surfactant_head_source, branch_source=surfactant_branch_source) self._be.add_surfactant( surfactant=surfactant_d, representation=protein_representation, position=position, rotation=rotation, random_seed=random_seed) def _add_surfactant_a(self, name, position, rotation, random_seed): surfactant_a = Surfactant( name=name, surfactant_protein=BioExplorer.SURFACTANT_PROTEIN_A, head_source=surfactant_head_source, branch_source=surfactant_branch_source) self._be.add_surfactant( surfactant=surfactant_a, representation=protein_representation, position=position, rotation=rotation, random_seed=random_seed) def _add_surfactants_d(self, frame): spd_sequences = [[0, 3750], [0, 2600], [0, 2600], [0, 3750]] spd_random_seeds = [1, 1, 1, 2] spd_flights = [ [Vector3(300, 124.0, 0.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(74.0, 24.0, -45.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL], # SP-D is used for the head focus on 3rd virus spike [Vector3(-50, 250.0, 20.0), Quaternion(0.087, 0.971, -0.147, -0.161), Vector3(-11.0, 108.0, 20.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], # SP-D attaching to lymphocyte [Vector3(-200.0, 100.0, 100.0), Quaternion(0.519, 0.671, 0.528, -0.036), Vector3(-135.0, 135.0, 140.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_LINEAR], [Vector3(100.0, 0.0, -80.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(-260.0, 50.0, 150.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL] ] for surfactant_index in range(len(spd_sequences)): name = 'Surfactant-D ' + str(surfactant_index) sequence = spd_sequences[surfactant_index] pos, rot, progress = self._get_transformation( start_frame=sequence[0], end_frame=sequence[1], frame=frame, data=spd_flights[surfactant_index]) self._log(3, '- ' + name + ' (%.01f pct)' % progress) self._add_surfactant_d( name=name, position=pos, rotation=rot, random_seed=spd_random_seeds[surfactant_index]) def _add_surfactants_a(self, frame): spa_sequences = [[0, 3750]] spa_random_seeds = [2] spa_frames = [ [Vector3(300.0, -50.0, -50.0), Quaternion(-0.095, 0.652, -0.326, 0.677), Vector3(100.0, 50.0, 150.0), Quaternion(1.0, 0.0, 0.0, 0.0), ROTATION_MODE_SINUSOIDAL], ] for surfactant_index in range(len(spa_frames)): name = 'Surfactant-A ' + str(surfactant_index) sequence = spa_sequences[surfactant_index] pos, rot, progress = self._get_transformation( start_frame=sequence[0], end_frame=sequence[1], frame=frame, data=spa_frames[surfactant_index]) self._log(3, '- ' + name + ' (%.01f pct)' % progress) self._add_surfactant_a( name=name, position=pos, rotation=rot, random_seed=spa_random_seeds[surfactant_index]) def _add_glucose(self, frame): glucose = Protein( sources=[glucose_path], load_non_polymer_chemicals=True, occurences=nb_glucoses) volume = Volume( name=BioExplorer.NAME_GLUCOSE, size=scene_size, protein=glucose, random_position_seed=frame + 20, random_position_stength=scene_size / 600.0, random_rotation_seed=frame + 21, random_rotation_stength=0.3 ) status = self._be.add_volume( volume=volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=100) def _add_lactoferrins(self, frame): lactoferrin = Protein( sources=[lactoferrin_path], load_non_polymer_chemicals=True, occurences=nb_lactoferrins) lactoferrins_volume = Volume( name=BioExplorer.NAME_LACTOFERRIN, size=scene_size, protein=lactoferrin, random_position_seed=frame + 30, random_position_stength=scene_size / 400.0, random_rotation_seed=frame + 31, random_rotation_stength=0.3 ) status = self._be.add_volume( volume=lactoferrins_volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=101) def _add_defensins(self, frame): defensin = Protein( sources=[defensin_path], load_non_polymer_chemicals=True, occurences=nb_defensins) defensins_volume = Volume( name=BioExplorer.NAME_DEFENSIN, size=scene_size, protein=defensin, random_position_seed=frame + 40, random_position_stength=scene_size / 400.0, random_rotation_seed=frame + 41, random_rotation_stength=0.3 ) status = self._be.add_volume( volume=defensins_volume, representation=protein_representation, position=Vector3(0.0, scene_size / 2.0 - 200.0, 0.0), random_seed=102) def _add_lymphocyte(self, frame): if frame < 1400: '''Lymphocyte is not in the field of view''' return '''Protein animation params''' params = [0, 0, 0.0, frame + 2, 0.2] clip_planes = [ [1.0, 0.0, 0.0, scene_size * 1.5 + 5], [-1.0, 0.0, 0.0, scene_size * 1.5 + 5], [0.0, 0.0, 1.0, scene_size + 5], [0.0, 0.0, -1.0, scene_size + 5] ] name = 'Emile' lymphocyte_sequence = [0, 3750] lymphocyte_frames = [Vector3(-2500.0, 100.0, 30.0), Quaternion(1.0, 0.0, 0.0, 0.0), Vector3(-830.0, 100.0, 30.0), Quaternion(0.707, 0.707, 0.0, 0.0), ROTATION_MODE_LINEAR] protein_sources = [ membrane_folder + 'segA.pdb', membrane_folder + 'segB.pdb', membrane_folder + 'segC.pdb', membrane_folder + 'segD.pdb' ] mesh_based_membrane = MeshBasedMembrane( mesh_source=lymphocyte_path, protein_sources=protein_sources, density=lymphocyte_density, surface_variable_offset=lymphocyte_surface_variable_offset, assembly_params=params ) pos, rot, progress = self._get_transformation( start_frame=lymphocyte_sequence[0], end_frame=lymphocyte_sequence[1], frame=frame, data=lymphocyte_frames) self._log(3, '- ' + name + ' (%.01f pct)' % progress) scale = Vector3(1.0, 1.0, 1.0) status = self._be.add_mesh_based_membrane( name, mesh_based_membrane, position=pos, rotation=rot, scale=scale, clipping_planes=clip_planes ) for i in range(len(protein_sources)): status = self._be.set_protein_color_scheme( assembly_name=name, name=BioExplorer.NAME_MEMBRANE + '_' + str(i), color_scheme=BioExplorer.COLOR_SCHEME_CHAINS, palette_name='OrRd', palette_size=5) def _set_materials(self): '''Default materials''' self._be.apply_default_color_scheme( shading_mode=BioExplorer.SHADING_MODE_DIFFUSE, specular_exponent=50.0) def _create_snapshot(self, shader, frame, movie_maker): samples_per_pixel = self._image_samples_per_pixel '''Renderer''' if shader == 'albedo': self._core.set_renderer(current='albedo') elif shader == 'ambient_occlusion': self._core.set_renderer( current='ambient_occlusion', samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = self._core.AmbientOcclusionRendererParams() params.samplesPerFrame = 32 params.rayLength = 5.0 self._core.set_renderer_params(params) samples_per_pixel = 4 elif shader == 'depth': status = self._core.set_renderer( current='depth', samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = status = self._core.DepthRendererParams() params.infinity = 2000.0 status = self._core.set_renderer_params(params) samples_per_pixel = 2 elif shader == 'raycast_Ns': status = self._core.set_renderer( current='raycast_Ns', samples_per_pixel=1, subsampling=1, max_accum_frames=1) samples_per_pixel = 2 else: status = self._core.set_renderer( background_color=[96 / 255, 125 / 255, 139 / 255], current='bio_explorer', head_light=False, samples_per_pixel=1, subsampling=1, max_accum_frames=1) params = self._core.BioExplorerRendererParams() params.exposure = 1.0 params.gi_samples = 1 params.gi_weight = 0.3 params.gi_distance = 5000 params.shadows = 0.8 params.soft_shadows = 0.05 params.fog_start = 1000 params.fog_thickness = 300 params.max_bounces = 1 params.use_hardware_randomizer = True status = self._core.set_renderer_params(params) samples_per_pixel = self._image_samples_per_pixel '''Lights''' status = self._core.clear_lights() status = self._core.add_light_directional( angularDiameter=0.5, color=[1, 1, 1], direction=[-0.7, -0.4, -1], intensity=1.0, is_visible=False ) movie_maker.create_snapshot( size=self._image_size, path=self._image_output_folder + '/' + shader, base_name='%05d' % frame, samples_per_pixel=samples_per_pixel) '''Camera''' status = self._core.set_camera(current='bio_explorer_perspective') def _build_frame(self, frame): self._log(2, '- Resetting scene...') self._be.reset() self._log(2, '- Building surfactants...') self._add_surfactants_d(frame) self._add_surfactants_a(frame) self._log(2, '- Building glucose...') self._add_glucose(frame) self._log(2, '- Building lactoferrins...') self._add_lactoferrins(frame) self._log(2, '- Building defensins...') self._add_defensins(frame) self._log(2, '- Building viruses...') self._add_viruses(frame) self._log(2, '- Building cell...') self._add_cell(frame) self._log(2, '- Building lymphocyte...') self._add_lymphocyte(frame) self._log(2, '- Setting materials...') self._set_materials() self._log(2, '- Showing models...') status = self._be.set_models_visibility(True) status = self._core.set_renderer() def _make_export_folder(self, folder): import os path = self._image_output_folder + '/' + folder command_line = 'mkdir -p ' + path os.system(command_line) command_line = 'ls ' + path if os.system(command_line) != 0: self._log(3, 'ERROR: Failed to create folder ' + path) def _make_export_folders(self): for folder in self._shaders: self._make_export_folder(folder) def _prepare_movie(self, projection, image_k): if projection == 'perspective': aperture_ratio = 1.0 self._image_size = [image_k*960, image_k*540] self._core.set_camera(current='bio_explorer_perspective') elif projection == 'fisheye': self._image_size = [int(image_k*1024), int(image_k*1024)] self._core.set_camera(current='fisheye') elif projection == 'panoramic': self._image_size = [int(image_k*1024), int(image_k*1024)] self._core.set_camera(current='panoramic') elif projection == 'opendeck': self._image_size = [7*2160, 3840] self._core.set_camera(current='cylindric') self._image_output_folder = self._image_output_folder + '/' + \ projection + '/' + str(self._image_size[0]) + 'x' + str(self._image_size[1]) self._make_export_folders() def _set_clipping_planes(self): '''Clipping planes''' clip_planes = [ [1.0, 0.0, 0.0, scene_size * 1.5 + 5], [-1.0, 0.0, 0.0, scene_size * 1.5 + 5], [0.0, 0.0, 1.0, scene_size + 5], [0.0, 0.0, -1.0, scene_size + 5] ] cps = self._core.get_clip_planes() ids = list() if cps: for cp in cps: ids.append(cp['id']) self._core.remove_clip_planes(ids) for plane in clip_planes: self._core.add_clip_plane(plane) def render_movie(self, start_frame=0, end_frame=0, frame_step=1, frame_list=list()): '''Accelerate loading by not showing models as they are loaded''' status = self._be.set_general_settings(model_visibility_on_creation=False) aperture_ratio = 0.0 cameras_key_frames = [ { # Virus overview (on 5th virus) 'apertureRadius': aperture_ratio * 0.02, 'direction': [0.0, 0.0, -1.0], 'focusDistance': 139.56, 'origin': [199.840, 20.634, 34.664], 'up': [0.0, 1.0, 0.0] }, { # Protein S (on 5th virus) 'apertureRadius': aperture_ratio * 0.02, 'direction': [0.0, 0.0, -1.0], 'focusDistance': 23.60, 'origin': [195.937, 74.319, -111.767], 'up': [0.0, 1.0, 0.0] }, { # Protein M and E 'apertureRadius': aperture_ratio * 0.02, 'direction': [-0.047, -0.298, -0.953], 'focusDistance': 54.56, 'origin': [208.156, 55.792, -59.805], 'up': [0.003, 0.954, -0.298] }, { # Overview SPA 'apertureRadius': aperture_ratio * 0.001, 'direction': [-0.471, -0.006, -0.882], 'focusDistance': 444.63, 'origin': [238.163, 46.437, 372.585], 'up': [0.0, 1.0, 0.0] }, { # Overview SPD 'apertureRadius': aperture_ratio * 0.001, 'focusDistance': 444.63, 'direction': [-0.471, -0.005, -0.881], 'origin': [238.163, 46.436, 372.584], 'up': [0.0, 1.0, 0.0] }, { # Zoom SPD (on 3rd virus) 'apertureRadius': aperture_ratio * 0.02, 'focusDistance': 31.86, 'direction': [-0.821, 0.202, -0.533], 'origin': [-9.827, 110.720, 60.944], 'up': [0.178, 0.979, 0.098] }, { # Overview scene 'apertureRadius': aperture_ratio * 0.0, 'focusDistance': 1.0, 'direction': [-1.0, 0.0, 0.0], 'origin': [1008.957, 29.057, 113.283], 'up': [0.0, 1.0, 0.0] }, { # Cell view 'apertureRadius': aperture_ratio * 0.0, 'direction': [0.0, 0.0, -1.0], 'focusDistance': 1.0, 'origin': [150.0, -170.0, 400.0], 'up': [0.0, 1.0, 0.0] } ] '''Double the frames to make it smoother''' key_frames = list() for cameras_key_frame in cameras_key_frames: key_frames.append(cameras_key_frame) key_frames.append(cameras_key_frame) mm = MovieMaker(self._be) mm.build_camera_path(key_frames, 250, 150) self._log(1, '- Total number of frames: %d' % mm.get_nb_frames()) self._core.set_application_parameters(viewport=self._image_size) self._core.set_application_parameters(image_stream_fps=0) frames_to_render = list() if len(frame_list) != 0: frames_to_render = frame_list else: if end_frame == 0: end_frame = mm.get_nb_frames() for i in range(start_frame, end_frame + 1, frame_step): frames_to_render.append(i) cumulated_rendering_time = 0 nb_frames = len(frames_to_render) frame_count = 1 '''Clipping planes''' self._set_clipping_planes() '''Frames''' for frame in frames_to_render: try: start = time.time() self._log(1, '- Rendering frame %i (%i/%i)' % (frame, frame_count, nb_frames)) self._log(1, '------------------------------') '''Stop rendering during the loading of the scene''' status = self._core.set_renderer( samples_per_pixel=1, subsampling=1, max_accum_frames=1) '''Frame setup''' self._build_frame(frame) mm.set_current_frame( frame=frame, camera_params=self._core.BioExplorerPerspectiveCameraParams()) self._log(1, '- Frame buffers') for shader in self._shaders: '''Rendering settings''' self._log(2, '- ' + shader) self._create_snapshot(shader, frame, mm) end = time.time() rendering_time = end - start cumulated_rendering_time += rendering_time average_rendering_time = cumulated_rendering_time / frame_count remaining_rendering_time = (nb_frames - frame_count) * average_rendering_time self._log(1, '------------------------------') self._log(1, 'Frame %i successfully rendered in %i seconds' % (frame, rendering_time)) hours = math.floor(remaining_rendering_time / 3600) minutes = math.floor((remaining_rendering_time - hours * 3600) / 60) seconds = math.floor(remaining_rendering_time - hours * 3600 - minutes * 60) expected_end_time = datetime.now() + timedelta(seconds=remaining_rendering_time) self._log(1, 'Estimated remaining time: %i hours, %i minutes, %i seconds' % (hours, minutes, seconds)) self._log(1, 'Expected end time : %s' % expected_end_time) self._log( 1, '--------------------------------------------------------------------------------') frame_count += 1 except Exception as e: self._log(1, 'ERROR: Failed to render frame %i' % frame) self._log(1, str(e)) time.sleep(10) self._be = BioExplorer(self._url) self._core = self._be.core_api() mm = MovieMaker(self._be) self._core.set_application_parameters(image_stream_fps=20) self._log(1, 'Movie rendered, live long and prosper \V/')